feat: cross-Analysis shared per-evaluation state in FactorGraphModel#1308
Open
Jammy2211 wants to merge 1 commit into
Open
feat: cross-Analysis shared per-evaluation state in FactorGraphModel#1308Jammy2211 wants to merge 1 commit into
Jammy2211 wants to merge 1 commit into
Conversation
Add an opt-in mechanism for the per-factor Analysis objects of a FactorGraphModel to compute a model-dependent object once per likelihood evaluation and reuse it across every factor, instead of each factor recomputing identical work. - Analysis.shared_state_from(instance) -> None: opt-in hook (default None), the per-evaluation cross-factor sibling of modify_before_fit. - Analysis.log_likelihood_function gains an optional shared= kwarg. - FactorGraphModel computes the shared object once from the lead factor and forwards it to each factor only when non-None, so existing graphs are byte-for-byte unchanged. - AnalysisFactor forwards shared=; PriorFactor and HierarchicalFactor accept and ignore it for a uniform calling convention. - af.ex.Analysis demonstrates it on the 1D Gaussian toy via an opt-in share_model_data flag. - New unit tests in test_autofit/graphical/test_shared_state.py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 1, 2026
Collaborator
Author
|
Workspace PR: PyAutoLabs/autofit_workspace#69 |
Collaborator
Author
|
Workspace PR: PyAutoLabs/autofit_workspace_test#31 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opt-in mechanism for the per-factor
Analysisobjects of aFactorGraphModelto compute a model-dependent object once per likelihood evaluation and reuse it across every factor, instead of each factor recomputing identical work. This is the generic, domain-agnostic foundation for the ALMA datacube likelihood (sub-task B, tracked separately), where ~97% of each channel's inversion-setup work is identical across channels and currently rebuilt N times.The design mirrors the existing
EPAnalysisFactorprecedent (graph-level state attached around the factor loop) andAnalysis.modify_before_fit(the precompute-then-reuse hook), but runs once per likelihood evaluation rather than once per fit. It is fully backward compatible: when no factor opts in, every graph behaves exactly as before.Resolves part of #1307 (autofit deliverable; the 1D Gaussian workspace tutorial and fast tests follow).
API Changes
All changes are additive and backward compatible — no removals or renames.
Analysis.shared_state_from(instance) -> None: an opt-in hook (default returnsNone) that computes a per-evaluation object shared across aFactorGraphModel's factors. The per-evaluation, cross-factor sibling ofmodify_before_fit.Analysis.log_likelihood_function(and theAnalysisFactor/PriorFactor/HierarchicalFactorvariants) gain an optionalshared=Nonekeyword argument. Existing analyses that do not declare it keep working becauseFactorGraphModelforwardssharedonly when a factor opts in.af.ex.Analysisgains an opt-inshare_model_data=Falseconstructor flag plus a workedshared_state_fromimplementation, demonstrating the mechanism on the 1D Gaussian toy.See full details below.
Test Plan
python -m pytest test_autofit/graphical/— 188 existing + 4 new tests passtest_autofit/graphical/test_shared_state.py:shared_state_fromreturnsNone(Note: the full
test_autofit/suite has 13 pre-existing failures undertest_autofit/non_linear/search/nest/nss/that are unrelated to this change and already broken onmain.)Full API Changes (for automation & release notes)
Added
autofit.non_linear.analysis.analysis.Analysis.shared_state_from(self, instance)— returnsNoneby default; override to share per-evaluation state acrossFactorGraphModelfactors.autofit.example.analysis.Analysis.__init__(..., share_model_data=False)— opt-in flag enabling the shared-state path on the 1D Gaussian example.autofit.example.analysis.Analysis.shared_state_from(self, instance)— worked example: computes the shared model data once whenshare_model_data=True.Changed Signature (backward compatible — new optional kwarg with default)
Analysis.log_likelihood_function(self, instance)→(self, instance, shared=None)AnalysisFactor.log_likelihood_function(self, instance)→(self, instance, shared=None)PriorFactor.log_likelihood_function(self, instance)→(self, instance, shared=None)(accepts and ignoresshared)HierarchicalFactorfamilylog_likelihood_function(self, instance)→(self, instance, shared=None)(accepts and ignoresshared)autofit.example.analysis.Analysis.log_likelihood_function(self, instance, xp=np)→(self, instance, shared=None, xp=np)Changed Behaviour
FactorGraphModel.log_likelihood_functionnow asks the lead factor for a shared object (_shared_state_from) before the per-factor loop and forwards it to each factor when non-None. When no factor opts in (the default), behaviour is unchanged.Migration
Analysissubclasses and graphs work unchanged. To opt in, overrideshared_state_fromto return a shared object and havelog_likelihood_function(self, instance, shared=None)consume it (falling back to its own computation whenshared is None).🤖 Generated with Claude Code