FLINT3.7.0-dev
Algorithm

Gaussian elimination and LU decomposition

Cost
O(mnrω−2)O(m n r^{\omega - 2}) field operations for an m×nm \times n matrix of rank rr, where ω≤3\omega \le 3 is the exponent of the matrix multiplication used; O(rω)O(r^\omega) for solving, inversion and determinants of r×rr \times r matrices.

Throughout, pp is a prime and AA an m×nm \times n matrix over the field Z/pZ\mathbb{Z}/p\mathbb{Z}; for the last sections NN is an arbitrary modulus. Gaussian elimination brings AA to row echelon form by row operations, and recording the operations gives an LU decomposition, from which FLINT computes solutions of linear systems, inverses, determinants, ranks, reduced echelon forms and nullspaces. The recursive variant reduces all of this to matrix multiplication [BH1974; IMH1982; JPS2013], so that the fast methods of Multiplying matrices over Z/nZ apply.

Generic version#

gr_mat_lu computes the decomposition PA=LUPA = LU over any field, and over rings pretending to be fields, with the same two algorithms as below: the classical elimination (gr_mat_lu_classical) and the recursive one (gr_mat_lu_recursive), which splits the columns, recurses on the left half, updates the right half with gr_mat_nonsingular_solve_tril and gr_mat_mul, and recurses on the lower right block. The default uses the classical algorithm when the matrix has fewer than 5 rows or columns. Pivots are chosen by a ring method: the first provably nonzero entry by default (GR_UNABLE if none is provably nonzero but some cannot be decided, as for balls containing zero), and the entry of largest magnitude in floating-point rings. Over Z/nZ\mathbb{Z}/n\mathbb{Z} the generic decomposition is not nmod_mat_lu: it does without the delayed reductions of the classical kernel, but its recursive form uses nmod_mat_mul and therefore runs at the speed of matrix multiplication for large matrices. fmpz_mod, mpn_mod and nfloat override the decomposition. Over integral domains that are not fields, the generic functions use fraction-free elimination instead (Fraction-free elimination); the choice for each operation is tabulated in Gaussian elimination and LU decomposition.

The decomposition#

Definition 1. A PLE decomposition of AA is a factorisation A=ΠLEA = \Pi L E where Π\Pi is an m×mm \times m permutation matrix, LL is an m×rm \times r lower triangular matrix with ones on the diagonal, and EE is an r×nr \times n matrix in row echelon form whose rr rows are nonzero. The pivot of row ii of EE is its first nonzero entry, in column cic_i, with c0<c1<⋯<cr−1c_0 < c_1 < \cdots < c_{r-1}.

Then rr is the rank of AA, since LL has full column rank and EE full row rank. FLINT stores LL below the diagonal and EE on and above it, in the array of AA; the permutation is returned as an array P with (LE)i=AP[i](LE)_i = A_{P[i]}, see Output. Elimination chooses as pivot of column cc the first row, among the rows not yet used, whose entry in column cc is nonzero after the previous eliminations.

Proposition 2. With this pivoting rule, column cc receives a pivot if and only if it is not a linear combination of the columns to its left. The pivot columns c0<⋯<cr−1c_0 < \cdots < c_{r-1} are therefore the column rank profile of AA, the lexicographically smallest set of rr linearly independent columns.

Proof. After the eliminations for the pivots in columns before cc, the rows not yet used have zeros in all those columns, and their entries in column cc are zero exactly when column cc of AA lies in the span of the earlier pivot columns, which span all earlier columns.

The row permutation, in contrast, is not the row rank profile in general when the pivot rows are brought into place by swaps, as in nmod_mat_lu. Using upward rotations of rows instead reveals both profiles, and more [JPS2013; DPS2017]; see Rank profile matrix. Here a swap exchanges two rows and leaves the others in place, while an upward rotation moves a row up to a given position and the rows it passes over down by one position each, keeping their order; a downward rotation is the inverse move.

Classical elimination#

Algorithm 1: Gaussian elimination

Input: A∈(Z/pZ)m×nA \in (\mathbb{Z}/p\mathbb{Z})^{m \times n}.

