FLINT3.7.0-dev

Solving linear systems over the rationals

Synopsis#include <flint/fmpz_mat.h>
int fmpz_mat_solve(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_solve_cramer(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_solve_fflu(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_solve_dixon_den(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_solve_multi_mod_den(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source

For a square matrix AA of dimension nn and an n×kn \times k matrix BB, sets (XX, den) to the solution of AX=BAX = B and returns 1 if AA is nonsingular; returns 0 if AA is singular. fmpz_mat_solve chooses the algorithm; the others force Cramer's rule (n≤3n \le 3 only), fraction-free elimination, pp-adic lifting, respectively multimodular solving.

fmpz_mat_solve_cramer and fmpz_mat_solve_fflu return den=det⁡(A)\mathit{den} = \det(A); fmpz_mat_solve_dixon_den and fmpz_mat_solve_multi_mod_den return the smallest positive common denominator of the solution. XX may be AA or BB. On a return value of 0, XX is unspecified and den is 0 for the fraction-free solvers. XX may be a window matrix.

int fmpz_mat_can_solve(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_can_solve_fflu(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_can_solve_dixon_den(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source
int fmpz_mat_can_solve_multi_mod_den(fmpz_mat_t X, fmpz_t den, const fmpz_mat_t A, const fmpz_mat_t B)source

For an m×nm \times n matrix AA of any rank and an m×km \times k matrix BB, returns 1 if AX=BAX = B has a solution over Q\mathbb{Q}, with (XX, den) set to one such solution (XX is n×kn \times k), and 0 if the system is inconsistent. The answer is proven.

The solution returned has zeros in the rows corresponding to the non-pivot columns of AA. fmpz_mat_can_solve_fflu uses fraction-free elimination; the other two find the rank structure modulo primes, solve the nonsingular pivot block with fmpz_mat_solve_dixon_den, respectively fmpz_mat_solve_multi_mod_den, and verify the other equations exactly. fmpz_mat_can_solve uses fmpz_mat_can_solve_fflu for m≤15m \le 15 and otherwise the modular method, solving the pivot block with fmpz_mat_solve. On a return value of 0, XX and den are unspecified. XX must not be aliased with AA or BB. See Systems of any shape.

The solvers of this module find solutions over Q\mathbb{Q} of AX=BAX = B for integer matrices AA and BB. A solution is returned as an integer matrix XX and a denominator den with AX=den⋅BAX = \mathit{den} \cdot B, so that X/denX/\mathit{den} is the rational solution. fmpz_mat_solve and its variants require a square AA and decide whether it is nonsingular; fmpz_mat_can_solve and its variants accept any AA and decide whether the system is consistent. Every answer is proven, including "singular" and "inconsistent".

AlgorithmMultimodular and p-adic linear algebra over the integersHow FLINT computes determinants, solutions of linear systems, ranks, echelon forms, characteristic and minimal polynomials and products of integer matrices by working modulo word-size primes or prime powers, with Hadamard bounds, rational reconstruction, output-sensitive termination and exact certificates for every answer.

Nonsingular systems#

For a square AA of dimension nn and an n×kn \times k matrix BB, fmpz_mat_solve(X, den, A, B) returns 1 and sets XX and den if AA is nonsingular, and returns 0 if AA is singular. It chooses the algorithm as follows.

ConditionFunctionDenominator returned
n≤3n \le 3fmpz_mat_solve_cramerdet⁡(A)\det(A)
4≤n≤154 \le n \le 15fmpz_mat_solve_ffludet⁡(A)\det(A)
n≥16n \ge 16, 2k≥n2k \ge nfmpz_mat_solve_multi_mod_denleast common denominator, positive
n≥16n \ge 16, 2k<n2k < nfmpz_mat_solve_dixon_denleast common denominator, positive

The fraction-free solvers produce det⁡(A)A−1B\det(A) A^{-1} B, whose entries are determinants by Cramer's rule; dividing out the gcd of the entries and den would give the reduced form. The modular solvers reconstruct the reduced solution directly. XX may be AA or BB in all of them.

Fraction-free elimination#

fmpz_mat_solve_cramer evaluates Cramer's rule with explicit cofactor formulas. fmpz_mat_solve_fflu computes a fraction-free LU decomposition of AA with fmpz_mat_fflu and solves with fraction-free forward and back substitution (fmpz_mat_solve_fflu_precomp), all of whose divisions are exact; see Solving. Entries grow to the size of n×nn \times n minors, about n(b+log⁡2n)n(b + \log_2 n) bits for bb-bit entries, so the cost grows like n5b2n^5 b^2 and the method is competitive only for small nn.

p-adic lifting#

fmpz_mat_solve_dixon_den implements Dixon's algorithm [Dix1982]. It finds a prime pp near 2302^{30} modulo which AA is nonsingular (or proves AA singular), computes the LU decomposition of AA modulo pp once, and then computes the pp-adic expansion X=X0+X1p+X2p2+⋯X = X_0 + X_1 p + X_2 p^2 + \cdots of A−1BA^{-1}B, one digit per step: Xi=A−1Ri mod pX_i = A^{-1} R_i \bmod p and Ri+1=(Ri−AXi)/pR_{i+1} = (R_i - A X_i)/p, exactly. Each step costs a triangular solve modulo pp and a product of AA with an n×kn \times k matrix of word-size entries. When the solution is long, the digits grow to pep^e for increasing ee, with an inverse of AA modulo pep^e computed by Newton iteration and products computed multimodularly from precomputed residues of AA.

The rational solution is recovered by rational reconstruction from XX modulo pip^i. Lifting to pi>2NDp^i > 2ND, with the bounds NN and DD of fmpz_mat_solve_bound, always suffices, but the solver stops as soon as the true solution is determined, which for small solutions happens much earlier; see Output-sensitive termination.

Chinese remaindering#

fmpz_mat_solve_multi_mod_den solves AX=BAX = B modulo primes above 2592^{59} with nmod_mat_solve, processing batches of primes in parallel, and combines the solutions modulo the product of the primes by the Chinese remainder theorem, with the same reconstruction and termination as the pp-adic solver. A prime costs an LU decomposition and a triangular solve, O(nω+n2k)O(n^\omega + n^2 k) word operations, against a product with AA, O(n2k(b/β+1))O(n^2 k (b/\beta + 1)), per pp-adic step. Many right-hand sides make the LU decomposition comparatively cheap, which is why fmpz_mat_solve uses this method when 2k≥n2k \ge n.

Output-sensitive termination#

Both modular solvers maintain a random linear combination ss of the entries of the solution modulo the current modulus mm at negligible cost, and periodically reconstruct ss as a fraction. Once that succeeds, its denominator is (with high probability) the common denominator of the solution and its numerator indicates the size of the solution. Only then is the whole solution reconstructed, and it is accepted when

n∥A∥∥X∥+den∥B∥<m,n \lVert A \rVert \lVert X \rVert + \mathit{den} \lVert B \rVert < m,

with maximum norms: since AX−den⋅B≡0(modm)AX - \mathit{den} \cdot B \equiv 0 \pmod m by construction and the inequality bounds its entries by mm in absolute value, it is zero. When this inequality would need a much larger modulus, the solution is verified by computing AXAX instead, if that is estimated to be cheaper [Cab1971; CheSto2005; Stef2010]. A wrong guess from the random combination can therefore never produce a wrong result; it only costs time. See Output-sensitive termination.

Singular matrices#

Both modular solvers search for a prime modulo which AA has full rank. A prime modulo which the rank drops is either a divisor of det⁡(A)≠0\det(A) \ne 0 (a bad prime) or a witness of singularity. The solvers try to prove singularity with an exact kernel vector, found by solving the nonsingular pivot block modulo pp against a non-pivot column and checking the remaining rows exactly. If that fails, they try another prime, and they also declare AA singular once the product of the primes with a rank drop exceeds Hadamard's bound for ∣det⁡(A)∣|\det(A)|. Singular input is thus detected after one or two primes in practice.

Systems of any shape#

For an m×nm \times n matrix AA and an m×km \times k matrix BB, fmpz_mat_can_solve(X, den, A, B) returns 1 if AX=BAX = B has a solution over Q\mathbb{Q}, and sets (XX, den) to the solution whose entries in the non-pivot rows (the rows of XX corresponding to columns of AA that are not pivot columns of its echelon form) are zero. It returns 0 if the system is inconsistent. For m≤15m \le 15 it calls fmpz_mat_can_solve_fflu, otherwise the modular method of fmpz_mat_can_solve_multi_mod_den with the pivot block solved by fmpz_mat_solve:

  1. Reduce AA modulo a batch of primes above 2592^{59} and compute the rank rr and the pivot rows and columns of AA modulo each, in parallel.
  2. For the first prime of maximal rank, solve the r×rr \times r pivot block of AA against the corresponding rows of BB exactly.
  3. Check the other m−rm - r equations exactly. If they hold, the solution is correct whatever the prime.
  4. If an equation i0i_0 fails, try to prove inconsistency: solve the transposed pivot system for a vector yy supported on the pivot rows and row i0i_0 with yTA=0y^T A = 0 on the pivot columns, and check exactly that yTA=0y^T A = 0 on all columns. Since yTB≠0y^T B \ne 0, such a yy proves that no solution exists (Fredholm alternative) [GieLobSau1998; MulSto2004].
  5. Otherwise the rank modulo the prime was too small. Continue with other primes, redoing exact work only when the rank increases, and declare the system inconsistent once the product of the primes exceeds a bound for all minors of AA (fmpz_mat_det_bound_submatrix), since then at least one prime gave the true rank.

fmpz_mat_can_solve_dixon_den and fmpz_mat_can_solve_multi_mod_den force the solver used in step 2. fmpz_mat_can_solve_fflu uses fraction-free elimination on AA, solves with the pivot rows, and checks the other equations. XX must be n×kn \times k and must not be aliased with AA or BB. On a return value of 0, XX and den are unspecified.

Example#

A 20×2020 \times 20 system with one right-hand side, solved by the default method (here pp-adic lifting) and by fraction-free elimination. The pp-adic solver returns the least common denominator, the fraction-free solver the determinant, which is −4000-4000 times larger. Then a 3×43 \times 4 system of rank 2, consistent for one right-hand side and inconsistent for another:

Examplefmpz_mat_solve_systems.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_mat.h>

int main(void)
{
    fmpz_mat_t A, B, X, Y, AX;
    fmpz_t den, den2;
    slong i, j, n = 20;

    fmpz_init(den);
    fmpz_init(den2);
    fmpz_mat_init(A, n, n);
    fmpz_mat_init(B, n, 1);
    fmpz_mat_init(X, n, 1);
    fmpz_mat_init(Y, n, 1);

    /* A[i][j] = (i + 2j)^2 mod 17 - 8, with 10 added on the diagonal */
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < n; j++)
            fmpz_set_si(fmpz_mat_entry(A, i, j),
                ((i + 2 * j) * (i + 2 * j)) % 17 - 8 + 10 * (i == j));
        fmpz_set_si(fmpz_mat_entry(B, i, 0), i + 1);
    }

    flint_printf("nonsingular: %d\n", fmpz_mat_solve(X, den, A, B));
    flint_printf("den = %{fmpz}\n", den);
    flint_printf("x_0 = %{fmpz} / %{fmpz}\n", fmpz_mat_entry(X, 0, 0), den);

    fmpz_mat_solve_fflu(Y, den2, A, B);
    flint_printf("fflu den = %{fmpz}\n", den2);
    fmpz_divexact(den, den2, den);
    flint_printf("ratio = %{fmpz}\n", den);

    /* check A X = den B */
    fmpz_mat_init(AX, n, 1);
    fmpz_mat_mul(AX, A, Y);
    fmpz_mat_scalar_mul_fmpz(B, B, den2);
    flint_printf("A Y = den B: %d\n", fmpz_mat_equal(AX, B));

    fmpz_mat_clear(A);
    fmpz_mat_clear(B);
    fmpz_mat_clear(X);
    fmpz_mat_clear(Y);
    fmpz_mat_clear(AX);

    /* a rank 2 system: the third row is the sum of the first two */
    fmpz_mat_init(A, 3, 4);
    fmpz_mat_init(B, 3, 1);
    fmpz_mat_init(X, 4, 1);
    for (j = 0; j < 4; j++)
    {
        fmpz_set_si(fmpz_mat_entry(A, 0, j), j + 1);
        fmpz_set_si(fmpz_mat_entry(A, 1, j), 3 * j * j - 2);
        fmpz_add(fmpz_mat_entry(A, 2, j),
                 fmpz_mat_entry(A, 0, j), fmpz_mat_entry(A, 1, j));
    }
    fmpz_set_si(fmpz_mat_entry(B, 0, 0), 1);
    fmpz_set_si(fmpz_mat_entry(B, 1, 0), 2);
    fmpz_set_si(fmpz_mat_entry(B, 2, 0), 3);

    flint_printf("consistent: %d\n", fmpz_mat_can_solve(X, den, A, B));
    flint_printf("X = ");
    fmpz_mat_print(X);
    flint_printf(", den = %{fmpz}\n", den);

    fmpz_set_si(fmpz_mat_entry(B, 2, 0), 4);
    flint_printf("consistent: %d\n", fmpz_mat_can_solve(X, den, A, B));

    fmpz_mat_clear(A);
    fmpz_mat_clear(B);
    fmpz_mat_clear(X);
    fmpz_clear(den);
    fmpz_clear(den2);
    return 0;
}
Output
nonsingular: 1
den = 30710924059369020030
x_0 = -15778958810838794440 / 30710924059369020030
fflu den = -122843696237476080120000
ratio = -4000
A Y = den B: 1
consistent: 1
X = 4 1  -3 4 0 0, den = 5
consistent: 0

Guides#

References#

  • [Dix1982] J. D. Dixon, "Exact solution of linear equations using p-adic expansions", Numerische Mathematik 40 (1982) 137-141
  • [Cab1971] S. Cabay, "Exact solution of linear equations", Proceedings of the Second ACM Symposium on Symbolic and Algebraic Manipulation (1971) 392-398
  • [CheSto2005] Z. Chen and A. Storjohann, "A BLAS based C library for exact linear algebra on integer matrices", Proceedings of the 2005 International Symposium on Symbolic and Algebraic Computation (ISSAC) (2005) 92-99
  • [Stef2010] D. E. Steffy, "Exact solutions to linear systems of equations using output sensitive lifting", ACM Communications in Computer Algebra 44:3/4 (2010) 160-182
  • [GieLobSau1998] M. Giesbrecht, A. Lobo and B. D. Saunders, "Certifying inconsistency of sparse linear systems", Proceedings of the 1998 International Symposium on Symbolic and Algebraic Computation (ISSAC) (1998) 113-119
  • [MulSto2004] T. Mulders and A. Storjohann, "Certified dense linear system solving", Journal of Symbolic Computation 37:4 (2004) 485-510
Cite this page

The FLINT team, “Solving linear systems over the rationals (fmpz_mat.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_mat/solve.html (generated 2026-11-02).