mixle.reason.fusion module

Differentiable product-of-experts fusion for structured multimodal evidence aggregation.

Dense cross-attention fuses N tokens in O(N^2). When the tokens are (conditionally) independent evidence about a shared latent – the common case for aggregating many partial observations (image patches, sensors, views) – precision-weighted product-of-experts fuses them in O(N) with few parameters: the fusion inductive bias is built in, not learned. Each expert is a diagonal Gaussian N(mu_i, diag(1/prec_i)) over the latent, and the posterior is their normalized product:

prec_fused = sum_i prec_i + prec_prior          # precisions add
mu_fused   = (sum_i prec_i * mu_i) / prec_fused  # precision-weighted mean

The reference benchmark in examples/structured_fusion_vlm.py reports that PoE fusion matches a cross-attention block’s accuracy with fewer parameters and faster training on exchangeable-evidence tasks.

Boundary condition: PoE fusion is permutation-invariant and assumes conditional independence, so it cannot model token order or pairwise interactions. On a task that depends on a specific pair or position, attention reaches ~0.96 while PoE sits at chance. Use structured fusion where evidence is exchangeable, and attention where relational interactions are part of the signal.

mixle.reason’s exact core (GaussianBelief) does this fusion in closed form for inference; this is the torch, end-to-end-trainable version – the encoders that emit the experts are learned, the fusion stays exact. Torch is imported lazily.

Workstream L (cross-model adjudication): the same precision-weighted product-of-experts rule above, applied not to learned tokens but to scalar claims from independent external models (a CMIP climate projection, a hydrology emulator, …). fuse_claims() fuses a list of ModelClaim into one FusedBelief, flags when two models disagree beyond a standardized-distance threshold, and – on disagreement – adjudicates via an IC-6-shaped verifier plus a predeclared, calibrated pairwise significance test (deterministic, no Monte Carlo tail luck involved) before ever emitting a fused point, classifying every claim as accepted, rejected, or unresolved so a driller-facing cross-model number is never quietly averaged out of – or contaminated by – a real disagreement.

L8 (multi-climate-model ensemble fusion) does not add new fusion math: a real climate question is never answered by one model, it is answered by an ensemble (CMIP members, AI emulators, …) with uneven skill against held-out observations. skill_weighted_fuse() maps each ClimateMember’s skill onto fuse_claims()’s reliability slot, so the ensemble posterior is the same precision-weighted product-of-experts rule with higher-skill members earning proportionally more weight – disagreement/abstention are inherited unchanged from L5.

fusion_flops(n_tokens, latent_dim, *, attention=False)[source]

Approximate multiply-adds to fuse n_tokens into one latent.

Product-of-experts fusion is O(N*M); attention is O(N^2*M).

Parameters:
  • n_tokens (int)

  • latent_dim (int)

  • attention (bool)

Return type:

int

class ModelClaim(value, variance, model_id, version, content_hash, reliability=1.0)[source]

Bases: object

One external model’s scalar claim about a shared quantity, with the provenance it must carry.

variance is that model’s own uncertainty about value (physical units, not log-precision); reliability is a prior trust weight (1.0 = taken at face value) folded into the fused precision the same way L8’s per-member skill later will. model_id/version/content_hash mirror IC-7’s ProvenancedResult fields so every fused belief traces back to the calls that produced it.

Parameters:
class FusedBelief(mean, variance, weights, disagreement, abstained, provenance)[source]

Bases: object

The precision-weighted fusion of several ModelClaim, with attribution and an honesty gate.

weights has exactly one entry per input claim, keyed by that claim’s model_id – except when two or more claims share a model_id (repeated ensemble members of the same model is the realistic case; see skill_weighted_fuse()), in which case only the FIRST such claim keeps the bare model_id key and every later one is disambiguated "{model_id}#{n}" (matching the id-collision convention in mixle.epistemic.portfolio.HypothesisPortfolio.resample()) so no claim’s share is dropped. This SAME stable per-claim identity (not the possibly-duplicated bare model_id) is threaded through cross-model adjudication too, so two distinct claims that happen to share a model_id are compared like any other pair instead of silently colliding. This same key appears in provenance["claims"] under "weight_key" for exact correlation.

disagreement fires when the worst pairwise standardized distance between two claims exceeds sigma_flag (default 3-sigma). On disagreement, every claim is independently classified as accepted, rejected, or unresolved by a predeclared, deterministic cross-model test (see _adjudicate_claims()); ONLY accepted claims contribute to mean/variance/weights, so one claim clearing adjudication no longer drags every conflicting claim along with it. weights is 0.0 for any claim excluded this way. abstained is True iff disagreement is True AND not a single claim was accepted – mean/variance then fall back to the precision-weighted fusion of ALL claims (still a number, never absent), but callers MUST check abstained before surfacing mean as a driller-facing number.