Output: the rank rr, the permutation and LL, EE stored in AA.

  1. r←0r \gets 0. For c=0,1,…,n−1c = 0, 1, \ldots, n - 1 while r<mr < m:

    1. find the first row i≥ri \ge r with Aic≠0A_{ic} \ne 0; if there is none, continue with the next cc;
    2. swap rows ii and rr and record the swap;
    3. for each row i>ri > r: ℓ←AicArc−1\ell \gets A_{ic} A_{rc}^{-1}, subtract ℓ\ell times row rr from row ii in columns c+1,…,n−1c + 1, \ldots, n - 1 (nothing to do if ℓ=0\ell = 0), and store ℓ\ell in column rr of row ii;
    4. r←r+1r \gets r + 1.

For a nonsingular d×dd \times d matrix this costs ∑i<d(d−1−i)2≈d3/3\sum_{i < d} (d - 1 - i)^2 \approx d^3/3 multiply-adds, dd inversions and, in nmod_mat_lu_classical, one reduction modulo pp per multiply-add.

Rank profile matrix#

Definition 3. The rank profile matrix of AA, of rank rr, is the m×nm \times n matrix RA\mathcal{R}_A with rr entries equal to 1, no two in the same row or column, and zeros elsewhere, such that for all i≤mi \le m and j≤nj \le n the submatrices of AA and RA\mathcal{R}_A formed by their first ii rows and first jj columns have the same rank.

It exists and is unique [DPS2017]: writing ρ(i,j)\rho(i, j) for the rank of the leading i×ji \times j submatrix of AA, the entry (i,j)(i, j) of RA\mathcal{R}_A is ρ(i+1,j+1)−ρ(i,j+1)−ρ(i+1,j)+ρ(i,j)\rho(i+1, j+1) - \rho(i, j+1) - \rho(i+1, j) + \rho(i, j). Its rows with a nonzero entry form the row rank profile of AA, its columns with a nonzero entry the column rank profile, and the same holds for every leading submatrix of AA with the entries of RA\mathcal{R}_A that lie in it.

Theorem 4. Run Algorithm 1 with step 2 replaced by the upward rotation of rows r,…,ir, \ldots, i: move row ii to position rr and the rows in positions r,…,i−1r, \ldots, i - 1 down by one position. Let P[k] be the index in AA of the row in position kk at the end. Then P[r] <⋯<< \cdots < P[m-1], and the nonzero entries of RA\mathcal{R}_A are at the positions (P[k], ckc_k) for k<rk < r.

Proof. An upward rotation keeps the relative order of the rows it passes over, hence preserves the following property: the rows that are not yet pivot rows are in increasing order of their indices in AA. This gives the first claim, and it shows that the pivot of column cc is in the row of smallest index, in AA, among the rows that are not yet pivot rows and have a nonzero entry in column cc. The rows of smaller index have a zero multiplier, so every row of AA is only modified by subtracting multiples of rows of smaller index: for every ii, the operations transform the first ii rows of AA by an invertible lower triangular matrix, which does not change the rank of the first jj columns of these rows. After the steps for the columns before jj, these columns are zero in the rows that are not pivot rows, and in the first jj columns the pivot rows form a matrix in row echelon form, with nonzero rows the pivot rows whose pivot column is before jj. The rank of the leading i×ji \times j submatrix of AA is therefore the number of pairs (P[k], ckc_k) with P[k] <i< i and ck<jc_k < j, which is the definition of RA\mathcal{R}_A.

nmod_mat_ple uses this rule. By the proof, the pivot of a column is the row of smallest index in AA with a nonzero entry among the rows that are not pivot rows yet, so that the order of the rows need not be kept in memory: nmod_mat_ple_classical keeps the rows in place and records their order in an array, an upward rotation costing O(i−r)O(i - r) operations on indices, and nmod_mat_ple_classical_delayed swaps the pivot row with the row in position rr; both put the rows in their order at the end, and nmod_mat_ple_recursive does so once for each half at each level of the recursion. With swaps, as in nmod_mat_lu, the pivot columns are the same, but a row swapped downwards passes over rows of larger index, and the pivot rows need not be the row rank profile. The output of nmod_mat_ple is unique, since RA\mathcal{R}_A determines the pivot rows and columns, and the other rows are in increasing order: all its algorithms return the same decomposition. Pivoting rules that reveal RA\mathcal{R}_A in other search orders, and the corresponding recursive algorithms, are studied in [DPS2017].

