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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions