mixle.reason.posterior_schema module¶
Semantic schema for IC-1 posteriors – the missing layer under the frozen Posterior protocol.
mixle.reason.posterior_protocol.Posterior fixes the mechanics of a posterior (.samples /
.mean / .cov over a d-vector) but says nothing about what the d axes mean – their
names, units, or coordinate space. That gap is a real, observed source of silent bugs: two posteriors
can both “satisfy IC-1” while their axes mean different things (the concrete case that motivated this:
G2’s invert_source reports (x, y, rate) while G6’s design_monitoring_network expects
(x, y, log_rate, onset), and composing them needed a hand-written transform bridge that nothing
validated – if a future edit reordered an axis or changed a unit, no error would fire; the numbers
would just be wrong).
This module adds, additively and opt-in (it changes no existing posterior), three things:
PosteriorSchema/AxisSpec– declare what each latent axis is.
adapt()– convert a posterior from one schema’s convention to another’s (reorder, coordinate-transform under an explicit supported probability model, marginalize dropped axes), and raise loudly when a target axis has no source axis to build it from, instead of silently producing a wrong number. This is the general, validated replacement for hand-written bridges.
join_independent()– block-diagonally combine independent posteriors (e.g. an(x, y, rate)inversion posterior plus a separately-estimatedonsetbelief with no cross-covariance to it) into one schematized posterior. This is the honest way to append a belief that genuinely isn’t in another posterior’s covariance – distinct fromadapt(), which only rearranges information already present.
- class AdaptationReceipt(transformation_model, transformed_axes, approximation_error, assumption)[source]
Bases:
objectAssumption and numerical status of a coordinate-space adaptation.
- class AxisSpec(name, unit='', space='linear')[source]
Bases:
objectOne latent axis’s meaning: the natural quantity
name, itsunit, and the coordinatespacethe posterior’s mean/cov are expressed in for this axis ("linear"or"log").Example: G2 stores the release rate directly ->
AxisSpec("rate", "kg/s", "linear"); G6 wants it log-transformed ->AxisSpec("rate", "kg/s", "log"). Samename/unit(it’s the same physical quantity), differentspace– which is exactly the informationadapt()needs, together with an explicit probability model, to build the transform.
- class PosteriorSchema(axes)[source]
Bases:
objectAn ordered list of
AxisSpec– the semantic contract for a posterior’sdaxes.- Parameters:
axes (tuple[AxisSpec, ...])
- class SchematizedPosterior(mean, cov, schema, prior_dominated=None, adaptation_receipt=None)[source]
Bases:
objectA Gaussian posterior (mean + cov) carrying its
PosteriorSchema. Satisfies the IC-1Posteriorprotocol (.samples/.mean/.cov/.credible_interval/.derived_quantity) so it’s a drop-in wherever aPosterioris expected, and additionally exposes.schemaso downstream code can check conventions instead of assuming them.
- adapt(mean, cov, source, target, *, transformation_model=None, prior_dominated=None)[source]
Convert a Gaussian posterior from
sourceconvention totargetconvention.Matches target axes to source axes by name, applies any supported coordinate change under an explicit probability model, reorders to the target order, and marginalizes (drops) any source axis not in the target. Raises
KeyErrorif atargetaxis has no source axis of the same name – the case that must never silently produce a wrong number, because the information to build that axis genuinely isn’t present (usejoin_independent()to append a belief that legitimately comes from elsewhere). RaisesValueErroron a unit mismatch for a matched axis – same name, different unit is a real inconsistency, not an adaptation.This is the general, validated replacement for hand-written convention bridges (e.g.
SourcePosterior.to_doe_prior’s rate->log_rate step).
- join_independent(*blocks)[source]
Block-diagonally combine independent Gaussian posteriors into one schematized posterior.
Each block is
(mean, cov, schema); the result stacks the means and places the covariances on the block diagonal (zero cross-covariance between blocks – the explicit statement that these beliefs are independent, which is exactly the honest way to append an axis likeonsetthat a separate estimate provides and is genuinely uncorrelated with the rest, rather than pretending a single posterior’s covariance contained it). Raises on a duplicate axis name across blocks.