mixle.evolve.objective module¶
The measure contract for self-improvement: a model-agnostic fitness.
An Objective turns (model, data) into a single comparable scalar and, when it can, a
per-observation paired vector. The paired vector is what lets the verify gate
(mixle.evolve.verify) run a paired significance test instead of comparing two bare score
totals. Objectives that cannot produce a paired vector (a pure summary like a calibration-error
scalar) set pointwise to return None; the gate then falls back to a bare scalar-delta-vs-
min_effect comparison, with p_value/ci set to the explicit nan “not applicable”
sentinel – no bootstrap, replication, or other resampling evidence backs a raw scalar delta, so a
scalar-only verdict is reported for a human to review but can never auto-promote on its own (see
mixle.evolve.verify module docstring point 8 and
has_statistical_evidence).
Every builder here is a thin adapter over an existing, verified scorer:
nll_objective-> per-obs-log p(y_i)frommodel.seq_log_density.log_score_objective-> per-obs-log p(y_i)computed directly from the log-density (the same quantity asnll_objective, kept as a separate name for the decision-theoretic framing). Computed straight from the log-density, never viaexpthen re-logthroughmixle.inference.scoring.log_score()– that round trip underflows to0.0for any log-density past about-745, after which the clip-and-relog step can no longer tell two bad fits apart.crps_objective->mixle.inference.scoring.crps_ensemble()on a sampled ensemble.interval_objective->mixle.inference.scoring.interval_score()(Winkler) on ensemble quantiles.calibration_objective-> PIT-based calibration error (mixle.inference.calibration()), scalar-only.decision_regret_objective->mixle.inference.decision.bayes_action()’s chosen action, scored by realized loss against the actualdata– not the model’s own posterior draws.
The model-to-array bridges (encoding, per-obs log density, ensemble sampling) live in this module so the scorers stay pure array functions and the objectives stay five-line adapters.
- class Objective(*args, **kwargs)[source]
Bases:
ProtocolA lower-is-better-or-higher-with-a-flag scalar fitness with an optional paired vector.
- pointwise(model, data)[source]
The
(n,)per-observation score, orNoneif the objective is scalar-only.
- nll_objective()[source]
Negative log-likelihood: per-obs
-log p(y_i)(strictly proper, lower is better).- Return type:
Objective
- log_score_objective()[source]
Logarithmic score (log loss) of the predictive density at the realised outcomes.
Computed directly from the log-density (
-log p(y_i)), never by exponentiating the log-density to a plain probability and then re-deriving a log-scale score from it. That round trip is destructive:exp(x)underflows to exactly0.0for anyxbelow about-745(the float64 underflow boundary), so every log-density past that point becomes the identical clipped probability and hence the identical score, even though the underlying fits are genuinely – and very differently – bad. Working from the log-density keeps that information: float64 has ample range in log-space, just not in probability-space.- Return type:
Objective
- crps_objective(*, ensemble=256, seed=0)[source]
Continuous Ranked Probability Score from a sampled predictive ensemble (lower is better).
- interval_objective(level=0.9, *, ensemble=256, seed=0)[source]
Winkler interval score for the central
levelpredictive interval (lower is better).
- calibration_objective(*, ensemble=256, seed=0, bins=10)[source]
PIT calibration error of the predictive distribution (scalar-only, lower is better).
Uses the rank-based Probability Integral Transform of a sampled ensemble: under a calibrated continuous forecast the PIT values are Uniform(0, 1), and
pit_calibration_errormeasures the histogram’s mean absolute deviation from uniform. There is no per-observation paired vector for a histogram statistic, sopointwisereturnsNoneand the verify gate falls back to a bare scalar comparison with no p-value or CI, reported for human review only – see this module’s docstring andmixle.evolve.verifymodule docstring point 8.(For classification models the natural calibration scalar is
mixle.inference.calibration.expected_calibration_error(); this builder targets the continuous-predictive case, which is the common one for the streaming/auto-select loop.)ensembleandbinsmust both be exact positive integers – they are the budget the reported calibration error is computed from.
- decision_regret_objective(loss, actions, *, n=2000, seed=0, vectorized=None)[source]
Realized decision regret of a model’s chosen action against actual
data(scalar-only, lower is better).For the chosen Bayes action
a* = bayes_action(posterior(model), loss, actions)– optimal under the model’s OWN predictive belief – this reports the realized lossmean(loss(a*, y_i) for y_i in data)against the actualdata, not draws from that same model’s own posterior. Scoring against self-generated draws would let a confidently wrong model look flawless: its chosen action and its “outcomes” both come from the same wrong belief, so they always agree with each other regardless of how far that belief is from reality. Checking the chosen action against real, shareddatais what makes this a genuine promotion metric rather than a self-consistency check. Scalar-only (this is a single realized-loss number per model, not a per-observation quantity), sopointwisereturnsNone.- Parameters:
loss (Callable[[Any, Any], float]) –
loss(action, draw) -> float(or a numpy-vectorizedloss(action, draws) -> array).n (int) – posterior draws used only to pick the Bayes-optimal action under the model’s own predictive belief; the reported score is the realized loss of that action on
data.seed (int) – RNG seed for the action-selection draws.
vectorized (bool | None) – the loss’s calling convention, forwarded to
bayes_action()and used for the realized-loss evaluation.True-> called once with the whole outcome array;False-> called once per outcome;None(default) -> readloss.vectorizedif the loss declares it, else auto-detect by probing the array call once. A probe is a real invocation of the loss, and a search scores many models against the same loss, so the resolved convention is reused for the rest of the search rather than re-probed per model. A loss that keeps state or has side effects should declare its convention.
- Return type:
Objective
- pointwise_log_density(model, data)[source]
Per-observation
log p(y_i)undermodelvia the vectorizedseq_log_densitypath.Models exposing a
seq_log_density_raw(rows)(e.g. an affine recalibration whose change-of-variables needs the raw values) are scored through that split-safe path instead of the encode-then-score path, which cannot recover the raw responses from an encoded handle.
- sample_ensemble(model, n, m, *, seed)[source]
Draw an
(n, m)predictive ensemble:miid draws repeated fornobservations.The plug-in predictive is exchangeable across observations, so one
(m,)draw row is broadcast to allnrows – the per-observation CRPS/interval scores then differ only throughy_i.The realized draw count is checked against
mrather than accepted and broadcast. Nothing verified it before, so a sampler that always returned two draws produced shape(n, 2)form=10– andm=0still produced two. The resulting CRPS/interval score is then a genuinely different (far noisier) estimator than the one the objective’sensembleargument advertises, with nothing in the score or the verdict to say so.