Repository navigation
feat(interferometer): pass data=None on the sparse precomputed-data-term path (Discussion #13 lens parity) #756
Description
Overview
PyAutoLens parity for phase 1 of https://github.com/orgs/PyAutoLabs/discussions/13 (PyAutoArray#589 + PyAutoGalaxy#637, merged 2026-09-30). On the sparse interferometer path a fit with no non-linear light profile can build its inversion with data=None, so fast_chi_squared reads the cached sparse_operator.data_term and the two per-call N_vis allocations (profile_visibilities, profile_subtracted_visibilities) are never formed. autolens.interferometer.FitInterferometer.tracer_to_inversion still passes data=self.profile_subtracted_visibilities unconditionally, so lens fits — the main consumer — still pay them. This task mirrors the autogalaxy change in autolens.
Plan
- Gate
tracer_to_inversionon autogalaxy'suses_precomputed_data_term_fromso sparse pixelization-only lens fits passdata=Noneinto the inversion. - Add
FitInterferometer.inversion_with_data(shallow copy carrying the fitted data) for output/plot paths; switch the lens visualizer's inversion subplot to it. - Make
profile_visibilities/profile_subtracted_visibilitiescached properties, matching autogalaxy, so "never evaluated" is testable. - Port autogalaxy's phase-1 tests with a lens-mass + pixelization-only-source tracer; add a bit-equality control against the ungated path.
- Verify nothing in autolens reads
inversion.dataset.data; ship as apending-releasePR on PyAutoLens.
Detailed implementation plan
Affected Repositories
- PyAutoLens (primary, only)
Branch Survey
| Repository | Current Branch | Dirty? |
|---|---|---|
| ./PyAutoLens | main (1 behind origin) | clean |
Worktree guard: PyAutoLens is also claimed by workspace-config-cleanup (#441); its PyAutoLens PR #751 is already merged (test_autolens/model_figure/* only) and the claim is held for the release gate. Disjoint files; parallel claim approved with the plan on 2026-09-30.
Suggested branch: feature/interferometer-sparse-precomputed-data-term
Implementation Steps
autolens/interferometer/fit_interferometer.py: importuses_precomputed_data_term_fromfromautogalaxy.interferometer.fit_interferometer(next to the existing_has_light_profile_non_linear,sparse_dirty_image_fromimports) andimport copy. Add@property _uses_precomputed_data_term→uses_precomputed_data_term_from(dataset=self.dataset, galaxies=self.tracer.galaxies, data=self.data, noise_map=self.noise_map).- In
tracer_to_inversion:data = None if self._uses_precomputed_data_term else self.profile_subtracted_visibilities; the rest of theaa.DatasetInterface(...)call (incl.sparse_dirty_image_from) unchanged. - Add
@property inversion_with_datamirroring autogalaxy (returnself.inversionwhen it is None or itsdataset.data is not None; else evaluateinversion.reconstruction,copy.copythe dataset withdata = self.data,copy.copythe inversion with that dataset). profile_visibilitiesandprofile_subtracted_visibilities:@property→ the file'scached_property(asprofile_imagealready is). Confirmtest__profile_visibilities__linear_light_only__zeros_without_fourier_transformstill passes.autolens/interferometer/model/visualizer.py~L157-160:plotter.inversion(inversion=fit.inversion_with_data).- Verify only:
autolens/lens/to_inversion.py~L197-204 propagatesdata=Noneintoag.GalaxiesToInversion(already exercised by PyAutoGalaxy#637); no.dataread on the preloads path. - Tests in
test_autolens/interferometer/test_fit_interferometer.py, sparse dataset built inline viainterferometer_7.apply_sparse_operator(use_jax=False), tracer = mass-only lens + pixelized source (rectangular mesh, constant regularization):..._sparse_operator__pixelization_only__data_term_scalar_matches_dense: predicate true,fit.inversion.dataset.data is None, log_evidence == dense at rel 1e-8,inversion_with_data.dataset.data is fit.datasharingreconstruction, non-sparse fit →inversion_with_data is inversion.- Spy block: monkeypatch
transformer.visibilities_fromandaa.Visibilities.zeros; both call lists empty afterfigure_of_merit; neither profile property infit.__dict__;profile_visibilitiesstill zeros when accessed. ..._light_profile__unchanged_vs_data_passed: lens light Sersic → predicate false, log_evidence equal to before...._pixelization_only__jax_jit_matches_numpy: jitted vs numpy figure of merit.- Control: predicate forced off → log_evidence bit-equal to the gated value.
- Witness script (scratchpad): 1e5-vis NUFFT sparse dataset; gated vs ungated log_evidence bit-equal;
tracemallocpeak perfigure_of_meritflat in N_vis (1e5 vs 4e5); numbers into the PR body. /ship_library:pytest test_autolensgreen; labelpending-release; Heart YELLOW ack.
Key Files
autolens/interferometer/fit_interferometer.py— gate,inversion_with_data, cached propertiesautolens/interferometer/model/visualizer.py— inversion subplot usesinversion_with_datatest_autolens/interferometer/test_fit_interferometer.py— ported tests + controlautogalaxy/interferometer/fit_interferometer.py(reference, merged chore: rename PyAutoConf → PyAutoNerves in docs/prose #637) —uses_precomputed_data_term_from,inversion_with_data
Original Prompt
Click to expand starting prompt
PyAutoLens parity: precomputed data term on the sparse interferometer path (streaming phase 1)
Type: feature
Target: PyAutoLens
Repos:
- PyAutoLens
Themes: - interferometer
- sparse-operator
- memory
Difficulty: small
Autonomy: supervised
Priority: medium
Status: draft
Consequence: glance
Witness:al.FitInterferometeron a sparse-operator dataset with a pixelization-only source (no non-linear light profiles) builds its inversion withdata=None, never evaluatesprofile_visibilities/profile_subtracted_visibilitiesduringfigure_of_merit(spy onaa.Visibilities.zerosandtransformer.visibilities_from), log_evidence is bit-equal to the data-passed path, andtest_autolens/interferometeris green.
Review-minutes: 3
Unattended: ready
Parent: complete/2026/09/interferometer-streaming-visibilities.md
Source: GitHub Discussion https://github.com/orgs/PyAutoLabs/discussions/13 (HRSAstro,
"Streaming visibilities for memory efficiency"); phase 1 = PyAutoArray#588 (PRs on
PyAutoArray + PyAutoGalaxy, branch feature/interferometer-streaming-visibilities).
Why
Phase 1 made the pixelization-only sparse path skip the two N_vis allocations per
likelihood call in PyAutoGalaxy: fast_chi_squared / noise_normalization read the
scalars carried by InterferometerSparseOperator, and
autogalaxy/interferometer/fit_interferometer.py passes data=None into
DatasetInterface when uses_precomputed_data_term_from(dataset, galaxies, data, noise_map) holds. PyAutoLens has its own FitInterferometer, whose
tracer_to_inversion (autolens/interferometer/fit_interferometer.py ~L155) still passes
data=self.profile_subtracted_visibilities unconditionally — so lens fits, the main
consumer, still allocate Visibilities.zeros + data - profile_visibilities over N_vis
on every call.
What
- In
autolens/interferometer/fit_interferometer.pytracer_to_inversion, reuse
ag.interferometer.fit_interferometer.uses_precomputed_data_term_from(self.dataset, self.tracer.galaxies, self.data, self.noise_map)(verify the import path on the
shipped autogalaxy) and passdata=Nonewhen it holds; keepsparse_dirty_image
as is. - Add
inversion_with_datamirroring autogalaxy's (an inversion rebuilt with the real
profile_subtracted_visibilities, for consumers that needinversion.data). - Switch
autolens/interferometer/model/visualizer.py(~L139-160) to
fit.inversion_with_datawhere it plots inversion quantities that read data. - Tests in
test_autolens/interferometer/test_fit_interferometer.pymirroring
autogalaxy's phase-1 additions: thedata=Nonegate, the spy, bit-equal log_evidence,
and the light-profile case still passing data. - Check
autolens/aggregator/andautolens/plot/(andal.aggfit reconstruction) for
inversion.data/inversion.data_vectorreads that would break ondata=None.
Blocked on the phase-1 PyAutoArray + PyAutoGalaxy PRs merging (library-first). (merged 2026-09-30)
🤖 Generated with Claude Code
Activity
Jammy2211 commentedon Sep 30, 2026
Library PR created
🤖 Generated with Claude Code
Jammy2211 commentedon Sep 30, 2026
Shipped
PyAutoLens parity for phase 1 of https://github.com/orgs/PyAutoLabs/discussions/13 is merged: #757 (merge 092897e). Sparse pixelization-only lens fits now build their inversion with
data=Noneand allocate no visibility-sized arrays per likelihood call;fit.inversion_with_datacarries the fitted visibilities for output paths. Labelledpending-release.Independent review findings were addressed in PyAutoArray#591 / autogalaxy_workspace#253 / autolens_workspace#581 (also merged).
🤖 Generated with Claude Code