FLINT3.7.0-dev
Module · 256 functions

gr_mat.h

#include <flint/gr_mat.h>

This module implements dense matrices over a ring R given by a generic context gr_ctx_t (see gr.h). A gr_mat_t stores its entries row by row in the representation of the elements of R, so the same functions serve integer, rational and modular matrices, matrices over finite fields and number fields, matrices of real and complex balls or floating-point numbers, and matrices over polynomial rings. The module contains the generic algorithms for matrix multiplication (classical, Strassen, Waksman, Rosowski), Gaussian elimination in its ordinary and fraction-free forms, triangular and general linear solving, determinants and permanents, ranks, echelon forms and nullspaces, characteristic and minimal polynomials, eigenvalues and diagonalisation, Jordan forms and functions of matrices, and QR decompositions.

Multiplication, LU decomposition, determinants, characteristic polynomials, triangular solving and pivot selection are methods of the coefficient context, which a ring can replace by its own implementation; every algorithm here that multiplies matrices calls gr_mat_mul, so a fast ring-specific product speeds up block LU decomposition, triangular solving and everything built on them. The overview Linear algebra over generic rings and its specialisations says which ring uses which algorithm and how the specialised modules (nmod_mat, fmpz_mat, fmpz_mod_mat, arb_mat and others) relate to the generic code.

The guide Linear algebra over general and inexact rings explains how the functions behave over rings that are not fields and over inexact rings, with complete programs.

OverviewLinear algebra over generic rings and its specialisationsHow the generic matrix module gr_mat organises multiplication, LU and fraction-free LU decomposition, solving, determinants, ranks, echelon forms, characteristic polynomials and eigenvalues over any ring, how it handles rings that are not fields and inexact rings, and how nmod_mat, fmpz_mat, mpn_mod, arb_mat, acb_mat and fq_mat specialise or reuse these algorithms.

Guides#

Types and conventions#

A matrix over the ring given by a gr_ctx_t. The structure has the fields entries (a pointer to the first entry), r and c (the numbers of rows and columns) and stride (the distance in elements between the starts of consecutive rows). The entry in row i and column j is at index i \cdot \mathit{stride} + j of entries. A matrix created by gr_mat_init has \mathit{stride} = c; a window shares the entries and the stride of its parent. A gr_mat_t is an array of one gr_mat_struct, so it is passed by reference.

The following conventions hold throughout the module.

  • The context is the coefficient ring. The ctx argument of every function describes R. A context for a ring of matrices (gr_ctx_init_matrix_ring, gr_ctx_init_matrix_space) is needed only to use matrices as elements of another generic structure or with the generic element functions such as gr_mul.
  • Shapes. Outputs must be initialised with the shape of the result; most functions return GR_DOMAIN when the shapes of their arguments are incompatible, but not all of them check. Functions that resize their output say so (for example gr_mat_nullspace).
  • Status codes. Functions returning int return GR_SUCCESS or a combination of GR_DOMAIN (no result in R: a singular matrix where an invertible one is needed, a non-invertible pivot, an impossible shape) and GR_UNABLE (the result may exist but cannot be computed, typically because a zero test is undecidable or the ring lacks a required operation). On failure the outputs are undefined but valid. Predicates return a truth_t.
  • Rings. Most functions assume that R is commutative. Elimination over a field uses inverses of pivots; fraction-free elimination needs exact division and works over integral domains. Algorithms designed for integral domains often work over other rings as long as every inversion they attempt succeeds, and report a failed inversion with GR_DOMAIN or GR_UNABLE. Rings with undecidable equality (balls, exact real numbers) can make a pivot search fail with GR_UNABLE; see Linear algebra over general and inexact rings.
  • Aliasing. The output may be the same matrix as an input for the entrywise operations and, unless stated otherwise, for the functions of this module, which use temporaries where needed. Several outputs of one function must be distinct.

The layout of gr_mat_t is that of fmpz_mat_t, fmpq_mat_t, fmpz_mod_mat_t, fq_mat_t, fq_nmod_mat_t, fq_zech_mat_t, arb_mat_t, acb_mat_t and ca_mat_t, so such matrices can be cast to a gr_mat_t over the matching context. nmod_mat_t stores its modulus in the matrix and must be converted.

Memory management#

void gr_mat_init(gr_mat_t mat, slong rows, slong cols, gr_ctx_t ctx)

Initialises mat as a zero matrix with the given numbers of rows and columns, which may be zero.

int gr_mat_init_set(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)

Initialises res as a copy of mat.

Clears the entries and frees the memory of mat. A window must be released with gr_mat_window_clear instead.

void gr_mat_swap(gr_mat_t mat1, gr_mat_t mat2, gr_ctx_t ctx)

Swaps mat1 and mat2 in constant time by exchanging the structures.

