feat: public register_galaxies_classes, the autolens register_tracer_classes counterpart - #537
Merged
Merged
Conversation
…ounterpart PyAutoLens ships autolens.jax.register_tracer_classes(tracer) as the public one-time pytree registration for code paths that do not go through an Analysis — a user's own @jax.jit that receives the aggregate as a traced argument. autogalaxy had no equivalent public entry point. autogalaxy/analysis/jax_pytrees.py::register_galaxies_pytree registers only the Galaxies list subclass, and is private (reached solely from the two Analysis classes via fit_from). It is NOT sufficient on its own. Measured with `@jax.jit def f(galaxies): return ag.FitImaging(..., galaxies=galaxies, xp=jnp).log_likelihood`: - no registration -> TypeError on Galaxies - register_galaxies_pytree() -> still TypeError, now on Galaxy at galaxies[0] - both steps -> works, matches the eager value exactly So autogalaxy.jax.register_galaxies_classes(galaxies) does both: it calls the existing shared Galaxies registration, then walks each galaxy registering Galaxy and every profile class. Idempotent; returns False as a silent no-op when JAX is not installed. Nothing inside autogalaxy calls this — unlike autolens, where PointSolver and Simulator do — because both Analysis classes already register inline. The docstring says so explicitly so it is not removed as unused. The recursive walker is duplicated from autolens/jax/registration.py rather than shared, deliberately: this keeps the change to one repo and one reversible PR instead of coupling autolens main to autogalaxy main right after 2026.7.29.2. Deduping it is recorded as a follow-up. Closes #536 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CWqjHGXUut25TEB8octU8H
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
PyAutoLens ships
autolens.jax.register_tracer_classes(tracer)— the public,one-time JAX pytree registration for code paths that do not go through an
Analysis: a user's own@jax.jitthat receives the aggregate object as atraced argument. PyAutoGalaxy had no equivalent public entry point.
Surfaced while writing the
__Custom Likelihood Functions__section ofautogalaxy_workspace/scripts/guides/using_jax.py(PyAutoLabs/autogalaxy_workspace#181, merged): the guide could document the
Analysis, hand-rolled-inside-jit andFitnesspaths, but not passing aGalaxiesas a jit argument, because no public call made it work.Why the existing helper wasn't enough
autogalaxy/analysis/jax_pytrees.py::register_galaxies_pytreeregisters onlythe
Galaxieslist subclass, and is private — reached solely from the twoAnalysisclasses viafit_from. Measured on the installed stack with:TypeError: ... problematic value is of type Galaxies ... at path galaxiesregister_galaxies_pytree()only... of type Galaxy ... at path galaxies[0]-270175.0553756637, exactly the eager valueWhat this adds
autogalaxy/jax/__init__.py— exportsregister_galaxies_classes, mirroringautolens/jax/__init__.py.autogalaxy/jax/registration.py—register_galaxies_classes(galaxies) -> bool, which calls the existing sharedregister_galaxies_pytree()and then walks each galaxy registeringGalaxyand every profile class. Idempotent; returnsFalseas a silent no-op when JAX is absent.Nothing else changes:
register_galaxies_pytree, bothAnalysisclasses andall of autolens are untouched.
autogalaxy.jaxis auto-discovered by[tool.setuptools.packages.find], so no packaging change is needed.Two things a reviewer should know
1. Nothing inside autogalaxy calls this. Unlike autolens — where
PointSolverandSimulatorinvokeregister_tracer_classesautomatically —both autogalaxy
Analysisclasses already register their pytrees inline fromfit_from. This is purely the public entry point for user code. The moduledocstring says so explicitly so it isn't later deleted as dead code.
2. The ~60-line recursive walker is duplicated from
autolens/jax/registration.pyrather than shared. Deliberate, and the human'scall: it keeps this to one repo and one reversible PR instead of coupling
autolens
mainto autogalaxymainimmediately after the2026.7.29.2release. Deduping (autogalaxy would own it; autolens may import autogalaxy) is
recorded as a follow-up, not done here.
Test Plan
python -m pytest test_autogalaxy/— 1009 passed, 0 failedGalaxies;register_galaxies_pytree()only → fails onGalaxy;register_galaxies_classes(galaxies)→ works and matches the eager log likelihood exactlyTrueand re-registers nothingimport autogalaxydoes not eagerly importautogalaxy.jax(verified viasys.modules), so the new module adds no import costimport jaxforced to raise,register_galaxies_classesreturnsFalseand does not raiseUnit tests in this repo are NumPy-only by policy, so the JAX behaviour is
validated by the probe rather than by
test_autogalaxy/.Follow-ups (not in this PR)
autogalaxy_workspace/scripts/guides/using_jax.py, matching how the autolens guide points atregister_tracer_classes. Blocked on this PR merging (library-first).autolens/jax/registration.pyandautogalaxy/jax/registration.py.using_jax.pystates "The simulator handles pytree registration internally", butautogalaxy/imaging/simulator.pyandinterferometer/simulator.pycontain no pytree registration calls. Either an autoarray base does it, or that sentence is wrong too. Pre-existing text, not introduced here.Generated by the PyAutoLabs agent workflow.