Delayed reduction#

The reductions dominate the cost of step 3 for small dimensions. nmod_mat_lu_classical_delayed performs the same operations but lets the entries of the active submatrix grow: a nonzero multiplier is turned into f=p−ℓ∈[1,p−1]f = p - \ell \in [1, p - 1], and ff times the pivot row is added without reduction, in one, two or three words. An entry is reduced only when it is about to be used: when its column becomes the pivot column, before the pivot is chosen, and when its row becomes the pivot row.

Proposition 5. Let s=min⁡(m,n)s = \min(m, n). In Algorithm 1 with delayed reduction, every stored entry is congruent to the true entry modulo pp and is at most (p−1)+(s−1)(p−1)2≤s(p−1)2(p - 1) + (s - 1) (p - 1)^2 \le s (p - 1)^2.

Proof. Adding ff times the pivot row, with f≡−ℓf \equiv -\ell, is congruent to subtracting ℓ\ell times it, so the congruence is preserved. An entry (i,j)(i, j) is updated once for each pivot that is found while it is still active, in a row above ii and a column to the left of jj; there are at most min⁡(i,j)≤s−1\min(i, j) \le s - 1 such pivots. Each update adds faf a with f≤p−1f \le p - 1 and a≤p−1a \le p - 1, a reduced entry of the pivot row, to an initial value at most p−1p - 1.

FLINT chooses the number of words from the bound s(p−1)2s (p - 1)^2 of How many words (_nmod_vec_dot_bound_limbs), which bounds every entry by Proposition 5. The reduction of a word uses the Lemire–Kaser–Kurz method when the bound is below 2322^{32} and Barrett's otherwise (Barrett and Lemire reduction).

nmod_mat_ple_classical_delayed applies the same reductions to the elimination of Theorem 4, swapping the rows of the matrix and of the buffer as nmod_mat_lu_classical_delayed does; the pivot of a column is found while the column is reduced, as the row of smallest index in AA with a nonzero entry (see Rank profile matrix).

For moduli of several limbs, mpn_mod_mat_lu_classical_delayed applies the same idea with unreduced entries of 2ℓ+12\ell + 1 limbs (delayed reduction for multiword moduli).

Crout elimination#

Algorithm 1 updates the whole active submatrix after each pivot. The Crout schedule performs the same operations in another order, computing each entry of LL and EE only when it is needed [DPS2017]. When column jj is processed, with rr pivots in the columns before it, the entry (i,j)(i, j) of a row ii without pivot is aij−∑k<rℓikekja_{ij} - \sum_{k < r} \ell_{ik} e_{kj}: one dot product of the multipliers of row ii with column jj of EE. When row ii becomes the pivot row rr, its entries to the right of column jj are ait−∑k<rℓikekta_{it} - \sum_{k < r} \ell_{ik} e_{kt}: one vector-matrix product of its multipliers with the rows of EE. The other entries are not touched before their column is processed.

nmod_mat_ple_crout uses this schedule with the pivoting of Theorem 4, swapping rows as nmod_mat_ple_classical_delayed does. Its dot products and vector-matrix products delay their reductions, with SIMD code (Dot products modulo a word-size integer, Thin matrices), so that no buffer of unreduced entries is needed, whereas the delayed algorithm needs two or three words per entry with scalar updates when min⁡(m,n)(p−1)2≥264\min(m, n) (p - 1)^2 \ge 2^{64}. On the other hand, the products only skip the zero multipliers before the first and after the last nonzero one of each row, while the classical and delayed algorithms skip every row whose multiplier is zero, which on some structured matrices saves most of the work.

Recursive decomposition#

Algorithm 2: Recursive PLE decomposition

Input: AA, m×nm \times n.

