mixle.stats.compute.pdist module

Defines abstract classes for SequenceEncodableProbabilityDistribution, SequenceEncodableStatisticAccumulator, ProbabilityDistribution, StatisticAccumulator, StatisticAccumulatorFactory, DataSequenceEncoder, ParameterEstimator, ConditionalSampler, and DistributionSampler for classes of the mixle.stats.

class DensitySemantics(*values)[source]

Bases: Enum

What a distribution’s log_density returns relative to the true log-density.

The default contract is EXACT; override density_semantics() on models whose log_density is a variational bound or an approximation, so callers can tell an exact likelihood from one (e.g. LDA’s per-document ELBO). Surfaced via the ExactDensity capability and describe.

EXACT = 'exact'
LOWER_BOUND = 'lower_bound'
UPPER_BOUND = 'upper_bound'
ESTIMATE = 'estimate'
join_density_semantics(semantics)[source]

Combine child density semantics for a combinator whose log_density is monotone in its children.

A combinator whose score rises with each child’s log_density – a mixture’s logsumexp, a composite’s sum – inherits: a lower bound if any child is a lower bound, an upper bound if any is an upper bound, exactness only if all children are exact, and an undirected ESTIMATE if bounds of both directions (or any estimate) are mixed.

Return type:

DensitySemantics

exception EnumerationError(dist, path='', reason='')[source]

Bases: NotImplementedError

Raised when a distribution (or a child of a combinator) cannot enumerate its support.

The path argument identifies the offending child within a combinator, e.g. ‘CompositeDistribution.dists[1]’.

Parameters:
Return type:

None

exception KeyValidationError[source]

Bases: ValueError

Raised when keyed sufficient-statistic sites are incompatible.

A key denotes an equality constraint across model sites. Sites sharing a key must therefore have the same accumulator family and compatible estimator settings before their sufficient statistics are pooled.

child_enumerator(child, path)[source]

Construct child.enumerator(), annotating EnumerationError with the child’s path.

Combinator enumerators use this so a failure deep in a nested model reports the full path to the offending leaf, e.g. ‘CompositeDistribution.dists[1] -> MixtureDistribution.components[0] -> GaussianDistribution …’.

Parameters:
  • child (ProbabilityDistribution)

  • path (str)

Return type:

DistributionEnumerator

class ProbabilityDistribution[source]

Bases: ABC

Base class for all probability distributions in mixle.stats.

A distribution evaluates the (log-)density of a single observation of its data type, creates a DistributionSampler for drawing observations, and creates a ParameterEstimator for re-estimating itself from data. Discrete distributions may additionally provide a DistributionEnumerator over their support.

to_dict()[source]

Return a safe JSON-compatible representation of this distribution.

Return type:

dict[str, Any]

classmethod from_dict(payload)[source]

Reconstruct a distribution from to_dict output.

Parameters:

payload (dict[str, Any])

Return type:

ProbabilityDistribution

to_json(**kwargs)[source]

Serialize this distribution as safe strict JSON.

Parameters:

kwargs (Any)

Return type:

str

classmethod from_json(text)[source]

Deserialize a distribution from to_json output.

Parameters:

text (str)

Return type:

ProbabilityDistribution

density(x)[source]

Return the probability density or mass at a single observation.

Concrete default: exponentiate log_density (the abstract method subclasses must provide). Leaves with a cheaper closed form may override this.

Parameters:

x (Any)

Return type:

float

capabilities()[source]

Return the capability names this distribution supports (see mixle.capability).

Feature detection by behaviour rather than class — e.g. "Enumerable", "Conditionable", "ExponentialFamily", "RankableByIndex". Equivalent to mixle.capabilities(self); combinators report the set their children jointly preserve.

Return type:

frozenset[str]

density_semantics()[source]

What log_density returns relative to the true log-density (default: exact).

Override to declare that this distribution’s log_density is a variational lower bound (ELBO), an upper bound, or an approximation rather than the exact log p(x). This is surfaced as the ExactDensity capability and noted in mixle.describe(), so code that needs an exact likelihood can require(x, ExactDensity) instead of silently trusting a bound.

Return type:

DensitySemantics

tropical_displacement_bits()[source]

Worst-case gap (in bits) between this law’s structural count cost and its true log-density.

