mixle.ppl.core module¶
Core of the mixle.ppl probabilistic-programming surface.
One immutable wrapper type, RandomVariable, sits over mixle’s existing
distribution / estimator / sampler objects. It adds no inference engine: every call
lowers (one routing site, lower()) to machinery that already exists and then
dispatches. See notes/ppl-syntax-spec.md for the design charter and invariants.
Slice 1-2 of the build order: the wrapper + free holes + fit (EM core).
Algebra, conditioning, latent-arg Compound, and MCMC routing land in later slices.
- class RandomVariable(kind, *, family=None, args=(), name=None, keys=None, dist=None, result=None, scope='shared', reparam=None)[source]
Bases:
objectThe single user-facing PPL type (immutable).
Two states:
sample(a symbolic draw: a family + argument expressions, some of which may befree) andbound(wraps a concrete fitted distribution). The verb surface is fixed and state-independent (invariant I3); validity depends on state. Construct via the family functions inmixle.pplorfit.- Parameters:
result (PosteriorResult | None)
- property certificate
The estimation certificate, when a fit attached one (penalized fits downgrade honestly; E2).
- each(by=None)[source]
Mark this prior as per-group (a random effect / local latent). Used in a parameter slot:
Normal(Normal(m, t).each(), s)is a hierarchical model.Two data layouts are supported:
nested –
each()with no argument:.fit(groups)wheregroupsis a list of per-group observation lists (one list per group).indexed-flat –
each(by="g"):.fit(y, given={"g": labels})whereyis one flat observation array andlabels[i]is observationi’s group. This is the varying-intercepts / 8-schools idiom; groups are taken in sorted order of the unique labels.
- Parameters:
by (str | None)
- Return type:
RandomVariable
- noncentered()[source]
Sample this location-scale prior in non-centered form (offset/multiplier).
For
mu = Normal(loc, scale)with a randomscale(a hierarchical prior), the centered parameterization couplesmu’s range toscaleand creates Neal’s funnel – a geometry HMC/NUTS samples badly.Normal(loc, scale).noncentered()instead samples a standard normalzand setsmu = loc + scale * z, whose geometry is independent ofscale. Mathematically identical posterior, far better mixing (fewer divergences) when the data are weakly informative. Applies toNormalpriors; a no-op marker on others.- Return type:
RandomVariable
- property scope: str
- exp()[source]
- Return type:
RandomVariable
- log()[source]
- Return type:
RandomVariable
- eq(other)[source]
- ne(other)[source]
- given(constraint)[source]
Condition this RV on a constraint over itself (e.g.
x.given(x > 0)-> truncation). The result samples by rejection and scores with the renormalized density. For relations among several RVs (a < b) useconstrain(...).- Return type:
RandomVariable
- property is_bound: bool
- property has_free: bool
- property columns: list
the variable names, in sample-column order. A vector-valued variable expands to one name per entry (
v[0],v[1], …).- Type:
For a
constrain(...)joint RV
- property dist
The lowered concrete distribution — the full original mixle API (escape hatch).
- property components
Fitted sub-models of a composite (mixture components, HMM state emissions, sequence element) as RandomVariables — query each with the same verbs (
.params,.sample,.log_prob). Raises for non-composite models.
- property params
Fitted parameters in the same parameterization used to construct the model (e.g.
{'mean': 5.0, 'sd': 2.0}for Normal — not the internalsigma2). Falls back to.distfor families without a registered reader.
- property result: PosteriorResult | None
Inference metadata (EM history / MCMC chain) when present; else None.
- log_prob(x)[source]
- log_likelihood(data)[source]
Total log-likelihood of
dataunder the fitted model (sum of log_prob).- Return type:
- aic(data, k=None)[source]
Akaike information criterion (lower is better).
kdefaults to a heuristic parameter count from.params.
- bic(data, k=None)[source]
Bayesian information criterion (lower is better).
- pointwise_log_likelihood(data)[source]
Return the
(n_draws, n_obs)log-likelihood matrix used by WAIC / PSIS-LOO.For a Bayesian fit (
how='mcmc'|'hmc'|'ensemble'|'vi') each row is the log-likelihood of the data under one posterior draw; for a point-estimate fit it is a single row.- Return type:
- waic(data)[source]
Widely Applicable Information Criterion from the posterior (lower
waicis better).Returns
{elpd_waic, p_waic, waic, se, n_draws, pointwise}. Estimates out-of-sample predictive accuracy by integrating over parameter uncertainty – the Bayesian analogue ofaic/bic– and falls back to a point estimate for non-Bayesian fits.- Return type:
- loo(data)[source]
Pareto-Smoothed Importance-Sampling Leave-One-Out cross-validation (lower
loobetter).Returns
{elpd_loo, p_loo, loo, se, khat_max, n_draws, pointwise}.khat_maxabove ~0.7 signals an unreliable estimate (refit with more posterior draws or preferwaic).- Return type:
- summary()[source]
Posterior summary of a Bayesian fit, or the fitted params for a point estimate.
For
how='mcmc'|'hmc'|'ensemble'|'vi'returns a per-parameter dict of{mean, std, q2.5, q97.5}(the 95% credible interval) plus_acceptance_rateand, for multi-chain runs,_rhat/_ess/_n_chains. Formap/emit returns.params.
- mean(samples=20000, seed=0)[source]
Expected value of the random variable (Monte-Carlo; works for any RV — concrete, transformed, convolved, or conditioned). For a joint
constrain(...)RV this is the per-variable mean vector.
- var(samples=20000, seed=0)[source]
Variance of the random variable (Monte-Carlo); per-variable for a joint RV.
- prob(samples=40000, seed=999)[source]
Probability that the relation holds (Monte-Carlo), for a
constrain(...)RV.
- prob_of_event()[source]
P(event) under the base distribution (Monte-Carlo), for a conditioned RV.
- predict(n=1, rng=None)[source]
Posterior-predictive draws. For a Bayesian fit (conjugate/mcmc/hmc) this integrates over parameter uncertainty (draw params from the posterior, then data); for a point fit (EM/MAP) it is the plug-in predictive (sample from the fitted distribution).
- Parameters:
n (int)
- posterior(x)[source]
Posterior over a latent or a parameter.
posterior(data)-> latent-state posterior (the E-step; e.g. mixture responsibilities), routed to the lowered distribution’sseq_posterior.posterior(handle | name | index)-> parameter posterior draws, when this RV was fit withhow='mcmc'(read from.result).
- explain_fit(*, how='auto', constraints=None, potentials=None, **_)[source]
Report which inference route
.fit(how=...)will take, and why – without fitting.Returns
{'route', 'reason', 'caveats'}. This is the teaching surface for mixle’s automatic cross-family inference selection:rv.explain_fit()answers “how will this be fit, and what are the honest limits of that choice?”. The route mirrorsfit()exactly (it shares_resolve_auto()for the flat tree and re-checks the same structural short-circuits).- Return type:
- fit(data, *, how='auto', max_its=100, delta=1e-8, backend='local', num_workers=None, engine=None, precision=None, print_iter=0, missing='error', **kw)[source]
Estimate / infer parameters from
dataand return a bound RV.how:'em'(EM/MLE, default for plainfreemodels),'map'(maximize the joint with priors),'mcmc'(posterior samples over parameters with priors),'auto'picksmapwhen the model has priors elseem. EM threads mixle’s parallel/distributed backends (backend='mp'|'mpi'|'dask').missing:'error'(default) rejects non-finite entries;'marginalize'integrates a missing entry (NaNin the data) out of the likelihood instead of imputing it – each leaf is fit from its present rows only, so you get a well-defined mode/posterior over the present data (no fabricated values). Supported on the EM path (the default forfreemodels, i.e. the posterior mode under flat priors); forhow='map'/'mcmc'with missing data build the model withmixle.stats.marginalized()leaves directly.
- lower(rv, *, target='dist')[source]
The one routing site: symbolic RandomVariable -> existing mixle object.
target='dist'returns a concrete*Distribution(needs nofreeholes);target='estimator'returns a*Estimator. Results are cached per RV (I7).- Parameters:
rv (RandomVariable)
target (str)
- register_family(name, dist_cls, est_cls, to_dist, arity, seed_at=None, positive=None, init_fit=None, read=None, support=None)[source]
- Return type:
Family
- class Family(name, dist_cls, est_cls, to_dist, arity, seed_at=None, positive=None, init_fit=None, read=None, support=None)[source]
Bases:
objectLowering recipe for one distribution family.
Keeps the alias namespace and the engine objects in one place so the wrapper never hard-codes a distribution.
to_distmaps user-facing (conventional) arguments to the underlying*Distributionkwargs;make_estimatorbuilds the paired*Estimatorfor the all-freecase.- name
- dist_cls
- est_cls
- to_dist
- arity
- seed_at
- positive
- support
- init_fit
- read
- class Constraint(leaves, pred, desc, residual=None, soft=False)[source]
Bases:
objectA boolean relation over one or more random variables.
Produced by comparisons on RVs —
x > 0(RV vs constant),a < b(RV vs RV), or2 * a - b >= 1(linear/transformed expressions on either side) — and combined with&(and),|(or),~(not). A constraint over a single RV is consumed byrv.given(c)(truncation); a constraint over several RVs is consumed byconstrain(c)(joint conditioning) orfit(..., constraints=c)(feasible region).leavesare the distinct leaf RVs the relation depends on;pred(env)evaluates the relation givenenv, a dict mapping each leaf RV to its value(s).- leaves
- pred
- desc
- residual
- soft
- property rv
The single RV this constraint restricts (back-compat for one-variable events).
- eval(env)[source]
- contains(x)[source]
Evaluate a single-variable constraint directly on that variable’s value(s).
- Event
alias of
Constraint
- constrain(*constraints)[source]
A joint random variable formed by conditioning several RVs on a relation among them.
constrain(a < b)is the pair(a, b)restricted toa < b; pass several constraints (or combine with& | ~) for richer regions, e.g.constrain(a < b, b < c)orders three variables. The result samples by joint rejection and answers.sample(n)(an(n, k)array, columns in.columnsorder),.mean()/.var()(per-variable),.prob()(probability the relation holds), and.log_prob(x)(renormalized joint density of the independent variables on the region).- Return type:
RandomVariable
- eq(lhs, rhs)[source]
Build an equality relation
lhs == rhsover RVs/expressions/constants.==is not overloaded onRandomVariable(RVs are used as dict keys by identity), so build equalities with this function orrv.eq(...). Equalities have measure zero and cannot be honored by rejection, so consume them with the soft-penalty inference path, e.g.model.fit(data, constraints=eq(a + b, 1.0), penalty=100.0).- Return type:
Constraint
- equal(lhs, rhs)
Build an equality relation
lhs == rhsover RVs/expressions/constants.==is not overloaded onRandomVariable(RVs are used as dict keys by identity), so build equalities with this function orrv.eq(...). Equalities have measure zero and cannot be honored by rejection, so consume them with the soft-penalty inference path, e.g.model.fit(data, constraints=eq(a + b, 1.0), penalty=100.0).- Return type:
Constraint
- ne(lhs, rhs)[source]
Build an inequality relation
lhs != rhs(boolean only; no smooth penalty surface).- Return type:
Constraint
- increasing(v, *, strict=False)[source]
The entries of a vector RV/expression are non-decreasing (
strict-> strictly increasing).- Parameters:
strict (bool)
- Return type:
Constraint
- decreasing(v, *, strict=False)[source]
The entries of a vector RV/expression are non-increasing (
strict-> strictly decreasing).- Parameters:
strict (bool)
- Return type:
Constraint
- monotone(v)[source]
The entries are monotone — non-decreasing or non-increasing.
- Return type:
Constraint
- convex(v)[source]
The entries are convex: the second difference is non-negative everywhere.
- Return type:
Constraint
- concave(v)[source]
The entries are concave: the second difference is non-positive everywhere.
- Return type:
Constraint
- lipschitz(v, bound)[source]
Bounded first difference:
|v[i+1] - v[i]| <= bound(a discrete smoothness constraint).- Parameters:
bound (float)
- Return type:
Constraint
- ode_residual(v, f, dt=1.0, *, tol=1e-2)[source]
A differential-equation constraint:
v(a function sampled on a uniform grid of spacingdt) satisfiesdv/dt = f(v). The signed residualdiff(v)/dt - f(v[:-1])feeds the soft-penalty inference path —fit(..., constraints=ode_residual(y, f), penalty=w)fits a physics-informed curve. Like an equality it is measure-zero, so consume it withpenalty=rather than by rejection.