Output: a PLE decomposition of AA in place, and its rank.

  1. If m≤1m \le 1 or n≤1n \le 1, use Algorithm 1.
  2. Let n1=⌊n/2⌋n_1 = \lfloor n/2 \rfloor and decompose the left m×n1m \times n_1 block recursively: Aleft=Π1L1E1A_{\text{left}} = \Pi_1 L_1 E_1 of rank r1r_1.
  3. Apply Π1−1\Pi_1^{-1} to the rows of the right block. Write the first r1r_1 rows of the result as A01A_{01} and the others as A11A_{11}, and the first r1r_1 rows of L1L_1 as L00L_{00} and the others as L10L_{10}.
  4. A01←L00−1A01A_{01} \gets L_{00}^{-1} A_{01} (triangular solve with unit diagonal), and A11←A11−L10A01A_{11} \gets A_{11} - L_{10} A_{01} (matrix multiplication).
  5. Decompose A11A_{11} recursively, of rank r2r_2, apply its permutation to the rows of L10L_{10}, and move its LL factor to columns r1,…,r1+r2−1r_1, \ldots, r_1 + r_2 - 1.
  6. Return r1+r2r_1 + r_2.

nmod_mat_lu_recursive calls nmod_mat_lu for the two halves, which switches to the classical or delayed algorithm below a crossover depending on the size of pp (see Algorithms).

The recursion performs the operations of Algorithm 1, with the same pivots, in another order: the pivots of the first n1n_1 columns depend only on these columns, step 4 applies the eliminations of the left half to the right half, and the row moves of step 5 act on the rows that are not pivot rows of the left half. nmod_mat_ple_recursive uses the upward rotations of Theorem 4 in both halves, so that it computes the decomposition of that theorem, the same as nmod_mat_ple_classical.

Theorem 6. If two matrices of dimensions a×ba \times b and b×cb \times c can be multiplied with O(ac bω−2)O(a c \, b^{\omega - 2}) operations for b≤a,cb \le a, c, with 2<ω≤32 < \omega \le 3, then Algorithm 2 costs O(mnrω−2+mnlog⁡n)O(m n r^{\omega - 2} + m n \log n) operations.

Proof. At depth ℓ\ell of the recursion there are at most 2ℓ2^\ell subproblems, each with at most mm rows and n/2ℓn / 2^\ell columns, with ranks ri≤n/2ℓr_i \le n/2^\ell summing to at most rr. Step 4 is skipped when the left half has rank 0; otherwise the triangular solve and the product cost O(m (n/2ℓ) riω−2)O(m \, (n/2^\ell) \, r_i^{\omega - 2}). Let k≤min⁡(2ℓ,r)k \le \min(2^\ell, r) be the number of nonzero rir_i. Since x↦xω−2x \mapsto x^{\omega - 2} is concave, ∑iriω−2≤k3−ωrω−2\sum_i r_i^{\omega - 2} \le k^{3 - \omega} r^{\omega - 2}. For 2ℓ≤r2^\ell \le r the level therefore costs O(mn 2−ℓ(ω−2)rω−2)O(m n \, 2^{-\ell(\omega - 2)} r^{\omega - 2}), and for 2ℓ>r2^\ell > r, using riω−2≤rir_i^{\omega - 2} \le r_i, it costs O(mnr 2−ℓ)O(m n r \, 2^{-\ell}). Both are geometric series in ℓ\ell, with sums O(mnrω−2)O(m n r^{\omega - 2}) and O(mn)O(m n). The row permutations of step 3 and 5 cost O(mn)O(mn) per level, and there are O(log⁡n)O(\log n) levels.

With classical multiplication (ω=3\omega = 3) this is O(mnr)O(mnr), the cost of Algorithm 1; with Strassen–Winograd it is O(mnr0.81)O(mnr^{0.81}). In practice the gain comes as much from the speed of the multiplication kernels as from the exponent.

Triangular systems#

nmod_mat_solve_tril and nmod_mat_solve_triu solve TX=BTX = B for a d×dd \times d triangular TT and a d×cd \times c matrix BB. For min⁡(d,c)<64\min(d, c) < 64 they use substitution, one dot product per entry of XX, O(d2c)O(d^2 c) operations. Otherwise they split TT into blocks of ⌊d/2⌋\lfloor d/2 \rfloor and ⌈d/2⌉\lceil d/2 \rceil rows and use

