Skip to content

fix: test-mode-gate singular/non-PD inversion crash (release tail) #388

Description

@Jammy2211

Overview

Release re-validation (run 29341418859, wheels 2026.7.14.1.dev65901) reported two chained-pipeline FAILs — interferometer/.../multi_gaussian_expansion/slam.py (numpy.linalg.LinAlgError: Singular matrix) and imaging/features/pixelization/cpu_fast_modeling.py (autoarray.exc.InversionException). Investigation + reproduction (dev venv, jax 0.10.2, matches release) shows this is a flaky test-mode tail, not a deterministic library bug: real inference is already protected by the resample guard in log_likelihood_function; the crash fires only in PYAUTO_TEST_MODE chained runs where an under-converged/fabricated model reaches an unguarded downstream inversion, and only tips into a raised exception under specific numeric conditions. Fix is therefore test-mode-gated in PyAutoArray and must not perturb real-mode numerics.

Plan

  • In normal mode, inversion behaviour is byte-for-byte unchanged (still raises → still resamples in the guarded likelihood).
  • Only when is_test_mode() (from autoconf), the inversion sites return a benign dummy instead of raising — neutralising the singular case wherever the inversion is invoked (likelihood, preload, result, chaining), which is why per-path guards in PyAutoLens are unnecessary.
  • No conditioning floor / jitter: that would shift every real evidence/reconstruction and conflicts with the "no silent guards / fix the producer" rule.
  • Validate with a numpy-only unit test; do not use the flaky end-to-end scripts as a gate.
Detailed implementation plan

Affected Repositories

  • PyAutoArray (primary)

Branch Survey

Repository Current Branch Dirty?
./PyAutoArray feature/ticks-minus-in-math clean (unrelated; new worktree off origin/main)

Suggested branch: feature/inversion-testmode-singular-guard

Implementation Steps

  1. autoarray/inversion/inversion/inversion_util.py reconstruction_positive_negative_from (~:224) — wrap xp.linalg.solve in try/except np.linalg.LinAlgError; in test mode return xp.ones_like(data_vector), else raise exc.InversionException.
  2. inversion_util.py reconstruction_positive_only_from (~:344-353) — the except already raises InversionException; in test mode return xp.ones_like(data_vector) instead.
  3. autoarray/inversion/inversion/abstract.py log_det_curvature_reg_matrix_term (~:715-721) — wrap the Cholesky; in test mode return 0.0 on LinAlgError (else the crash moves here once the reconstruction stops raising).
  4. abstract.py log_det_regularization_matrix_term (~:740-746) — same.
  5. Small shared helper to keep the gate DRY; import is_test_mode from autoconf.

Key Files

  • autoarray/inversion/inversion/inversion_util.py — the two reconstruction solvers that raise on singular.
  • autoarray/inversion/inversion/abstract.py — the two log-det Cholesky evidence terms that also raise on singular.
  • test_autoarray/inversion/inversion/ — numpy-only unit test for the guard.

Testing

  • Numpy-only unit test: a deliberately singular curvature_reg_matrix (a) raises normally, (b) under monkeypatched PYAUTO_TEST_MODE returns finite dummies.
  • No JAX in unit tests; JAX path covered by existing *_workspace_test parity scripts.

Notes

Follow-up to PyAutoHeart#72 and the G fix PyAutoLens#607. Diagnosis reversed the original prompt's scope (dropped the conditioning floor + PyAutoLens guards). Autonomy: supervised — filed and implemented under --auto; ship sign-off parks for a human.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions