Overview
Audit JAX autodiff support across the PyAutoLens likelihoods so gradient-based inference (NUTS/HMC via BlackJAX, gradient-aware nested sampling) stands on validated ground. Covers parametric light profiles (Sérsic, linear Sérsic, MGE), pixelized source reconstructions (Delaunay, rectangular), the point-source source-plane χ², and the weak-lensing likelihood. Deliverables are a per-likelihood gradient status report, autodiff-vs-finite-difference correctness tests (none exist today — current jax_grad/ scripts assert finiteness only), and documented root causes where differentiation breaks.
Plan
- Build a shared finite-difference comparison helper in
autolens_workspace_test/scripts/jax_grad/ (vmap-honest evaluation so pure_callback const-folding can't fake results).
- Phase 1 — light profiles: re-run existing gradient probes on current mains; upgrade
imaging_lp.py/imaging_mge.py from finiteness-only to FD-correctness; add a standard (non-linear) Sérsic case; document any breaks.
- Phase 2 — pixelized sources: re-confirm and write up why full Delaunay gradients are infeasible today (scipy
pure_callback has no JVP rule); validate rectangular-mesh gradients vs FD, characterising the intentional stop_gradient approximation (anchor paper: https://arxiv.org/abs/2606.30620); check gradient flow through the NNLS solve.
- Phase 3 — validate point-source source-plane χ² gradients (they work under
value_and_grad despite the forward-JIT blocker) and probe + validate the weak-lensing FitWeak likelihood (xp=jnp path exists, never gradient-probed).
- Wrap-up: audit README in
jax_profiling/gradient/, follow-up tasks (e.g. Delaunay custom_jvp, Grid2DIrregular xp gap) filed as ideas, not fixed here.
Detailed implementation plan
Affected Repositories
- autolens_workspace_developer (primary — gradient probes + audit report)
- autolens_workspace_test (FD correctness tests)
- Read-only: PyAutoArray, PyAutoGalaxy, PyAutoLens, autolens_profiling (claimed by in-flight tasks; any library fix escalates as a follow-up task)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./autolens_workspace_developer |
main |
1 untracked |
| ./autolens_workspace_test |
main |
clean |
| ./autolens_profiling |
main |
claimed: profiling-preopt-campaign |
| ./PyAutoArray |
main |
claimed: nnls-solver-optimization |
Suggested branch: feature/jax-autodiff-gradients-audit
Worktree: ~/Code/PyAutoLabs-wt/jax-autodiff-gradients-audit/
Implementation Steps
- Shared FD helper
autolens_workspace_test/scripts/jax_grad/util.py: central finite differences of the log-likelihood per model parameter (step scaled to parameter magnitude), compared to jax.grad with per-parameter rel/abs tolerance report; evaluate via vmapped fitness (fitness._vmap), never single-JIT on concrete arrays.
- Phase 1: re-run
autolens_workspace_developer/jax_profiling/gradient/imaging/mge.py and autolens_workspace_test/scripts/jax_grad/{imaging_lp,imaging_mge}.py on current mains; upgrade both jax_grad scripts to FD comparison; add lp.Sersic (standard, non-linear) coverage alongside lp_linear.Sersic and MGE; document tracing/differentiation breaks with file:line root cause.
- Phase 2a (Delaunay): reproduce the 3 PASS / 8 ERROR result of
jax_profiling/gradient/imaging/delaunay.py — root cause jax.pure_callback → scipy.spatial.Delaunay at PyAutoArray/autoarray/inversion/mesh/interpolator/delaunay.py:80, no JVP rule; write up why full gradients are infeasible (frozen triangulation = discrete combinatorial structure; a custom_jvp zero-rule unblocks the chain but leaves mesh-position derivatives undefined at cell boundaries).
- Phase 2b (rectangular): read arXiv:2606.30620 first; validate existing gradients vs FD, explicitly characterising which parameter directions the
lax.stop_gradient in create_transforms drops; add jax_grad/imaging_pixelization.py with tolerances informed by that analysis.
- Phase 2c: gradient flow through the linear-inversion NNLS/fnnls solve — extend the existing solver-level guard
jax_assertions/nnls.py, don't duplicate it.
- Phase 3a:
jax_grad/point_source.py — FD-validate FitPositionsSource.log_likelihood gradients including the magnification-via-Hessian term.
- Phase 3b: new probe
jax_profiling/gradient/weak/likelihood.py (FitWeak, xp=jnp) + jax_grad/weak.py FD test.
- Wrap-up: per-likelihood status README (
jax_profiling/gradient/README.md), follow-up ideas filed to the backlog, ship both workspace repos.
Key Files
autolens_workspace_developer/jax_profiling/gradient/ — existing step-by-step value_and_grad probes (imaging mge/pixelization/delaunay, interferometer mge, point_source ×2); docstrings hold prior findings to re-validate.
autolens_workspace_test/scripts/jax_grad/{imaging_lp,imaging_mge}.py — finiteness-only tests to upgrade.
autolens_workspace_test/scripts/jax_assertions/nnls.py — solver-level finite-grad guard to extend.
PyAutoLens/autolens/weak/fit.py — FitWeak, traceable with xp=jnp, pytree registered (read-only).
PyAutoArray/autoarray/inversion/mesh/interpolator/{delaunay,rectangular}.py — the two gradient-killers/fixes under audit (read-only).
Verification
- Every new/upgraded
jax_grad/ script runs green from the autolens_workspace_test root on CPU JAX; existing finiteness checks keep passing.
- FD agreement reported per parameter; intentional
stop_gradient deviations documented with measured magnitude, not hidden by loose tolerances.
- Delaunay failure reproduced on current mains before being documented as current fact.
Original Prompt
Click to expand starting prompt
You're working in the PyAutoLens or PyAutoArray codebase, using the usual profiling workspace, profiling agent, and PyAutoBrain flow. First, investigate the state of JAX autodiff support for Sérsic light profiles, linear Sérsic light profiles, and Multi-Gaussian Expansion light profiles. Profile what's there, identify what breaks tracing or differentiation, and add or refine automated tests comparing autodiff against finite differences. Second, investigate gradients for pixelized source reconstructions, starting with the Delaunay mesh. We expect that full gradients may not be feasible there. Confirm why and document where it fails. Then move to the rectangular mesh, where we think gradients might be possible. Before starting that part, ask me for the relevant paper if you don't already have it. Third, validate gradients for the source plane chi-squared used for point sources, and for the weak lensing likelihood.
Overview
Audit JAX autodiff support across the PyAutoLens likelihoods so gradient-based inference (NUTS/HMC via BlackJAX, gradient-aware nested sampling) stands on validated ground. Covers parametric light profiles (Sérsic, linear Sérsic, MGE), pixelized source reconstructions (Delaunay, rectangular), the point-source source-plane χ², and the weak-lensing likelihood. Deliverables are a per-likelihood gradient status report, autodiff-vs-finite-difference correctness tests (none exist today — current
jax_grad/scripts assert finiteness only), and documented root causes where differentiation breaks.Plan
autolens_workspace_test/scripts/jax_grad/(vmap-honest evaluation sopure_callbackconst-folding can't fake results).imaging_lp.py/imaging_mge.pyfrom finiteness-only to FD-correctness; add a standard (non-linear) Sérsic case; document any breaks.pure_callbackhas no JVP rule); validate rectangular-mesh gradients vs FD, characterising the intentionalstop_gradientapproximation (anchor paper: https://arxiv.org/abs/2606.30620); check gradient flow through the NNLS solve.value_and_graddespite the forward-JIT blocker) and probe + validate the weak-lensingFitWeaklikelihood (xp=jnppath exists, never gradient-probed).jax_profiling/gradient/, follow-up tasks (e.g. Delaunaycustom_jvp,Grid2DIrregularxp gap) filed as ideas, not fixed here.Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/jax-autodiff-gradients-auditWorktree:
~/Code/PyAutoLabs-wt/jax-autodiff-gradients-audit/Implementation Steps
autolens_workspace_test/scripts/jax_grad/util.py: central finite differences of the log-likelihood per model parameter (step scaled to parameter magnitude), compared tojax.gradwith per-parameter rel/abs tolerance report; evaluate via vmapped fitness (fitness._vmap), never single-JIT on concrete arrays.autolens_workspace_developer/jax_profiling/gradient/imaging/mge.pyandautolens_workspace_test/scripts/jax_grad/{imaging_lp,imaging_mge}.pyon current mains; upgrade both jax_grad scripts to FD comparison; addlp.Sersic(standard, non-linear) coverage alongsidelp_linear.Sersicand MGE; document tracing/differentiation breaks with file:line root cause.jax_profiling/gradient/imaging/delaunay.py— root causejax.pure_callback→scipy.spatial.DelaunayatPyAutoArray/autoarray/inversion/mesh/interpolator/delaunay.py:80, no JVP rule; write up why full gradients are infeasible (frozen triangulation = discrete combinatorial structure; acustom_jvpzero-rule unblocks the chain but leaves mesh-position derivatives undefined at cell boundaries).lax.stop_gradientincreate_transformsdrops; addjax_grad/imaging_pixelization.pywith tolerances informed by that analysis.jax_assertions/nnls.py, don't duplicate it.jax_grad/point_source.py— FD-validateFitPositionsSource.log_likelihoodgradients including the magnification-via-Hessian term.jax_profiling/gradient/weak/likelihood.py(FitWeak,xp=jnp) +jax_grad/weak.pyFD test.jax_profiling/gradient/README.md), follow-up ideas filed to the backlog, ship both workspace repos.Key Files
autolens_workspace_developer/jax_profiling/gradient/— existing step-by-step value_and_grad probes (imaging mge/pixelization/delaunay, interferometer mge, point_source ×2); docstrings hold prior findings to re-validate.autolens_workspace_test/scripts/jax_grad/{imaging_lp,imaging_mge}.py— finiteness-only tests to upgrade.autolens_workspace_test/scripts/jax_assertions/nnls.py— solver-level finite-grad guard to extend.PyAutoLens/autolens/weak/fit.py— FitWeak, traceable withxp=jnp, pytree registered (read-only).PyAutoArray/autoarray/inversion/mesh/interpolator/{delaunay,rectangular}.py— the two gradient-killers/fixes under audit (read-only).Verification
jax_grad/script runs green from the autolens_workspace_test root on CPU JAX; existing finiteness checks keep passing.stop_gradientdeviations documented with measured magnitude, not hidden by loose tolerances.Original Prompt
Click to expand starting prompt
You're working in the PyAutoLens or PyAutoArray codebase, using the usual profiling workspace, profiling agent, and PyAutoBrain flow. First, investigate the state of JAX autodiff support for Sérsic light profiles, linear Sérsic light profiles, and Multi-Gaussian Expansion light profiles. Profile what's there, identify what breaks tracing or differentiation, and add or refine automated tests comparing autodiff against finite differences. Second, investigate gradients for pixelized source reconstructions, starting with the Delaunay mesh. We expect that full gradients may not be feasible there. Confirm why and document where it fails. Then move to the rectangular mesh, where we think gradients might be possible. Before starting that part, ask me for the relevant paper if you don't already have it. Third, validate gradients for the source plane chi-squared used for point sources, and for the weak lensing likelihood.