Skip to content

fix: EP projection — transform samples to base space + use log weights#1383

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/ep-projection-weights
Jul 17, 2026
Merged

fix: EP projection — transform samples to base space + use log weights#1383
Jammy2211 merged 1 commit into
mainfrom
feature/ep-projection-weights

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Fixes #1382.

What was broken

Every sampler-driven EP factor update projects its posterior samples into a mean-field message via Result.projected_model. Two stacked defects made that projection land near a prior bound with spuriously tiny std — poisoning the EP cavity and driving the F10 sigma-collapse on any hierarchical graph (the #1335 diagnostics flagged the collapse correctly; the cause was upstream of them):

  1. TransformedMessage.project never transformed its samples (primary). Physical samples went straight into the base (e.g. logit-normal) message's moment match. Even equal-weighted samples clustered at 2.05 inside UniformPrior(1.5, 3.0) projected to mean 2.97.
  2. Result.projected_model passed linear importance weights into a log-weight moment match (w = exp(log_w − max)), near-uniformly weighting the entire nested-sampling run, prior-exploration phase included.

The fix

  • TransformedMessage.project maps samples through self._transform before the base moment match — exactly as @transform does for pdf and friends. No Jacobian on the weights: a weighted empirical distribution transforms its atoms, not its weights.
  • Result.projected_model converts weight_list to log weights (zeros → −inf → drop out; all-zero raises ValueError).
  • Prior.project's kwarg renamed weightslog_weight_list with the scale requirement documented, so the ambiguity that hid defect 2 can't recur.

Tests

  • New regression test test_projected_model_moments: nested-sampling-shaped weighted samples (broad negligible-weight prior phase + concentrated posterior) through a UniformPrior must project to the posterior moments — fails on either defect alone.
  • Full test_autofit: 1494 passed, 1 skipped.

Real-case evidence & post-merge validation

Found by the slope_hierarchy science project deliberately exercising the 2026-07 EP wave on a realistic lensing case (full forensics: Jammy2211/slope_hierarchy#1). Smoking gun (RAL probe, 1 imaging lens × 1 EP step): the factor's own Nautilus fit found slope = 2.0448 (2.015, 2.075) while its projected message was 2.9875 ± 0.011; with this branch the same projection probe lands at 2.0493. After merge, slope_hierarchy reruns its 5-lens EP fit for the EP-vs-NUTS parity check (its goal 2, currently blocked on this PR).

Note: weight_list-as-log may have silently biased historic sampler-driven EP results (e.g. concr-era H0 runs) — worth keeping in mind when comparing against old EP outputs.

🤖 Generated with Claude Code

…1382)

Two stacked defects made every sampler-driven EP factor update project its
posterior to a message pinned near a prior bound (boundary attractor ->
cavity poisoning -> hierarchical sigma-collapse, flagged as F10 by the EP
diagnostics):

1. TransformedMessage.project forwarded PHYSICAL samples straight into the
   base message's moment match without applying the transform stack — the
   primary defect: even equal-weighted samples clustered at 2.05 inside
   UniformPrior(1.5, 3.0) projected to mean 2.97. It now maps samples
   through self._transform first, exactly as @Transform does for pdf and
   friends (weights need no Jacobian: a weighted empirical distribution
   transforms its atoms, not its weights).

2. Result.projected_model passed LINEAR importance weights into a moment
   match that requires LOG weights (w = exp(log_w - max)), near-uniformly
   weighting the whole nested run. It now converts (zero weights -> -inf
   -> drop out) and raises on all-zero weights. Prior.project's kwarg is
   renamed to log_weight_list so the expected scale is unambiguous.

Regression test: nested-sampling-shaped weighted samples through a
UniformPrior must project to the posterior moments, not the prior spread
(fails on either defect alone). Full test_autofit: 1494 passed, 1 skipped.

End-to-end forensics and repro: Jammy2211/slope_hierarchy#1 (RAL probe
330591: factor fit slope 2.0448 vs projected message 2.9875).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Jammy2211
Jammy2211 merged commit b32e58b into main Jul 17, 2026
5 checks passed
@Jammy2211
Jammy2211 deleted the feature/ep-projection-weights branch July 17, 2026 07:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: EP projection feeds linear sample weights as log weights (boundary attractor, sigma-collapse)

1 participant