Bivariate resultants over nmod via geometric multipoint evaluation - #2822
Bivariate resultants over nmod via geometric multipoint evaluation#2822maelhos wants to merge 7 commits into
Conversation
Adds _gr_poly_resultant_multipoint / gr_poly_resultant_multipoint, a specialization of the resultant for bivariate polynomials, i.e. for the case where the coefficient ring is itself a polynomial ring. The coefficients of both inputs are evaluated at a geometric progression of points, the resultants of the resulting univariate polynomials are computed, and the result is interpolated back, using the geometric evaluation/interpolation added in flintlib#2449. Currently only a base ring of nmod (word-size prime modulus) is supported; fmpz, fmpq and fmpz_mod can follow later. _gr_poly_resultant dispatches to it whenever it applies, replacing the Sylvester determinant that was previously used for these rings. Follows the algorithm in PML's lzz_pXY, with the blockwise evaluation of Antoine Bak's fork so that the working space stays proportional to the input and output sizes: the points are processed in blocks sized to a fixed memory target, each block being reduced to the same progression 1, q, q^2, ... by a substitution x -> s x on the inputs, so that a single evaluation precomputation serves for all of them. Two further refinements over PML: the evaluation points are scaled by a random constant (the FLINT geometric progression always starts at 1, so retrying alone would not avoid a leading coefficient vanishing at 1), and only the leading coefficient of the first argument is required not to vanish at the evaluation points, the drop in degree of the specialisations of the second argument being corrected for afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Nice! Concerning the evaluation at |
|
(note that this adds a dependency that is not wanted in case you plan to introduce multithreading in the evaluation step) |
|
Overall, I made a few tests, and it's about the same performance, though extrapolation is slightly worse in theory (it takes 2L + 2B scalar muls vs. 2L + B for the current version) for L, the total length, and B, the batch length. It also loses the opportunity of parallelization and seems to also be slightly worse for cache / branching. It's still not bad and makes the code easier to read for sure. I'd also argue that since we want to port this code to |
|
Guess crediting Vincent and Antoine now breaks the CI... windows is interesting |
Adds _gr_poly_resultant_modular / gr_poly_resultant_modular, which computes
the resultant of bivariate polynomials over Z and Q by reducing modulo
word-size primes, calling the geometric multipoint algorithm for each of
them, and reconstructing by Chinese remaindering. _gr_poly_resultant
dispatches to it above a degree cutoff, below which the subresultant PRS
is still faster.
Over Q, denominators are cleared first, using the homogeneity
res(a f, b g) = a^deg_y(g) b^deg_y(f) res(f, g); the same identity divides
out the contents of the inputs in Z and in Z[x] beforehand.
The number of primes is bounded by
||res_y(f,g)||_oo <= (sum_i ||f_i||_1^2)^(deg_y(g)/2)
(sum_j ||g_j||_1^2)^(deg_y(f)/2)
which is the univariate Hadamard-type bound already used by
fmpz_poly_resultant_modular, applied to the maximum modulus of the
resultant on the unit circle. That bound is only a limit: primes are added
until the reconstruction stops changing, which is detected on a random
linear combination of the coefficients and then confirmed against a fresh
prime. This makes the cost track the actual size of the resultant, which
matters most when it is far below the bound, for instance when the inputs
have a common factor and the resultant vanishes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ok, yes (these are negligible compared to the
Giving it a second thought, instead of doing the extrapolations with the same offset one after another, we may as well use different offsets
Agreed.
Ok, thanks for having investigated the extrapolation version. I agree that consistency is a plus. There's no clear winner it seems, so, just pick the version you prefer! For the rest, I'll read the code more carefully in the next few days. |
|
Ok, then I'll keep the current version and finish my prototype of
|
|
I'm trying to use FFT-primes for multimodular @vneiger maybe we should make some kind of like "whatever multipoint" that depending on the primes either gives dft points (the right one) or geometric or in last resort subproduct tree. This could be usefull for some other things no ? More generally we could implement this algorithm for generic dense |
|
Noticed this is a comment:
Normally they do, but e.g. for |
When the nmod modulus satisfies the fft_small bounds and p - 1 is divisible by a large enough power of two, _gr_poly_resultant_multipoint evaluates the coefficients in y at roots of unity with one sd_fft transform each, instead of the Bluestein product used for a geometric progression. Measured with alternating rounds on the same prime and inputs, this is 1.10x to 1.26x faster overall, best at small degrees in y. A transform produces all its points at once, so this path keeps every value resident rather than working in blocks; it is used only when they fit a fixed memory budget, and the blocked geometric evaluation still handles everything else. The points come out in bit-reversed order, which is undone by gathering through that permutation, and the geometric interpolation is reused with the square root of the transform's root of unity as its ratio. Not used for the Z and Q path: fft_small accepts primes of at most 50 bits, and needing 1.24x more of them cancels the gain, measured at 0.94x to 1.04x end to end there, so those keep 62-bit primes and the geometric evaluation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nmod, nmod8 and nmod32 answered GR_METHOD_CTX_IS_INTEGRAL_DOMAIN and GR_METHOD_CTX_IS_FIELD with their primality predicate but left GR_METHOD_CTX_IS_UNIQUE_FACTORIZATION_DOMAIN unimplemented, so it fell back to the generic predicate and returned T_UNKNOWN. fmpz_mod, the same situation of a modulus that may or may not be prime, already answers all three with the same predicate; Z/nZ is a UFD exactly when n is prime, since otherwise it is not even a domain. Anything dispatching on this over nmod, or over a ring built on top of one, was taking a worse branch. For instance _gr_poly_resultant skipped the subresultant PRS for bivariate polynomials over nmod and fell through to the Sylvester determinant, which for degree 8 in y and 8 in x over Z/101Z is 23 times slower. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With nmod rings now reporting whether they are a UFD, _gr_poly_resultant reaches the subresultant PRS for bivariate polynomials over nmod instead of falling through to the Sylvester determinant. The subresultant PRS is faster than the multipoint algorithm at the smallest sizes, up to about 1.7 times at degree 3 in y, so the cutoff that was measured against it applies again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
||
| /* a prime p = m 2^16 + 1, for which the evaluation can use a DFT */ | ||
| static ulong | ||
| _fft_prime(flint_rand_t state, int bits) |
There was a problem hiding this comment.
is there alrady a function that gives fft_primes ?
|
A few things: For the FFT-friendly idea: yes, but no. Basically, for
It seems like it wasn't reported as far as I understand; see a97b017 |
Following Issue #2605, this PR adds
_gr_poly_resultant_multipoint/gr_poly_resultant_multipoint, a specialization for the resultant for bivariate polynomials, i.e. for the case where the coefficient ring is itself a polynomial ring. The coefficients of both inputs are evaluated at a geometric progression of points, the resultants of the resulting univariate polynomials are computed, and the result is interpolated back, using the geometric evaluation/interpolation added in #2449.Currently only a base ring of nmod (word-size prime modulus) is supported;
fmpz,fmpqandfmpz_modcan follow later (see discussion in the related issue)._gr_poly_resultantdispatches to it whenever it applies, replacing the Sylvester determinant that was previously used for these rings.Follows the algorithm in PML's lzz_pXY, with the blockwise evaluation of @AntoineBak fork so that memory doesnt grow as n^3.
Two further refinements over PML: the evaluation points are scaled by a random constant (the FLINT geometric progression always starts at 1, so retrying alone would not avoid a leading coefficient vanishing at 1), and only the leading coefficient of the first argument is required not to vanish at the evaluation points.
The timing is unsurprisingly much better than before (on my small Zen 3 laptop)
This PR is partially made using Claude Opus 5.