The structural count-DP (and the seek built on it) bins each value by a cost that is EXACT for decomposable families – composites/sequences/markov chains whose log p(x) is a sum of independent per-factor terms – so this returns 0.0 by default.

For a marginal family the latent index is summed out and the count index bins by the tropical (dominant-component/path) cost M(x) instead of the true log p(x). Because M(x) <= log p(x) <= M(x) + log N for an N-way logsumexp, the two costs differ by at most log2(N) bits. mixle.enumeration.density_rank.marginal_seek() widens its rank bracket by exactly this many bits so the bracket is a guaranteed bound on the true marginal rank (not merely the tropical rank); override to return log2(N) for such a family.

Return type:

float

abstractmethod log_density(x)[source]

Return the log-density or log-mass at a single observation.

Parameters:

x (Any)

Return type:

float

abstractmethod sampler(seed=None)[source]

Return a sampler for drawing observations from this distribution.

Parameters:

seed (int | None)

Return type:

DistributionSampler

abstractmethod estimator(pseudo_count=None)[source]

Return an estimator for fitting this distribution from data.

Parameters:

pseudo_count (float | None)

Return type:

ParameterEstimator

to_fisher(**kwargs)[source]

Return a Fisher-geometry view of this distribution.

The default view is accumulator-backed, so distributions inherit a generic sufficient-statistic/Fisher-vector interface. Each distribution owns its Fisher view by overriding this method in its own module; families not yet migrated to a per-file hook are resolved by the transitional type-name dispatch in mixle.inference.fisher._legacy_to_fisher().

to_exponential_family(engine=None)[source]

Return the canonical exponential-family view, or None.

The canonical form is p(x) = h(x) * exp(<eta, T(x)> - A(eta)). The default reads declaration_for(self).exponential_family (the per-family ExponentialFamilySpec) and wraps it in an ExponentialFamilyForm; it returns None when this family is not a (single) exponential family. There is no type switch – adding a family is a matter of providing its spec.

Parameters:

engine (Any)

get_prior()[source]

Return the conjugate/parameter prior carried by this distribution, if any.

A distribution participates in the Bayesian (variational) protocol by carrying a prior over its parameters. The default returns whatever was stored on the prior attribute (None for a plain point model), so frequentist distributions answer None and behave as MLE models.

Return type:

ProbabilityDistribution | None

set_prior(prior)[source]

Attach a parameter prior to this distribution.

The default just records the prior; conjugate families override this to precompute the variational expected natural parameters used by expected_log_density.

Parameters:

prior (ProbabilityDistribution | None)

Return type:

None

has_conjugate_prior()[source]

Return whether this family supports a closed-form conjugate Bayesian update.

Uniform, family-level signal backed by the single conjugate_posterior registry: True means mixle.stats.bayes.conjugate_posterior(self, data) returns an exact closed-form posterior; False means Bayesian inference must go through the numerical fitters (MAP / Laplace / MCMC / VI). This is the top tier of the inference-capability ladder (see mixle.capability.ConjugateUpdatable). Distinct from the per-instance has_conj_prior flag, which records whether a prior is currently attached.

Return type:

bool

expected_log_density(x)[source]

Return the variational expectation E_q[log p(x | theta)].

When the distribution carries a conjugate parameter posterior q this is the Bayesian E-step term; for a plain point model (no prior) it degenerates to the plug-in log_density(x). Conjugate families override this with their closed form.

Parameters:

x (Any)

Return type:

float

enumerator()[source]

Return a DistributionEnumerator over this distribution’s support.

Distributions with an enumerable (discrete) support override this; the default raises EnumerationError.

Return type:

DistributionEnumerator

support_size()[source]

Return the number of distinct support points, or None if infinite/unknown.

This is the cardinality primitive for bounding a truncated descending-probability sum: after enumerating the top k items (whose smallest probability is p_k), every un-enumerated item has probability <= p_k, so the remaining mass is <= (support_size - k) * p_k (see mixle.enumeration.density_rank.truncated_sum_bound()). Finite discrete leaves return their cardinality; decomposable combinators compose it structurally; an upper bound is acceptable (it only loosens the tail bound). Infinite or continuous supports return None.

Return type:

int | None

support_is_finite()[source]

Return whether the support has a known finite cardinality.

Return type:

bool

quantized_index(max_bits, bin_width_bits=1.0)[source]

Build a bounded bit-quantized index over this distribution’s support.

This is a convenience wrapper around self.enumerator().quantized_index. Non-enumerable distributions raise EnumerationError through enumerator().

Parameters:
  • max_bits (float) – Maximum information content in bits to index.

  • bin_width_bits (float) – Width of each quantized probability bin in bits.

Returns:

mixle.enumeration.algorithms.QuantizedEnumerationIndex.

density_quantile(q, n_samples=20000, seed=None)[source]

Return a representative value at cumulative-density index q (descending-density order).

The arbitrary-index / inverse of the probability-ordered cumulative that mixle.enumeration.density_rank.density_rank() computes (G(x) = P(p(Y) >= p(x))): q = 0 is the mode, q -> 1 walks into the tail. Families with a closed form override this (univariate continuous leaves expose the spatial quantile; multivariate Gaussians and von Mises-Fisher override density_quantile exactly); the default here is the universal Monte-Carlo representative for any samplable family whose support is uncountable or coupled (parameter priors, continuous mixtures, …): draw n_samples points, order them by descending density, and return the one at fractional rank q. Stochastic and approximate – use the exact methods (enumerator/count_dp_seek for discrete) where available.

Parameters:
  • q (float) – Cumulative-density index in [0, 1].

  • n_samples (int) – Monte-Carlo sample budget.

  • seed (Optional[int]) – Sampler seed (reproducible).

Return type:

Any

density_enumeration(num_points, n_samples=20000, seed=None)[source]

Return num_points representative (value, log_density) pairs in descending density.

The continuous analogue of enumerator() (which enumerates a countable support exactly): for an uncountable or coupled support there is no exact element enumeration, so this returns a Monte-Carlo representative sweep – n_samples draws ordered by descending density, keeping the num_points most probable (distinct) representatives, i.e. “the support, most-probable region first”. Stochastic and approximate; prefer enumerator() where the support is countable.

Parameters:
  • num_points (int) – Number of representatives to return.

  • n_samples (int) – Monte-Carlo sample budget.

  • seed (Optional[int]) – Sampler seed (reproducible).

Return type:

list[tuple[Any, float]]

quantized_count_index(quantizer, max_fine_bucket)[source]

Build a structural CountIndex over this distribution’s support, bounded by depth.

This is the count-semiring counterpart of quantized_index: it returns per-fine-bucket counts of the complete model probability together with a structural unranker, so the support can be indexed without being enumerated. The default builds a leaf index from the exact enumerator() truncated at max_fine_bucket (cheap for closed-form/small-support families); exponential-support composers (Composite/Sequence/MarkovChain) override this with a dynamic program over the model’s likelihood recursion.

Parameters:
  • quantizer (mixle.enumeration.quantization.Quantizer) – Fine/coarse bucketing.

  • max_fine_bucket (int) – Inclusive depth bound on indexed fine buckets.

Returns:

Tuple (CountIndex, truncated) – truncated is True when in-support values were dropped because they fell beyond the depth bound.

count_budget_index(budget_bits, bin_width_bits=1.0, oversample=8, num_workers=None)[source]

Build a budget-bounded quantized seek index covering the top 2**budget_bits values.

Computes per-bin counts structurally (never enumerating the domain) and accumulates coarse bins in descending-probability order until the cumulative count reaches the budget. The returned LazyQuantizedEnumerationIndex supports arbitrary-rank seek/unranking; each unranked value carries its exact log_density.

Parameters:
  • budget_bits (float) – Index into the top 2**budget_bits most probable values.

  • bin_width_bits (float) – Coarse output bin width in bits.

  • oversample (int) – Fine buckets per coarse bin (accumulation resolution).

  • num_workers (int | None)

Returns:

mixle.enumeration.algorithms.LazyQuantizedEnumerationIndex.

count_budget_distinct(budget_bits, bin_width_bits=1.0, oversample=8, dedup='canonical', start=0, stop=None, max_entries=1 << 16, num_workers=None)[source]

Iterate DISTINCT (value, exact_log_prob) over the count-budget index, approx descending.

