Skip to content

Remove pynufft and the legacy TransformerNUFFTPyNUFFT backend - #475

Merged
Jammy2211 merged 1 commit into
mainfrom
claude/remove-pynufft-6uwt2z
Aug 22, 2026
Merged

Remove pynufft and the legacy TransformerNUFFTPyNUFFT backend#475
Jammy2211 merged 1 commit into
mainfrom
claude/remove-pynufft-6uwt2z

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Removes the legacy pynufft-backed interferometer transformer and drops pynufft from the optional and dev extras. The nufftax-backed TransformerNUFFT has been the default backend since the nufftax migration, and TransformerDFT remains as the pure-numpy transformer.

This also resolves a pre-existing break: the pinned pynufft==2022.2.2 calls scipy.linalg.pinv2, which SciPy 1.17.1 no longer provides, so the dev extra could not install-and-pass on Python 3.13. Confirmed on a clean 3.13 environment — hasattr(scipy.linalg, "pinv2") is False. pynufft 2022.2.2 also emits SyntaxWarning: "is" with 'str' literal on 3.13, i.e. it is unmaintained against the supported interpreter range.

Merge order: merge PyAutoGalaxy#(see below) and PyAutoLens# first, then this. Those two only drop a re-export, which is safe against an autoarray that still has the class — so main is never red. Merging this one first would break their main CI.

Two corrections to the task's premise

The task assumed pynufft was a base dependency costing ~0.23 s of import. Both were wrong, and measuring is what found it:

  1. pynufft was never a base dependencyoptional and dev extras only. A plain pip install autoarray never had it, so TransformerNUFFTPyNUFFT already raised for most users.
  2. The import saving is ~10 ms, not ~230 ms. Median of 7 runs, Python 3.13, dev extras: import autoarray 369.8 ms → 359.9 ms. pynufft's 0.19 s cumulative import is ~95% scipy.sparse (0.11 s), which autoarray/operators/derivative_util.py:30 imports eagerly for csr_matrix regardless. Only ~10 modules are exclusive to pynufft.

The removal still stands on its own merits — unmaintained dependency, dead class, broken dev extra — just not on import-time grounds. The real ~0.10 s win is deferring that scipy.sparse import, filed separately.

Platform note (Intel macOS)

nufftax is pure-JAX; even its xp=np path calls nufftax.nufft2d2. jaxlib's last macOS x86_64 wheel is 0.4.38 (2024-12-17) and jaxlib has never shipped an sdist, so there is no pip path to JAX on Intel Mac. Those users therefore keep TransformerDFT only for interferometry — exact, but O(N_vis × N_pix). Accepted deliberately; the broader platform-support question is filed separately.

API Changes

Breaking: TransformerNUFFTPyNUFFT is removed, along with its autoarray top-level and autoarray.type re-exports and its arm of the Transformer union. Migration is TransformerNUFFT (nufftax-backed, differentiable, ~zero gridding error), or TransformerDFT where JAX is unavailable. pynufft is no longer an optional or dev dependency.

See full details below.

Test Plan

  • pytest test_autoarray1164 passed, 1 skipped (Python 3.13, dev extras)
  • import autoarray succeeds; hasattr(aa, "TransformerNUFFTPyNUFFT") is False
  • python -X importtime -c "import autoarray" | grep pynufft is empty
  • Downstream verified against this branch: PyAutoGalaxy 1103 passed, 1 skipped; PyAutoLens 532 passed, 1 skipped
Full API Changes (for automation & release notes)

Removed

  • autoarray.TransformerNUFFTPyNUFFT — the legacy pynufft-backed NUFFT transformer; replaced by autoarray.TransformerNUFFT
  • autoarray.operators.transformer.TransformerNUFFTPyNUFFT — same class at its defining module
  • autoarray.operators.transformer.pynufft_exception() — raised only by the removed class
  • autoarray.operators.transformer.NUFFTPlaceholder — the absent-pynufft stand-in base class
  • pynufft from [project.optional-dependencies] optional, and the pynufft==2022.2.2 pin from dev

Changed Behaviour

  • autoarray.type.Transformer — union narrows from Union[TransformerDFT, TransformerNUFFT, TransformerNUFFTPyNUFFT] to Union[TransformerDFT, TransformerNUFFT]
  • nufftax_exception() message — no longer directs users to the removed pynufft backend; now names TransformerDFT as the fallback where JAX is unavailable
  • use_adjoint_scaling is now a no-op on every remaining transformer. It was load-bearing only for the removed class, whose pynufft-internal IFFT normalisation left its raw adjoint a factor 4 * N_y * N_x low. The parameter is retained as a stable part of the transformer interface and its docstrings updated; removing it is deliberately left as a separate change.

Migration

  • Before: transformer = aa.TransformerNUFFTPyNUFFT(uv_wavelengths=uv, real_space_mask=mask)
  • After: transformer = aa.TransformerNUFFT(uv_wavelengths=uv, real_space_mask=mask)
  • Without JAX (e.g. Intel macOS): transformer = aa.TransformerDFT(uv_wavelengths=uv, real_space_mask=mask)

Note that TransformerNUFFT.image_from returns the plain mathematical adjoint, which differs in absolute scale from the removed class' adjoint (that one applied pynufft's internal IFFT and kernel deconvolution). The structure of the dirty image is unchanged, and the values match TransformerDFT.image_from exactly.


Generated by Claude Code

Deletes the legacy pynufft-backed interferometer transformer and drops
pynufft from the `optional` and `dev` extras. The nufftax-backed
`TransformerNUFFT` has been the default backend since the nufftax
migration, and `TransformerDFT` remains as the pure-numpy transformer.

Removed:
- `TransformerNUFFTPyNUFFT`, the `NUFFTPlaceholder` / `NUFFT_cpu`
  module-scope try-import, and `pynufft_exception()`
- the `TransformerNUFFTPyNUFFT` re-exports from `autoarray/__init__.py`
  and `autoarray/type.py`, and its arm of the `Transformer` union
- the three `test__nufft_pynufft__*` tests and the `"pynufft"` arm of the
  nufftax-absent skip filter in `test_autoarray/conftest.py`
- `pynufft` from `[project.optional-dependencies]` `optional` and the
  `pynufft==2022.2.2` pin from `dev`

`nufftax_exception()` no longer points users at the deleted class; it now
names `TransformerDFT` as the fallback where JAX is unavailable, and the
`use_adjoint_scaling` docstrings no longer describe a pynufft-specific
normalisation.

This also resolves the pinned `pynufft==2022.2.2` dev-extra failure under
SciPy >= 1.17 (it calls the removed `scipy.linalg.pinv2`).

Note on import time: the measured saving is ~10 ms, not the ~230 ms the
task assumed. `pynufft`'s 0.19 s cumulative import is ~95% `scipy.sparse`,
which `autoarray/operators/derivative_util.py` imports eagerly for
`csr_matrix` regardless. Deferring that import is the real ~0.10 s win and
is filed separately.
@Jammy2211
Jammy2211 merged commit c330e3c into main Aug 22, 2026
3 checks passed
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.

2 participants