From 31cee4e8b7d3aafb18ed167c3b381632db422d05 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Tue, 12 May 2026 17:46:30 +0100 Subject: [PATCH] fix: return figure_of_merit, not log_likelihood, from CPU AnalysisImaging.log_likelihood_function The CPU branch returned fit.log_likelihood while the JAX branch returned fit.figure_of_merit. For pixelization (inversion) fits these differ by the regularization log-det terms, so any nested sampler driven by the CPU path optimised a chi^2-only target and drifted toward outer_coefficient ~ 0 (noise-overfit), while JAX runs converged to the physical Bayesian-evidence maximum. Add a regression test that exercises a Rectangular Pixelization with Constant regularization so the two quantities differ; the existing parametric-Sersic test still passes because fom == log_likelihood when there is no inversion. Co-Authored-By: Claude Opus 4.7 (1M context) --- autolens/imaging/model/analysis.py | 2 +- .../imaging/model/test_analysis_imaging.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/autolens/imaging/model/analysis.py b/autolens/imaging/model/analysis.py index 4ca751448..39415f6b5 100644 --- a/autolens/imaging/model/analysis.py +++ b/autolens/imaging/model/analysis.py @@ -79,7 +79,7 @@ def log_likelihood_function(self, instance: af.ModelInstance) -> float: return self.fit_from(instance=instance).figure_of_merit - log_likelihood_penalty try: - return self.fit_from(instance=instance).log_likelihood - log_likelihood_penalty + return self.fit_from(instance=instance).figure_of_merit - log_likelihood_penalty except Exception as e: raise af.exc.FitException diff --git a/test_autolens/imaging/model/test_analysis_imaging.py b/test_autolens/imaging/model/test_analysis_imaging.py index 7e2df58ed..a401df196 100644 --- a/test_autolens/imaging/model/test_analysis_imaging.py +++ b/test_autolens/imaging/model/test_analysis_imaging.py @@ -44,6 +44,33 @@ def test__figure_of_merit__matches_correct_fit_given_galaxy_profiles( assert fit.log_likelihood == analysis_log_likelihood +def test__log_likelihood_function__returns_figure_of_merit_for_pixelization( + masked_imaging_7x7, +): + pixelization = al.Pixelization( + mesh=al.mesh.RectangularUniform(shape=(3, 3)), + regularization=al.reg.Constant(coefficient=1.0), + ) + + lens = al.Galaxy( + redshift=0.5, + mass=al.mp.IsothermalSph(einstein_radius=1.0), + ) + source = al.Galaxy(redshift=1.0, pixelization=pixelization) + + model = af.Collection(galaxies=af.Collection(lens=lens, source=source)) + instance = model.instance_from_unit_vector([]) + + analysis = al.AnalysisImaging(dataset=masked_imaging_7x7, use_jax=False) + analysis_log_likelihood = analysis.log_likelihood_function(instance=instance) + + tracer = analysis.tracer_via_instance_from(instance=instance) + fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer) + + assert analysis_log_likelihood == pytest.approx(fit.figure_of_merit) + assert fit.figure_of_merit != pytest.approx(fit.log_likelihood, rel=1e-6) + + def test__positions__likelihood_overwrites__changes_likelihood(masked_imaging_7x7): lens = al.Galaxy(redshift=0.5, mass=al.mp.IsothermalSph(centre=(0.05, 0.05))) source = al.Galaxy(redshift=1.0, light=al.lp.SersicSph(centre=(0.05, 0.05)))