(T000T10T11)−1(B0B1)=(X0T11−1(B1−T10X0)),X0=T00−1B0,\begin{pmatrix} T_{00} & 0 \\ T_{10} & T_{11} \end{pmatrix}^{-1} \begin{pmatrix} B_0 \\ B_1 \end{pmatrix} = \begin{pmatrix} X_0 \\ T_{11}^{-1} (B_1 - T_{10} X_0) \end{pmatrix}, \qquad X_0 = T_{00}^{-1} B_0,

and its upper triangular analogue, which costs O(c dω−1)O(c \, d^{\omega - 1}) for c≥dc \ge d. nmod_mat_solve_tril_right and nmod_mat_solve_triu_right solve XT=BXT = B for BB with dd columns in the same way: by substitution along the rows of XX, with the triangle of TT transposed for the dot products, or by the transposed block formulas.

Applications#

  • Solving AX=BAX = B for nonsingular AA: a PLE decomposition with early exit on rank deficiency, a permutation of BB, and two triangular solves. For d×dd \times d matrices AA and BB, O(dω)O(d^\omega).
  • Inversion: solving AX=IAX = I, O(dω)O(d^\omega).
  • Determinant: det⁡A=±∏iEii\det A = \pm \prod_i E_{ii}, the sign being that of the permutation; O(dω)O(d^\omega).
  • Rank: the number of pivots.
  • General systems AX=BAX = B: with the pivot columns cic_i, the solution with zero free variables is found by a triangular solve with LL, a consistency check of the rows beyond the rank (one matrix product), and a triangular solve with the r×rr \times r matrix of pivot columns of EE.
  • Reduced row echelon form: with E=(E1∣E2)E = (E_1 \mid E_2) up to a permutation of the columns, where E1E_1 is the upper triangular r×rr \times r matrix of pivot columns, the reduced form is (I∣E1−1E2)(I \mid E_1^{-1} E_2) with the columns put back in place; one triangular solve.
  • Nullspace: from the reduced form RR, one basis vector per free column ff, with a 1 in position ff and −Rif-R_{i f} in the position of the pivot of row ii. These entries are those of E1−1E2E_1^{-1} E_2, so the basis is computed from a PLE decomposition with one triangular solve, without forming RR.
  • Left nullspace: from a PLE decomposition, the rows of (−L2L1−1∣I)(-L_2 L_1^{-1} \mid I) with their columns put in the order of the rows of AA, where L1L_1 and L2L_2 are the first rr and the other rows of LL; one triangular solve with L1L_1 on the right. With the decomposition of Theorem 4, the identity matrix is at the rows of AA outside its row rank profile, and the basis is the transpose of the basis of the nullspace of ATA^T above.

Division-free determinants#

