feat: route MGE-only interferometer fits through the W~ sparse operator (#575) - #576
Merged
Merged
Conversation
…se operator (#575) - factory: an interferometer dataset with a sparse operator now selects InversionInterferometerSparse for every linear object list, including MGE-only (no mapper); imaging routing unchanged (commented why). - DatasetInterface gains sparse_dirty_image; the sparse data vector uses it when set, else the operator's cached dirty image. - TransformerDFT.image_from / image_direct_from take xp so the adjoint DFT traces under jax.jit. - Tests: func-list-only sparse vs dense parity (1e-10), sparse_dirty_image override with a cached-image control, JAX-vs-NumPy func-list-only case, factory routing, DFT image_from under jit. Refs #575 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 26, 2026
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
MGE-only (func-list-only) interferometer inversions now use the W~ sparse operator whenever
apply_sparse_operator()has been applied, instead of always taking the densetransform_mapping_matrixpath. On the #308 breakdown this is 356–1746x faster on the A100 (dense 0.86–23.8 s vs W~ 1.9–13.5 ms). At alma on CPU under jit, the full fit takes 1.03 s sparse against 12.1 s dense, with identical log likelihood. The dense path also runs out of A100 memory at alma and above.InversionInterferometerSparsealready handled zero mappers, so the only routing change is removing the factory guard. The sparsedata_vectorcan now take a dirty image for data that differs from the dataset the operator was built from (DatasetInterface.sparse_dirty_image). This is the seam fixed in the PyAutoGalaxy and PyAutoLens PRs: sparse fits with ordinary light profiles used to form D from the unsubtracted visibilities. Imaging routing is unchanged; its version of the seam is tracked separately insparse_inversion_ignores_profile_subtracted_image.Closes #575 together with the PyAutoGalaxy and PyAutoLens PRs (merge this one first).
API Changes
apply_sparse_operator(), an interferometer inversion made only of linear light profiles (e.g. an MGE) now buildsInversionInterferometerSparserather thanInversionInterferometerMapping. Results are identical to float precision.DatasetInterface(sparse_dirty_image=None), which the sparse interferometerdata_vectoruses when it is set.TransformerDFT.image_from(..., xp=)andtransformer_util.image_direct_from(..., xp=np)now honourxp, so they work underjax.jit. This is an incidental fix; before this change they were NumPy-only and crashed inside jit.See full details below.
Test Plan
test_autoarrayfull suite: 1706 passedtest__interferometer_sparse_operator__func_list_only__identical_to_mapping,..._sparse_dirty_image_override__used_by_data_vector(1e-10, with a control showing the cached image is wrong for subtracted data), func-list-only JAX-vs-NumPy,test__inversion_interferometer__via_linear_obj_func_list__sparse_operator,test__dft__image_from__jax_jit_matches_numpyInversionInterferometerSparseandInversionInterferometerMapping.Full API Changes (for automation & release notes)
Added
autoarray.DatasetInterface(..., sparse_dirty_image=None): the noise-weighted dirty imageRe(Fᴴ W d)of the interface'sdata, for the sparse interferometer inversion.Changed Signature
autoarray.operators.transformer_util.image_direct_from(visibilities, grid_radians, uv_wavelengths, xp=np)Changed Behaviour
inversion_interferometer_from:dataset.sparse_operator is not Nonealone selects the sparse (W~) formalism, including func-list-only linear object lists. Previously func-list-only lists always usedInversionInterferometerMapping.InversionInterferometerSparse.data_vector: usesdataset.sparse_dirty_imagewhen it is not None, and otherwisesparse_operator.dirty_image.TransformerDFT.image_from: honoursxp(JAX-traceable).Migration
Heart RED override (development only)
The human authorized the AUTONOMY.md "Human override for Heart RED (development only)" for this task (PyAutoArray#575, branch
feature/interferometer-mge-w-tilde-route) on 2026-09-26. When asked how to proceed with the three library PRs, they chose "Override, open PRs". The override covers commit, push and opening pending-release PRs only. Merging needs a separate/prmwith every required check green. This branch does not claim to fix Heart.Exact RED reasons at ship time:
Branch gates passed: 24/24 targeted interferometer smoke scripts pass on the branch (autolens_workspace 11, autogalaxy_workspace 5, autolens_workspace_test 5, autogalaxy_workspace_test 3: MGE, pixelization, linear light profiles, sparse-operator JAX assertions and likelihood pins).
autolens_workspace_test/.../jax_likelihood/mge.pyfirst failed identically on the branch and on the mains because the local dataset was stale (2026-08-06, older than the 09-18 simulator change); after regenerating it, the script passes on both. Unit suites: PyAutoArray 1706 passed, PyAutoGalaxy 1240 passed, PyAutoLens 757 passed + 1 xfailed. My own diff review is in-session only; the human reviews at merge.🤖 Generated with Claude Code