Skip to content

fix(inversion): make AbstractMeshGeometry picklable (xp module → _use_jax bool + property)#321

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/mesh-geometry-picklable
May 16, 2026
Merged

fix(inversion): make AbstractMeshGeometry picklable (xp module → _use_jax bool + property)#321
Jammy2211 merged 1 commit into
mainfrom
feature/mesh-geometry-picklable

Conversation

@Jammy2211
Copy link
Copy Markdown
Collaborator

Summary

Phase 4 subprocess visualization (PyAutoFit #1279) requires sending FitImaging instances over an IPC boundary. A spike against the current FitImaging showed it's unpicklable: AbstractMeshGeometry.__init__ stores self._xp = xp (the literal numpy or jax.numpy module) and Python can't pickle modules. This was the only pickle barrier — the rest of the fit graph (mappers, linear operators, computed matrices, tracer, dataset, mask) serialises fine.

Fix: replace the module-attribute pattern with the _use_jax: bool + _xp property pattern already used in Analysis._xp (PyAutoFit) and AbstractMaker._xp (PyAutoArray decorators, per CLAUDE.md). Eliminates the pickle barrier at the API level instead of working around it with __getstate__/__setstate__ hooks.

API Changes

  • AbstractMeshGeometry.__init__(xp=np) continues to accept the same xp= kwarg — no caller changes needed.
  • The instance no longer holds _xp as a module attribute; it holds _use_jax: bool and exposes _xp as a @property that returns numpy or jax.numpy on demand.
  • All existing self._xp reads continue to work transparently (property has the same interface as attribute access).

See full details below.

Test Plan

  • New test_autoarray/inversion/pixelization/mesh_geometry/test_picklability.py — 5 new tests covering numpy + JAX backends across MeshGeometryRectangular and MeshGeometryDelaunay, plus a __init__-state invariant test.
  • Existing test_autoarray/inversion/pixelization/mesh_geometry/ tests still pass.
  • Wider test_autoarray/inversion/ suite passes (171/171).
  • End-to-end: a populated FitImaging (Sersic lens + Rectangular-adaptive-density pixelization source) round-trips through pickle.dumps/loads with log_likelihood Δ=0.00e+00 on both numpy and JAX backends. Pickle size 4637.7 KB.
Full API Changes (for automation & release notes)

Changed Behaviour

  • autoarray.inversion.mesh.mesh_geometry.abstract.AbstractMeshGeometry:
    • Instance attribute _xp removed; replaced by _use_jax: bool (set from the xp= kwarg as xp is not np).
    • _xp is now a @property that returns numpy if _use_jax is False else jax.numpy. JAX is imported lazily on access.

Migration

  • No required migration. The xp= kwarg on __init__ is unchanged. Any reader of instance._xp continues to work (property returns the same module the old attribute held).
  • Any writer of instance._xp = ... (none currently exist in the codebase) would now fail at runtime. Confirmed via grep: zero writes outside __init__.

Why this matters

  • FitImaging now pickles cleanly, unblocking PyAutoFit #1279 (Phase 4 subprocess visualization). The single-class fix on the abstract parent covers both MeshGeometryRectangular and MeshGeometryDelaunay.

🤖 Generated with Claude Code

Carve-out from PyAutoFit #1279 Q2 (Phase 4 of the JAX visualization
roadmap). A picklability spike found FitImaging cannot be pickled
today because AbstractMeshGeometry.__init__ stores `self._xp = xp`
— the literal numpy or jax.numpy module — and Python's pickle cannot
serialise module references. This blocked sending a FitImaging over
an mp.Process+Queue or ProcessPoolExecutor boundary, which is the
production target for Phase 4 subprocess visualization.

Replace the module-attribute pattern with `self._use_jax: bool` +
`_xp` as a property derived from that flag. Same pattern already
used in Analysis._xp (PyAutoFit) and AbstractMaker._xp (PyAutoArray
decorators per CLAUDE.md). All existing `self._xp` reads continue to
work transparently via the property.

End-to-end verified: a populated FitImaging round-trips through
pickle.dumps/loads with log_likelihood delta=0.00e+00 on both numpy
and JAX backends. Pickle size ~4.6 MB for a Rectangular-adaptive-
density pixelization fit.

Closes #320. Carve-out from #1279.
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label May 16, 2026
@Jammy2211 Jammy2211 merged commit ae375ae into main May 16, 2026
6 checks passed
@Jammy2211 Jammy2211 deleted the feature/mesh-geometry-picklable branch May 16, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant