Model Lifecycle¶
mixle.Model is a convenience facade over the library’s main lifecycle:
propose a model, fit it, evaluate it, inspect it, query it, distill it, and
deploy it. It does not introduce a separate inference engine. It gives users one
place to stand while delegating to the same distribution, inference,
capability, task, and artifact systems used elsewhere.
Use it when a workflow needs a durable object with consistent verbs. Use the lower-level APIs directly when you are developing a new estimator, benchmarking an inference route, or controlling each E-step and M-step explicitly.
Basic Flow¶
import mixle
model = mixle.Model().fit(rows)
quality = model.evaluate(holdout)
samples = model.sample(5, seed=0)
explanation = model.explain()
print(quality["mean_log_density"])
print(explanation)
Model(spec=None) means “infer the estimator from data at fit time.” The
spec may also be an estimator or a prototype distribution:
from mixle.stats import GaussianEstimator, GaussianDistribution
from_estimator = mixle.Model(GaussianEstimator()).fit(values)
from_prototype = mixle.Model(GaussianDistribution(0.0, 1.0)).fit(values)
Fitting delegates to mixle.inference.optimize. Scoring, sampling,
enumeration, and posterior calls delegate to the fitted distribution.
The facade should not hide the fitted object. When a workflow depends on a
specific capability, inspect model.fitted with mixle.describe and store
the fitted distribution type in the artifact notes.
Certified Creation Alternative¶
Use mixle.inference.create when you want a fitted artifact plus explicit
post-conditions rather than a convenience lifecycle facade.
from mixle.inference import create
artifact = create(rows, calibrate=0.2, quantify_uq=True, seed=0)
print(artifact.certificate.table())
CreatedModel carries the fitted model, an estimation certificate, optional
calibration and UQ objects, and provenance. Model is still the shorter
interactive facade; create is the stronger artifact boundary.
Use create for release-like evidence when the certificate, calibration, or
provenance will be reviewed independently from the notebook that produced the
fit.
Proposal Frontier¶
mixle.propose builds a candidate frontier and returns a Model whose
spec is the best candidate:
proposed = mixle.propose(rows, fit=False)
for candidate in proposed.frontier:
print(candidate)
proposed.fit(rows)
The frontier can include:
recommend_modelfrommixle.taskfor dependency-aware structural recommendation;the plain automatic estimator from
mixle.utils.automatic.get_estimatoras an independence baseline;an LLM-designed model from
mixle.task.design_modelwhen an LLM handle is provided.
Each candidate is fit on a train split and scored on held-out data. Candidate
failures are reported in the frontier instead of being silently ignored. The
winning estimator becomes the model spec, while field-level recommendation
notes and dependency hints are stored in Model.notes.
Keep the full frontier when model selection matters. The rejected candidates and their failure notes explain why the chosen spec was accepted and prevent the proposal step from becoming an opaque recommendation.
Automatic Restart Guard¶
Latent-variable models can land on symmetric saddle points, especially mixtures
whose components start identical. Model.fit uses restarts="auto" by
default:
model = mixle.Model(mixture_estimator).fit(rows)
The fit first runs the ordinary route. If the fitted object exposes a posterior and components, Mixle checks whether every sampled observation has an almost uniform component posterior. When that pattern suggests a symmetric saddle, the model is refit with symmetry-breaking restarts and the better likelihood is kept. Notes record whether the automatic restart changed the result.
Pass an integer to force a number of restarts, or restarts=None to keep the
raw single fit.
For latent models, record whether the restart guard changed the result. A model that needed symmetry-breaking restarts should carry that fact into provenance.
Query Verbs¶
Once fitted, the lifecycle object exposes common distribution queries:
logp = model(x)
top = model.enumerate().top_k(10)
z = model.posterior(x)
forecast = model.forecast(history, horizon=7)
effect = model.do({"treatment": "on"})
parts = model.explain_prediction(x)
The available queries depend on the fitted model’s capabilities. A continuous
Gaussian will not enumerate. A mixture can expose posterior responsibilities. A
Bayesian network can answer interventions when the necessary graph structure is
available. Use mixle.describe(model.fitted) when you need to know what the
object supports.
Query verbs should preserve capability failures. If a fitted object cannot enumerate, condition, forecast, or answer an intervention, the lifecycle layer should report that limitation rather than inventing an unsupported answer.
Distillation¶
Model.distill routes into mixle.task.solve:
solution = model.distill(teacher, examples, seed=0)
answer = solution(new_input)
If teacher is omitted, the fitted model teaches from its latent posterior:
inputs are labeled by the most probable latent component. This turns a fitted
mixture into a calibrated local classifier of its own clusters.
The returned object is a task Solution. It answers locally when calibrated
and escalates to the teacher when it should not guess. See
Task Distillation and Task Serving, Routing, and Edge Deployment.
When latent posteriors become task labels, document that the labels are model-derived. They are useful for distillation, but they are not external ground truth unless a separate review validates them.
Deployment¶
Model.deploy writes a durable artifact directory:
path = model.deploy("artifacts/customer-regime-model")
restored = mixle.Model.load(path)
The artifact contains the fitted model and a manifest with family, creation time, fit metadata, notes, and artifact schema name. This is a lightweight lifecycle artifact, not a full model registry. For production registry, provenance, drift, and serving concepts, see Production Workflows.
Load the artifact in a fresh process before relying on it. A deploy directory that only works from the source checkout is not durable.
Reusable Skills¶
mixle.inference.skill wraps a fitted model, CreatedModel, or callable
as a named capability. A skill can be registered, searched by query, indexed
into a substrate, and used as a compute action by a reasoner.
from mixle.inference import SkillRegistry, skill
registry = SkillRegistry()
sk = skill(
"sample-customers",
model.fitted,
description="sample synthetic customer rows",
registry=registry,
)
print(registry.find("customer sample"))
Use skills when the fitted artifact becomes an application verb. Use
Model.deploy or Registry when the artifact is primarily a model
version.
When to Use Lower-Level APIs¶
Use the facade when:
you want a short path from raw data to a fitted, inspectable object;
you are building examples, notebooks, or application-level integrations;
you want proposal notes and held-out frontier scoring in one place;
the model lifecycle matters more than the exact optimizer steps.
Use lower-level APIs when:
you need a fixed estimator tree with no recommendation step;
you are controlling initialization, streaming updates, or restarts manually;
you are testing a new distribution family, capability, or backend;
you need explicit access to encoded data, accumulators, kernels, or engines.
Release Evidence¶
For lifecycle workflows, preserve:
fitted distribution type and capability report;
proposal frontier and rejected candidates when automatic proposal is used;
restart policy and whether it changed a latent fit;
held-out evaluation output;
artifact load smoke test from a fresh process; and
escalation or calibration evidence for distilled task solutions.