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

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
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant