Skip to content

feat: array-free interferometer fits with ordinary light profiles (streaming P4) - #642

Merged
Jammy2211 merged 2 commits into
mainfrom
feature/streaming-p4-light-profile-identity
Oct 1, 2026
Merged

Jammy2211 merged 2 commits into
mainfrom
feature/streaming-p4-light-profile-identity

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Streaming visibilities phase 4 (epic streaming-visibilities, Discussion https://github.com/orgs/PyAutoLabs/discussions/13; issue PyAutoLabs/PyAutoArray#598). ag.FitInterferometer with 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 under jax.jit, matching the in-memory dense fit at rel ≤ 1e-8 (measured 1.8e-15). The light profiles enter through their real-space profile_image and the identity Σ|d − F i_p|²/σ² = data_term − 2 i_pᵀd̃ + i_pᵀW̃i_p; profile_visibilities is never formed (a transformer spy test proves it). Requires the PyAutoArray companion PR (DatasetInterface.data_term, sparse_profile_terms_from, sparse_chi_squared hook).

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 None takes the identity path.

API Changes

Mostly additive. The array-free raise in profile_visibilities is gone (it returns None); model_data, galaxy_model_visibilities_dict and model_visibilities_of_galaxies_list now raise a typed DatasetException on an array-free dataset pointing at model_image_natural / dirty_model_image_natural. New module helper sparse_profile_terms_from; uses_precomputed_data_term_from gains 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):

  • F1 (high, introduced) — fixed: a fit subclass overriding noise_map/data on an array-free dataset made _uses_precomputed_data_term false while profile_subtracted_visibilities stayed None, so the inversion paired the subtracted dirty image with the raw operator data_term (LP+pix fom −37.0125 vs dense −37.9117). Now _require_no_array_free_overrides raises a typed DatasetException (array-free datasets support no data/noise-map overrides).
  • F2 (high, introduced) — fixed: without an inversion sparse_chi_squared ignored an overridden noise map (χ² 5.2983 unscaled vs 1.3246 dense while noise_normalization switched). Same guard.
  • F3 (medium) — fixed: array-free log_likelihood with an inversion returned fast_chi_squared, which carries eps·Σs² from no_regularization_add_to_curvature_diag_value (packaged 1e-3; −0.25 nats at ×100 data). sparse_chi_squared now applies the identity to the total real-space model image (profile_image + inversion.mapped_reconstructed_data), matching the dense log_likelihood at rel 1e-15 for every source type, numpy and jax.jit. fast_chi_squared / log_evidence unchanged.
  • F4 (medium, pre-existing on main) — filed, not fixed: galaxy_image_dict dict-merge overwrites a mixed ordinary+linear galaxy's ordinary image (also fit_imaging.py); Mind draft draft/bug/autogalaxy/galaxy_image_dict_mixed_galaxy_overwrites_ordinary_light.md.

Test Plan

  • New parity tests vs the in-memory dense fit (rel 1e-8): LP-only (figure_of_merit == log_likelihood), LP+pixelization, LP+linear LP, LP+Basis; jax.jit LP-only and LP+pixelization (traced intensity re-evaluated to prove it is not frozen); TransformerNUFFT/TransformerDFT.visibilities_from spy never called; model_data typed raise; aggregator round-trip and visualizer with an ordinary LP on array-free data.
  • Deleted test__fit_figure_of_merit__array_free_dataset__light_profile__raises (behaviour it asserted no longer exists).
  • test_autogalaxy: 1305 passed (main: 1293).
  • CI green on all legs; merge after PyAutoArray.
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); None without a sparse operator. Raises DatasetException if the fit overrides data/noise_map on an array-free dataset.

Changed Behaviour

  • ag.FitInterferometer.profile_visibilities — on an array-free dataset returns None instead of raising DatasetException when ordinary light profiles are present.
  • ag.FitInterferometer.profile_subtracted_visibilities — returns None on array-free without evaluating profile_visibilities.
  • ag.FitInterferometer.model_data, galaxy_model_visibilities_dict, model_visibilities_of_galaxies_list — raise aa.exc.DatasetException on an array-free dataset (previously only reachable for pixelization/linear fits, where they failed with None + array).
  • uses_precomputed_data_term_from — returns True for any array-free dataset (dataset.data is None), with the subtracted data_term supplied to the inversion.
  • ag.FitInterferometer.log_likelihood / chi_squared on an array-free fit equal the dense residual-map values (identity on the total model image); figure_of_merit / log_evidence unchanged.

Internal

  • sparse_dirty_image_from now wraps sparse_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):

  • release validation FAILED (stage integrate)
  • workspace validation not passing (0 failed, 1 timeout, cloud#36404726969: autolens_test scripts/multi_dataset/rectangular.py)
  • manifest drift: public front-door organ tables (generated) — 1 mismatch(es) vs PyAutoMind/repos.yaml

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 /prm with 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

Jammy2211 and others added 2 commits October 1, 2026 09:16
…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>
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Oct 1, 2026
@Jammy2211
Jammy2211 merged commit 574743a into main Oct 1, 2026
4 checks passed
@Jammy2211
Jammy2211 deleted the feature/streaming-p4-light-profile-identity branch October 1, 2026 08:53
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Oct 7, 2026
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.

1 participant