Skip to content

fix(interferometer): resample non-PD inversion instead of crashing the search #606

Description

@Jammy2211

Overview

The interferometer analysis crashes the whole non-linear search when a sampled model produces a non-positive-definite inversion matrix. AnalysisInterferometer.log_likelihood_function returns the fit's figure_of_merit unwrapped, so a numpy.linalg.LinAlgError: Matrix is not positive definite from the Cholesky log-det term (PyAutoArray/autoarray/inversion/inversion/abstract.py:743) propagates through Nautilus's multiprocessing pool and kills the search (~38 s). The imaging analysis already guards this; interferometer does not. Surfaced on the 2026-07-13 release-validation tail (resolves item G, PyAutoHeart#72).

This is NOT jax-0.10.2 numerical drift (the original hypothesis). It is a NumPy/JAX backend divergence: the release profile runs interferometer/model_fit.py with PYAUTO_DISABLE_JAX=1 (NumPy path), where np.linalg.cholesky raises on a non-PD matrix; the JAX path returns NaN, which the fitness resamples — so JAX silently rejects the same pathological point that NumPy crashes on. Reproduced locally on jax 0.10.2: crashes with PYAUTO_DISABLE_JAX=1, completes cleanly without it.

Plan

  • Mirror the imaging analysis's NumPy-path guard in the interferometer analysis so a non-PD inversion at a sampled model resamples instead of crashing.
  • Split log_likelihood_function on self._use_jax: JAX path returns unwrapped (must stay exception-free for tracing); NumPy path wraps the fit in try/except Exception → raise af.exc.FitException (caught by autofit/non_linear/fitness.pyresample_figure_of_merit).
  • Verify whether the point-source analysis has the same missing guard; align only if it shares the unwrapped figure_of_merit path.
  • Validate: NumPy-path interferometer/model_fit.py completes (bad point resampled) instead of LinAlgError; JAX path unchanged; PyAutoLens unit suite green.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary — the fix)
  • autolens_workspace_test (repro / validation only; no edit expected)

Branch Survey

Repository Current Branch Dirty?
./PyAutoLens main clean
./autolens_workspace_test main clean

Suggested branch: feature/interferometer-analysis-fitexception

Implementation Steps

  1. autolens/interferometer/model/analysis.pylog_likelihood_function (~L166–173): replace the direct return (fit… - penalty) with the imaging pattern from autolens/imaging/model/analysis.py:132-144:
    log_likelihood_penalty = self.log_likelihood_penalty_from(instance=instance)
    if self._use_jax:
        return (self.fit_from(instance=instance, preloads=shared).figure_of_merit
                - log_likelihood_penalty)
    try:
        return (self.fit_from(instance=instance, preloads=shared).figure_of_merit
                - log_likelihood_penalty)
    except Exception:
        raise af.exc.FitException
    (af is already imported at analysis.py:22.)
  2. autolens/point/model/analysis.py — inspect log_likelihood_function (L91–160); align to the same guard only if it returns an unwrapped NumPy-path figure_of_merit.
  3. Add/mirror a unit test asserting a non-PD interferometer inversion raises FitException on the NumPy path, if an imaging analogue exists to mirror.

Testing

  • Repro (must now pass): wipe output/build/model_fit/interferometer, then
    PYAUTO_TEST_MODE=0 PYAUTO_SKIP_WORKSPACE_VERSION_CHECK=1 PYAUTO_DISABLE_JAX=1 JAX_ENABLE_X64=True python scripts/interferometer/model_fit.py → completes instead of LinAlgError.
  • JAX path unchanged: same script with no env → still completes.
  • Unit: pytest test_autolens/interferometer/ (NumPy-only).
  • Trade-off: catching broad Exception → FitException is the accepted sibling (imaging) pattern; real bugs still surface on the unwrapped JAX path.

Key Files

  • autolens/interferometer/model/analysis.py — the fix (missing _use_jax split + try/except).
  • autolens/imaging/model/analysis.py:132-144 — the reference pattern to mirror.
  • PyAutoArray/autoarray/inversion/inversion/abstract.py:743 — where the raw LinAlgError originates (Cholesky log-det of the regularization matrix).
  • autofit/non_linear/fitness.py:235,239 — where FitException / NaN become resample_figure_of_merit.

Original Prompt

Click to expand starting prompt

interferometer/model_fit crashes with numpy.linalg.LinAlgError: Matrix is not positive definite on the 2026-07-13 release-validation tail (PyAutoHeart#72), under the release profile (PYAUTO_TEST_MODE=0). Confirmed diagnosis (2026-07-14): the release profile runs the script with PYAUTO_DISABLE_JAX=1 (NumPy path); np.linalg.cholesky raises on a non-PD regularization matrix at a sampled model, whereas the JAX path returns NaN and resamples. The interferometer analysis lacks the NumPy-path try/except → FitException guard that the imaging analysis has (imaging/model/analysis.py:132-144). Fix: mirror the imaging guard in interferometer/model/analysis.py; verify point_source. NOT jax-0.10.2 drift.

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