Repository navigation
feat: array-free interferometer fits with ordinary light profiles (streaming P4) - #642
Merged
Merged
Conversation
…reaming P4) Ordinary (non-linear) light profiles on an array-free `Interferometer.from_stream` dataset are now fitted via the data-term identity sum|d - F i_p|^2/sigma^2 = data_term - 2 i_p.d~ + i_p.W~ i_p instead of raising, never forming the N_vis profile visibilities. - sparse_profile_terms_from(dataset, galaxies, image, xp) -> (sparse_dirty_image, data_term) from one W~ i_p product; sparse_dirty_image_from wraps it. - uses_precomputed_data_term_from: array-free datasets (data is None) always take the precomputed path; in-memory sparse fits with ordinary light keep passing the profile-subtracted visibilities (bit-for-bit unchanged). - galaxies_to_inversion passes data=None + subtracted dirty image + data_term. - profile_visibilities returns None array-free; profile_subtracted_visibilities short-circuits without evaluating it. - sparse_chi_squared hook: inversion.fast_chi_squared with an inversion, else the identity from profile_image, so LP-only fits have log_likelihood/figure_of_merit. - model_data / galaxy_model_visibilities_dict raise a typed DatasetException pointing at model_image_natural / dirty_model_image_natural. - Tests: parity vs the in-memory dense fit at rel 1e-8 (LP-only, LP+pixelization, LP+linear, LP in a Basis), jax.jit with traced intensity, a visibilities_from spy, model_data typed raise, aggregator round-trip and visualizer with an ordinary LP. The old "light profile raises" test is replaced. Refs PyAutoLabs/PyAutoArray#598 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… overrides (streaming P4 review) - sparse_chi_squared_from(fit, galaxies): the array-free chi-squared now applies the data-term identity to the TOTAL real-space model image (profile_image + the inversion's mapped_reconstructed_data), so log_likelihood equals the dense residual-map value exactly with an inversion too; previously it returned inversion.fast_chi_squared, which includes s^T (eps I) s for unregularized linear objects (rel 1.1e-7 at test eps 1e-8; 0.25 nats at packaged eps 1e-3). fast_chi_squared / log_evidence / figure_of_merit are unchanged. - _require_no_array_free_overrides: an array-free dataset's fit whose data or noise_map is not the dataset's own now raises a DatasetException in sparse_chi_squared and galaxies_to_inversion, instead of pairing the subtracted dirty image with the raw data term (F1) or switching noise_normalization without the chi-squared (F2). - Tests: strict log_likelihood parity vs the dense fit, jit log_likelihood with an inversion, noise-map-override raise (in-memory path unaffected). Refs PyAutoLabs/PyAutoArray#598 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
Streaming visibilities phase 4 (epic
streaming-visibilities, Discussion https://github.com/orgs/PyAutoLabs/discussions/13; issue PyAutoLabs/PyAutoArray#598).ag.FitInterferometerwith ordinary (non-linear) light profiles now runs on an array-free dataset (Interferometer.from_stream/from_sparse_terms), with or without an inversion, in numpy and underjax.jit, matching the in-memory dense fit at rel ≤ 1e-8 (measured 1.8e-15). The light profiles enter through their real-spaceprofile_imageand the identityΣ|d − F i_p|²/σ² = data_term − 2 i_pᵀd̃ + i_pᵀW̃i_p;profile_visibilitiesis never formed (a transformer spy test proves it). Requires the PyAutoArray companion PR (DatasetInterface.data_term,sparse_profile_terms_from,sparse_chi_squaredhook).Red-check recorded in the test file history: with the old raise removed but the override not wired, LP+pixelization log_evidence was −37.0125 vs dense −37.9117 (−2.4 %) and LP+linear −24.3192 vs −25.2183 (−3.6 %), silently. The override closes that.
In-memory sparse fits with ordinary light are unchanged bit-for-bit (they keep passing the profile-subtracted visibilities); only
dataset.data is Nonetakes the identity path.API Changes
Mostly additive. The array-free raise in
profile_visibilitiesis gone (it returnsNone);model_data,galaxy_model_visibilities_dictandmodel_visibilities_of_galaxies_listnow raise a typedDatasetExceptionon an array-free dataset pointing atmodel_image_natural/dirty_model_image_natural. New module helpersparse_profile_terms_from;uses_precomputed_data_term_fromgains the array-free rule.See full details below.
Review (Codex gpt-6-astra, 3 independent runs, 2026-10-01)
Four distinct findings, all reproduced before editing (numbers in the second commit's tests):
noise_map/dataon an array-free dataset made_uses_precomputed_data_termfalse whileprofile_subtracted_visibilitiesstayedNone, so the inversion paired the subtracted dirty image with the raw operatordata_term(LP+pix fom −37.0125 vs dense −37.9117). Now_require_no_array_free_overridesraises a typedDatasetException(array-free datasets support no data/noise-map overrides).sparse_chi_squaredignored an overridden noise map (χ² 5.2983 unscaled vs 1.3246 dense whilenoise_normalizationswitched). Same guard.log_likelihoodwith an inversion returnedfast_chi_squared, which carrieseps·Σs²fromno_regularization_add_to_curvature_diag_value(packaged 1e-3; −0.25 nats at ×100 data).sparse_chi_squarednow applies the identity to the total real-space model image (profile_image + inversion.mapped_reconstructed_data), matching the denselog_likelihoodat rel 1e-15 for every source type, numpy andjax.jit.fast_chi_squared/log_evidenceunchanged.galaxy_image_dictdict-merge overwrites a mixed ordinary+linear galaxy's ordinary image (alsofit_imaging.py); Mind draftdraft/bug/autogalaxy/galaxy_image_dict_mixed_galaxy_overwrites_ordinary_light.md.Test Plan
figure_of_merit == log_likelihood), LP+pixelization, LP+linear LP, LP+Basis;jax.jitLP-only and LP+pixelization (traced intensity re-evaluated to prove it is not frozen);TransformerNUFFT/TransformerDFT.visibilities_fromspy never called;model_datatyped raise; aggregator round-trip and visualizer with an ordinary LP on array-free data.test__fit_figure_of_merit__array_free_dataset__light_profile__raises(behaviour it asserted no longer exists).test_autogalaxy: 1305 passed (main: 1293).Full API Changes (for automation & release notes)
Added
autogalaxy.interferometer.fit_interferometer.sparse_profile_terms_from(dataset, galaxies, image, xp=np)→(sparse_dirty_image, data_term);(None, None)when no sparse operator or no ordinary light.ag.FitInterferometer.sparse_chi_squared— the identity on the total real-space model image (profile_image+inversion.mapped_reconstructed_data);Nonewithout a sparse operator. RaisesDatasetExceptionif the fit overridesdata/noise_mapon an array-free dataset.Changed Behaviour
ag.FitInterferometer.profile_visibilities— on an array-free dataset returnsNoneinstead of raisingDatasetExceptionwhen ordinary light profiles are present.ag.FitInterferometer.profile_subtracted_visibilities— returnsNoneon array-free without evaluatingprofile_visibilities.ag.FitInterferometer.model_data,galaxy_model_visibilities_dict,model_visibilities_of_galaxies_list— raiseaa.exc.DatasetExceptionon an array-free dataset (previously only reachable for pixelization/linear fits, where they failed withNone + array).uses_precomputed_data_term_from— returnsTruefor any array-free dataset (dataset.data is None), with the subtracteddata_termsupplied to the inversion.ag.FitInterferometer.log_likelihood/chi_squaredon an array-free fit equal the dense residual-map values (identity on the total model image);figure_of_merit/log_evidenceunchanged.Internal
sparse_dirty_image_fromnow wrapssparse_profile_terms_from(same result)._require_transformer(fit, quantity),_require_no_array_free_overrides(fit),sparse_chi_squared_from(fit, galaxies)helpers (reused by PyAutoLens).Heart RED development override (human-authorized, 2026-10-01)
Shipped under the AUTONOMY.md "Human override for Heart RED (development only)". Live human authorization in the CLI session (Fable 5.1), quoted: "Yes, ship (push + PR-open)" for task
streaming-p4-light-profile-identity(PyAutoLabs/PyAutoArray#598). Exact RED reasons at ship time (pyauto-heart readiness):None relate to this branch. Branch gates passed: test_autoarray 1903, test_autogalaxy 1305, test_autolens 793 + 1 xfailed; Codex review 4 findings (3 fixed in-branch, 1 pre-existing filed). Scope: push + PR-open only. Merge requires a separate human
/prmwith every required check green; this is not a release and does not claim Heart is healthy.Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code