For exact-count families this equals the ordered index stream. For the over-counting MARGINAL families (Mixture/HMM) it removes the component/path duplicates by one of two modes:

  • dedup='canonical' (default): a STATELESS predicate (is_canonical_copy) keeps a value only at its dominant copy (best-weighted component / min-cost path), via the value’s structural fine bucket (structural_fine_bucket – the SAME sum-of-floored sub-buckets the count index used, so nested composite/sequence values are binned consistently and never dropped). O(1) memory and random-accessible: start/stop select an arbitrary STRUCTURAL rank range, so you can begin anywhere and the work partitions across workers with no shared state. GUARANTEE: every distinct in-budget value is emitted at least once (completeness). It is NOT strictly once – a value is emitted once per component/path that ties within its minimal 1-bit coarse bin; that residue is inherent to a stateless (value, coarse_bin) rule (the tied copies are indistinguishable to it) and is bounded by the number of components/contributing paths (not reduced by oversample, which only refines the intermediate fine bucket). For a strictly-once stream, use dedup='window' or de-duplicate downstream.

  • dedup='window': a bounded max_entries LRU over the stream (catches every duplicate within the window regardless of dominance, but is sequential – start must be 0).

Note: start/stop index the STRUCTURAL enumeration, not the distinct rank. Jumping to the k-th distinct value in O(1) is not possible – it needs exact distinct per-bin counts, which require materializing the component/path overlap structure.

Parameters:
  • budget_bits (float)

  • bin_width_bits (float)

  • oversample (int)

  • dedup (str)

  • start (int)

  • stop (int | None)

  • max_entries (int)

  • num_workers (int | None)

is_canonical_copy(value, coarse_bin, quantizer)[source]

Return True if coarse_bin is value’s dominant (canonical) bin in the count index.

Stateless deduplication hook for the over-counting MARGINAL families: a value that the structural index emits once per component / state-path is kept only at the copy whose bin is the minimal (most probable) one. The default returns True – exact-count families (Composite/Sequence/MarkovChain) never duplicate, so every copy is canonical.

Parameters:

coarse_bin (int)

Return type:

bool

structural_fine_bucket(value, quantizer)[source]

Minimum fine bucket where value is placed by this distribution’s count index.

Mirrors quantized_count_index exactly so that stateless canonical-copy dedup can predict the bucket the index actually used. The count DP bins a composite/nested value by a SUM of floored per-factor buckets (a convolution), which differs from a single floor of the exact joint log-density by up to the number of factors – so a canonical check that used fine_bucket(log_density(value)) would mispredict and silently drop nested values. The leaf default is that single floor (correct for atomic families); combinators (Composite/Sequence/Mixture) override to recurse the same way their count index composes.

Return type:

int

quantized_multi_cross_index(others, max_bits, bin_width_bits=1.0)[source]

Build an aligned bounded cross-bin view against other distributions.

The generic implementation is a bounded candidate join: it unions the bounded quantized indexes of all participating distributions, then evaluates every candidate under every distribution. Structured distributions can override this to build the same aligned rows from support algebra instead.

Parameters:
  • others (list[ProbabilityDistribution])

  • bin_width_bits (float)

quantized_cross_index(other, max_bits, bin_width_bits=1.0)[source]

Build an aligned bounded cross-bin view against another distribution.

Parameters:
  • other (ProbabilityDistribution)

  • bin_width_bits (float)

class SequenceEncodableProbabilityDistribution[source]

Bases: ProbabilityDistribution

ProbabilityDistribution with vectorized log-density evaluation on encoded data.

dist_to_encoder() returns a DataSequenceEncoder whose seq_encode() output is consumed by seq_log_density() (and by the matching accumulator’s seq_update / seq_initialize), enabling fast vectorized estimation over iid sequences.

engine_ready = ('numpy',)
supported_engines()[source]

Return engine names this distribution can evaluate on directly.

Return type:

tuple[str, …]

supports_engine(engine)[source]

Return True when the distribution can safely use engine.

Parameters:

engine (Any)

Return type:

bool

decomposition()[source]

Return how this distribution may be split across devices (model parallelism).

Defaults to Decomposition.atomic() – not split, replicated. Combinators / latent families override this to declare their component / factor / state axis. See mixle.stats.compute.decomposition.

Return type:

Decomposition

seq_ld_lambda()[source]

Return vectorized log-density callables for encoded data.

seq_log_density(x)[source]

Return vectorized log-density values for sequence-encoded observations.

Parameters:

x (Any)

Return type:

ndarray

seq_expected_log_density(x)[source]

Vectorized expected_log_density over sequence-encoded observations.

Degenerates to seq_log_density for a plain point model; conjugate families override with a closed form. See expected_log_density.

Parameters:

x (Any)

Return type:

ndarray

seq_log_density_lambda()[source]

Return vectorized log-density callables for encoded data.

kernel(engine=None, estimator=None)[source]

Return an engine-aware evaluation kernel for this distribution.

Parameters:

estimator (ParameterEstimator | None)

abstractmethod dist_to_encoder()[source]

Return the data encoder used by this distribution for vectorized methods.

Return type:

DataSequenceEncoder

class DistributionSampler(dist, seed=None, *, rng=None)[source]

Bases: ABC

Draws iid observations from a distribution using a seeded RandomState.

sample(size=None) returns a single observation of the distribution’s data type; sample(size=n) returns a length-n collection of observations.

Parameters:
  • dist (SequenceEncodableProbabilityDistribution)

  • seed (int | None)

  • rng (RandomState | None)

new_seed()[source]

Return a fresh random seed drawn from this sampler’s RandomState.

Return type:

int

abstractmethod sample(size=None, *, batched=True)[source]

Draw observations.

Combinator samplers (mixture/sequence/…) accept batched. With batched=True (the default) each child stream is drawn in one vectorized call instead of a per-draw Python loop – far faster. Because every child sampler owns an independent RandomState, batching consumes each stream in the same order as the loop, so the draws are identical to the legacy path. batched=False forces that legacy per-draw loop as a guaranteed- stable reference. Leaf samplers are already vectorized and ignore the flag.

Parameters:
Return type:

Any

class DistributionEnumerator(dist)[source]

Bases: ABC

Lazy iterator over the support of dist in non-increasing probability order.

Yields (value, log_prob) pairs, possibly infinitely many. Contract:
  • Each support value is yielded exactly once (deduplication is the enumerator’s responsibility).

  • log_prob equals dist.log_density(value) up to float round-off (~1e-10), and the sequence of log_probs is non-increasing up to the same tolerance.

  • Values with zero probability are skipped, never yielded.

  • Ties are broken deterministically by insertion order; no further guarantee.

Parameters:

dist (SequenceEncodableProbabilityDistribution)

top_k(k)[source]

Return the k most probable (value, log_prob) pairs (fewer if the support is smaller).

Parameters:

k (int)

Return type:

list[tuple[Any, float]]

top_p(p, max_items=None)[source]

Return the smallest descending-probability prefix whose total probability reaches p.

The nucleus / minimal high-probability set: because values are yielded in non-increasing probability order, the returned prefix is a minimum-size set of outcomes whose summed mass is >= p (e.g. p=0.95 gives a 95%-coverage support set – the discrete analogue of nucleus sampling). Accumulation stops as soon as the cumulative probability reaches p.

max_items caps how many values are pulled so an infinite or heavy-tailed support cannot run away; if the cap is hit before the threshold, the (sub-threshold) prefix gathered so far is returned. p >= 1.0 on an infinite support therefore requires max_items.

Parameters:
  • p (float) – Target cumulative probability; p <= 0 returns the empty set.

  • max_items (Optional[int]) – Hard cap on the number of values pulled.

Returns:

List of (value, log_prob) pairs in non-increasing probability order.

Return type:

list[tuple[Any, float]]

quantized_index(max_bits, bin_width_bits=1.0)[source]

Precompute a bounded bit-quantized index over this enumeration.

The index groups values by floor((-log2 p(x)) / bin_width_bits), includes only values with -log2 p(x) <= max_bits, and returns exact log probabilities for indexed values. Building the index consumes this enumerator.

Parameters:
  • max_bits (float) – Maximum information content in bits to index.

  • bin_width_bits (float) – Width of each quantized probability bin in bits.

Returns:

mixle.enumeration.algorithms.QuantizedEnumerationIndex.

rank(value)[source]

Rank and cumulative probability of value in the descending-probability order.

Returns a DensityRankResult with .rank (0-based count of strictly-more-probable outcomes; None if only the sampling estimate was used) and .cumulative_probability (G(value) = P(p(Y) >= p(value))). Exact head enumeration where the support is countable, with a Monte-Carlo fallback for the deep tail.

Parameters:

value (Any)

seek(index)[source]

The value at descending-probability index (0-based) – the inverse of rank().

Returns a CountDPSeekResult carrying the value and a provable [rank_lower, rank_upper] bracket. Uses the structural count-DP for decomposable families, so arbitrarily deep indices are reachable without enumerating the prefix.

Parameters:

index (int)

seek_certified(index)[source]

The value at descending index with a GUARANTEED bracket on its TRUE marginal rank.

Unlike seek() – whose bracket bounds only the tropical rank for a marginal family (mixture/HMM) – this widens the rank window by the family’s tropical_displacement_bits and divides out the component over-count, so the returned MarginalSeekResult [true_rank_lower, true_rank_upper] provably contains #{u : log p(u) > log p(value)}. It pins the rank exactly (.exact) for decomposable / provably-disjoint families and for shallow indices, and otherwise returns the honest provable envelope. For a decomposable family it agrees with seek().

Parameters:

index (int)

cumulative(value)[source]

G(value) = P(p(Y) >= p(value)) – total mass of outcomes at least as probable as value.

Parameters:

value (Any)

nucleus_size(p)[source]

Size of top_p() (the minimal >= p-mass set) WITHOUT materializing it.

Returns a CountDPTopPResult with a provable size bracket, from the structural count-DP – usable when the nucleus is far too large to list.

Parameters:

p (float)

from_index(start, stop=None)[source]

Iterate (value, log_prob) in descending-probability order starting at structural start.

Yields the same stream as iterating a fresh enumerator but beginning at index start (and ending before stop if given). A fresh underlying enumeration is used, so this does not consume self. (Decomposable families admit a direct structural jump via the count-budget index; the current implementation skips the best-first prefix – the structural fast path is a WS-3 performance follow-up.)

Parameters:
  • start (int)

  • stop (int | None)

class ConditionalSampler[source]

Bases: ABC

Sampler mixin for conditional draws: sample_given(x) draws from P(. | x).

abstractmethod sample_given(x)[source]
class StatisticAccumulator[source]

Bases: ABC, Generic[SS]

Accumulates weighted sufficient statistics of type SS from observations.

update(x, weight, estimate) adds one observation (estimate is the previous model, used for E-step posteriors; it may be None during initialization). Accumulators merge across partitions via combine(suff_stat) / value() / from_value(), and key_merge / key_replace pool statistics shared across model components through a stats_dict keyed by the accumulator’s key.

update(x, weight, estimate)[source]
Parameters:
Return type:

None

initialize(x, weight, rng)[source]
Parameters:
Return type:

None

abstractmethod combine(suff_stat)[source]
Parameters:

suff_stat (SS)

Return type:

StatisticAccumulator

abstractmethod value()[source]
Return type:

SS

abstractmethod from_value(x)[source]
Parameters:

x (SS)

Return type:

SequenceEncodableStatisticAccumulator

scale(c)[source]

Scale linear sufficient statistics in-place by c.

The structural default is correct for ordinary weighted sums, nested tuples/lists/dicts, and numeric arrays. Families whose value() payload includes non-linear metadata such as support bounds must override this method and leave that metadata unscaled.

Parameters:

c (float)

Return type:

StatisticAccumulator

key_merge(stats_dict)[source]

Pool this accumulator’s statistics into stats_dict under its merge key.

The structural default implements the common single-key pattern: store the accumulator under self.keys the first time the key is seen, else combine into the one already there. Accumulators with several named keys (e.g. an HMM’s init/trans/state keys) or a non-accumulator stats payload override this. A keys of None (the default) is a no-op.

Parameters:

stats_dict (dict[str, Any])

Return type:

None

key_replace(stats_dict)[source]

Replace this accumulator’s statistics from the pooled stats_dict entry (see key_merge).

Parameters:

stats_dict (dict[str, Any])

Return type:

None

class SequenceEncodableStatisticAccumulator[source]

Bases: StatisticAccumulator[SS]

StatisticAccumulator with vectorized updates on encoded data sequences.

seq_update / seq_initialize consume the output of the matching DataSequenceEncoder’s seq_encode() (obtained via acc_to_encoder()) together with a per-observation weight vector.

get_seq_lambda()[source]
abstractmethod seq_update(x, weights, estimate)[source]
Parameters:

weights (ndarray)