int gr_mat_swap_entrywise(gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Swaps the entries of two matrices of the same shape one by one, leaving the structures in place. This is the way to exchange the contents of windows.

Entries and dimensions#

GR_MAT_ENTRY(mat, i, j, sz)

A pointer to the entry in row i and column j of mat, whose elements have size sz bytes (ctx->sizeof_elem).

gr_ptr gr_mat_entry_ptr(gr_mat_t mat, slong i, slong j, gr_ctx_t ctx)
gr_srcptr gr_mat_entry_srcptr(const gr_mat_t mat, slong i, slong j, gr_ctx_t ctx)

Return a pointer to the entry in row i and column j. The indices must be in bounds.

gr_mat_nrows(mat, ctx)
gr_mat_ncols(mat, ctx)

The number of rows and of columns of mat.

Return whether mat has no entries (zero rows or zero columns), respectively as many rows as columns. These predicates depend only on the shape and always return T_TRUE or T_FALSE.

Windows and shallow transposes#

void gr_mat_window_init(gr_mat_t window, const gr_mat_t mat, slong r1, slong c1, slong r2, slong c2, gr_ctx_t ctx)

gr_mat_window_init makes window the submatrix of mat formed by rows r_1 \le i < r_2 and columns c_1 \le j < c_2, sharing the entries of mat (writing to the window modifies mat). The indices must be within bounds. gr_mat_window_clear releases a window without touching the entries.

GR_MAT_TMP_INIT_SHALLOW_TRANSPOSE makes AT a temporary transpose of A whose entries are shallow copies (sharing heap data) of those of A, allocated on the stack when small. It can be read like a window, and written to provided that the changes are copied back with GR_MAT_SHALLOW_TRANSPOSE(A, AT, ctx), which copies the transpose of its second argument shallowly into its first (the two must not be aliased). GR_MAT_TMP_CLEAR_SHALLOW_TRANSPOSE frees the temporary without clearing the shared entries. The classical multiplication uses this to turn the columns of the right factor into contiguous vectors for dot products.

Input and output#

int gr_mat_write(gr_stream_t out, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_print(const gr_mat_t mat, gr_ctx_t ctx)

Write mat to a stream or to standard output, as a bracketed list of rows with one row per line.

int gr_mat_set_str(gr_mat_t mat, const char * s, int resize, gr_ctx_t ctx)

Sets mat to the matrix described by s, of the form [[e11, ..., e1n], ..., [em1, ..., emn]], where each row is parsed as by gr_vec_set_str and each entry by gr_set_str. Whitespace around brackets and separators, including the line breaks written by gr_mat_write, is ignored.

More

Assignment and conversion#

Set res to the zero matrix, respectively to the matrix with ones on the main diagonal and zeros elsewhere (the identity if square).

int gr_mat_set(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_set_gr_mat_other(gr_mat_t res, const gr_mat_t mat, gr_ctx_t mat_ctx, gr_ctx_t ctx)

Set res to a copy of mat, converting the entries from integers, rationals or the ring mat_ctx into R. A conversion that is not possible gives GR_DOMAIN or GR_UNABLE. The shapes must agree.

int gr_mat_set_fmpz(gr_mat_t res, const fmpz_t c, gr_ctx_t ctx)
int gr_mat_set_fmpq(gr_mat_t res, const fmpq_t c, gr_ctx_t ctx)

Set res to the matrix with c on the main diagonal and zeros elsewhere.

Comparisons and structure#

truth_t gr_mat_equal(const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Returns whether the matrices are equal: T_FALSE if the shapes differ, otherwise the conjunction of the entrywise comparisons.

Return whether mat is zero, has 1 or -1 on the main diagonal and zeros elsewhere, or is a scalar matrix (a diagonal matrix with equal diagonal entries).

Return whether all entries off the main diagonal, below it, above it, or below the first subdiagonal (upper Hessenberg form) are zero. The matrix need not be square.

Rows, columns and transposition#

int gr_mat_concat_horizontal(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)
int gr_mat_concat_vertical(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Set res to (A \mid B), respectively to A stacked above B. Return GR_DOMAIN if the numbers of rows (columns) of the inputs, or the shape of res, do not match.

int gr_mat_transpose(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)

Sets res to the transpose of mat. Aliasing is allowed for square matrices, in which case the entries are swapped in place.

int gr_mat_swap_rows(gr_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx)
void _gr_mat_swap_rows(gr_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx)
int gr_mat_swap_cols(gr_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx)
void _gr_mat_swap_cols(gr_mat_t mat, slong * perm, slong r, slong s, gr_ctx_t ctx)

Swap rows (columns) r and s of mat, and the entries r and s of the permutation perm if it is not NULL. The non-underscore versions return GR_DOMAIN for indices out of bounds; the underscore versions do not check them.

Reverse the order of the rows (columns): swap row i and row r - 1 - i for 0 \le i < r/2, and apply the same permutation to perm if it is not NULL.

int gr_mat_permute_rows(gr_mat_t mat, slong * perm_store, const slong * perm_act, gr_ctx_t ctx)
int gr_mat_permute_rows_inv(gr_mat_t mat, slong * perm_store, const slong * perm_act, gr_ctx_t ctx)
int gr_mat_permute_cols(gr_mat_t mat, slong * perm_store, const slong * perm_act, gr_ctx_t ctx)
int gr_mat_permute_cols_inv(gr_mat_t mat, slong * perm_store, const slong * perm_act, gr_ctx_t ctx)

Permute the rows (columns) by perm_act, or by its inverse for the inv versions, and apply the same permutation to perm_store if it is not NULL. gr_mat_permute_rows moves row perm_act[i] to row i (and perm_store[perm_act[i]] to perm_store[i]); the inv version moves row i to row perm_act[i], without computing the inverse permutation. perm_store and perm_act may be the same array.

More

Moves row i to position \mathit{new\_i}, shifting the rows in between by one: with i = 4 and \mathit{new\_i} = 7 the rows A_4, A_5, A_6, A_7 become A_5, A_6, A_7, A_4, and with i = 7 and \mathit{new\_i} = 4 they become A_7, A_4, A_5, A_6. Returns GR_DOMAIN if an index is out of bounds and otherwise succeeds.

Entrywise operations#

int gr_mat_entrywise_unary_op(gr_mat_t res, gr_method_unary_op f, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_entrywise_binary_op(gr_mat_t res, gr_method_binary_op f, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)
int gr_mat_entrywise_binary_op_scalar(gr_mat_t res, gr_method_binary_op f, const gr_mat_t mat, gr_srcptr c, gr_ctx_t ctx)

Set each entry of res to f applied to the corresponding entry of mat, to the entries of mat1 and mat2, or to the entry of mat and the scalar c. Return GR_DOMAIN if the shapes do not match. These are declared only when gr.h is included before gr_mat.h.

truth_t gr_mat_entrywise_unary_predicate_all(gr_method_unary_predicate f, const gr_mat_t mat, gr_ctx_t ctx)
truth_t gr_mat_entrywise_unary_predicate_any(gr_method_unary_predicate f, const gr_mat_t mat, gr_ctx_t ctx)
truth_t gr_mat_entrywise_binary_predicate_all(gr_method_binary_predicate f, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Return whether the predicate f holds for all entries, for some entry, or for all pairs of corresponding entries (T_FALSE if the shapes differ).

Addition and scalar arithmetic#

int gr_mat_neg(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_add(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)
int gr_mat_sub(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Set res to -A, A + B or A - B.

int gr_mat_add_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx)
int gr_mat_add_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx)
int gr_mat_add_fmpz(gr_mat_t res, const gr_mat_t mat, const fmpz_t x, gr_ctx_t ctx)
int gr_mat_add_fmpq(gr_mat_t res, const gr_mat_t mat, const fmpq_t x, gr_ctx_t ctx)

Set res to A + xI or xI + A, adding x to the main diagonal.

int gr_mat_sub_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx)
int gr_mat_sub_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx)
int gr_mat_sub_fmpz(gr_mat_t res, const gr_mat_t mat, const fmpz_t x, gr_ctx_t ctx)
int gr_mat_sub_fmpq(gr_mat_t res, const gr_mat_t mat, const fmpq_t x, gr_ctx_t ctx)

Set res to A - xI or xI - A.

int gr_mat_mul_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx)
int gr_mat_mul_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx)
int gr_mat_mul_fmpz(gr_mat_t res, const gr_mat_t mat, const fmpz_t x, gr_ctx_t ctx)
int gr_mat_mul_fmpq(gr_mat_t res, const gr_mat_t mat, const fmpq_t x, gr_ctx_t ctx)

Set res to Ax or xA (the order matters over noncommutative rings).

int gr_mat_div_ui(gr_mat_t res, const gr_mat_t mat, ulong x, gr_ctx_t ctx)
int gr_mat_div_si(gr_mat_t res, const gr_mat_t mat, slong x, gr_ctx_t ctx)
int gr_mat_div_fmpz(gr_mat_t res, const gr_mat_t mat, const fmpz_t x, gr_ctx_t ctx)
int gr_mat_div_fmpq(gr_mat_t res, const gr_mat_t mat, const fmpq_t x, gr_ctx_t ctx)

Set res to A / x, dividing each entry with gr_div (GR_DOMAIN if a quotient does not exist in R).

Set res to \mathit{res} + Ac, respectively \mathit{res} - Ac.

int gr_mat_mul_diag(gr_mat_t res, const gr_mat_t A, const gr_vec_t D, gr_ctx_t ctx)
int gr_mat_diag_mul(gr_mat_t res, const gr_vec_t D, const gr_mat_t A, gr_ctx_t ctx)

Set res to AD or DA, where D is the diagonal matrix with the entries of the vector D on its diagonal: column j (row i) of A is multiplied by D_j (D_i).

Matrix multiplication#

int gr_mat_mul(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)
int gr_mat_mul_generic(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)

Set res to the product AB. gr_mat_mul calls the ring method GR_METHOD_MAT_MUL; the default gr_mat_mul_generic is classical multiplication. Most rings with a dedicated matrix module override the method. Returns GR_DOMAIN if the shapes are incompatible: gr_mat_mul itself does not check them, so every ring method must (all methods in FLINT do). See Multiplying matrices over generic rings.

Full documentation
int gr_mat_mul_classical(gr_mat_t res, const gr_mat_t mat1, const gr_mat_t mat2, gr_ctx_t ctx)

Computes the m \times n by n \times p product with the classical algorithm, as mp dot products of length n (_gr_vec_dot), with the right factor transposed shallowly so that its columns are contiguous.

Full documentation
int gr_mat_mul_strassen(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)

One level of Strassen's algorithm [Str1969] with the 7-multiplication, 15-addition sequence of Winograd [Win1971] in the order given by Bodrato [Bodrato2010], which saves further operations when squaring. The seven products of half size are computed with gr_mat_mul, so the recursion continues only if the ring method dispatches back to this function above a cutoff; then the complexity is O(n^{\log_2 7}) = O(n^{2.81}). See Strassen–Winograd multiplication.

Full documentation
int gr_mat_mul_waksman(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)
int gr_mat_mul_rosowski(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)

Compute AB with about half the multiplications of the classical algorithm over a commutative ring, at the cost of more additions, which pays off when multiplications are much more expensive than additions (large integers, polynomials). Waksman's algorithm [Waksman1970] (refining Winograd's inner product trick [Win1968]) needs exact division by 2, implemented as gr_mul_2exp_si by -1. Rosowski's algorithm [Rosowski2023] needs no division and uses fewer multiplications than Waksman's when the inner dimension is odd.

Full documentation

Powers and polynomial evaluation#

See also Jordan form and matrix functions for non-integer powers.

int gr_mat_sqr(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)

Sets res to A^2 (currently gr_mat_mul of A by itself).

int gr_mat_pow_ui(gr_mat_t res, const gr_mat_t mat, ulong e, gr_ctx_t ctx)
int gr_mat_pow_si(gr_mat_t res, const gr_mat_t mat, slong e, gr_ctx_t ctx)
int gr_mat_pow_fmpz(gr_mat_t res, const gr_mat_t mat, const fmpz_t e, gr_ctx_t ctx)

Set res to A^e for a square matrix, by repeated squaring in the matrix ring (gr_generic_pow_ui, gr_generic_pow_fmpz); a negative exponent requires an invertible matrix. A^0 is the identity. Returns GR_DOMAIN if the matrices are not square of the same size.

int gr_mat_gr_poly_evaluate(gr_mat_t res, const gr_poly_t poly, const gr_mat_t mat, gr_ctx_t ctx)

Set res to f(A) for a scalar polynomial f and a square matrix A, by rectangular splitting [PS1973]: about 2\sqrt{\mathit{len}} matrix products and O(\mathit{len}) scalar multiplications.

Norms#

int gr_mat_norm_max(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_norm_1(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_norm_inf(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)

Set res to the max norm \max_{i,j} |a_{ij}|, the 1-norm (largest absolute column sum) \max_j \sum_i |a_{ij}|, the \infty-norm (largest absolute row sum) \max_i \sum_j |a_{ij}|, or the Frobenius norm (\sum_{i,j} |a_{ij}|^2)^{1/2}. The ring must provide absolute values, comparisons and (for the Frobenius norm) square roots; the result is an element of R.

Triangular solving#

int gr_mat_nonsingular_solve_tril(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx)
int gr_mat_nonsingular_solve_triu(gr_mat_t X, const gr_mat_t U, const gr_mat_t B, int unit, gr_ctx_t ctx)

Solve LX = B for a lower triangular L, or UX = B for an upper triangular U. Only the relevant triangle is read. If unit is set, the diagonal is taken to be all ones and is not read (it may hold other data, such as the U factor of a packed LU decomposition). Otherwise the diagonal entries are inverted if possible and divided by otherwise; a division that fails gives GR_DOMAIN, even if the system has a solution.

More

LU decomposition and solving#

int gr_mat_find_nonzero_pivot(slong * pivot_row, gr_mat_t mat, slong start_row, slong end_row, slong column, gr_ctx_t ctx)
int gr_mat_find_nonzero_pivot_generic(slong * pivot_row, gr_mat_t mat, slong start_row, slong end_row, slong column, gr_ctx_t ctx)
int gr_mat_find_nonzero_pivot_large_abs(slong * pivot_row, gr_mat_t mat, slong start_row, slong end_row, slong column, gr_ctx_t ctx)

Look for an entry that is provably nonzero in column column, in rows \mathit{start\_row} \le i < \mathit{end\_row}. On success, set *pivot_row and return GR_SUCCESS. Return GR_DOMAIN if all these entries are provably zero, and GR_UNABLE if none is provably nonzero but some cannot be decided.

More
int gr_mat_lu(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)
int gr_mat_lu_generic(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)
int gr_mat_lu_classical(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)
int gr_mat_lu_recursive(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)

Compute a generalised LU decomposition PA = LU of an m \times n matrix A with row permutation P, writing the rank to rank, the permutation to the array P of length m, and L and U packed into LU. See LU decompositions and linear systems.

Full documentation
int gr_mat_fflu(slong * rank, slong * P, gr_mat_t LU, gr_ptr den, const gr_mat_t A, int rank_check, gr_ctx_t ctx)

Computes a fraction-free LU decomposition of A by Bareiss' algorithm, over an integral domain with exact division, writing the final pivot (a minor of A) to den. See LU decompositions and linear systems.

Full documentation

Solve AX = B for a square matrix A. Return GR_DOMAIN if A is singular, even if the system has solutions, and if X does not have entries in R. See LU decompositions and linear systems.

Full documentation
int gr_mat_nonsingular_solve_lu_precomp(gr_mat_t X, const slong * perm, const gr_mat_t LU, const gr_mat_t B, gr_ctx_t ctx)
int gr_mat_nonsingular_solve_fflu_precomp(gr_mat_t X, const slong * perm, const gr_mat_t LU, const gr_mat_t B, gr_ctx_t ctx)

Solve AX = B given an LU or fraction-free LU decomposition of A with full rank, as computed by gr_mat_lu or gr_mat_fflu. The data are assumed to be valid, which is not checked. The fflu version computes \mathit{den} \cdot X, where den is the denominator returned by gr_mat_fflu.

Solve AX = B over the fraction field of an integral domain R: compute X and \mathit{den} \in R such that A X = \mathit{den} \cdot B, with \mathit{den} = \pm \det A from fraction-free elimination (\mathit{den} = 1 for 0 \times 0 matrices). Return GR_DOMAIN if A is singular. See LU decompositions and linear systems.

Full documentation
int gr_mat_solve_field(gr_mat_t X, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)

Solves AX = B for an arbitrary (possibly rectangular or singular) A over a field. If the system has several solutions, an arbitrary one is returned; GR_DOMAIN means that it has none. See LU decompositions and linear systems.

Full documentation

Determinant, permanent and trace#

int gr_mat_det(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_det_berkowitz(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_det_cofactor(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_det_lu(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_det_fflu(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)

Set res to the determinant of a square matrix (GR_DOMAIN otherwise), with the division-free Berkowitz algorithm, cofactor expansion, LU decomposition or fraction-free LU decomposition. See Determinants and permanents.

Full documentation
int gr_mat_permanent(gr_ptr res, const gr_mat_t A, gr_ctx_t ctx)

Set res to the permanent \operatorname{perm}(A) = \sum_{\sigma} \prod_i a_{i,\sigma(i)} of a square matrix, the determinant without signs. Computing it is #P-hard [Val1979], and all algorithms take exponential time. See Permanents.

Full documentation
int gr_mat_trace(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)

Sets res to the sum of the diagonal entries of a square matrix. Returns GR_DOMAIN if the matrix is not square.

Rank, echelon form and nullspace#

int gr_mat_rank(slong * rank, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rank_lu(slong * rank, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rank_fflu(slong * rank, const gr_mat_t A, gr_ctx_t ctx)

Set rank to the rank of A, by LU decomposition or by fraction-free LU decomposition. gr_mat_rank uses LU over finite fields (and finite rings pretending to be fields), fraction-free LU over other integral domains, which keeps the entries small over \mathbb{Z} and \mathbb{Q}, and returns GR_DOMAIN for rings that are known not to be integral domains, where the rank is not defined here. The lu and fflu versions do not check the ring; any failure of the decomposition (an impossible inverse, an undecidable pivot) is reported with GR_UNABLE.

int gr_mat_rref(slong * rank, gr_mat_t R, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rref_lu(slong * rank, gr_mat_t R, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rref_fflu(slong * rank, gr_mat_t R, const gr_mat_t A, gr_ctx_t ctx)

Set R to the reduced row echelon form of A (pivots equal to 1, zeros above and below them) and rank to the rank, using LU decomposition or fraction-free LU decomposition followed by back substitution. This requires a field, or at least that all pivots are invertible. gr_mat_rref uses the LU version.

int gr_mat_rref_den(slong * rank, gr_mat_t R, gr_ptr den, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rref_den_fflu(slong * rank, gr_mat_t R, gr_ptr den, const gr_mat_t A, gr_ctx_t ctx)

Compute R and \mathit{den} such that R / \mathit{den} is the reduced row echelon form of A over the fraction field of an integral domain, with entries of R in the ring. The denominator is a common, not necessarily minimal, denominator: the pivots of R all equal \mathit{den}.

Set the columns of X to a basis of the right nullspace \{x : Ax = 0\} of the m \times n matrix A, read off from the reduced row echelon form: one basis vector per non-pivot column. gr_mat_nullspace resizes X to n rows and as many columns as the nullity; the no_resize version requires X with n rows and at least that many columns, zero-pads the rest and writes the nullity to nullity.

More

Sets X to a nullspace basis given a reduced row echelon form A of rank rank, as computed by gr_mat_rref, or by gr_mat_rref_den with the denominator Aden (NULL for an ordinary rref). X must have n rows and n - \mathit{rank} columns. Returns GR_UNABLE if a pivot position cannot be identified because a zero test is undecidable.

Inverse and adjugate#

int gr_mat_inv(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)

Sets res to the inverse of a square matrix in the ring, computed with gr_mat_nonsingular_solve and the identity matrix. Returns GR_DOMAIN if the matrix is shown to be not invertible over R (this is not reliable over rings with zero divisors) and GR_UNABLE if invertibility cannot be decided. For the inverse over the fraction field, use gr_mat_nonsingular_solve_den or gr_mat_adjugate.

int gr_mat_adjugate(gr_mat_t adj, gr_ptr det, const gr_mat_t mat, gr_ctx_t ctx)

Set adj to the adjugate of A and det to its determinant, so that \operatorname{adj}(A) A = A \operatorname{adj}(A) = \det(A) I. The cofactor version computes n^2 minors; the charpoly version evaluates (-1)^{n-1}(A^{n-1} + c_{n-1} A^{n-2} + \cdots + c_1 I) from the characteristic polynomial x^n + c_{n-1} x^{n-1} + \cdots + c_0 by rectangular splitting, with O(\sqrt{n}) matrix products. The default uses cofactors for n \le 5 and the characteristic polynomial otherwise. All versions are division-free when the characteristic polynomial is.

Characteristic and minimal polynomials#

int _gr_mat_charpoly(gr_ptr res, const gr_mat_t mat, gr_ctx_t ctx)
int gr_mat_charpoly(gr_poly_t res, const gr_mat_t mat, gr_ctx_t ctx)

Set res to the characteristic polynomial \det(xI - A) of a square matrix (GR_DOMAIN otherwise). _gr_mat_charpoly calls the ring method GR_METHOD_MAT_CHARPOLY; the default _gr_mat_charpoly_generic uses Berkowitz's algorithm, which works over any commutative ring. Rings with fast arithmetic override it: nmod and fmpz_mod use Danilevsky's algorithm above dimension 8 (16 for fmpz_mod), falling back to Berkowitz when it meets a non-invertible pivot; fq and its variants use Berkowitz up to dimension 12 and Danilevsky above; fmpz and fmpq call fmpz_mat_charpoly and fmpq_mat_charpoly; mpn_mod has its own. The underscore versions write n + 1 coefficients. See Characteristic and minimal polynomials.

The characteristic polynomial by Berkowitz's division-free algorithm [Ber1984], with O(n^4) ring operations (as O(n) matrix-vector products for each of n leading principal submatrices). Since it needs no divisions and no zero tests, it succeeds whenever the ring arithmetic does.

The characteristic polynomial with O(n^3) operations, by Danilevsky's reduction to a block companion (Frobenius) form [Dan1937], or by reduction to Hessenberg form with Gaussian elimination or with Householder reflections followed by gr_mat_charpoly_from_hessenberg. The inplace version overwrites its input.

More

The characteristic polynomial by the Faddeev-LeVerrier algorithm [FadSom1972], which computes M_k = A M_{k-1} + c_{n-k+1} I and c_{n-k} = -\operatorname{tr}(A M_k) / k, and, if adj is not NULL, the adjugate matrix at no extra cost. The bsgs version is the baby-step giant-step variant of Preparata and Sarwate [PreSar1978], with O(n^{3.5}) operations instead of O(n^4) and \sqrt{n} temporary matrices. Both divide by 1, \ldots, n and fail (with GR_DOMAIN or GR_UNABLE) in small positive characteristic or without division.

The characteristic polynomial of a matrix in upper Hessenberg form (not checked), by the recurrence on its leading principal submatrices, with O(n^3) operations and no divisions.

int gr_mat_hessenberg(gr_mat_t res, const gr_mat_t mat, gr_ctx_t ctx)

Set res to an upper Hessenberg matrix similar to A, computed with Gaussian elimination (similarity transformations by elementary matrices) or with Householder reflections; the default uses Gaussian elimination. They need divisions and zero tests, and the Householder version also square roots and complex conjugation, and return GR_DOMAIN or GR_UNABLE if these fail.

Sets res to the minimal polynomial of a square matrix over a field, by computing the minimal polynomials of Krylov sequences v, Av, A^2 v, \ldots of unit vectors with incremental Gaussian elimination (gr_mat_reduce_row) and taking their least common multiple, with O(n^3) field operations. See Minimal polynomial.

int gr_mat_companion(gr_mat_t res, const gr_poly_t poly, gr_ctx_t ctx)

Sets the n \times n matrix res to the companion matrix of a polynomial of degree n, whose characteristic polynomial is the monic associate of the polynomial. The leading coefficient must be invertible (not checked). The underscore version reads n + 1 coefficients.

int gr_mat_companion_fraction(gr_mat_t res_num, gr_ptr res_den, const gr_poly_t poly, gr_ctx_t ctx)

Set res_num and the scalar res_den such that \mathit{res\_num} / \mathit{res\_den} is the companion matrix of a polynomial of degree n, without dividing: res_den is the leading coefficient. The underscore version reads n + 1 coefficients.

Replaces the n \times n matrix M by P^{-1} M P in place, where P is the identity matrix with the zero entries of row r replaced by d (an elementary similarity transformation). Requires 0 \le r < n; returns GR_DOMAIN if M is not square or r is out of range. Such transformations preserve the determinant and the characteristic and minimal polynomials.

int gr_mat_reduce_row(slong * column, gr_mat_t A, slong * P, slong * L, slong m, gr_ctx_t ctx)
int gr_mat_reduce_row_generic(slong * column, gr_mat_t A, slong * P, slong * L, slong m, gr_ctx_t ctx)

Reduces row m of A by the previous rows, which are assumed to be in Gauss form though not necessarily in order, as needed for incremental elimination (minimal polynomials). Entry i of P is the row of A with a pivot in column i, or -1; entry i of L is the number of possibly nonzero columns of row i (all equal to the number of columns unless A is zero on the right), with nondecreasing entries. On return, column is the column of the new pivot of row m (the first available column from the left, also recorded in P), or -1 if the row reduces to zero.

More

Eigenvalues and diagonalisation#

int gr_mat_eigenvalues(gr_vec_t lambda, fmpz_vec_t mult, const gr_mat_t mat, int flags, gr_ctx_t ctx)
int gr_mat_eigenvalues_other(gr_vec_t lambda, fmpz_vec_t mult, const gr_mat_t mat, gr_ctx_t mat_ctx, int flags, gr_ctx_t ctx)

Find the eigenvalues of a square matrix in the ring ctx, without repetition, with their multiplicities in mult, as the roots of the characteristic polynomial (gr_poly_roots, respectively gr_poly_roots_other for a matrix over another ring mat_ctx). As for gr_poly_roots, the multiplicities may add up to less than n if the ring is not algebraically closed. Over exact real and complex numbers, see Linear algebra over exact numbers.

int gr_mat_diagonalization(gr_vec_t D, gr_mat_t L, gr_mat_t R, const gr_mat_t A, int flags, gr_ctx_t ctx)
int gr_mat_diagonalization_precomp(gr_vec_t D, gr_mat_t L, gr_mat_t R, const gr_mat_t A, const gr_vec_t eigenvalues, const fmpz_vec_t mult, gr_ctx_t ctx)

Compute a diagonalisation L A R = D of a square matrix: D is the vector of eigenvalues repeated according to multiplicity, the columns of R are right eigenvectors and the rows of L = R^{-1} left eigenvectors, so that A = R D R^{-1}. L or R may be NULL to skip computing it.

More

Jordan form and matrix functions#

int gr_mat_jordan_blocks(gr_vec_t lambda, slong * num_blocks, slong * block_lambda, slong * block_size, const gr_mat_t A, gr_ctx_t ctx)

Computes the Jordan block structure of a square matrix over a field containing its eigenvalues: the distinct eigenvalues in lambda, the number of blocks in num_blocks, and for each block the index of its eigenvalue in block_lambda and its size in block_size (arrays of length at least n). The block sizes are determined from the ranks of the powers of A - \lambda I.

int gr_mat_set_jordan_blocks(gr_mat_t mat, const gr_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, gr_ctx_t ctx)

Sets mat to the Jordan matrix with the given blocks (each block has its eigenvalue on the diagonal and ones on the superdiagonal).

int gr_mat_jordan_transformation(gr_mat_t mat, const gr_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, const gr_mat_t A, gr_ctx_t ctx)

Given the block structure computed by gr_mat_jordan_blocks, sets mat to an invertible matrix P with A = P J P^{-1}, where J is the Jordan matrix.

Computes the Jordan form J of a square matrix and, if P is not NULL, a transformation with A = P J P^{-1}. The eigenvalues must lie in the ring, which must be a field with decidable equality for the result to be meaningful (exact fields such as qqbar and ca). The algorithm and its use over exact numbers are described in linear algebra over exact numbers.

int gr_mat_func_jordan(gr_mat_t res, const gr_mat_t A, __gr_method_vec_op jet_func, gr_ctx_t ctx)
int gr_mat_func_param_jordan(gr_mat_t res, const gr_mat_t A, __gr_method_vec_scalar_op jet_func, gr_srcptr c, gr_ctx_t ctx)

Compute the matrix function f(A) = P f(J) P^{-1} from the Jordan decomposition A = P J P^{-1}. The function is given by jet_func, with signature int jet_func(gr_ptr r, gr_srcptr x, slong n, gr_ctx_t ctx), which writes the Taylor coefficients f(x), f'(x), \ldots, f^{(n-1)}(x) / (n-1)! to r. The param version takes a function int jet_func(gr_ptr r, gr_srcptr x, slong n, gr_srcptr c, gr_ctx_t ctx) of x and an extra parameter c, which may in fact point to arbitrary data understood by jet_func.

int gr_mat_exp(gr_mat_t res, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_log(gr_mat_t res, const gr_mat_t A, gr_ctx_t ctx)

Set res to the exponential or the (principal) logarithm of a square matrix. The default methods use the Jordan decomposition; arb and acb override the exponential with arb_mat_exp and acb_mat_exp (scaling and squaring of Taylor series with error bounds). The Jordan versions need the eigenvalues in the ring and are meant for exact fields such as qqbar and ca; elsewhere they typically return GR_UNABLE.

int gr_mat_pow_fmpq(gr_mat_t res, const gr_mat_t mat, const fmpq_t exp, gr_ctx_t ctx)
int gr_mat_pow_fmpq_jordan(gr_mat_t res, const gr_mat_t mat, const fmpq_t exp, gr_ctx_t ctx)

Set res to A^c for a scalar or rational exponent, using the Jordan decomposition (principal branch). The non-Jordan versions first check for small integer exponents and use gr_mat_pow_si for them.

int gr_mat_sqrt(gr_mat_t res, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_rsqrt(gr_mat_t res, const gr_mat_t A, gr_ctx_t ctx)

Set res to a square root A^{1/2} or reciprocal square root A^{-1/2}, computed from the Jordan decomposition (the only algorithm implemented). This often fails with GR_UNABLE when the ring is not an algebraically closed field, even if a square root exists.

Orthogonality and QR decomposition#

Returns whether A is square with A A^T = A^T A = I. The ring is assumed to be commutative.

Return whether A A^T (row versions) or A^T A (column versions) is diagonal (orthogonal) or the identity (orthonormal).

Sets the square matrix A to a random orthogonal matrix, using Cayley's construction (I + S)^{-1}(I - S) with S skew-symmetric, or a permutation matrix if that fails, and then negates random rows. Returns GR_DOMAIN if A is not square. The ring is assumed to be commutative.

int gr_mat_qr(gr_mat_t Q, gr_mat_t R, const gr_mat_t A, gr_ctx_t ctx)
int gr_mat_lq(gr_mat_t L, gr_mat_t Q, const gr_mat_t A, gr_ctx_t ctx)

Compute a reduced QR decomposition A = QR of an m \times n matrix of full column rank (m \ge n; Q is m \times n with orthonormal columns and R is n \times n upper triangular), or the transposed LQ decomposition A = LQ of a matrix of full row rank (m \le n; L is m \times m lower triangular and Q is m \times n with orthonormal rows).

More

LLL reduction tests#

Let the rows a_0, \ldots, a_{n-1} of A be linearly independent vectors over \mathbb{R} with Gram-Schmidt orthogonalisation b_0, \ldots, b_{n-1} and coefficients \mu_{i,j} = \langle a_i, b_j \rangle / \| b_j \|^2. The basis is LLL-reduced with parameters (\delta, \eta), where 1/4 < \delta \le 1 and 1/2 \le \eta < \sqrt{\delta}, if it is size reduced, |\mu_{i,j}| \le \eta for 0 \le j < i < n, and satisfies the Lovász condition (\delta - \mu_{i,i-1}^2) \| b_{i-1} \|^2 \le \| b_i \|^2 for 1 \le i < n [LLL1982]; see Lattice reduction (LLL).

Return whether the rows of A are LLL-reduced with parameters (\delta, \eta), by Gram-Schmidt orthogonalisation in the ring and checking the conditions row by row. The with_removal version checks only the first newd rows, as needed when rows whose Gram-Schmidt norm exceeds the bound gs_B are to be removed (as in fmpz_lll).

More

Special matrices#

For the following functions, the output matrix must have the intended shape.

Sets all entries of res to one.

int gr_mat_pascal(gr_mat_t res, int triangular, gr_ctx_t ctx)

Sets res to a Pascal matrix of binomial coefficients: for triangular 0 the symmetric matrix with entries \binom{i+j}{i} (the rows of Pascal's triangle along the antidiagonals), for 1 the upper triangular matrix with entries \binom{j}{i}, and for -1 the lower triangular matrix with entries \binom{i}{j}.

int gr_mat_stirling(gr_mat_t res, int kind, gr_ctx_t ctx)

Sets res to the matrix of Stirling numbers: unsigned of the first kind for kind 0, signed of the first kind for 1, and of the second kind for 2.

Sets res to the Hilbert matrix with entries 1 / (i + j + 1), which requires these inverses in R.

Sets the square matrix res to a Hadamard matrix of its size if possible. Returns GR_DOMAIN if none exists (the size must be 0, 1, 2 or a multiple of 4), and GR_UNABLE if the implementation cannot construct one.

More

Random matrices#

Sets res to a random matrix with a nonuniform distribution meant for testing (sparse matrices and special values are favoured).

int gr_mat_randops(gr_mat_t mat, flint_rand_t state, slong count, gr_ctx_t ctx)

Randomises mat in place by at most count random additions or subtractions of one row (column) to another, which preserves the determinant and the rank.

int gr_mat_randpermdiag(int * parity, gr_mat_t mat, flint_rand_t state, gr_ptr diag, slong n, gr_ctx_t ctx)

Sets mat to a random row and column permutation of the diagonal matrix whose first n diagonal entries are given by the vector diag, writing the parity (0 or 1) of the permutation to parity. Returns GR_DOMAIN if the diagonal of mat is shorter than n.

Sets mat to a random sparse matrix with the given rank and exactly rank nonzero entries (meaningful over integral domains). A dense matrix of the same rank is obtained by calling gr_mat_randops afterwards.

int gr_mat_randsimilar(gr_mat_t mat, flint_rand_t state, slong opcount, gr_ctx_t ctx)

Randomises the square matrix mat in place by at most opcount conjugations by random elementary matrices, which preserve the characteristic and minimal polynomials.

Linear differential equations#

int gr_mat_gr_poly_solve_lode_newton(gr_mat_t Y, const gr_mat_t A_numerator, const gr_poly_t A_denominator, const gr_mat_t Y0, slong len, gr_ctx_t A_poly_ctx, gr_ctx_t sol_poly_ctx)
int _gr_mat_gr_poly_solve_lode_newton(gr_mat_t Y, gr_mat_t Z, const gr_mat_t A_numerator, const gr_poly_t A_denominator, const gr_mat_t Y0, slong len, gr_ctx_t A_poly_ctx, gr_ctx_t sol_poly_ctx)
int _gr_mat_gr_poly_solve_lode_newton_start(gr_mat_t Y, gr_mat_t Z, gr_poly_t A_denominator_inv, const gr_mat_t A_numerator, const gr_poly_t A_denominator, const gr_mat_t Y0, gr_ctx_t sol_poly_ctx)
int _gr_mat_gr_poly_solve_lode_newton_step(gr_mat_t Y, gr_mat_t Z, gr_poly_t A_denominator_inv, slong len, const gr_mat_t A_numerator, const gr_poly_t A_denominator, int A_is_companion, gr_ctx_t sol_poly_ctx)

Solve the system of linear differential equations Y'(t) = A(t) Y(t) with Y(0) = Y_0, where A(t) is a matrix of rational functions given by a matrix of polynomials A_numerator (over the polynomial ring A_poly_ctx) and a common denominator A_denominator with nonzero constant term, and set Y to the power series solution truncated to length len. The entries of Y are polynomials over the ring sol_poly_ctx.

More

Internal functions#

Helper for the contexts of matrix rings and spaces (here ctx is such a context, not the coefficient ring): resizes mat to r \times c if the context allows matrices of all sizes, and otherwise returns GR_DOMAIN unless r \times c is the shape of the context.

Test functions#

The following functions run iters random tests of an implementation of a method, with matrices of size up to maxn. If ctx is NULL, a random ring is chosen for each iteration; otherwise the given ring is used.

void gr_mat_test_mul(gr_method_mat_binary_op mul_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_lu(gr_method_mat_lu_op lu_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_det(gr_method_mat_unary_op_get_scalar det_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_charpoly(gr_method_mat_unary_op_get_scalar charpoly_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_nonsingular_solve_tril(gr_method_mat_binary_op_with_flag solve_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_nonsingular_solve_triu(gr_method_mat_binary_op_with_flag solve_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)

Test an implementation of gr_mat_mul, gr_mat_lu, gr_mat_det, _gr_mat_charpoly, gr_mat_nonsingular_solve_tril or gr_mat_nonsingular_solve_triu by comparing with the generic algorithms and checking algebraic identities.

void gr_mat_test_approx_mul_max_norm(gr_method_mat_binary_op mul_impl, gr_srcptr rel_tol, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
void gr_mat_test_approx_mul_pos_entrywise_accurate(gr_method_mat_binary_op mul_impl, gr_srcptr rel_tol, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)

Test the accuracy of a matrix multiplication over an approximate (floating-point) ring: the first checks \|C - AB\| \le \|A\| \|B\| \cdot \mathit{rel\_tol} in the max norm against classical multiplication; the second generates matrices with nonnegative entries and checks that every entry has relative error at most \mathit{rel\_tol}.

References#

  • [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
  • [Waksman1970] Waksman, Abraham, "On Winograd's algorithm for inner products", IEEE Transactions on Computers 19.04 (1970): 360-361.
  • [Win1968] S. Winograd. A new algorithm for inner product. IEEE Transactions on Computers C-17 (1968), 693–694. https://doi.org/10.1109/TC.1968.227420
  • [Rosowski2023] Rosowski, Andreas. "Fast commutative matrix algorithms". Journal of Symbolic Computation 114 (2023): 302–321.
  • [PS1973] M. S. Paterson and L. J. Stockmeyer, "On the number of nonscalar multiplications necessary to evaluate polynomials", SIAM J. Comput (1973)
  • [Val1979] L. G. Valiant. The complexity of computing the permanent. Theoretical Computer Science 8 (1979), 189–201. https://doi.org/10.1016/0304-3975(79)90044-6
  • [Ber1984] S. J. Berkowitz, "On computing the determinant in small parallel time using a small number of processors", Information Processing Letters 18 (1984), 147-150
  • [Dan1937] A. M. Danilevsky, "On the numerical solution of the secular equation" (in Russian), Matematicheskii Sbornik 2(44):1 (1937), 169-171
  • [FadSom1972] D. K. Faddeev and I. S. Sominsky. Problems in Higher Algebra. Mir Publishers, Moscow, 1972 (translated from the Russian edition of 1954). The method of Le Verrier and Faddeev for the characteristic polynomial.
  • [PreSar1978] F. P. Preparata and D. V. Sarwate. An improved parallel processor bound in fast matrix inversion. Information Processing Letters 7 (1978), 148–150. https://doi.org/10.1016/0020-0190(78)90079-0
  • [LLL1982] A. K. Lenstra, H. W. Lenstra, Jr. and L. Lovász, "Factoring polynomials with rational coefficients", Mathematische Annalen 261 (1982), 515–534. https://doi.org/10.1007/BF01457454
Cite this page

The FLINT team, “gr_mat.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/gr_mat/index.html (generated 2026-10-20).