Overview
Phase 4 of the EP framework review (umbrella: PyAutoMind/research/graphical_ep/ep_framework_review.md; audit #1332). EP fits currently emit one evidence/KL plot (graph.png) and a text graph.results; there is no machine-readable fit log, no record of how the mean field evolved, no per-factor status accounting, no guard against the F10 sigma-collapse pathology, and no post-fit summary helpers. This adds all of those, additively (no behaviour change to the fitting itself).
Autonomy: --auto, effective level supervised (feature cap). Plan below per contract; run parks at ship sign-off.
Coexistence note: PyAutoFit is also claimed by the parked ep-graphical-docs task (PR #1334, docs-only). This task's files (expectation_propagation/, new diagnostics module, test_autofit/graphical/) are disjoint from that diff (README, mean_field.py, composed_transform.py, abstract.py docstrings); disjointness is re-verified before ship. Human directed both to proceed in parallel.
Plan
New autofit/graphical/expectation_propagation/diagnostics.py:
MeanFieldSnapshot recording per factor-step: step index, factor name, status (success/updated/flag), factor log-evidence, factor KL, and per-variable (mean, std) of the global mean field (arrays summarised as mean-of-means / max-std).
EPDiagnostics collector — accumulates snapshots during a run; writers for:
ep_history.csv — step, factor, success, flag, log_evidence, kl_divergence;
mean_field_history.csv — step, variable, mean, std;
mean_field_summary(mean_field) — post-fit text table (variable, mean, std) usable at the end of any example.
check_sigma_collapse(...) — the F10 guard: flags variables whose std shrinks monotonically below a floor across steps; returned as warnings, logged at run end, and appended to the results text.
visualise.py upgrades:
- Enable the (currently commented-out) per-factor evidence/KL curves as
graph_factors.png.
- New
mean_field_evolution.png — per-variable mean ± std band vs step, from the diagnostics collector.
optimiser.py wiring:
EPOptimiser instantiates EPDiagnostics when paths is set; snapshot after each factor update (cheap float extraction); CSVs written at output_interval; final summary + collapse warnings emitted at run end.
- Fix F3 while here: guard the unconditional
self.visualiser() / _output_results at the end of ParallelEPOptimiser.run (crash when paths=None) — one-line, same file, in scope as the wiring touches these call sites.
Tests (test_autofit/graphical/functionality/test_diagnostics.py, numpy-only):
- Tiny exact-conjugate graph run via
EPOptimiser with paths at tmp_path → CSVs exist, expected columns, row counts match steps×factors; summary text contains all variables.
check_sigma_collapse fires on a synthetic collapsing history, silent on a healthy one.
ParallelEPOptimiser completion with paths=None no longer raises (F3).
Out of scope: wiring diagnostics calls into workspace examples (follow-up on the parked Phase 3 branch or later); richer aggregated posterior views (graphical_scoping.md limitation 3 — the CSV/plot layer here is its foundation).
Overview
Phase 4 of the EP framework review (umbrella:
PyAutoMind/research/graphical_ep/ep_framework_review.md; audit #1332). EP fits currently emit one evidence/KL plot (graph.png) and a textgraph.results; there is no machine-readable fit log, no record of how the mean field evolved, no per-factor status accounting, no guard against the F10 sigma-collapse pathology, and no post-fit summary helpers. This adds all of those, additively (no behaviour change to the fitting itself).Autonomy:
--auto, effective levelsupervised(feature cap). Plan below per contract; run parks at ship sign-off.Coexistence note: PyAutoFit is also claimed by the parked
ep-graphical-docstask (PR #1334, docs-only). This task's files (expectation_propagation/, new diagnostics module,test_autofit/graphical/) are disjoint from that diff (README,mean_field.py,composed_transform.py,abstract.pydocstrings); disjointness is re-verified before ship. Human directed both to proceed in parallel.Plan
New
autofit/graphical/expectation_propagation/diagnostics.py:MeanFieldSnapshotrecording per factor-step: step index, factor name, status (success/updated/flag), factor log-evidence, factor KL, and per-variable (mean, std) of the global mean field (arrays summarised as mean-of-means / max-std).EPDiagnosticscollector — accumulates snapshots during a run; writers for:ep_history.csv— step, factor, success, flag, log_evidence, kl_divergence;mean_field_history.csv— step, variable, mean, std;mean_field_summary(mean_field)— post-fit text table (variable, mean, std) usable at the end of any example.check_sigma_collapse(...)— the F10 guard: flags variables whose std shrinks monotonically below a floor across steps; returned as warnings, logged at run end, and appended to the results text.visualise.pyupgrades:graph_factors.png.mean_field_evolution.png— per-variable mean ± std band vs step, from the diagnostics collector.optimiser.pywiring:EPOptimiserinstantiatesEPDiagnosticswhenpathsis set; snapshot after each factor update (cheap float extraction); CSVs written atoutput_interval; final summary + collapse warnings emitted at run end.self.visualiser()/_output_resultsat the end ofParallelEPOptimiser.run(crash whenpaths=None) — one-line, same file, in scope as the wiring touches these call sites.Tests (
test_autofit/graphical/functionality/test_diagnostics.py, numpy-only):EPOptimiserwithpathsat tmp_path → CSVs exist, expected columns, row counts match steps×factors; summary text contains all variables.check_sigma_collapsefires on a synthetic collapsing history, silent on a healthy one.ParallelEPOptimisercompletion withpaths=Noneno longer raises (F3).Out of scope: wiring diagnostics calls into workspace examples (follow-up on the parked Phase 3 branch or later); richer aggregated posterior views (
graphical_scoping.mdlimitation 3 — the CSV/plot layer here is its foundation).