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

    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