Core Concepts¶
The central idea in mixle is not “many distributions.” It is that model
structure, data structure, and inference structure are the same object viewed
from three angles.
One Observation Is a Python Value¶
mixle does not require a flat matrix. One observation can be a scalar, a
tuple, a dictionary, a sequence, a graph-like object, or a neural training pair.
Observation |
Natural model shape |
|---|---|
|
scalar continuous distribution |
|
categorical distribution |
|
composite tuple distribution |
|
record distribution |
|
sequence distribution |
|
next-token distribution |
|
emission sequence with latent HMM states |
The fitted model scores that whole value with log_density(x). If the model
can sample, it samples values with the same shape.
Estimator Shape Mirrors Data Shape¶
The most important modeling move is to make the estimator look like one row of data.
from mixle.stats import CompositeEstimator, GammaEstimator, PoissonEstimator
# Observation: (count, wait)
est = CompositeEstimator((PoissonEstimator(), GammaEstimator()))
Combinators can be nested:
from mixle.stats import CategoricalEstimator, MixtureEstimator, SequenceEstimator
row = CompositeEstimator(
(
CategoricalEstimator(),
SequenceEstimator(PoissonEstimator(), len_estimator=CategoricalEstimator()),
)
)
clustered_rows = MixtureEstimator([row, row, row])
The estimator says three things at once:
what the observation looks like;
which distribution family fits each part;
which inference route is needed when the structure contains latents, neural leaves, priors, or constraints.
The Five Pieces¶
Each full distribution family is built from five cooperating pieces:
Piece |
Role |
|---|---|
|
Stores parameters and implements |
|
Draws observations from a fitted distribution. |
|
Declares the model shape and performs estimation. |
|
Collects mergeable sufficient statistics or training telemetry. |
|
Packs Python values into vectorized encoded data. |
That contract is what makes scale-out possible. Encoded data can be folded locally, on a multiprocessing backend, on Spark/Dask/MPI, or through a device engine while the model code remains the same.
What Happens During optimize¶
optimize(data, estimator) runs this outer loop:
choose an encoder;
encode raw Python observations;
initialize a candidate distribution;
accumulate evidence under the current distribution;
ask the estimator for an updated distribution;
repeat until convergence or
max_its.
Different structures specialize the same loop:
Structure |
What the loop means |
|---|---|
Closed-form leaves |
one or more maximum-likelihood or conjugate sufficient-statistic updates |
Mixtures |
E-step responsibilities, M-step component updates |
HMMs |
forward-backward expectations, emission and transition updates |
Neural leaves |
gradient M-step against weighted or streamed batches |
PPL expressions |
lowered estimator or target, then route selected by |
Task cascades |
fit local model, calibrate, decide answer versus escalation |
This is why mixle can fit heterogeneous records and latent structures without a new training loop for every combination. The child estimators do different work, but they present the same outer shape to the parent composite or latent model.
Distributions Are Query Objects¶
After fitting, stay on the distribution surface:
score = model.log_density(x)
samples = model.sampler(seed=0).sample(10)
encoder = model.dist_to_encoder()
Latent models add posterior queries:
responsibilities = mixture.posterior(rows)
path = hmm.viterbi(sequence)
Discrete and structured models may also support enumeration:
enum = dist.enumerator()
top = enum.top_k(10)
Capabilities, Not Class Checks¶
Ask what an object supports instead of guessing from its class:
import mixle
print(mixle.describe(model))
print(mixle.capabilities(model))
print(mixle.supports(model, mixle.capability.Enumerable))
Capabilities cover exact density, finite support, enumeration, ranking, conditioning, marginalization, latent posterior behavior, backend scoring, conjugate updates, and more.
See Capabilities And Contracts for the full capability catalog and the contracts used by distribution, estimator, accumulator, and encoder objects. See Compute Layer for the encoded-data and kernel machinery beneath the public distribution families.
Public Surfaces¶
Namespace |
Use it for |
|---|---|
|
distribution families, estimators, combinators, latent models |
|
fit loops, EM, priors, calibration, diagnostics, model comparison |
|
compact expression language that lowers to stats/inference objects |
|
incubating applied helpers: neural leaves, GPs, random forests, graphs |
|
LLM labeling, distillation, active learning, cascades, artifacts |
|
LLM uncertainty and cross-modal latent evidence fusion |
|
top-k, rank, seek, nucleus, and structured support traversal |
|
NumPy, Torch, JAX, symbolic, and precision-aware compute engines |
|
schemas, data sources, validation, hashes, encoded IO |
|
design of experiments, active labeling, optimization, sensitivity |
|
low-level contracts, encoded data, generated kernels, backend scoring |
|
automatic typing, serialization, optional dependencies, metrics, parallel runtime helpers |
The shortest practical advice is: start with mixle.stats when you know the
model, mixle.task.recommend_model when you want help choosing one,
mixle.ppl when the formula is clearer than the estimator tree, and
mixle.describe whenever you are unsure what the fitted object can do.