Multiplying matrices over the integers
Multiplying an by a integer matrix with entries of and bits produces entries of up to bits. Two parameters decide the best method: the dimension and the entry size. For small entries the cost is dominated by memory traffic and by the overhead of the fmpz representation; for large matrices of moderate entries, by the multiply-adds; for large entries, by the cost of each integer multiplication. fmpz_mat_mul implements the choice; the exact tests are in How the method is chosen.
The generic gr_mat_mul over the integers (gr_ctx_init_fmpz) calls fmpz_mat_mul. Conversely, several other modules reduce their matrix products to it: fmpq_mat_mul after clearing denominators of rows and columns, fmpz_mod_mat_mul before reducing, fmpz_poly_mat_mul_KS and nmod_poly_mat_mul_KS after Kronecker substitution, arb_mat_mul_block and nfloat's matrix multiplication on blocks of exponent-aligned mantissas, and padic_mat_mul.
The methods#
| Method | Function | Cost | Best for |
|---|---|---|---|
| Dot products in machine words | _fmpz_mat_mul_small_internal, _fmpz_mat_mul_double_word_internal | word multiply-adds, 1 to 5 words | entries up to two words, up to a few hundred |
| Classical dot products | fmpz_mat_mul_classical | multiplications of entries | tiny , irregular entries |
| Waksman | fmpz_mat_mul_waksman | multiplications, additions | , balanced entries of thousands of bits |
| Strassen–Winograd | fmpz_mat_mul_strassen | multiplications of entries | , entries of hundreds of bits |
Floating-point gemm | fmpz_mat_mul_blas | dgemm calls, or one if | large , up to a few hundred bits |
| Multimodular | fmpz_mat_mul_multi_mod | products over , plus reductions | large , entries of up to thousands of bits |
| Transformed entries | fmpz_mat_mul_fft_small | transforms, pointwise products | entries of many thousands of bits |
| Schönhage–Strassen entries | fmpz_mat_mul_fft | as above, with the fft module | not used by fmpz_mat_mul |
Machine words#
When all entries fit in a signed word minus two bits (small fmpz), the product can be computed without touching the multiprecision machinery: the kernels read the words, multiply them with one hardware multiplication, and accumulate in one, two or three words depending on the bound . _fmpz_mat_mul_small_internal transposes into an array of words and processes blocks of 16 rows of against 128 entries of the inner dimension, which keeps the working set in cache, and splits the rows over threads. Entries of up to two words are handled likewise by _fmpz_mat_mul_double_word_internal, which multiplies two-word integers with four word products and accumulates in four or five words. For dimensions above about 1000 these lose to Strassen–Winograd (when fits in a word) or to multimodular multiplication.
Fewer multiplications#
For entries of thousands of bits, each multiplication of entries costs , much more than an addition, so algorithms that trade multiplications for additions win for small dimensions. Waksman's algorithm [Waksman1970] computes, for each pair of inner indices, the products , whose sum over is the dot product plus terms depending only on row or column ; it needs multiplications. Strassen–Winograd [Str1969; Win1971], in the operation order of Bodrato [Bodrato2010], needs 7 instead of 8 half-size products per level at the cost of 15 additions; FLINT applies one level and recurses through fmpz_mat_mul. See Strassen–Winograd multiplication.
Products modulo primes#
The entries of are less than in absolute value, so is determined by modulo moduli with product at least (or if all entries are nonnegative). The multimodular method reduces and modulo each , multiplies with nmod_mat_mul, and reconstructs by the Chinese remainder theorem (Chinese remaindering). FLINT uses the modulus , for which reduction is free, and primes above , so ; if , the single modulus .
Proposition 1. For matrices with entries of bits, multimodular multiplication costs
word operations, where is the cost of nmod_mat_mul and that of reducing a -bit integer modulo primes, or of reconstructing it, with a subproduct tree.
Proof. There are entries to reduce and to reconstruct, each by a tree of products of the moduli [GG2003, §10.3], and matrix products modulo word-size moduli.
Compared with the of the classical algorithm, the matrix products cost word operations per prime, that is, about in total, which for up to a few thousand bits is much less than , and the conversions are only quadratic in . Since nmod_mat_mul runs at nearly the floating-point peak of the processor (Multiplying matrices over Z/nZ), this is the method of choice for large matrices.
Floating point#
fmpz_mat_mul_blas is a multimodular method with primes small enough for a double matrix product to be exact: residues in the symmetric range below with , so that every dot product is computed exactly (Exactness). That gives primes of about bits (at most about 21 bits when , to keep the reconstruction cheap), and about calls to flint_dgemm. If , a single dgemm on the entries suffices. With a tuned BLAS library or FLINT's own kernels (Floating-point matrix multiplication (gemm)) this is the fastest method for large matrices with entries up to a few hundred bits: fmpz_mat_mul uses it for when , and from about to depending on .
Transformed entries#
For entries of bits, each product of entries costs a multiplication of large integers, which with an FFT means two forward transforms, a pointwise product and an inverse transform. In a matrix product each entry of takes part in products and each entry of in , so transforming every entry once and adding the pointwise products of each entry of in the transformed domain saves almost all transforms.
Proposition 2. With transforms of length points, multiplying through transformed entries costs
operations, against for multiplying the entries separately.
Proof. Each of the input entries and output entries is transformed once, and each of the products is a pointwise product of length . The transform length must accommodate the accumulated sum of products, which adds bits to the coefficients and changes by a constant factor.
fmpz_mat_mul_fft_small implements this with the transformed integer ring of gr, built on the small-prime FFT of fft_small.h (Sums of products and fixed operands). The transforms of the inputs must be stored, numbers, which the function limits with flint_fft_small_max_transformed_ring_size, falling back to row and column blocks and, if necessary, to blocks of the inner dimension. fmpz_mat_mul uses it when the smaller entry size exceeds about bits (10000 for ). The older fmpz_mat_mul_fft does the same with the Schönhage–Strassen transform of the fft.h module, for entries of at least 2000 bits.
Squaring and powers#
For , the transformed method keeps one pool of transforms, and Bodrato's variant of Strassen–Winograd [Bodrato2010] uses squarings of half-size blocks where possible. fmpz_mat_sqr applies Bodrato's formulas for dimensions up to 3 (and 4 with large entries) and otherwise fmpz_mat_mul. fmpz_mat_pow uses binary powering.
Rational and polynomial matrices#
fmpq_mat_mulmultiplies and , where and are and with rows, respectively columns, multiplied by their least common denominators and , so that one integer product suffices.- Polynomial matrices over and are multiplied by Kronecker substitution into integer matrices, or by evaluation and interpolation; see Matrices of polynomials.
Referenced from#
- Floating-point matrix multiplication (gemm) (algorithm)
- Vectors and matrices (overview)
- Multimodular and p-adic linear algebra over the integers (algorithm)
- Linear algebra over generic rings and its specialisations (overview)
- Matrices of polynomials (algorithm)
arb_mat_mul_classical,arb_mat_mul_threaded,arb_mat_mul_block,arb_mat_mul- fmpz_mat.h (module)
fmpz_mat_mul,fmpz_mat_mul_classical,fmpz_mat_mul_waksman,fmpz_mat_mul_strassen,fmpz_mat_mul_multi_mod,fmpz_mat_mul_fft- Multiplying integer matrices
- Multiplying polynomial matrices modulo n
padic_mat_mul
References#
- [Waksman1970] Waksman, Abraham, "On Winograd's algorithm for inner products", IEEE Transactions on Computers 19.04 (1970): 360-361.
- [Str1969] V. Strassen, "Gaussian elimination is not optimal", Numerische Mathematik 13 (1969), 354-356, https://doi.org/10.1007/BF02165411
- [Win1971] S. Winograd, "On multiplication of 2 × 2 matrices", Linear Algebra and its Applications 4 (1971), 381-388, https://doi.org/10.1016/0024-3795(71)90009-7
- [Bodrato2010] Bodrato, Marco : A Strassen-like Matrix Multiplication Suited for Squaring and Higher Power Computation. Proceedings of the ISSAC 2010 München, Germany, 25-28 July, 2010
- [GG2003] J. von zur Gathen and J. Gerhard, Modern Computer Algebra, second edition, Cambridge University Press (2003)
The FLINT team, “Multiplying matrices over the integers,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/linear-algebra/integer-matrix-multiplication.html (generated 2026-11-02).
@misc{flint-doc-algorithms-linear-algebra-integer-matrix-multiplication,
author = {{The FLINT team}},
title = {{Multiplying matrices over the integers}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/linear-algebra/integer-matrix-multiplication.html},
note = {Generated 2026-11-02}
}