Solving rational linear systems
#include <flint/fmpq_mat.h>int fmpq_mat_solve(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_solve_fmpz_mat(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceint fmpq_mat_solve_fraction_free(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_solve_fmpz_mat_fraction_free(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceint fmpq_mat_solve_dixon(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_solve_fmpz_mat_dixon(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceint fmpq_mat_solve_multi_mod(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_solve_fmpz_mat_multi_mod(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceFor a square , sets to the solution of and returns 1 if is nonsingular, and returns 0 if is singular. The functions without algorithm suffix choose; the others use fmpz_mat_solve (which uses fraction-free elimination up to dimension 15), fmpz_mat_solve_dixon_den, respectively fmpz_mat_solve_multi_mod_den.
fmpq_mat_solve and fmpq_mat_solve_fmpz_mat use the fraction-free versions for , the multimodular versions if has at least columns, and the -adic versions otherwise. The functions with algorithm suffix (except the fraction-free ones) throw if the dimensions are incompatible. On a return value of 0, is unchanged.
int fmpq_mat_can_solve(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_can_solve_fraction_free(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_can_solve_dixon(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_can_solve_multi_mod(fmpq_mat_t X, const fmpq_mat_t A, const fmpq_mat_t B)sourceint fmpq_mat_can_solve_fmpz_mat_dixon(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceint fmpq_mat_can_solve_fmpz_mat_multi_mod(fmpq_mat_t X, const fmpz_mat_t A, const fmpz_mat_t B)sourceFor an matrix of any rank and an matrix , returns 1 and sets the matrix to a solution of if one exists, and returns 0 if the system is inconsistent. The answer is proven. The solution has zeros in the rows corresponding to the non-pivot columns of .
These call fmpz_mat_can_solve_fflu, fmpz_mat_can_solve_dixon_den and fmpz_mat_can_solve_multi_mod_den on the integer systems. fmpq_mat_can_solve uses the fraction-free version for and otherwise the modular method of fmpz_mat_can_solve. The dimensions are checked and an exception is thrown if they are incompatible.
int fmpq_mat_inv(fmpq_mat_t B, const fmpq_mat_t A)sourceSets to the inverse of the square matrix and returns 1 if is nonsingular; returns 0 if is singular. may be . For dimension at least 3, the denominators of the rows of are cleared, , and is solved with fmpq_mat_solve_fmpz_mat.
The solvers of this module find exact solutions of over for rational or integer matrices and , returning the solution as an fmpq_mat_t in canonical form. All of them reduce the problem to integer matrices and call the solvers of fmpz_mat.h, which work modulo primes and reconstruct the rational solution; see Solving linear systems over the rationals.
Reduction to integer systems#
Multiplying row of the augmented matrix by the least common denominator of its entries gives an integer system with the same solutions, since and with invertible. fmpq_mat_get_fmpz_mat_rowwise_2 computes and . The integer solver returns as an integer matrix and a denominator, which fmpq_mat_set_fmpz_mat_div_fmpz turns into a rational matrix in canonical form. The variants whose names contain fmpz_mat take and as integer matrices directly.
Clearing denominators row by row keeps the integer entries as small as possible: for a matrix with a common structure of denominators, such as the Hilbert matrix, the integers are the least common multiples of the denominators in each row, not of the whole matrix.
Choice of algorithm#
For a square matrix and right-hand sides, fmpq_mat_solve and fmpq_mat_solve_fmpz_mat use
- for :
fmpz_mat_solve, that is Cramer's rule for and fraction-free elimination otherwise (thefraction_freevariants); - for and : multimodular solving (
fmpz_mat_solve_multi_mod_den, themulti_modvariants); - otherwise: -adic lifting (
fmpz_mat_solve_dixon_den, thedixonvariants).
All of them return 1 if is nonsingular and 0 otherwise, and in the latter case leave unchanged. The modular solvers are output-sensitive: their running time depends on the size of the solution rather than on a worst-case bound.
fmpq_mat_can_solve accepts any matrix . It returns 1 with a solution if the system is consistent, and 0 if it is not; the answer is proven, by exact verification of the solution or by an exact certificate of inconsistency. For it uses fraction-free elimination (fmpq_mat_can_solve_fraction_free), otherwise the modular method of fmpz_mat_can_solve; fmpq_mat_can_solve_dixon and fmpq_mat_can_solve_multi_mod force the solver used for the nonsingular pivot block.
fmpq_mat_inv solves with fmpq_mat_solve_fmpz_mat, where , so that ; it uses explicit formulas for dimensions up to 2.
Example#
The Hilbert matrix , with entries , is notoriously ill-conditioned but has an integral inverse. Solving exactly, inverting , and testing two singular systems:
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpq.h>
#include <flint/fmpq_mat.h>
int main(void)
{
fmpq_mat_t H, B, X, Hinv, A, Y;
slong i, n = 10;
fmpq_mat_init(H, n, n);
fmpq_mat_init(B, n, 1);
fmpq_mat_init(X, n, 1);
fmpq_mat_init(Hinv, n, n);
fmpq_mat_hilbert_matrix(H);
for (i = 0; i < n; i++)
fmpq_one(fmpq_mat_entry(B, i, 0));
flint_printf("solvable: %d\n", fmpq_mat_solve(X, H, B));
flint_printf("x_0 = %{fmpq}, x_9 = %{fmpq}\n",
fmpq_mat_entry(X, 0, 0), fmpq_mat_entry(X, 9, 0));
flint_printf("invertible: %d\n", fmpq_mat_inv(Hinv, H));
flint_printf("inverse is integral: %d\n", fmpq_mat_is_integral(Hinv));
flint_printf("entry (4, 4) of the inverse: %{fmpq}\n", fmpq_mat_entry(Hinv, 4, 4));
/* a singular system: rows 0, 1 and their sum */
fmpq_mat_init(A, 3, 2);
fmpq_mat_init(Y, 2, 1);
fmpq_mat_clear(B);
fmpq_mat_init(B, 3, 1);
fmpq_set_si(fmpq_mat_entry(A, 0, 0), 1, 2);
fmpq_set_si(fmpq_mat_entry(A, 0, 1), 1, 3);
fmpq_set_si(fmpq_mat_entry(A, 1, 0), 1, 4);
fmpq_set_si(fmpq_mat_entry(A, 1, 1), -1, 5);
fmpq_add(fmpq_mat_entry(A, 2, 0), fmpq_mat_entry(A, 0, 0), fmpq_mat_entry(A, 1, 0));
fmpq_add(fmpq_mat_entry(A, 2, 1), fmpq_mat_entry(A, 0, 1), fmpq_mat_entry(A, 1, 1));
fmpq_set_si(fmpq_mat_entry(B, 0, 0), 1, 1);
fmpq_set_si(fmpq_mat_entry(B, 1, 0), 2, 1);
fmpq_set_si(fmpq_mat_entry(B, 2, 0), 3, 1);
flint_printf("consistent: %d, ", fmpq_mat_can_solve(Y, A, B));
flint_printf("y = (%{fmpq}, %{fmpq})\n",
fmpq_mat_entry(Y, 0, 0), fmpq_mat_entry(Y, 1, 0));
fmpq_set_si(fmpq_mat_entry(B, 2, 0), 4, 1);
flint_printf("consistent: %d\n", fmpq_mat_can_solve(Y, A, B));
fmpq_mat_clear(H);
fmpq_mat_clear(B);
fmpq_mat_clear(X);
fmpq_mat_clear(Hinv);
fmpq_mat_clear(A);
fmpq_mat_clear(Y);
return 0;
}solvable: 1 x_0 = -10, x_9 = 923780 invertible: 1 inverse is integral: 1 entry (4, 4) of the inverse: 176752976400 consistent: 1, y = (52 / 11, -45 / 11) consistent: 0
The FLINT team, “Solving rational linear systems (fmpq_mat.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpq_mat/solve.html (generated 2026-11-02).
@misc{flint-doc-fmpq-mat-solve,
author = {{The FLINT team}},
title = {{Solving rational linear systems (fmpq\_mat.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/fmpq_mat/solve.html},
note = {Generated 2026-11-02}
}