Repository navigation
refactor: einstein_radius_jit_from finds its own seed inside the JIT trace - #615
Merged
Merged
Conversation
…trace `init_guess` is now optional. When omitted, the new `LensCalc._seed_via_coarse_grid_argmin` evaluates the tangential eigen value on a coarse uniform grid (25x25, ±3 arcsec by default) from the raw Hessian and returns the cell of minimum |eigen value| as the Newton seed for `jax_zero_contour.ZeroSolver`. It is xp-generic, masks non-finite cells (the odd-shaped grid puts a cell on the singular centre), and uses no skimage and no Python control flow on traced values, so the jit path no longer needs a caller-supplied seed. `seed_grid_shape` / `seed_grid_extent` let off-centre or cluster-scale callers widen the search without leaving the JIT-friendly path. The explicit `init_guess` path, the closure cache and the jax_zero_contour-missing soft-fail are unchanged. The signature-lock test flips to assert the argument is optional; numpy-path unit tests cover the centred, off-centre and radial cases and the soft-fail without a seed. Closes #614. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014JqpPWfk6nUAqnyv4P5oNM
This was referenced Sep 11, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LensCalc.einstein_radius_jit_fromrequired callers to pass static Newton seed positions (init_guess) forjax_zero_contour.ZeroSolver, because the non-jit seed search (_init_guess_from_coarse_grid) goes through skimage marching squares and cannot be traced. The only production caller (PyAutoLens'effective_einstein_radiuslatent) hardcodes a 4-seed fan at ±1 arcsec from the origin.This PR makes
init_guessoptional. When omitted, a new private helper_seed_via_coarse_grid_argminevaluates the tangential eigen value on a coarse uniform grid (25×25, ±3 arcsec by default) straight from the raw Hessian tuple, masks non-finite cells, and returns the cell of minimum|eigen value|as the seed. It isxp-generic (numpy for unit tests,jax.numpyinside the trace), uses no skimage and no Python control flow on traced values.seed_grid_shape/seed_grid_extentlet off-centre or cluster-scale callers widen the search without leaving the JIT path.Unchanged: the explicit
init_guesspath, the(f, ZeroSolver)closure cache, thejax_zero_contour-missing soft-fail (still the first thing in the body, so a seedless call also returns NaN with one warning),_init_guess_from_coarse_grid, the non-jit zero-contour methods and the plotter path.Closes #614. Follow-on: PyAutoLabs/PyAutoLens#735 drops the hardcoded fan (merge after this PR).
API Changes
LensCalc.einstein_radius_jit_from:init_guessis now optional (defaultNone→ in-trace seed search); two new keyword argumentsseed_grid_shape=(25, 25)andseed_grid_extent=3.0. Every existing call that passesinit_guessbehaves exactly as before. New private helperLensCalc._seed_via_coarse_grid_argmin.See full details below.
Test Plan
test_autogalaxy/operate/test_deflections.py: 41 passed (was 37). Signature-lock test flipped to assertinit_guessis optional; new numpy-only tests for the seed helper on a centred SIS (seed within one cell width of the 1.0" curve), an off-centre SIE at (2.0, −1.5) withgrid_extent=5.0, the radial branch, and the soft-fail with no seed (asserts the seed search is never entered)._seed_via_coarse_grid_argmin(xp=jnp)traces underjax.jitand returns the same cell asxp=np([[0.24, -1.2]]for an SIE witheinstein_radius=1.2).einstein_radius_fromon a 200×200/0.05" grid gives 1.19706.)einstein_radius=1.0: no seed withseed_grid_extent=5.0→ 0.971 (2.9% low, from coarse-cell seed quantisation). Note: the ±1 fan also converged on this particular model (1.004) — Newton walked onto the off-centre curve from the fan points. The seed finder's case is that it needs no caller knowledge of where the lens is, not that the fan always fails.jax.jitover a function that buildsIsothermalSph(einstein_radius=r)from a traced scalar and callseinstein_radius_jit_from()works: r=0.8 → 0.793, r=1.5 → 1.494.tests/test_compute_latent_variable.py::test_effective_einstein_radiusre-checks the latent value against the Phase B baseline.Full API Changes (for automation & release notes)
Added
LensCalc._seed_via_coarse_grid_argmin(kind="tangential", grid_shape=(25, 25), grid_extent=3.0, pixel_scales=(0.05, 0.05), xp=np)— private; JIT-traceable single-seed finder (argmin of|eigen value|on a coarse grid, non-finite cells masked).pixel_scalesaccepted for signature symmetry only.Changed Signature
LensCalc.einstein_radius_jit_from(init_guess=None, delta=0.05, N=500, pixel_scales=(0.05, 0.05), tol=1e-6, max_newton=5, seed_grid_shape=(25, 25), seed_grid_extent=3.0)—init_guesswas required; two new trailing keyword arguments.Changed Behaviour
einstein_radius_jit_from()with noinit_guessruns the in-trace seed search instead of raisingTypeError. A model with several distinct tangential critical curves is seeded on only one of them; passinit_guessexplicitly for those.Migration
lens_calc.einstein_radius_jit_from(init_guess=jnp.array([[1.0, 0.0], [0.0, 1.0], [-1.0, 0.0], [0.0, -1.0]]))lens_calc.einstein_radius_jit_from()(orseed_grid_extent=<half-width>for off-centre / cluster-scale lenses). The old call still works.Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code
https://claude.ai/code/session_014JqpPWfk6nUAqnyv4P5oNM