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:
- 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";
- 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
- 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.
- 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.
- 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
Summary
On the canonical imaging potential-correction example,
al.pc.IterFitDpsiSrcImagingperforms worse than the one-shotal.pc.FitDpsiSrcImagingit is documented to improve on: it places thedkappapeak 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.pyunmodified, under the release profile (PYAUTO_TEST_MODE=1,PYAUTO_SMALL_DATASETSreleased by the script'sENV: full_datasetsdeclaration), onautolens2026.7.23.1:The simulation is seeded (
noise_seed=1), so this is reproducible.Why this is worth looking at
The script's own prose states the iterative engine
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:x0=fit.src_dpsi_slim), with the stated rationale that it "then refines inside the right basin instead of searching from zero";reg_optimize_every=1).The imaging example calls
iter_fit.solve_joint_optimization()with nox0and 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 possiblen_iter=5is simply too few to converge.Suggested triage
x0warm-started from the one-shot solution and confirm whether the peak snaps back onto the subhalo and the evidence rises above the one-shot.solve_joint_optimizationshould warn — or refuse — when cold-started, since the interferometer script already treats warm-starting as required practice rather than an option.IterFitDpsiSrcImagingand 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/autogalaxy2026.7.23.1PYAUTO_DISABLE_JAX=0but the dense kernels default to numpy)