2020 DistributionType ,
2121 GenericCharacteristicName ,
2222 ParametrizationName ,
23+ UnivariateContinuous ,
2324)
2425
2526if TYPE_CHECKING :
@@ -44,9 +45,14 @@ def transform_to_base_parametrization(self) -> ExponentialFamilyParametrization:
4445
4546
4647@dataclass
47- class ExponentialConjugateHyperparameters :
48- effective_suff_stat_value : NumberParameter
49- effective_sample_size : int
48+ class ExponentialConjugateHyperparameters (Parametrization ):
49+ effective_suff_stat_value : NumericArray
50+ effective_sample_size : Number
51+
52+ def transform_to_base_parametrization (self ) -> ExponentialFamilyParametrization :
53+ return ExponentialFamilyParametrization (
54+ np .append (self .effective_suff_stat_value , self .effective_sample_size )
55+ )
5056
5157
5258class ContinuousExponentialClassFamily (ParametricFamily ):
@@ -250,10 +256,10 @@ def func(parametrization: Parametrization, x: Any) -> Any:
250256 return func
251257
252258 def posterior_hyperparameters (
253- self , prior_hyper : ExponentialConjugateHyperparameters , sample : list [Any ]
259+ self , parametrizaiton : ExponentialConjugateHyperparameters , sample : list [Any ]
254260 ) -> ExponentialConjugateHyperparameters :
255- posterior_effective_suff_stat_value = prior_hyper .effective_suff_stat_value
256- posterior_effective_sample_size = prior_hyper .effective_sample_size
261+ posterior_effective_suff_stat_value = parametrizaiton .effective_suff_stat_value
262+ posterior_effective_sample_size = parametrizaiton .effective_sample_size
257263 if hasattr (sample , "__iter__" ) and not isinstance (sample , str ):
258264 posterior_effective_suff_stat_value += np .sum (
259265 [self ._sufficient (x ) for x in sample ], # type: ignore[arg-type]
@@ -268,3 +274,36 @@ def posterior_hyperparameters(
268274 effective_suff_stat_value = posterior_effective_suff_stat_value ,
269275 effective_sample_size = posterior_effective_sample_size ,
270276 )
277+
278+ @property
279+ def posterior_predictive (self ) -> ParametricFamily :
280+ def conjugate_log_partition (
281+ parametrization : ExponentialConjugateHyperparameters ,
282+ ) -> NumberParameter :
283+ conjugate_value = self .conjugate_prior_family ._log_partition (
284+ parametrization .transform_to_base_parametrization ().theta
285+ )
286+ return np .exp (conjugate_value )
287+
288+ def posterior_density (parametrization : Parametrization , x : NumberParameter ) -> Number :
289+ parametrization = cast (ExponentialConjugateHyperparameters , parametrization )
290+ return cast (
291+ np .float32 ,
292+ self ._normalization (x )
293+ * conjugate_log_partition (parametrization )
294+ / conjugate_log_partition (
295+ self .posterior_hyperparameters (
296+ parametrizaiton = parametrization , sample = [self ._sufficient (x )]
297+ )
298+ ),
299+ )
300+
301+ family = ParametricFamily (
302+ name = f"PosteriorPredictive{ self .name } " ,
303+ distr_type = UnivariateContinuous ,
304+ distr_characteristics = {CharacteristicName .PDF : posterior_density },
305+ distr_parametrizations = ["posterior" ],
306+ support_by_parametrization = lambda _ : ContinuousSupport (),
307+ )
308+ parametrization (family = family , name = "posterior" )(ExponentialConjugateHyperparameters )
309+ return family
0 commit comments