Skip to content

fix: flag hierarchical parent-scale collapse in EP diagnostics (#1464) - #1465

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/ep-hierarchical-scale-collapse-guard
Aug 11, 2026
Merged

fix: flag hierarchical parent-scale collapse in EP diagnostics (#1464)#1465
Jammy2211 merged 1 commit into
mainfrom
feature/ep-hierarchical-scale-collapse-guard

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Closes #1464. Leg 1 of #1405 follow-up 2.

A hierarchical EP fit can settle into a basin where the parent scale
hyperparameter of a HierarchicalFactor collapses to ~0 and is reported with an
over-confident ~0 error — a confident claim of "no scatter" that is wrong
(measured at 7% of 30 identical-problem runs on a clean known-answer toy, truth
σ=10). The F10 sigma-collapse guard passed this silently, so the bad value
reached the user with no warning at all.

It missed on both limbs, structurally rather than by a mis-set threshold:

  • Floor limb needs std < 1e-8; the measured collapses sit at std 0.11 and
    ~1e-5 against a parent hyper-prior of mean 10. Misses by orders of magnitude.
  • Monotone limb was effectively dead code in any multi-factor graph.
    EPDiagnostics.snapshot records every variable on every factor update, but a
    factor update only moves the marginals of the variables adjacent to that
    factor. A variable's history is therefore dominated by steps at which it did not
    move, which give diff == 0 and defeat the strict np.all(np.diff(tail) < 0)
    test. It fired only in a unit test that hand-built a np.geomspace series
    directly into variable_rows.

Both limbs are absolute and variable-agnostic, because #1332 is a pathology in
which every std goes to zero. This collapse has a different shape: the parent
scale's mean goes to ~0 while its std stays moderate in absolute terms and is
over-confident only relative to that mean. So an absolute std test cannot see it,
and the fix is a dedicated parent-scale check rather than a retuned threshold.

Three changes:

  • EPDiagnostics.register_hierarchical_scales records which variables are parent
    scale hyperparameters, reusing the existing DeclarativeFactorGraph.hierarchical_factors
    accessor. It no-ops on a plain FactorGraph — diagnostics must never kill a fit.
  • check_sigma_collapse gains a relative, boundary-aware limb for those variables:
    flagged when the mean falls below a fraction of its initial value and
    std / |mean| is small.
  • The monotone limb drops consecutive unchanged rows before testing, restoring it
    to what it was written to mean.

Thresholds separate the measured data cleanly: the two collapses (mean 0.80 and
0.0030) flag, the recover band (9.1–12.8 ± 0.9–2.4) does not.

This change reports; it never alters the fit. Curing the collapse basin is
deliberately out of scope and stays on #1405.

API Changes

Additive and backward-compatible. EPDiagnostics gains a
register_hierarchical_scales(factor_graph) method and a scale_variables
attribute; check_sigma_collapse gains two optional keyword arguments with
defaults. No symbol is removed, renamed, or has a required argument added, so no
caller needs to change.

One behaviour change worth noting for release notes: check_sigma_collapse
now emits warnings in two situations where it previously returned nothing — a
collapsed hierarchical parent scale, and a genuine monotone std shrink in a
multi-factor graph (which the strict test could not previously detect). Callers
that assert on an empty warning list for a collapsed fit will now see a warning;
that is the point of the change.

See full details below.

Test Plan

  • pytest test_autofit/1714 passed, 4 skipped, 0 failed
  • pytest test_autofit/graphical/functionality/test_diagnostics.py — 16 passed
  • 5 of the 9 new tests fail against unmodified main, so they pin new
    behaviour rather than passing either way. The other 4 are negative
    (no-false-positive) guards and pass on main by construction.
  • Thresholds are tested against the measured values from the Hierarchical EP: parent scale hyperparameter collapses to ~0 with over-confident error (+ init-crash) #1405 toy
    rather than invented ones: both COLLAPSE states flag, both ends of the
    RECOVER band do not, an honestly uncertain small scale does not, and an
    unregistered variable is not subject to the relative test.
  • End-to-end on a real 5-drawn-variable hierarchical graph: the parent sigma
    is registered and the parent mean correctly is not, and the shallow
    collapse that main passed silently now emits a specific warning.
Full API Changes (for automation & release notes)

Added

  • EPDiagnostics.register_hierarchical_scales(factor_graph) — records the names of
    hierarchical parent scale variables so check_sigma_collapse can apply the
    scale-specific test. Silently records nothing for a graph with no hierarchical
    factors, or one that does not expose them.
  • EPDiagnostics.scale_variables: Set[str] — the set populated by the above.

Changed Signature

  • check_sigma_collapse(diagnostics, std_floor=1e-8, monotone_steps=5, shrink_factor=1e-3)
    → adds scale_mean_fraction=0.2 and scale_relative_error=0.5. Both optional
    with defaults; existing calls are unaffected.

Changed Behaviour

  • check_sigma_collapse — flags a registered parent scale variable whose mean has
    fallen below scale_mean_fraction of its initial value with a relative error
    below scale_relative_error, emitting a scale-collapse: warning naming Hierarchical EP: parent scale hyperparameter collapses to ~0 with over-confident error (+ init-crash) #1405.
  • check_sigma_collapse — the monotone limb now compares a variable's updates
    rather than every recorded step, so it can fire on a real multi-factor graph
    instead of only on a synthetic strictly-decreasing series.
  • EPOptimiser.__init__ — registers hierarchical scales from its factor graph.
    No signature change.

Migration

  • None required — additive.

Generated by the PyAutoLabs agent workflow.


Generated by Claude Code

The F10 sigma-collapse guard passed a collapsed hierarchical parent scale
silently. It missed on both limbs, for structural reasons rather than a
mis-set threshold:

- The floor limb needs std < 1e-8; the measured collapses sit at std 0.11
  and ~1e-5 against a parent hyper-prior of mean 10, so it misses by
  orders of magnitude.
- The monotone limb was effectively dead code in any multi-factor graph.
  snapshot() records every variable on every factor update, but a factor
  update only moves the marginals of the variables adjacent to that
  factor, so a variable's history is dominated by steps at which it did
  not move. Those give diff == 0 and defeat the strict np.diff(tail) < 0
  test. It fired only in a unit test that hand-built a geomspace series.

Both limbs are absolute and variable-agnostic because #1332 is a
pathology in which every std goes to zero. The parent scale of a
HierarchicalFactor collapses in a different shape: its mean goes to ~0
while the std stays moderate in absolute terms and is over-confident only
relative to that mean — a confident claim of no scatter.

- EPDiagnostics.register_hierarchical_scales records which variables are
  parent scale hyperparameters, reusing DeclarativeFactorGraph's existing
  hierarchical_factors accessor. It no-ops on a plain FactorGraph.
- check_sigma_collapse gains a relative, boundary-aware limb for those
  variables: flagged when the mean falls below a fraction of its initial
  value and std/|mean| is small.
- The monotone limb now drops consecutive unchanged rows before testing,
  restoring it to what it was written to mean.

Thresholds separate the measured data cleanly: the two collapses (mean
0.80 and 0.0030) flag, the recover band (9.1-12.8) does not. Tests use
those measured values as fixtures; five of them fail on unmodified main.

The guard reports; it never alters the fit.
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Aug 11, 2026 — with Claude
@Jammy2211
Jammy2211 merged commit 26470db into main Aug 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: hierarchical parent-scale collapse is reported silently (F10 misses it)

2 participants