For an arbitrary modulus NN, elimination can meet nonzero pivots that are zero divisors. nmod_mat_det avoids this: it uses cofactor expansion for dimensions up to 4, the division-free algorithm of Berkowitz (Berkowitz's algorithm) up to 8, and above it PLE decomposition if NN is prime and the following triangularisation by Euclidean row operations otherwise.

Lemma 7. For 0≤a,b<N0 \le a, b < N, not both zero, let g=gcd⁡(a,b)g = \gcd(a, b). There are integers s,ts, t with sa−tb=gs a - t b = g and gcd⁡(s,N)=1\gcd(s, N) = 1.

Proof. Take any s0,t0s_0, t_0 with s0a−t0b=gs_0 a - t_0 b = g. Then s=s0+jb/gs = s_0 + j b/g and t=t0+ja/gt = t_0 + j a/g satisfy sa−tb=gsa - tb = g for every integer jj, and gcd⁡(s0,b/g)=1\gcd(s_0, b/g) = 1 since s0(a/g)−t0(b/g)=1s_0 (a/g) - t_0 (b/g) = 1. By the Chinese remainder theorem there is a jj with s0+jb/g≢0s_0 + j b/g \not\equiv 0 modulo every prime factor qq of NN: for q∤b/gq \nmid b/g one value of jj modulo qq is excluded, and for q∣b/gq \mid b/g none is, since then q∤s0q \nmid s_0.

To clear an entry bb below a pivot aa in the same column, nmod_mat_det_howell subtracts a multiple of the pivot row if bb is a multiple of aa modulo NN. Otherwise it replaces the pivot row by ss times itself minus tt times row bb, with s,ts, t from Lemma 7 (found by increasing jj until gcd⁡(s,N)=1\gcd(s, N) = 1). The new pivot gg divides bb, so the entry can then be cleared. The second operation multiplies the determinant by the unit ss, and the product of these units is divided out at the end. The cost is O(d3)O(d^3) operations and O(d2)O(d^2) extended gcd computations.

Howell form#

Over Z/NZ\mathbb{Z}/N\mathbb{Z} for composite NN, the row echelon form of a matrix is not unique, and its rows need not generate all elements of the row span with leading zeros. The Howell form repairs both [How1986; StoMul1998].

Definition 8. A matrix HH over Z/NZ\mathbb{Z}/N\mathbb{Z} is in Howell form if it is in row echelon form with its zero rows last, every pivot is a divisor of NN, every entry above a pivot is reduced modulo that pivot, and, for every nonzero row ii, every element of the row span of HH whose entries vanish up to and including the pivot column of row ii is a combination of the rows below row ii.

Every matrix is row equivalent to a unique matrix in Howell form, so two matrices span the same submodule of (Z/NZ)c(\mathbb{Z}/N\mathbb{Z})^c if and only if their Howell forms are equal [How1986]. FLINT computes the strong echelon form of Fieker and Hofmann [FieHof2014], which is the Howell form with zero rows inserted so that each pivot lies on the diagonal, and nmod_mat_howell_form then moves the zero rows to the bottom. The algorithm:

  1. Triangularise AA with Euclidean row operations, as for the determinant but with a unimodular 2×22 \times 2 transformation of the pivot row and the other row, so that the row span is preserved.
  2. For each diagonal entry aa from top to bottom: multiply its row by a unit uu such that uaua divides NN, and reduce the entries above it modulo it. If aa is a zero divisor, the row multiplied by N/gcd⁡(a,N)N / \gcd(a, N) is a new element of the span with a zero in this column; it is reduced into the rows below with the same Euclidean operations, which is what establishes the Howell property. If the diagonal entry is zero, the row itself is reduced in this way.

The matrix must have at least as many rows as columns, so that each column has a row to hold its pivot. The cost is O(c2m)O(c^2 m) operations plus O(cm)O(c m) extended gcd computations for an m×cm \times c matrix. Fast algorithms based on matrix multiplication exist [StoMul1998; Sto2000] but are not implemented.

Referenced from#

References#

  • [BH1974] J. R. Bunch and J. E. Hopcroft, "Triangular factorization and inversion by fast matrix multiplication", Mathematics of Computation 28 (1974), 231-236, https://doi.org/10.1090/S0025-5718-1974-0331751-8
  • [IMH1982] O. H. Ibarra, S. Moran and R. Hui, "A generalization of the fast LUP matrix decomposition algorithm and applications", Journal of Algorithms 3 (1982), 45-56
  • [JPS2013] C.-P. Jeannerod, C. Pernet and A. Storjohann, "Rank-profile revealing Gaussian elimination and the CUP matrix decomposition", Journal of Symbolic Computation 56 (2013), 46-68, https://doi.org/10.1016/j.jsc.2013.04.004
  • [DPS2017] J.-G. Dumas, C. Pernet and Z. Sultan, "Fast computation of the rank profile matrix and the generalized Bruhat decomposition", Journal of Symbolic Computation 83 (2017), 187-210
  • [How1986] J. A. Howell, "Spans in the module (Zm)s(\mathbb{Z}_m)^s", Linear and Multilinear Algebra 19 (1986), 67-77
  • [StoMul1998] Storjohann, Arne and Mulders, Thom : Fast algorithms for linear algebra modulo :math:NN : Algorithms—{ESA} '98 (Venice), Lecture Notes in Comput. Sci. 1461 139–150
  • [FieHof2014] Fieker C. and Hofmann T.: "Computing in quotients of rings of integers" LMS Journal of Computation and Mathematics, 17(A), 349-365
  • [Sto2000] A. Storjohann, Algorithms for Matrix Canonical Forms, PhD thesis, ETH Zürich (2000), https://doi.org/10.3929/ethz-a-004141007
Cite this page

The FLINT team, “Gaussian elimination and LU decomposition,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/linear-algebra/gaussian-elimination.html (generated 2026-11-02).