Delayed reduction for multiword moduli
- Cost
- A sum of products costs products of limbs, additions of about limbs and one reduction, instead of modular multiplications (each about three products of limbs) and modular additions.
A modular multiplication with an -limb modulus costs about three -limb products: one to form the product and two for the reduction (Modular multiplication with a multiword modulus). Most of the time in linear algebra and polynomial arithmetic is spent in sums of products . Delayed reduction computes such a sum exactly as an integer, in a few more limbs than a product, and reduces it once. This replaces reductions by one and saves about two thirds of the multiplications, and modular additions become plain multi-limb additions. It is the multiword counterpart of the delayed reduction for word-size moduli (Dot products modulo a word-size integer), which goes back to FFLAS [DGP2002; DGP2008].
Throughout, , the modulus has limbs and bits, and residues are integers in .
Generic algorithms and specialised kernels#
The generic algorithms of gr_vec, gr_poly and gr_mat (schoolbook polynomial multiplication, basecase division, Gaussian elimination, classical matrix multiplication, ...) are written in terms of ring operations, and reduce after every operation. They become delayed algorithms over a particular ring when the ring overrides the low-level methods they call. mpn_mod overrides the vector methods (the dot products _gr_vec_dot, _gr_vec_dot_rev and _gr_vec_dot_strided), polynomial multiplication and division, LU decomposition, row reduction and matrix multiplication; the higher-level generic algorithms (Newton iteration, half-gcd, block recursive LU, triangular solving, nullspaces, ...) are unchanged and inherit the speed of the kernels. This is the design described in [Joh2025gr]. The speedups of mpn_mod over the fmpz-based fmpz_mod ring come from these basecases, from fewer temporary allocations, and from cheap additions, which make Karatsuba and Waksman multiplication worthwhile.
The ring fmpz_mod uses a simpler form of the same idea: its dot products (_fmpz_mod_vec_dot) and matrix products (fmpz_mod_mat_mul) compute the exact integer result with fmpz arithmetic (_fmpz_vec_dot, fmpz_mat_mul) and reduce once at the end, but the intermediate values are heap-allocated multiprecision integers of variable size.
How many limbs#
Lemma 1. Let and for , and let . Then
So the sum fits in limbs.
Proof. The left-hand side is at most for (for the claim is obvious). Since and , the claim follows.
Since , at least limbs are needed; limbs suffice when , that is, when the top limb of leaves about bits free, and limbs always suffice for . The code computes the exact limb count where it matters for speed (dot products, schoolbook polynomial multiplication, division) and uses limbs elsewhere. The final reduction of an -limb sum is mpn_mod_set_mpn, which costs about one modular multiplication.
Dot products#
_mpn_mod_vec_dot and its reversed and strided variants accumulate the full products in the number of limbs given by Lemma 1. For they call generated kernels from mpn_extras (flint_mpn_dot_tab, flint_mpn_dot_rev_tab and flint_mpn_dot_strided_tab, indexed by the operand sizes and the output size), which keep the accumulator in registers and use the fixed-size multiplication macros; for there are dedicated forward and reversed kernels. For larger each product is formed with flint_mpn_mul_n and added to a -limb accumulator. The initial value and the sign are applied after the reduction. Lengths 1 and 2 use mpn_mod_mul and mpn_mod_fmma instead.
Every generic algorithm that calls _gr_vec_dot benefits: classical matrix multiplication, triangular solving, power series inversion and division in the basecase, and many more.
Polynomial multiplication#
The coefficients of a product of polynomials are dot products, and all algorithms of _mpn_mod_poly_mulmid compute the integer coefficients of the product of the residue polynomials and reduce each coefficient once:
- the schoolbook algorithm with the limb count of Lemma 1 for ;
- Karatsuba's algorithm on unreduced, signed coefficients, which grow by up to two bits per recursion level, with an output size of bits (
_flint_mpn_poly_mulmid_slimbs); - Kronecker substitution with bits per coefficient;
- the small-prime FFT, which reconstructs the integer coefficients from their residues modulo several 50-bit primes.
See Polynomial multiplication over Z/nZ for multiword n for the choice between them.
Division with remainder#
The schoolbook division of (length ) by (length ) computes the quotient coefficients from the top. Each step reduces the current top coefficient of the remainder, sets and subtracts from the remainder. _mpn_mod_poly_divrem_basecase_preinv1 keeps the remainder unreduced: it adds the products with , the residue of , so that all intermediate values are nonnegative integers. Each coefficient receives at most products and starts below , so by Lemma 1 with it fits in limbs. A coefficient is reduced only when it becomes the top coefficient, and the low coefficients are reduced at the end. Each quotient coefficient costs plain products and additions and two modular operations, instead of modular multiplications and subtractions.
Euclid's algorithm#
In the Euclidean algorithm for polynomial gcds, almost every step divides a polynomial of length by one of length , with a two-term quotient . The remainder coefficients are , two products per coefficient. _mpn_mod_poly_divrem_q1_preinv1 computes them in one of three ways:
- with one fused reduction per coefficient (
flint_mpn_fmmamod_preinvn), that is, two products and one reduction; - with the matrix method of preconditioned multiplication for and , which avoids the full reductions (The matrix method);
with a Karatsuba-like trick, using precomputed multipliers , and for the matrix method. For odd ,
where was computed for the previous coefficient and is reused for the next one, which needs only more. Two coefficients thus cost three products instead of four.
The fmma form is used for moduli up to 576 bits or short divisors, the Karatsuba form for long divisors and large moduli.
Gaussian elimination#
mpn_mod_mat_lu_classical_delayed stores, next to the reduced matrix, an unreduced copy of every entry in limbs. For each pivot in row and column and each row below, it computes the multiplier (reduced, stored in ) and adds to the unreduced entry for all columns , where is the reduced pivot row. An entry receives at most such products before it is reduced, so by Lemma 1 limbs suffice for any matrix of fewer than rows. Entries are reduced lazily: the next pivot column when it is searched for a pivot, and the pivot row when it is used.
Proposition 2 (Row updates as one long addition). Let and with and for all . Then , that is, adding the concatenations adds the slots.
Proof. No slot sum reaches , so there is no carry from one slot to the next.
Since no unreduced entry ever exceeds limbs, the code forms the products for the whole row in a temporary row with the same layout and adds it to the unreduced row with a single mpn_add_n over limbs, which is faster than one call per entry. mpn_mod_mat_reduce_row (row reduction for minimal polynomials) uses the same unreduced layout.
Matrix multiplication#
Classical matrix multiplication uses the dot products above. Waksman's algorithm halves the number of products by forming products of sums of residues, which are -limb (or, if the top bit of is set, -limb) integers; the products are accumulated with signs in limbs and each entry is reduced once. The multimodular algorithm reduces the residues modulo word-size primes, where nmod_mat_mul applies word-size delayed reduction, and reduces the reconstructed integer entries modulo once. See Matrix multiplication over Z/nZ for multiword n.
Accumulation in transform space#
The transformed polynomial rings over mpn_mod (gr_ctx_init_gr_poly_transformed_repr) take the idea one step further: products of polynomials are accumulated pointwise in the transform domain modulo the fft_small primes, and only the final sum is transformed back, reconstructed and reduced modulo . The number of primes is provisioned for sums of up to terms_bound products (with a factor 4 for the sign bias and the reconstruction), the analogue of the limb count of Lemma 1. This is used for the transformed representation of polynomial moduli in gr_poly_preinv_set.
Use in FLINT#
_mpn_mod_vec_dot,_mpn_mod_vec_dot_rev,_mpn_mod_vec_dot_strided: Dot products._mpn_mod_poly_mulmidand the individual multiplication algorithms: Polynomial multiplication._mpn_mod_poly_divrem_basecase_preinv1: Division with remainder._mpn_mod_poly_divrem_q1_preinv1, used by Euclid's algorithm in_mpn_mod_poly_gcdand_mpn_mod_poly_xgcd: Euclid's algorithm.mpn_mod_mat_lu_classical_delayed,mpn_mod_mat_reduce_row: Gaussian elimination.mpn_mod_mat_mul_waksman,mpn_mod_mat_mul_multi_mod: Matrix multiplication._fmpz_mod_vec_dot,fmpz_mod_mat_mul,fmpz_mod_mat_mul_fmpz_vec: exactfmpzarithmetic and one reduction (Generic algorithms and specialised kernels).
Referenced from#
- Modular multiplication with a multiword modulus (algorithm)
- Arithmetic modulo multiword integers (overview)
- Dot products modulo a word-size integer (algorithm)
- Gaussian elimination and LU decomposition (algorithm)
- Multiplying matrices over Z/nZ (overview)
- Dot products
- mpn_mod.h (module)
_mpn_mod_vec_dot,_mpn_mod_vec_dot_rev,_mpn_mod_vec_dot_stridedmpn_mod_mat_lu,mpn_mod_mat_lu_classical_delayed_mpn_mod_poly_divrem_basecase,_mpn_mod_poly_divrem_basecase_preinv1_mpn_mod_poly_divrem_q1_preinv1,_mpn_mod_poly_divrem_q1_preinv1_fmma,_mpn_mod_poly_divrem_q1_preinv1_fmma_precond,_mpn_mod_poly_divrem_q1_preinv1_karatsuba_precond- Matrix multiplication over Z/nZ for multiword n
- Polynomial multiplication over Z/nZ for multiword n
- Using mpn_mod
References#
- [DGP2002] J.-G. Dumas, T. Gautier and C. Pernet, "Finite field linear algebra subroutines", Proceedings of the 2002 International Symposium on Symbolic and Algebraic Computation (ISSAC) (2002), 63-74, https://doi.org/10.1145/780506.780515
- [DGP2008] J.-G. Dumas, P. Giorgi and C. Pernet, "Dense linear algebra over word-size prime fields: the FFLAS and FFPACK packages", ACM Transactions on Mathematical Software 35:3 (2008), 1-42, https://doi.org/10.1145/1391989.1391992
- [Joh2025gr] F. Johansson. Generic rings in FLINT. Preprint, 2025. https://fredrikj.net/math/flintgenerics.pdf
The FLINT team, “Delayed reduction for multiword moduli,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/arithmetic/multiword-delayed-reduction.html (generated 2026-11-02).
@misc{flint-doc-algorithms-arithmetic-multiword-delayed-reduction,
author = {{The FLINT team}},
title = {{Delayed reduction for multiword moduli}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/arithmetic/multiword-delayed-reduction.html},
note = {Generated 2026-11-02}
}