Repository navigation
fix: mask invalid mapper triplets on the imaging sparse path; backend-dispatched scatter-add helpers - #649
Merged
Conversation
sparse_triplets_from gains pix_sizes_for_sub: entries mapping_matrix_from drops (slot >= pix_sizes, or a negative source index) get value 0 and column 0 on both numpy and JAX branches. Mapper.sparse_triplets_data / sparse_triplets_curvature pass it, so every imaging sparse consumer is covered; the interferometer _sparse_triplets_slim_from uses the shared masking and drops its local copy (outputs bit-identical). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
data_vector_via_psf_weighted_data_from and mapped_reconstructed_operated_data_via_sparse_operator_from take xp: numpy uses np.bincount with no JAX import, JAX keeps segment_sum with the import inside its branch. InversionImagingSparse passes xp=self._xp. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- sparse_triplets_from zeroes a -1 index and unused slots with non-zero weights (numpy and JAX), and its triplets scatter to mapping_matrix_from; - InversionImagingSparse on a mapper with -1 indices, a negative index in a used slot and weighted unused slots matches the mapping inversion (data_vector, curvature_matrix, mapped reconstructed data) on numpy and JAX backends; - the mapper triplets and both imaging scatter-add helpers run with jax, jaxlib and nufftax blocked (subprocess import hook). 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.
Closes #643. Side finding from #639 / #641.
Summary
The imaging sparse-inversion path read
Mapper.sparse_triplets_data/sparse_triplets_curvaturebuilt without the slot-size and negative-index zeroing the interferometer path applied locally, and its two scatter-add helpers imported JAX inside the function on every call.mapper_util.sparse_triplets_fromgainspix_sizes_for_sub=Noneand masks invalid entries (slot ≥pix_sizes, orcols < 0→ weight 0, column 0) on both backends, afterslim_weights.Mapper.sparse_triplets_data/sparse_triplets_curvaturepass it. The interferometer_sparse_triplets_slim_fromnow uses the shared masking (its local block removed); its triplets,data_vector,curvature_matrixandreconstructionare identical before and after (24 arrays, Delaunay + rectangular, with and without primary beam).data_vector_via_psf_weighted_data_fromandmapped_reconstructed_operated_data_via_sparse_operator_fromtakexp; numpy usesnp.bincount(minlength=)with no JAX import, JAX keepssegment_sum. The four imaging call sites passxp=self._xp.Is the defect latent? Yes. On the 7×7 fixtures (Delaunay meshes also given a grid reaching outside the hull): Rectangular (all variants), KNN and KNNBarycentric emit no unused slots and no negative indices; Delaunay (56 unused slots) and DelaunayNN (1082) hold index −1 with weight exactly 0 in every unused slot, never a negative index in a used slot nor a non-zero weight in an unused one. Those entries wrap harmlessly under
segment_sumtoday, but the new numpybincountbranch raises on −1, so the masking is a prerequisite, not only a guard.Narrower than planned:
ImagingSparseOperator.from_noise_map_and_psfand the imaging curvature methods still import JAX unconditionally, soInversionImagingSparseas a whole cannot run without JAX even on numpy; fixing that is beyond this PR (follow-up). The interferometer_sparse_triplets_curvature_fromis left as is (its util drops out-of-range columns itself).API Changes
Additive/internal:
mapper_util.sparse_triplets_from(..., pix_sizes_for_sub=None); the two imaging util helpers gainxp=np. No public behaviour changes.See full details below.
Test Plan
test_autoarray/inversion/pixelization/mappers/test_mapper_util.py: hand-built index table with a −1 index and an unused slot with non-zero weight → zeroed on numpy and JAX.test_autoarray/inversion/inversion/imaging/test_imaging.py: imaging sparse parity (data vector, curvature, mapped reconstructed image) vs the dense mapping inversion on such a mapper, numpy backend and JAX backend; subprocess no-JAX test (jax/jaxlib/nufftax blocked) covering the triplets and both helpers against the dense mapping matrix.pytest test_autoarray/inversion -q→ 1037 passed, 4 xfailed;pytest test_autoarray/dataset/imaging -q→ 36 passed; no-JAX emulation 23 passed, 10 skipped, no jax module loaded.Heart YELLOW acknowledged by the human on 2026-10-21 (manifest drift 1 mismatch; release validation stale: source moved since rehearsal (PyAutoArray)).
Full API Changes (for automation & release notes)
Changed Signature
autoarray.inversion.mappers.mapper_util.sparse_triplets_from(..., pix_sizes_for_sub=None)— new optional kwarg; when given, invalid stencil entries are zeroed.inversion_imaging_util.data_vector_via_psf_weighted_data_from(..., xp=np),mapped_reconstructed_operated_data_via_sparse_operator_from(..., xp=np)— backend dispatch; numpy branch no longer imports JAX.Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code