mixle.ppl.vmp module

Variational Message Passing (VMP) engine for mixle.ppl.

A real message-passing engine for conjugate-exponential (Gaussian-Gamma) models (Winn & Bishop, 2005): each unobserved node carries a variational factor q in an exponential family, holds its natural parameters, and exchanges messages with the factors it touches —

node posterior natural params = prior natural params + sum of incoming factor messages

Coordinate ascent updates each node from the others’ expected sufficient statistics; the ELBO is computed each sweep and increases monotonically.

The graph is built from a model by object identity: the same RandomVariable handle used in multiple positions becomes ONE node that combines messages from every factor touching it (parameter tying / shared latents). Priors that are themselves handles become parent nodes — hierarchies of any depth. Use Graph directly for multi-factor models, or fit(how="vmp") which auto-builds a single-factor graph.

class MeanConst(v)[source]

Bases: object

ex()[source]
ex2()[source]
class PrecConst(v)[source]

Bases: object

et()[source]
elogt()[source]
class GaussianVNode(prior_mean, prior_prec)[source]

Bases: object

Node q(x) = Normal(m, s2); prior Normal(prior_mean, 1/prior_prec) where prior_mean may be another node (hierarchy). inbox holds message thunks from the factors / children touching this node — the mechanism behind sharing.

is_gaussian = True
ex()[source]
ex2()[source]
update()[source]
entropy()[source]
cross_prior()[source]
class GammaVNode(a0, b0)[source]

Bases: object

Node q(t) = Gamma(a, b) over a precision.

is_gaussian = False
et()[source]
elogt()[source]
update()[source]
entropy()[source]
cross_prior()[source]
class DirichletVNode(alpha0)[source]

Bases: object

Node q(pi) = Dirichlet(alpha) over a simplex (categorical probabilities).

is_gaussian = False
expected()[source]
expected_log()[source]
update()[source]
entropy()[source]
cross_prior()[source]
class GraphResult(node_of, elbo_trace)[source]

Bases: object

posterior(rv)[source]
samples(rv, n=4000, rng=None)[source]
Parameters:

n (int)

class Graph[source]

Bases: object

A VMP factor graph for arbitrary conjugate-Gaussian DAGs with shared variables.

mu = Normal(0, 10) # one shared latent handle fit = (Graph()

.observe(Normal(mu, 1.0), data_a) # factor A uses mu .observe(Normal(mu, 2.0), data_b) # factor B uses the SAME mu .fit())

fit.posterior(mu) # evidence from A and B combined

A prior that is itself a RandomVariable becomes a parent node (hierarchy, any depth). A Gamma in a scale slot is read as a prior on the precision (the conjugate choice).

observe(model, data)[source]
Return type:

Graph

fit(*, max_its=300, tol=1e-8)[source]
Parameters:
Return type:

GraphResult

vmp_fit(rv, data, *, max_its=300, tol=1e-8, rng=None)[source]

Auto-build a single-factor VMP graph for a nested Gaussian model and fit it.

Handles Normal(mean, scale) where mean is a (possibly deeply nested) Normal prior chain and scale is a constant sd or a Gamma prior on the precision — e.g. Normal(Normal(0,10), Gamma(1,1)) (unknown mean + precision) or Normal(Normal(Normal(0,100), 5), 1) (mean with a hyperprior). For multi-factor models or shared variables across datasets, use Graph directly.

Parameters:
  • rv (RandomVariable)

  • max_its (int)

  • tol (float)

Return type:

RandomVariable

class MixtureVMPResult(weights, comps, responsibilities, elbo_trace, normalizer_trace)[source]

Bases: object

summary()[source]
mixture_vmp(data, K, *, max_its=300, tol=1e-7, rng=None, m0=None, s0=None, a0=1.0, b0=1.0, alpha0=1.0)[source]

Bayesian Gaussian mixture by variational message passing (VBEM).