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.
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.
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.
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.
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.
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.
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.
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.