Return type:

None

abstractmethod seq_initialize(x, weights, rng)[source]
Parameters:
Return type:

None

abstractmethod acc_to_encoder()[source]
Return type:

DataSequenceEncoder

scale_suff_stat(x, c)[source]

Return x with numeric sufficient-statistic leaves multiplied by c.

Parameters:
Return type:

Any

class StatisticAccumulatorFactory[source]

Bases: ABC

Factory whose make() returns a fresh, zeroed accumulator for one estimator.

abstractmethod make()[source]
Return type:

SequenceEncodableStatisticAccumulator

class ParameterEstimator[source]

Bases: ABC, Generic[SS]

Estimates a distribution from accumulated sufficient statistics.

accumulator_factory() supplies accumulators that gather sufficient statistics of type SS, and estimate(nobs, suff_stat) maps those statistics (plus optional regularization configured on the estimator) to a new distribution.

to_dict()[source]

Return a safe JSON-compatible representation of this estimator.

Return type:

dict[str, Any]

classmethod from_dict(payload)[source]

Reconstruct an estimator from to_dict output.

Parameters:

payload (dict[str, Any])

Return type:

ParameterEstimator

to_json(**kwargs)[source]

Serialize this estimator as safe strict JSON.

Parameters:

kwargs (Any)

Return type:

str

classmethod from_json(text)[source]

Deserialize an estimator from to_json output.

Parameters:

text (str)

Return type:

ParameterEstimator

abstractmethod estimate(nobs, suff_stat)[source]
Parameters:
  • nobs (float | None)

  • suff_stat (SS)

Return type:

SequenceEncodableProbabilityDistribution

abstractmethod accumulator_factory()[source]
Return type:

StatisticAccumulatorFactory

resident_accumulation_supported()[source]

Return whether engine-resident (fixed-width) sufficient statistics suffice for estimate.

Most exponential-family M-steps consume only the resident sufficient statistics, so the default is True. Estimators whose M-step needs more than that (e.g. a full count histogram for the negative-binomial dispersion solve) override this to False so stacked/generated kernels fall back to the host accumulator, keeping every backend’s fixed point identical.

Return type:

bool

get_prior()[source]

Return the parameter prior configured on this estimator, if any.

The unified estimation contract treats the prior as the single regularization concept: None gives maximum likelihood, a conjugate prior gives the Bayesian posterior update inside estimate. The default reads the prior attribute (None when unset).

Return type:

ProbabilityDistribution | None

model_log_density(model)[source]

Return the prior log-density of model’s parameters (the ELBO global term).

Used by the variational/MAP objective in fit. The default is 0.0 (no prior); conjugate estimators override this to evaluate their prior at the model’s parameters, mapping to the prior’s parameterization first.

Parameters:

model (ProbabilityDistribution)

Return type:

float

class DataSequenceEncoder[source]

Bases: ABC

Encodes an iid data sequence into the vectorized form used by seq_* methods.

seq_encode(x) transforms a sequence of observations into the encoding consumed by seq_log_density / seq_update / seq_initialize. Encoders must define __eq__ (so equivalent encoders are interchangeable when batching) and a readable __str__.

seq_encode(x)[source]

Encode the iid observation sequence x for vectorized evaluation.

Parameters:

x (Any)

Return type:

Any

nbytes(x)[source]

Return the approximate in-memory byte size of an encoded payload.

Parameters:

x (Any)

Return type:

int

encoded_nbytes(x)[source]

Return an approximate byte size for nested encoded array payloads.

Encoders mostly return arrays or tuples/lists/dicts of arrays. The helper keeps accounting structural and deterministic; Python object overhead is included only for scalar leaves where no array-native byte count exists.

Parameters:

x (Any)

Return type:

int

validate_estimator_keys(estimator)[source]

Validate keyed estimator and accumulator sites before EM folds stats.

The validator catches the classic keying footgun: two different families, or two sites with incompatible estimator settings, accidentally sharing the same key string. Validation is intentionally protocol-level and best-effort; a family can still perform stricter checks in its own factory if needed.

Parameters:

estimator (ParameterEstimator)

Return type:

None

validate_accumulator_keys(accumulator)[source]

Validate keyed sites in an already-created accumulator tree.

Parameters:

accumulator (StatisticAccumulator)

Return type:

None