mixle.stats.bayes.conjugate module

Conjugate-prior posterior inference, derived from the exponential-family map.

Every exponential-family likelihood p(x | eta) = h(x) exp(<eta, T(x)> - A(eta)) has a conjugate prior p(eta | chi, nu) propto exp(<eta, chi> - nu A(eta)); after observing data the posterior is simply

chi’ = chi + sum_i T(x_i), nu’ = nu + n.

This module realises that posterior in closed form, full-Bayesian terms for every exponential-family leaf that has a tractable conjugate – exact parameter samples, marginal likelihood (evidence), posterior mean / point estimate, and a posterior predictive:

  • fully (all parameters): Gaussian, multivariate & diagonal Gaussian, LogGaussian, Poisson, Exponential, Bernoulli/Binomial/Geometric, Categorical, Rayleigh, half-normal;

  • conditional on the distribution’s known nuisance parameter (shape / location / scale / number-of-trials / concentration, taken from the instance exactly as a Binomial’s n is): Gamma, InverseGamma, InverseGaussian, Pareto, NegativeBinomial, von Mises.

Likelihoods with no tractable closed-form conjugate (full Beta, full Gamma, LogSeries, …) and structured distributions (mixtures, HMMs, …) raise rather than return a partial answer. mixture_conjugate_posterior() extends this to priors that are themselves mixtures of conjugates (Diaconis-Ylvisaker). The public entry point is conjugate_posterior().

class ConjugatePosterior[source]

Bases: object

Base class for a closed-form conjugate posterior over a likelihood’s parameters.

Subclasses provide the family-specific hyperparameters and the four capabilities: mean (the posterior mean of the parameters), sample (exact draws of the parameters), point_estimate (a fitted distribution at the posterior mean), log_marginal_likelihood (the evidence of the observed data under the prior), and posterior_predictive (the distribution of a new draw).

family: str = 'conjugate'
log_base: float = 0.0
mean()[source]
Return type:

dict[str, Any]

sample(n=1, rng=None)[source]
Parameters:
Return type:

dict[str, ndarray]

sampler(seed=None)[source]

Return a sampler exposing the standard obj.sampler(seed).sample(size) API.

Mirrors the distribution sampling convention so conjugate posteriors read the same way as every other mixle object; here each draw is a parameter set from the posterior. size=None returns one parameter set (scalars), size=n a dict of length-n arrays. The explicit-rng form sample(n, rng) remains available.

Parameters:

seed (int | None)

Return type:

ConjugatePosteriorSampler

point_estimate()[source]
log_marginal_likelihood()[source]
Return type:

float

posterior_predictive()[source]
summary()[source]
Return type:

dict[str, Any]

hyper()[source]
Return type:

dict[str, Any]

class ConjugatePosteriorSampler(posterior, seed=None)[source]

Bases: object

Standard .sample(size) adapter over a ConjugatePosterior (draws parameter sets).

Parameters:
  • posterior (ConjugatePosterior)

  • seed (int | None)

sample(size=None)[source]
Parameters:

size (int | None)

Return type:

dict[str, Any]

class MixtureConjugatePosterior(components, post_weights, prior_weights, comp_log_evidence)[source]

Bases: ConjugatePosterior

Posterior under a prior that is itself a mixture of conjugate priors.

Diaconis-Ylvisaker (1979): if the prior is sum_m w_m * pi_m(theta) with each pi_m conjugate to the likelihood, the posterior is again a mixture of the component conjugate posteriors, sum_m w'_m * pi_m^post(theta), with the mixing weights reweighted by each component’s marginal likelihood Z_m:

w’_m proportional to w_m * Z_m.

Everything stays closed-form, so a prior can be multimodal (e.g. “the rate is near 1 OR near 10”) or robust (a heavy-tailed prior as a mixture of conjugates) without losing exact inference.

Parameters:

components (list[ConjugatePosterior])

family: str = 'MixtureOfConjugates'
components: list[ConjugatePosterior]
mean()[source]
Return type:

dict[str, Any]

sample(n=1, rng=None)[source]
Parameters:
Return type:

dict[str, ndarray]

point_estimate()[source]

The maximum-a-posteriori component’s point estimate (the dominant conjugate mode).

posterior_predictive()[source]

A mixle MixtureDistribution of the component predictives, weighted by the posterior weights.

log_marginal_likelihood()[source]
Return type:

float

hyper()[source]
Return type:

dict[str, Any]

conjugate_posterior(dist, data, prior=None, weights=None)[source]

Closed-form conjugate posterior over the parameters of dist given data.

Every supported family returns a closed-form, full-Bayesian posterior: exact parameter samples, marginal likelihood, posterior mean / point estimate, and a posterior predictive. For families with a multi-parameter likelihood whose conjugate is conditional (Gamma, InverseGamma, InverseGaussian, Pareto, NegativeBinomial, vonMises), the non-target parameter (shape / location / scale / number-of-trials / concentration) is taken as known from dist – exactly as a Binomial’s number of trials is. Families with no closed-form conjugate (full Beta, full Gamma, LogSeries, …) raise a clear error rather than returning a partial answer.

Parameters:
  • dist – A mixle likelihood distribution instance whose type selects the conjugate family.

  • data – A sequence of observations of the kind dist scores.

  • prior (dict | None) – Optional dict of conjugate-prior hyperparameters (family specific). None uses a weak proper prior.

  • weights (ndarray | None) – Optional per-observation weights (e.g. EM responsibilities).

Returns:

A ConjugatePosterior exposing mean, sample, point_estimate, log_marginal_likelihood, posterior_predictive and summary.

Return type:

ConjugatePosterior

mixture_conjugate_posterior(dist, data, priors, prior_weights=None, weights=None)[source]

Posterior under a prior that is a mixture of conjugate priors (Diaconis-Ylvisaker).

Parameters:
  • dist – The likelihood distribution (must map to a closed-form conjugate realiser, since the reweighting needs each component’s marginal likelihood).

  • data – The observations.

  • priors (list[dict]) – One hyperparameter dict per mixture component (same keys conjugate_posterior() accepts for this family).

  • prior_weights (ndarray | None) – Prior mixing weights w_m (default uniform); normalised internally.

  • weights (ndarray | None) – Optional per-observation weights.

Returns:

the exact posterior, again a mixture of conjugate posteriors with weights w'_m proportional to w_m * Z_m.

Return type:

A MixtureConjugatePosterior

is_conjugate_family(dist)[source]

Return whether dist (instance or type) has a closed-form conjugate posterior.

Single source of truth: membership in the conjugate_posterior builder registry. This is the family-level capability — “can this distribution be updated in closed form?” — distinct from the instance-level has_conj_prior flag (whether a conjugate prior is currently attached for the MAP path). Backs mixle.capability.ConjugateUpdatable and ProbabilityDistribution.has_conjugate_prior().

Parameters:

dist (Any)

Return type:

bool