Hybrid Schonhage-Strassen-NTT convolution - #2789
Open
fredrik-johansson wants to merge 3 commits into
Open
Conversation
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.
TLDR: multiplying polynomials with huge coefficients gets (usually) slightly faster and uses (consistently) less memory.
Example improvement for
fmpz_poly_mul; length-leninput polynomials withbits-bit coefficients:Done using Claude Fable 5.
Algorithm
Implements #1362. The Schonhage-Strassen FFT (our$\mathbb{Z}[x]$ working modulo $2^N+1$ . In particular, the pointwise multiplications which in practice tend to dominate the running time are integer multiplications modulo $2^N+1$ . These were previously performed using $N$ and via Schonhage-Strassen negacyclic convolutions for large $N$ . We replace the large - $N$ case with
fftmodule) does convolutions inflint_mpn_mulfor smallfft_small-based negacyclic convolutions. Note that these are asymptotically twice as fast as computing the full products usingfft_small-basedflint_mpn_mulas they involve FFTs of half the length.The main goal is to speed up polynomial multiplication; it's possible that this also makes our SS-based integer multiplication more competitive with
fft_smallagain, but I haven't investigated that.The result is that
fmpz_poly_mul_SSgets 2-3 faster than before, reaching 0.6x-1.0x the speed offmpz_poly_mul_KSwhere it previously only reached 0.3-0.5x, and eventually overtaking it.The crossover where
fft_smallnegacyclic multiplication beatsflint_mpn_mulis around 16000 bits, but the crossover formul_SSbeatingmul_KSis much higher at around 40000 bits.When the coefficients are large enough,
mul_SSovertakesmul_KSfairly consistently when one starts to havebits * length > 1e9, so I implemented this additional criterion infmpz_poly_mul/fmpz_poly_mullow/fmpz_poly_mulmid.It might be worth setting the cutoffs even lower to prioritize memory efficiency even when this means, say, a 10-30% slowdown over
mul_KS.I would like to find another 10-30% speedup so that
mul_SSwins at smaller bit sizes, ideally all the way down to bit sizes where we can use direct CRT so that we never need the memory-hungrymul_KSfor huge polynomials. I know two things to improve: the negacyclicfft_smallconvolution could fuse the twists with the input conversions and output CRT, and thefftbutterflies could use SIMD or at least a fused sumdiff in assembly (ideally running twice as fast as the separatempn_add_nandmpn_sub_n). Not sure how much these would actually yield together.More detailed profiling
Timings for
fmpz_poly_mulandfmpz_poly_mul_SS.bits = bits of input coefficients
len = length of input polynomials
mul = old
fmpz_poly_muldefault (meaningfmpz_poly_mul_KSbelow except for very small sizes)SSA = old
fmpz_poly_mul_SSSSB = new
fmpz_poly_mul_SS(withfft_smallbased pointwise products)inf = timing omitted because mul_KS starts using too much memory