Skip to content

IterFitDpsiSrcImaging underperforms the one-shot fit on the imaging potential-correction example #666

Description

@Jammy2211

Summary

On the canonical imaging potential-correction example, al.pc.IterFitDpsiSrcImaging performs worse than the one-shot al.pc.FitDpsiSrcImaging it is documented to improve on: it places the dkappa peak far from the true subhalo and reports a substantially lower Bayesian evidence.

Surfaced while validating a file move in autolens_workspace (PyAutoLabs/autolens_workspace#389, PR #393). That PR changed zero code lines — its diff is three docstring hunks — so this is pre-existing behaviour, not a regression from it.

Observed

Running autolens_workspace:scripts/imaging/features/advanced/potential_correction/start_here.py unmodified, under the release profile (PYAUTO_TEST_MODE=1, PYAUTO_SMALL_DATASETS released by the script's ENV: full_datasets declaration), on autolens 2026.7.23.1:

joint source + dpsi log evidence = 9.1506e+03
dkappa peak at (y, x) = (1.45, 0.15) — true subhalo at (1.41, 0.00)
iterative Laplace log evidence = 4.2083e+03
iterative dkappa peak at (y, x) = (-0.55, 0.85)

The simulation is seeded (noise_seed=1), so this is reproducible.

  • One-shot: peak at (1.45, 0.15), ~0.16" from the true subhalo at (1.41, 0.00). Good recovery.
  • Iterative: peak at (-0.55, 0.85) — roughly 2.2" away, on the far side of the lens centre. Not a refinement of the one-shot solution; a different answer entirely.
  • Evidence: 4.21e3 iterative vs 9.15e3 one-shot. The iterative result is disfavoured by ~4.9e3 in log evidence.

Why this is worth looking at

The script's own prose states the iterative engine

optimizes the combined state [source | dpsi] with a Levenberg-Marquardt loop, and after every accepted step re-ray-traces the image grid through the corrected lens … The corrections thus feed back into the source mapping, capturing compact perturbers more faithfully than a single linearization.

On this example it does the opposite. Either the claim needs qualifying, or the engine's configuration here is wrong, or there is a genuine defect. The evidence gap is large enough that it is not a tie-break — the method's own model-selection statistic ranks the iterative solution well below the one-shot.

Note the interferometer sibling (scripts/interferometer/features/advanced/potential_correction/start_here.py) deliberately does two things this imaging example does not:

  1. warm-starts the iterative engine from the one-shot solution (x0=fit.src_dpsi_slim), with the stated rationale that it "then refines inside the right basin instead of searching from zero";
  2. lets the evidence re-optimize the regularization strengths each step (reg_optimize_every=1).

The imaging example calls iter_fit.solve_joint_optimization() with no x0 and with fixed regularization, i.e. cold-started from zero. That is the most likely explanation — the engine is finding a different, worse basin — which would make this primarily a usage/example problem rather than an engine defect. It is also possible n_iter=5 is simply too few to converge.

Suggested triage

  1. Re-run the imaging example with x0 warm-started from the one-shot solution and confirm whether the peak snaps back onto the subhalo and the evidence rises above the one-shot.
  2. If it does: fix the example to warm-start (matching the interferometer sibling), and consider whether solve_joint_optimization should warn — or refuse — when cold-started, since the interferometer script already treats warm-starting as required practice rather than an option.
  3. If it does not: this is an engine-level issue in IterFitDpsiSrcImaging and needs a closer look at the LM loop and the gauge constraints.

Either way the docstring claim in the imaging example should be qualified until the behaviour matches it.

Environment

  • autolens / autoarray / autofit / autogalaxy 2026.7.23.1
  • Linux (WSL2), numpy path (PYAUTO_DISABLE_JAX=0 but the dense kernels default to numpy)
  • Full run: exit 0, 534s

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