weights sums to 1 across the surviving claims when fuse_claims() was called with no prior (the default). A positive prior_prec takes its own share of the fused precision – weights (which only ever has one entry per CLAIM) then sums to 1 - prior_weight, and provenance["prior_prec"]/["prior_mean"]/["prior_weight"] report exactly what that prior was and how much of the shrinkage it is responsible for (MXR-080-0286).

Parameters:
fuse_claims(claims, *, prior_prec=0.0, prior_mean=None, sigma_flag=3.0, verifier=None)[source]

Precision-weighted product-of-experts fusion of independent external-model claims (workstream L5).

Exactly the rule stated at the top of this module generalized to an explicit prior mean (prec_fused = sum(prec_i) + prior_prec, mean = (sum(prec_i * value_i) + prior_prec * prior_mean) / prec_fused), applied to scalar ModelClaims instead of learned tokens: prec_i = reliability_i / variance_i. On disagreement (worst pairwise standardized distance > sigma_flag), every claim is independently classified as accepted, rejected, or unresolved by a predeclared, deterministic cross-model test (_adjudicate_claims()); ONLY accepted claims feed mean/variance/weights (see FusedBelief’s docstring for the full inclusion-gating and abstention contract). provenance records every claim’s id/version/content_hash/weight/adjudication-status so a fused belief is always attributable back to the models that produced it and to exactly why each one was or was not trusted.

prior_prec MUST be paired with an explicit prior_mean whenever it is positive: unlike the torch ProductOfExpertsFusion at the bottom of this module, whose experts describe an arbitrary LEARNED latent space where a zero-mean prior is the standard, principled convention (as in a VAE), a ModelClaim’s value is a real PHYSICAL quantity (a temperature, a flow rate, …) – silently shrinking it toward 0 has no physical justification and can quietly change a physical-unit prediction (MXR-080-0286). provenance["prior_weight"] reports the prior’s own share of the fused precision so the attribution is honest about where any shrinkage comes from; weights (which is claims-only) then sums to 1 - prior_weight rather than always summing to 1.

Every scalar that reaches the precision arithmetic is validated up front (value/variance/ reliability per claim, plus prior_prec/prior_mean/sigma_flag) and the resulting per-claim and total precision are both re-checked as strictly positive and finite immediately before they are divided by – this function never returns a FusedBelief carrying a NaN or negative variance (MXR-080-0283); it raises ValueError instead.

Parameters:
Return type:

FusedBelief

class ClimateMember(value, variance, model_id, version, content_hash, skill=1.0)[source]

Bases: object

One external climate model’s projection in a multi-model ensemble (workstream L8).

A ClimateMember is a CMIP ensemble member or an AI emulator’s projection of a shared climate quantity. skill is a per-member inverse validation error against held-out observations (1.0 = neutral trust) – it plays exactly the role ModelClaim’s reliability plays in L5, because L8 folds skill into L5’s frozen precision-weighted rule rather than inventing new fusion math. model_id/version/ content_hash mirror IC-7’s ProvenancedResult fields so every ensemble member traces back to the domain-model call that produced it.

Parameters:
skill_weighted_fuse(members, *, sigma_flag=3.0, verifier=None)[source]

Skill-weighted Bayesian model averaging of a multi-climate-model ensemble (workstream L8/DR-ALG L8).

Each ClimateMember maps onto an L5 ModelClaim with reliability = skill, then fuse_claims() (the frozen precision-weighted product-of-experts rule) does the actual fusion: prec_i = skill_i / variance_i and the BMA posterior weight is prec_i / sum_j prec_j – skill enters ONCE, through the precision it defines, exactly like L5’s reliability (this is NOT skill_i * prec_i / sum_j skill_j * prec_j, which would equal skill_i^2 / variance_i normalized and double-count skill’s influence against the variance-based weighting fuse_claims() already does), so a higher-skill ensemble member earns proportionally more weight in the fused projection. Disagreement/abstention are inherited unchanged from L5: the max pairwise standardized distance flags at sigma_flag (default 3-sigma) and, on disagreement, routes through the same IC-6 verifier + deterministic cross-model adjudication before a fused ensemble point is ever trusted. provenance records every member’s {model_id, version, content_hash, weight, skill} so the fused projection driving L2/L3/L7 is always attributable back to the ensemble members that produced it.

Parameters:
  • members (list[ClimateMember])

  • sigma_flag (float)

  • verifier (Any)

Return type:

FusedBelief