Skip to content

Document the DFT/NUFFT trade-off on the sparse-operator setup path - #479

Merged
Jammy2211 merged 1 commit into
mainfrom
claude/sparse-operator-transformer-guidance
Aug 22, 2026
Merged

Document the DFT/NUFFT trade-off on the sparse-operator setup path#479
Jammy2211 merged 1 commit into
mainfrom
claude/sparse-operator-transformer-guidance

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Closes the last open item from the pynufft removal (#475): whether apply_sparse_operator is still incompatible with TransformerNUFFT.

It is not, and has not been since May. The NotImplementedError guard was removed by #329 (bd18a769, 2026-05-22); only a stale workspace comment still claimed otherwise. Verified directly: apply_sparse_operator runs with TransformerNUFFT at every scale tried, and its dirty image matches TransformerDFT to ~3e-13 relative.

Both paths are supported. What was undocumented is which one you should actually pick — and the answer isn't the visibility count.

The crossover is the product, not the visibility count

The DFT setup costs O(N_vis × N_pix); the NUFFT costs O((N_vis + N_pix) log N) plus a fixed ~2 s overhead. So the product decides it. Measured on CPU (use_jax=False), seven points agree on a crossover near 1e7:

N_vis × N_pix DFT / NUFFT time
1.3e6 0.21×
2.6e6 0.27×
5.2e6 0.70×
1.0e7 1.16×
2.1e7 1.50×
2.3e7 1.41×
8.3e7 1.92×

At a typical 64×64 mask that's ~5,000 visibilities — but on a 32×32 mask the DFT still wins at 4,000. Quoting a visibility count alone would be wrong on half the grids.

Memory is the decisive axis

At fixed N_vis=4000, growing the grid:

grid N_pix DFT ΔMB NUFFT ΔMB
32² 648 60 81
64² 2 608 239 0
96² 5 860 293 0
128² 10 428 446 0

The DFT allocates with N_vis × N_pix; the NUFFT allocates nothing measurable beyond its working buffers. At 10.7 bytes/element that extrapolates to ~109 GB at 1M visibilities — independently corroborating the ~123 GB figure bd18a769 recorded by a different route, and confirming the NUFFT is the only feasible ALMA-scale path.

Why an INFO and not a warning

Interferometer defaults to TransformerNUFFT (dataset.py:34). A "NUFFT below the crossover" warning would therefore fire on the default path for every small dataset — every tutorial, test and workspace example. That's warning fatigue for a ~2 s cost.

So the guidance is an INFO on the existing setup log, emitted only when a NUFFT-backed transformer is used below the crossover: an explicit, expensive, opt-in call, never fired when the advice would be moot. The genuinely dangerous direction is already a hard DatasetException above 10,000 visibilities with an opt-out, so nothing is left unguarded.

API Changes

None — internal changes only. One added INFO log and docstring text; no signature, symbol or behaviour changes.

Test Plan

  • Advisory fires for small+NUFFT; stays silent for small+DFT and for large+NUFFT (all three checked explicitly)
  • pytest test_autoarray1179 passed
  • Diff is purely additive (29 insertions, 0 deletions) — the repo's black version wants to reformat an unrelated DatasetException block, and that churn was deliberately kept out

Generated by Claude Code

Both transformers work with `apply_sparse_operator` and agree to ~3e-13
relative, but which is *faster* was undocumented, and the answer is not the
one the codebase's existing 10,000-visibility guard implies.

Measured on CPU (`use_jax=False`), the crossover is governed by the product
`N_vis * N_pix`, not by visibility count alone — which follows from the DFT
setup being `O(N_vis * N_pix)` against the NUFFT's `O((N_vis + N_pix) log N)`
plus a fixed ~2s overhead. Seven measurements agree on a crossover near 1e7:

    N_vis x N_pix    DFT/NUFFT time ratio
    1.3e6            0.21x   (DFT faster)
    2.6e6            0.27x
    5.2e6            0.70x
    1.0e7            1.16x   (crossover)
    2.1e7            1.50x
    2.3e7            1.41x
    8.3e7            1.92x   (NUFFT faster)

So at a typical 64x64 mask the crossover sits near 5,000 visibilities, but on
a 32x32 mask the DFT still wins at 4,000. Quoting a visibility count alone
would be wrong on half the grids.

Memory is the more decisive axis and is what makes this more than a
micro-optimisation. The DFT's allocation grows with `N_vis * N_pix` (measured
60 -> 239 -> 293 -> 446 MB as the grid grows at fixed N_vis=4000) while the
NUFFT path allocates nothing measurable beyond its working buffers. At 10.7
bytes per element that extrapolates to ~109 GB at 1M visibilities, which
independently corroborates the ~123 GB figure recorded in bd18a76 and
confirms the NUFFT is the only feasible path at ALMA scale.

Adds the guidance as an INFO on the existing setup log, emitted only when a
NUFFT-backed transformer is used below the crossover — i.e. only on an
explicit, expensive, opt-in call, and never when the advice would be moot.

Deliberately NOT a warning on `Interferometer` construction: that class
defaults to `TransformerNUFFT`, so a small-dataset warning would fire on the
default path for every tutorial, test and workspace example. The dangerous
direction is already a hard `DatasetException` above 10,000 visibilities with
an opt-out, so nothing is left unguarded by keeping this advisory quiet.

Verified the advisory fires for small+NUFFT and stays silent for both
small+DFT and large+NUFFT. Suite green: 1179 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