Repository navigation
perf: generic odd-radix FFT pass for lengths with prime factors above 7 - #45
Merged
Merged
Conversation
MixedRadixPlan gains a generic pass for any odd prime radix (the pocketfft passg butterfly, written per output group with four j at a time on fused multiply-adds), so lengths off vDSP with factors such as 11, 13 or 23 no longer all go through Bluestein. FFT2D picks the plan or Bluestein with the pocketfft make_cfft_plan rule (below 50 or largest prime factor at most sqrt(n): the plan), otherwise Bluestein when 2.5 m log2(m) < cost_guess(n); pocketfft weighs Bluestein at 6 m log2(m), but vDSP power-of-two DFTs are cheaper than its own, measured with FFTBenchmarkTests. Local forward fft2, median of 21, one thread: 506 (2 x 11 x 23) 3.77 to 3.06 ms; 1001 (7 x 11 x 13) 11.5 ms against about 19 ms for Bluestein at 1009; primes 97 and up and 2 x 53 stay on Bluestein, where it is two to four times faster than the generic pass. Against a direct DFT the generic lengths agree to 1e-16 to 8e-15 relative in both directions (reviewer scratch run); the tests hold numpy assert_allclose rtol 1e-7. Reviewed before the commit: no must-fix; the inverse is now also checked against a direct inverse DFT at 121, 169 and 198. Done: generic radix pass, calibrated routing rule, path, cost-rule and inverse tests, benchmark lengths at the boundary. Next: 506 still trails NumPy (2.34 ms) by about 1.3x; docs/open-items.md and the parity row still describe the old FFT routing and need a line once the open docs PRs land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Requested by Paul · project thread
Fixes #4
Summary
MixedRadixPlangains a generic odd-radix pass for any prime factor other than 2, 3, 4, 5 and 7. It uses the pocketfftpassgbutterfly, works on one output group at a time, and runs four j at a time on fused multiply-adds. Before this, lengths off vDSP with factors such as 11, 13 or 23 always went through Bluestein.FFT2Dchooses between the plan and Bluestein with the shape of pocketfft'smake_cfft_plan:cost_guess(n).pocketfft's own Bluestein weight is 6 · m · log2(m). vDSP's power-of-two DFT is cheaper than pocketfft's, so the weight here is measured with
FFTBenchmarkTestsinstead.Issue perf: mixed-radix FFT for lengths off vDSP that factor into 2, 3, 5 and 7 #42 already brought in the 2, 3, 5, 7 plan. With this PR, every length now takes the cheaper of the two paths.
Timings
Local forward
fft2, median of 21, one thread:NumPy 2.5.4 takes 2.34 ms at 506², so a gap of about 1.3x remains there. Lengths in 2, 3, 5 and 7 are unchanged from #42.
Tests
lengthsPickTheirFFTPath: red before the change, because 506, 11, 13 and 1001 took Bluestein. It now lists the boundary lengths on both sides.mixedRadixCostRuleIsPocketffts: the factorisation,cost_guessand the rule at worked values.assert_allclosertol 1e-7. In the reviewer's scratch run, the generic lengths agreed with a direct DFT to between 1e-16 and 8e-15 relative, in both directions.swift test -c release --parallel --skip SimulatoKitParityTests. The parity target was not run in this session.Left for later
docs/open-items.mdand theGridrow indocs/parity.mdstill describe the old FFT routing. Both files are touched by open docs PRs, so they get a line once those PRs land. README,docs/status.mdand the DocC article are updated here.🤖 Generated with Claude Code