Skip to content

perf(interferometer): cache curvature_matrix / data_vector on sparse and mapping inversions (#581) - #582

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/interferometer-sparse-cache
Sep 27, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/interferometer-sparse-cache

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

On the NumPy path, a single figure_of_merit of InversionInterferometerSparse or InversionInterferometerSparseNumba built the curvature matrix F twice and the data vector D four times. The reason is that data_vector, curvature_matrix and curvature_matrix_diag were plain @property attributes, read separately by curvature_reg_matrix, reconstruction and fast_chi_squared. On RAL CPU (autolens_profiling #326 / PR #328) that repeat work is 43–50 % of every alma / alma_high call.

They now use autonerves.cached_property, the same decorator the imaging inversions already use for these attributes, and those run under jit / vmap / grad. Changes:

  • interferometer/sparse.py: data_vector, curvature_matrix, curvature_matrix_diag
  • interferometer_numba/sparse.py: the curvature_matrix_diag override
  • interferometer/mapping.py: data_vector, curvature_matrix (brought in line with imaging/mapping.py)

A new inversion is built for every fit, so the cache never needs invalidating. The preloads.curvature_matrix short-circuit is unchanged, and its test still asserts that the injected matrix object is returned as-is.

Measured (laptop, sma, indicative; phase-1 harness interferometer_pixelized_numpy.py, 20 iid instances, 1 thread)

cell / arm evaluations F, D FoM before = after (bit-identical) full call median before → after
Delaunay / numba {2, 4} → {1, 1} -3162.6272344520685 492 → 343 ms
Delaunay / NumPy FFT {2, 4} → {1, 1} same 1783 → 923 ms
rect 39x39 / numba {2, 4} → {1, 1} -3168.595092417778 (= pin) 1275 → 1245 ms (fnnls-dominated; fast-χ² step 163 → 1.3 ms)
rect 39x39 / NumPy FFT {2, 4} → {1, 1} same 2348 → 2079 ms

The JAX sma Delaunay cell gives FoM -3162.627234758772 both before and after. On a small sparse fixture, the traced graph shrinks from 305 to 272 equations, and jit, vmap and grad values are identical before and after. The quotable RAL CPU re-run (sma / alma / alma_high, both meshes) will land as a separate autolens_profiling PR after this merges. That PR also needs a harness counter that understands cached_property, because the current counter wraps the attribute in a plain property via .fget.

API Changes

None — internal changes only (internal caching; no public API change). The attribute names, signatures and returned values are unchanged. The only behavioural difference is that repeated reads on the same inversion instance return the cached value instead of recomputing it.
See full details below.

Test Plan

  • New evaluation-count tests assert F == 1 and D == 1 per likelihood for InversionInterferometerSparse, InversionInterferometerSparseNumba (serial and parallel kernel) and InversionInterferometerMapping. They count with wrappers that keep the property type, plus the underlying operator call curvature_matrix_diag_from and the numba kernel.
  • Red on the unfixed source: all 4 failed (Sparse F=2 D=2; Numba kernel=2 D=2 in both modes; Mapping F=2 D=2). Green after the change, with the likelihood unchanged.
  • pytest test_autoarray: 1736 passed
  • PyAutoGalaxy interferometer tests: 40 passed; PyAutoLens interferometer + potential_correction tests: 35 passed (run against this branch)
  • autolens_workspace_test JAX scripts against this branch: misc/jax_assertions/fit_interferometer_sparse_operator.py, interferometer/jax_likelihood/rectangular_sparse.py (jit + vmap), interferometer/jax_grad/gradient.py (sparse-path grad) all pass
  • Downstream impact: nothing in PyAutoGalaxy, PyAutoLens, the workspaces or the pipeline assigns or patches these attributes. The only exception is the profiling harness counter noted above.

Heart readiness: YELLOW, acknowledged by the human 2026-09-27: "manifest drift: hub organism blurb (organs present) — 7 mismatch(es) vs PyAutoMind/repos.yaml; manifest drift: organism-map blocks (generated) — 1 mismatch(es) vs PyAutoMind/repos.yaml; manifest drift: workspace checkouts (manifest ↔ disk) — 1 mismatch(es) vs PyAutoMind/repos.yaml; release validation incomplete: no rehearsal for current source".

Full API Changes (for automation & release notes)

Changed Behaviour

  • InversionInterferometerSparse.data_vector, .curvature_matrix, .curvature_matrix_diag, InversionInterferometerSparseNumba.curvature_matrix_diag, InversionInterferometerMapping.data_vector, .curvature_matrix — cached per instance (autonerves.cached_property), no longer recomputed on each access. Values are unchanged.

Closes #581

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

…and mapping inversions (#581)

On the NumPy path one figure_of_merit of InversionInterferometerSparse /
InversionInterferometerSparseNumba built F twice and D four times, because
data_vector, curvature_matrix and curvature_matrix_diag were plain
properties read by curvature_reg_matrix, reconstruction and
fast_chi_squared (43-50 % of an alma RAL CPU call, autolens_profiling
#326). They are now autonerves cached_property, as the imaging inversions'
already are; the numba curvature_matrix_diag override and the dense
InversionInterferometerMapping data_vector / curvature_matrix follow.
An inversion is built per fit, so no invalidation is needed; the
preloads.curvature_matrix short-circuit is unchanged.

Tests: evaluation-count tests (descriptor-preserving counters plus the
underlying operator / numba kernel) assert F == 1 and D == 1 per
likelihood for Sparse, SparseNumba (serial + parallel kernel) and Mapping;
red on the unfixed source (2 / 2 each).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(interferometer): cache curvature_matrix / data_vector on sparse + mapping inversions

1 participant