Overview
Companion to a filed autoarray bug (simulator_jax_jit_path_broken). That bug may
sit for a while; the docs claims below are false today and should not stand
while it waits. Docs-only — no behaviour change.
Measured 2026-07-29 on the installed stack.
The false claims
- "The simulator handles pytree registration internally" — no simulator anywhere registers pytrees (autolens, autogalaxy, and both autoarray bases: zero
register hits). The jitted call fails with TypeError ... value is of type Tracer / Galaxies. It is also unimplementable as worded: per PointSolver.solve_triangles' own note, JAX flattens function arguments at trace time, so registration must run before the first jitted call and cannot happen inside the callee.
- "eager
via_tracer_from(...) already runs on JAX" — eager with use_jax=True succeeds but returns dataset.data.array of type numpy.ndarray, not jax.Array, in both libraries.
- The
@jax.jit simulator recipe does not work at all, even with correct registration — it dies inside autoarray (preprocess.py:153, then array_2d_util.py). That is the separate bug; the docs must stop presenting the recipe as working.
Plus one regression introduced this session, and one pre-existing half-truth:
TransformerNUFFT is not the un-traceable one — this was shipped backwards. autolens_workspace#375 / autogalaxy_workspace#181 (merged today) put "TransformerDFT (the default). TransformerNUFFT is not JAX-traceable." into both using_jax.py guides. Inherited from the old __JAX__ blocks, and wrong. Per autoarray's own error text TransformerNUFFT is "the default JAX-native" transformer (nufftax-backed; nufftax 0.3.1 installed) and TransformerNUFFTPyNUFFT is "the legacy pynufft backend". Defaults also differ by class: SimulatorInterferometer → TransformerDFT (autoarray/dataset/interferometer/simulator.py:16); Interferometer, which a fit uses → TransformerNUFFT (.../dataset.py:34). autolens_workspace/scripts/interferometer/simulator.py already states this correctly, so the guides contradict a sibling script.
guides/tracer.py says "Pytree registration runs as a side effect of the first fit_from / via_tracer_from call; you write nothing JAX-specific." True for fit_from (both Analysis classes register inline); false for via_tracer_from.
Plan
- Mirror the two scripts that already get this right rather than inventing wording:
point_source/simulator.py __JAX Variant (Advanced)__ and cluster/simulator.py __JAX JIT__ — both state the one-time setup, call register_tracer_classes(tracer), and give the trace-time reason.
- Make registration the caller's responsibility everywhere, naming
autolens.jax.register_tracer_classes / autogalaxy.jax.register_galaxies_classes (the latter added in PyAutoGalaxy#537).
- Stop presenting the
@jax.jit simulator wrap as working; link the autoarray issue.
- Drop the "eager already runs on JAX" claim.
- Fix the NUFFT sentence in both guides.
- Correct the stale auto-call claims in
autolens/jax/registration.py's module docstring.
Detailed implementation plan
Work Classification
Both (one docstring-only library file + two workspace repos)
Affected Repositories
- autolens_workspace (primary)
- autogalaxy_workspace
- PyAutoLens (module docstring only)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./autolens_workspace |
main |
clean |
| ./autogalaxy_workspace |
main |
clean |
| ./PyAutoLens |
main |
clean |
Suggested branch: feature/correct-simulator-jax-claims
Files
| File |
What |
autolens_workspace/scripts/guides/using_jax.py |
claims 1+2 in __Writing @jax.jit Yourself__ item 1; claim 4 in __Custom Likelihood Functions__ (~line 125) |
autogalaxy_workspace/scripts/guides/using_jax.py |
same two (claim 4 at ~line 116) |
autolens_workspace/scripts/guides/tracer.py |
claim 5 (~533-537) — split fit_from (true) from via_tracer_from (false) |
autolens_workspace/scripts/imaging/simulator.py |
claims 1+2+3 (~359-395) |
autolens_workspace/scripts/interferometer/simulator.py |
claims 1+2+3 (~336-378); its NUFFT paragraph is already correct — keep |
autolens_workspace/scripts/group/simulator.py |
claim 1 (~339) |
autolens_workspace/scripts/multi_galaxy/simulator.py |
claim 1 (~339) |
autogalaxy_workspace/scripts/imaging/simulator.py |
claims 1+2+3 (~252-285) |
autogalaxy_workspace/scripts/interferometer/simulator.py |
claims 1+2+3 (~191-225) |
PyAutoLens/autolens/jax/registration.py |
module docstring claims registration "is called automatically by PointSolver(use_jax=True).solve(...) ... and by Simulator(...).via_tracer_from(...) once Phase 2 ships". Nothing in autolens calls it |
Leave alone — already correct: point_source/simulator.py, cluster/simulator.py.
Testing
py_compile every touched file; run_smoke.py in both workspaces (structural — docstring-only).
scripts/check_sizes.sh in autolens_workspace (the simulator sections shrink).
- Regenerate notebooks in both workspaces.
- Re-grep for
pytree registration internally, already runs on JAX, TransformerNUFFT is not JAX-traceable → zero hits outside corrected contexts.
pytest test_autolens/ for the docstring change (expected no-op; run anyway).
Ordering
The library change is docstring-only with zero API surface, so the library-first gate is vacuous — but merge PyAutoLens first anyway since it is trivial, then the two workspace PRs.
Governing lesson
From autolens_workspace#368 and this follow-on: a documented JAX recipe that no
script executes will be wrong. Where these sections keep a runnable snippet,
prefer letting CI execute it over asserting in prose that it works.
Original Prompt
Click to expand starting prompt
Correct the false simulator-JAX claims in both workspaces (and one stale library docstring)
Type: docs
Target: workspaces
Repos:
- autolens_workspace
- autogalaxy_workspace
- PyAutoLens
Difficulty: medium
Autonomy: supervised
Priority: high
Companion to draft/bug/autoarray/simulator_jax_jit_path_broken.md. That bug may
sit for a while; these claims are false today and should not stand while it
waits. Docs-only — no behaviour change.
The three false claims
Measured 2026-07-29 on the installed stack (see the bug prompt for frame chains):
- "The simulator handles pytree registration internally" — no simulator
anywhere registers pytrees (autolens, autogalaxy and autoarray bases: zero
register hits). The jitted call fails with TypeError ... value is of type Tracer / Galaxies. It is also unimplementable as worded: per
PointSolver.solve_triangles' own note, JAX flattens function arguments at
trace time, so registration must run before the first jitted call and cannot
be done inside the callee.
- "eager
via_tracer_from(...) already runs on JAX" — eager with
use_jax=True succeeds but returns dataset.data.array of type
numpy.ndarray, not jax.Array, in both libraries.
- The
@jax.jit simulator recipe does not work at all, even with correct
registration — it dies in autoarray (preprocess.py:153, then
array_2d_util.py). That is the separate bug; docs must stop presenting the
recipe as working.
Plus one regression this session introduced, and one pre-existing half-truth:
TransformerNUFFT is NOT the un-traceable one — I got this backwards.
autolens_workspace#375 / autogalaxy_workspace#181 (merged 2026-07-29) shipped
"TransformerDFT (the default). TransformerNUFFT is not JAX-traceable." into
both using_jax.py __Custom Likelihood Functions__ sections. The claim was
inherited from the old __JAX__ blocks and is wrong. Per autoarray's own error
text, TransformerNUFFT is "the default JAX-native" transformer
(nufftax-backed, nufftax 0.3.1 installed) and TransformerNUFFTPyNUFFT is
"the legacy pynufft backend". Defaults differ by class:
SimulatorInterferometer defaults to TransformerDFT
(autoarray/dataset/interferometer/simulator.py:16) while Interferometer
(what a fit uses) defaults to TransformerNUFFT
(.../dataset.py:34). autolens_workspace/scripts/interferometer/simulator.py
already states this correctly — the guides contradict it.
guides/tracer.py says "Pytree registration runs as a side effect of the
first fit_from / via_tracer_from call; you write nothing JAX-specific."
True for fit_from (both Analysis classes register inline). False for
via_tracer_from.
Use the two correct exemplars
Do not invent wording. Two scripts already get this right and should be mirrored:
autolens_workspace/scripts/point_source/simulator.py __JAX Variant (Advanced)__
— states the one-time setup, calls register_tracer_classes(tracer), and gives
the reason ("Inside @jax.jit, JAX flattens function arguments at trace time —
auto-registration inside solve() runs too late").
autolens_workspace/scripts/cluster/simulator.py __JAX JIT__ /
__JAX JIT — Point Solver__ — same, and actually calls it.
Files
Fix (9 workspace + 1 library):
| File |
What |
autolens_workspace/scripts/guides/using_jax.py |
claim 1+2 in __Writing @jax.jit Yourself__ item 1; claim 4 in __Custom Likelihood Functions__ (line ~125) |
autogalaxy_workspace/scripts/guides/using_jax.py |
same two (claim 4 at line ~116) |
autolens_workspace/scripts/guides/tracer.py |
claim 5 (~line 533-537) — split fit_from (true) from via_tracer_from (false) |
autolens_workspace/scripts/imaging/simulator.py |
claims 1+2+3 (~359-395) |
autolens_workspace/scripts/interferometer/simulator.py |
claims 1+2+3 (~336-378); its NUFFT paragraph is already correct — keep it |
autolens_workspace/scripts/group/simulator.py |
claim 1 (~339) |
autolens_workspace/scripts/multi_galaxy/simulator.py |
claim 1 (~339) |
autogalaxy_workspace/scripts/imaging/simulator.py |
claims 1+2+3 (~252-285) |
autogalaxy_workspace/scripts/interferometer/simulator.py |
claims 1+2+3 (~191-225) |
PyAutoLens/autolens/jax/registration.py |
module docstring claims registration "is called automatically by PointSolver(use_jax=True).solve(...) ... and by Simulator(...).via_tracer_from(...) once Phase 2 ships". Nothing in autolens calls it. Docstring only |
Leave alone — already correct: point_source/simulator.py, cluster/simulator.py.
What the corrected text must say
- Registration is the caller's responsibility, with the trace-time reason,
naming autolens.jax.register_tracer_classes /
autogalaxy.jax.register_galaxies_classes (the latter added in PyAutoGalaxy#537).
- The
@jax.jit simulator wrap is not currently supported — link the
autoarray issue — so readers do not burn time on a broken recipe. Keep it short;
do not turn each simulator script into an essay ([[feedback_docs_minimal_not_maximal]]).
- Do not claim eager
use_jax=True returns JAX-backed data.
- Interferometer:
TransformerDFT and the nufftax-backed TransformerNUFFT are
both JAX-traceable; only TransformerNUFFTPyNUFFT is not. Name the differing
simulator-vs-dataset defaults rather than saying "the default".
Validation
- Docstring-only, so
py_compile all touched files plus run_smoke.py in both
workspaces for the structural check.
scripts/check_sizes.sh in autolens_workspace; the simulator scripts shrink.
- Regenerate notebooks in both workspaces.
- Re-grep afterwards for
pytree registration internally, already runs on JAX
and TransformerNUFFT is not JAX-traceable — must be zero hits outside the
corrected/allowed contexts.
python -m pytest test_autolens/ for the library docstring change (expected
no-op; run it anyway).
Ordering
The library change is docstring-only with zero API surface, so the
library-first merge gate is vacuous here — but merge PyAutoLens first anyway
since it is trivial, then the two workspace PRs.
Governing lesson
From autolens_workspace#368 and this follow-on: a documented JAX recipe that no
script executes will be wrong. Where these sections keep a runnable snippet,
prefer letting CI execute it over asserting in prose that it works.
Overview
Companion to a filed autoarray bug (
simulator_jax_jit_path_broken). That bug maysit for a while; the docs claims below are false today and should not stand
while it waits. Docs-only — no behaviour change.
Measured 2026-07-29 on the installed stack.
The false claims
registerhits). The jitted call fails withTypeError ... value is of type Tracer / Galaxies. It is also unimplementable as worded: perPointSolver.solve_triangles' own note, JAX flattens function arguments at trace time, so registration must run before the first jitted call and cannot happen inside the callee.via_tracer_from(...)already runs on JAX" — eager withuse_jax=Truesucceeds but returnsdataset.data.arrayof typenumpy.ndarray, notjax.Array, in both libraries.@jax.jitsimulator recipe does not work at all, even with correct registration — it dies inside autoarray (preprocess.py:153, thenarray_2d_util.py). That is the separate bug; the docs must stop presenting the recipe as working.Plus one regression introduced this session, and one pre-existing half-truth:
TransformerNUFFTis not the un-traceable one — this was shipped backwards. autolens_workspace#375 / autogalaxy_workspace#181 (merged today) put "TransformerDFT(the default).TransformerNUFFTis not JAX-traceable." into bothusing_jax.pyguides. Inherited from the old__JAX__blocks, and wrong. Per autoarray's own error textTransformerNUFFTis "the default JAX-native" transformer (nufftax-backed; nufftax 0.3.1 installed) andTransformerNUFFTPyNUFFTis "the legacy pynufft backend". Defaults also differ by class:SimulatorInterferometer→TransformerDFT(autoarray/dataset/interferometer/simulator.py:16);Interferometer, which a fit uses →TransformerNUFFT(.../dataset.py:34).autolens_workspace/scripts/interferometer/simulator.pyalready states this correctly, so the guides contradict a sibling script.guides/tracer.pysays "Pytree registration runs as a side effect of the firstfit_from/via_tracer_fromcall; you write nothing JAX-specific." True forfit_from(bothAnalysisclasses register inline); false forvia_tracer_from.Plan
point_source/simulator.py__JAX Variant (Advanced)__andcluster/simulator.py__JAX JIT__— both state the one-time setup, callregister_tracer_classes(tracer), and give the trace-time reason.autolens.jax.register_tracer_classes/autogalaxy.jax.register_galaxies_classes(the latter added in PyAutoGalaxy#537).@jax.jitsimulator wrap as working; link the autoarray issue.autolens/jax/registration.py's module docstring.Detailed implementation plan
Work Classification
Both (one docstring-only library file + two workspace repos)
Affected Repositories
Branch Survey
Suggested branch:
feature/correct-simulator-jax-claimsFiles
autolens_workspace/scripts/guides/using_jax.py__Writing @jax.jit Yourself__item 1; claim 4 in__Custom Likelihood Functions__(~line 125)autogalaxy_workspace/scripts/guides/using_jax.pyautolens_workspace/scripts/guides/tracer.pyfit_from(true) fromvia_tracer_from(false)autolens_workspace/scripts/imaging/simulator.pyautolens_workspace/scripts/interferometer/simulator.pyautolens_workspace/scripts/group/simulator.pyautolens_workspace/scripts/multi_galaxy/simulator.pyautogalaxy_workspace/scripts/imaging/simulator.pyautogalaxy_workspace/scripts/interferometer/simulator.pyPyAutoLens/autolens/jax/registration.pyPointSolver(use_jax=True).solve(...)... and bySimulator(...).via_tracer_from(...)once Phase 2 ships". Nothing in autolens calls itLeave alone — already correct:
point_source/simulator.py,cluster/simulator.py.Testing
py_compileevery touched file;run_smoke.pyin both workspaces (structural — docstring-only).scripts/check_sizes.shin autolens_workspace (the simulator sections shrink).pytree registration internally,already runs on JAX,TransformerNUFFT is not JAX-traceable→ zero hits outside corrected contexts.pytest test_autolens/for the docstring change (expected no-op; run anyway).Ordering
The library change is docstring-only with zero API surface, so the library-first gate is vacuous — but merge PyAutoLens first anyway since it is trivial, then the two workspace PRs.
Governing lesson
From autolens_workspace#368 and this follow-on: a documented JAX recipe that no
script executes will be wrong. Where these sections keep a runnable snippet,
prefer letting CI execute it over asserting in prose that it works.
Original Prompt
Click to expand starting prompt
Correct the false simulator-JAX claims in both workspaces (and one stale library docstring)
Type: docs
Target: workspaces
Repos:
Difficulty: medium
Autonomy: supervised
Priority: high
Companion to
draft/bug/autoarray/simulator_jax_jit_path_broken.md. That bug maysit for a while; these claims are false today and should not stand while it
waits. Docs-only — no behaviour change.
The three false claims
Measured 2026-07-29 on the installed stack (see the bug prompt for frame chains):
anywhere registers pytrees (autolens, autogalaxy and autoarray bases: zero
registerhits). The jitted call fails withTypeError ... value is of type Tracer / Galaxies. It is also unimplementable as worded: perPointSolver.solve_triangles' own note, JAX flattens function arguments attrace time, so registration must run before the first jitted call and cannot
be done inside the callee.
via_tracer_from(...)already runs on JAX" — eager withuse_jax=Truesucceeds but returnsdataset.data.arrayof typenumpy.ndarray, notjax.Array, in both libraries.@jax.jitsimulator recipe does not work at all, even with correctregistration — it dies in autoarray (
preprocess.py:153, thenarray_2d_util.py). That is the separate bug; docs must stop presenting therecipe as working.
Plus one regression this session introduced, and one pre-existing half-truth:
TransformerNUFFTis NOT the un-traceable one — I got this backwards.autolens_workspace#375 / autogalaxy_workspace#181 (merged 2026-07-29) shipped
"
TransformerDFT(the default).TransformerNUFFTis not JAX-traceable." intoboth
using_jax.py__Custom Likelihood Functions__sections. The claim wasinherited from the old
__JAX__blocks and is wrong. Per autoarray's own errortext,
TransformerNUFFTis "the default JAX-native" transformer(nufftax-backed, nufftax 0.3.1 installed) and
TransformerNUFFTPyNUFFTis"the legacy pynufft backend". Defaults differ by class:
SimulatorInterferometerdefaults toTransformerDFT(
autoarray/dataset/interferometer/simulator.py:16) whileInterferometer(what a fit uses) defaults to
TransformerNUFFT(
.../dataset.py:34).autolens_workspace/scripts/interferometer/simulator.pyalready states this correctly — the guides contradict it.
guides/tracer.pysays "Pytree registration runs as a side effect of thefirst
fit_from/via_tracer_fromcall; you write nothing JAX-specific."True for
fit_from(bothAnalysisclasses register inline). False forvia_tracer_from.Use the two correct exemplars
Do not invent wording. Two scripts already get this right and should be mirrored:
autolens_workspace/scripts/point_source/simulator.py__JAX Variant (Advanced)__— states the one-time setup, calls
register_tracer_classes(tracer), and givesthe reason ("Inside
@jax.jit, JAX flattens function arguments at trace time —auto-registration inside
solve()runs too late").autolens_workspace/scripts/cluster/simulator.py__JAX JIT__/__JAX JIT — Point Solver__— same, and actually calls it.Files
Fix (9 workspace + 1 library):
autolens_workspace/scripts/guides/using_jax.py__Writing @jax.jit Yourself__item 1; claim 4 in__Custom Likelihood Functions__(line ~125)autogalaxy_workspace/scripts/guides/using_jax.pyautolens_workspace/scripts/guides/tracer.pyfit_from(true) fromvia_tracer_from(false)autolens_workspace/scripts/imaging/simulator.pyautolens_workspace/scripts/interferometer/simulator.pyautolens_workspace/scripts/group/simulator.pyautolens_workspace/scripts/multi_galaxy/simulator.pyautogalaxy_workspace/scripts/imaging/simulator.pyautogalaxy_workspace/scripts/interferometer/simulator.pyPyAutoLens/autolens/jax/registration.pyPointSolver(use_jax=True).solve(...)... and bySimulator(...).via_tracer_from(...)once Phase 2 ships". Nothing in autolens calls it. Docstring onlyLeave alone — already correct:
point_source/simulator.py,cluster/simulator.py.What the corrected text must say
naming
autolens.jax.register_tracer_classes/autogalaxy.jax.register_galaxies_classes(the latter added in PyAutoGalaxy#537).@jax.jitsimulator wrap is not currently supported — link theautoarray issue — so readers do not burn time on a broken recipe. Keep it short;
do not turn each simulator script into an essay ([[feedback_docs_minimal_not_maximal]]).
use_jax=Truereturns JAX-backed data.TransformerDFTand the nufftax-backedTransformerNUFFTareboth JAX-traceable; only
TransformerNUFFTPyNUFFTis not. Name the differingsimulator-vs-dataset defaults rather than saying "the default".
Validation
py_compileall touched files plusrun_smoke.pyin bothworkspaces for the structural check.
scripts/check_sizes.shin autolens_workspace; the simulator scripts shrink.pytree registration internally,already runs on JAXand
TransformerNUFFT is not JAX-traceable— must be zero hits outside thecorrected/allowed contexts.
python -m pytest test_autolens/for the library docstring change (expectedno-op; run it anyway).
Ordering
The library change is docstring-only with zero API surface, so the
library-first merge gate is vacuous here — but merge PyAutoLens first anyway
since it is trivial, then the two workspace PRs.
Governing lesson
From autolens_workspace#368 and this follow-on: a documented JAX recipe that no
script executes will be wrong. Where these sections keep a runnable snippet,
prefer letting CI execute it over asserting in prose that it works.