nmod_mat.h
#include <flint/nmod_mat.h>This module implements dense matrices over for a word-size modulus . An nmod_mat_t stores its entries as ulong values in in row-major order, together with its dimensions and the modulus as an nmod_t. Matrix multiplication, the operation on which everything else rests, chooses among classical multiplication with delayed reduction, Strassen–Winograd, vectorised kernels for moduli up to , bit- and byte-packed kernels for moduli up to 255 and floating-point gemm; see Multiplying matrices. On top of it the module provides LU decomposition, linear system solving, determinants, inverses, echelon forms, nullspaces and characteristic and minimal polynomials, most of which require to be prime. The multimodular algorithms for matrices over in fmpz_mat.h are built on this module.
The guide Linear algebra modulo n explains which functions work for which moduli and how they fit together.
OverviewMultiplying matrices over Z/nZThe methods FLINT uses to multiply matrices modulo a word-size integer, from classical multiplication with delayed reduction to Strassen–Winograd, SIMD kernels, floating-point gemm with Chinese remaindering and bit-packed kernels for tiny moduli, and hownmod_mat_mul chooses among them.Guides#
Types and conventions#
An nmod_mat_struct has the fields entries (a pointer to the entry in row 0, column 0), r and c (the numbers of rows and columns), stride (the distance in words between the starts of consecutive rows) and mod (the modulus as an nmod_t). An nmod_mat_t is an array of one nmod_mat_struct, so that it is passed by reference.
The following conventions apply throughout the module.
- Reduced entries. Unless stated otherwise, the entries of input matrices must lie in , and output entries do. Entries may be written directly with
nmod_mat_entry; it is then the caller's responsibility to keep them reduced. Nothing is checked. - Dimensions. The output must be initialised with dimensions compatible with the operation; most functions do not check this (some check it with
FLINT_ASSERTonly). Matrices with zero rows or columns are allowed everywhere. - Modulus. All matrices passed to one function must have the same modulus. Any is allowed for memory management, arithmetic, multiplication, determinants, characteristic polynomials and the Howell form. LU decomposition, solving, inversion, rank, echelon forms, nullspaces and minimal polynomials divide by pivots and assume that is prime. This is not checked: a pivot that is not invertible raises a
FLINT_IMPINVexception, and other results may be silently wrong. See Which functions need a prime modulus. - Aliasing. Each function states whether the output may be the same matrix as an input. Partially overlapping windows are never allowed.
Memory management#
void nmod_mat_init(nmod_mat_t mat, slong rows, slong cols, ulong n)Initialises mat as a rows by cols matrix modulo with all entries zero. Requires . Throws an exception if overflows an slong.
void nmod_mat_init_set(nmod_mat_t mat, const nmod_mat_t src)Initialises mat as a copy of src, with the same dimensions and modulus. The copy owns its entries even if src is a window.
void nmod_mat_clear(nmod_mat_t mat)Frees the memory used by mat. Must not be called on a window.
void nmod_mat_set(nmod_mat_t B, const nmod_mat_t A)Copies the entries of to , which must have the same dimensions. The modulus of is not changed.
void nmod_mat_swap(nmod_mat_t mat1, nmod_mat_t mat2)Swaps mat1 and mat2 in constant time by swapping their structs. Must not be used with windows, whose entries belong to another matrix.
void nmod_mat_swap_entrywise(nmod_mat_t mat1, nmod_mat_t mat2)Swaps the entries of two matrices of the same dimensions one by one. This works for windows.
nmod_t nmod_mat_mod(const nmod_mat_t mat)Returns the modulus of mat.
void nmod_mat_set_mod(nmod_mat_t mat, ulong n)Sets the modulus of mat to . The entries are not changed, so they must be reduced afterwards if they may exceed .
Entries and dimensions#
nmod_mat_entry(mat, i, j)The entry in row and column of mat (indexed from zero), as an lvalue that can be read and assigned. No bounds checking is performed.
ulong nmod_mat_get_entry(const nmod_mat_t mat, slong i, slong j)void nmod_mat_set_entry(nmod_mat_t mat, slong i, slong j, ulong x)Returns, respectively sets, the entry in row and column . x must be reduced.
ulong * nmod_mat_entry_ptr(const nmod_mat_t mat, slong i, slong j)ulong * nmod_mat_row_ptr(const nmod_mat_t mat, slong i)Returns a pointer to the entry in row and column , respectively to the first entry of row . The entries of a row are contiguous; the next row starts mat->stride words later.
slong nmod_mat_nrows(const nmod_mat_t mat)slong nmod_mat_ncols(const nmod_mat_t mat)Returns the number of rows, respectively columns, of mat.
int nmod_mat_is_empty(const nmod_mat_t mat)int nmod_mat_is_square(const nmod_mat_t mat)Returns 1 if mat has no rows or no columns, respectively if it has as many rows as columns, and 0 otherwise.
Windows#
void nmod_mat_window_init(nmod_mat_t window, const nmod_mat_t mat, slong r1, slong c1, slong r2, slong c2)Initialises window as the submatrix of mat formed by rows to and columns to , where mat->r and mat->c. The window shares its entries with mat, so writing to one changes the other.
void nmod_mat_window_clear(nmod_mat_t window)Releases a window. This does nothing at present, but every window should be cleared for future compatibility.
Concatenation#
void nmod_mat_concat_vertical(nmod_mat_t res, const nmod_mat_t mat1, const nmod_mat_t mat2)void nmod_mat_concat_horizontal(nmod_mat_t res, const nmod_mat_t mat1, const nmod_mat_t mat2)Sets res to mat1 placed above mat2, respectively to the left of mat2. For an matrix mat1, mat2 must be and res , respectively mat2 and res . res must not be aliased with the inputs.
Special matrices and comparison#
void nmod_mat_zero(nmod_mat_t mat)void nmod_mat_one(nmod_mat_t mat)Sets mat to the zero matrix, respectively to the matrix with ones on the main diagonal and zeros elsewhere. mat need not be square.
int nmod_mat_equal(const nmod_mat_t mat1, const nmod_mat_t mat2)Returns 1 if the two matrices have the same dimensions and the same entries, and 0 otherwise. The moduli are not compared.
int nmod_mat_is_zero(const nmod_mat_t mat)int nmod_mat_is_one(const nmod_mat_t mat)int nmod_mat_is_zero_row(const nmod_mat_t mat, slong i)Returns 1 if mat is zero, if it has ones on the main diagonal and zeros elsewhere, or if its row is zero, respectively, and 0 otherwise. Empty matrices are both zero and one.
Random matrices#
These functions are intended for testing.
void nmod_mat_rand(nmod_mat_t mat, flint_rand_t state)Sets the entries to independent integers chosen uniformly at random in .
void nmod_mat_randtest(nmod_mat_t mat, flint_rand_t state)Sets each row with _nmod_vec_randtest: entries from n_randtest reduced modulo , and with probability 1/2 a sparse row.
void nmod_mat_randfull(nmod_mat_t mat, flint_rand_t state)Sets the entries to independent integers chosen uniformly at random in , so that no entry is zero.
Moreint nmod_mat_randpermdiag(nmod_mat_t mat, flint_rand_t state, nn_srcptr diag, slong n)Sets mat to where is the matrix with (the entries of diag) on the main diagonal and zeros elsewhere, and and are random permutation matrices. Requires the number of rows and of columns. Returns the parity (0 for even, 1 for odd) of the two permutations combined.
void nmod_mat_randrank(nmod_mat_t mat, flint_rand_t state, slong rank)Sets mat to a random matrix of the given rank, with exactly rank nonzero entries, each uniform in and no two in the same row or column. Throws an exception if rank is negative or exceeds a dimension. Follow with nmod_mat_randops to obtain a dense matrix of the same rank.
void nmod_mat_randrank_profile(nmod_mat_t mat, flint_rand_t state, const slong * mrp_r, const slong * mrp_c, slong rank)For a prime modulus, sets mat to a random matrix of rank = rank whose rank profile matrix has its nonzero entries at the positions (mrp_r[k], mrp_c[k]) for , given in any order. Throws an exception if rank is negative or exceeds a dimension, or if two positions share a row or a column or one lies outside the matrix.
void nmod_mat_randops(nmod_mat_t mat, flint_rand_t state, slong count)Performs count random elementary operations on mat, each adding or subtracting a row to or from another row, or a column to or from another column (operations whose two indices coincide are skipped). These operations have determinant 1, so the rank and, for square matrices, the determinant are preserved.
void nmod_mat_randtril(nmod_mat_t mat, flint_rand_t state, int unit)void nmod_mat_randtriu(nmod_mat_t mat, flint_rand_t state, int unit)Sets mat to a random lower, respectively upper, triangular matrix. The entries strictly below (above) the diagonal are random, the diagonal entries are 1 if unit is nonzero and random nonzero values otherwise. mat need not be square.
Printing#
void nmod_mat_print_pretty(const nmod_mat_t mat)int nmod_mat_fprint_pretty(FILE * file, const nmod_mat_t mat)Prints a header line with the dimensions and modulus, then one line per row, with the entries in brackets and right-aligned to the number of decimal digits of . nmod_mat_fprint_pretty returns a positive value on success and a nonpositive value on a write error. Functions with a FILE argument are declared only if <stdio.h> is included before nmod_mat.h.
int nmod_mat_print(const nmod_mat_t mat)int nmod_mat_fprint(FILE * f, const nmod_mat_t mat)The same as nmod_mat_fprint_pretty, writing to stdout and f respectively.
Transposition and permutations#
void nmod_mat_transpose(nmod_mat_t B, const nmod_mat_t A)Sets to the transpose of . Throws an exception unless has as many rows as has columns and vice versa. may be aliased with if is square.
MoreWrites the transpose of the array (row stride Astride) to the array (row stride Bstride). The words are copied as they are. The two arrays must not overlap.
void nmod_mat_swap_rows(nmod_mat_t mat, slong * perm, slong r, slong s)void nmod_mat_swap_cols(nmod_mat_t mat, slong * perm, slong r, slong s)Swaps rows (columns) and of mat. If perm is not NULL, entries and of the array perm are swapped as well.
void nmod_mat_invert_rows(nmod_mat_t mat, slong * perm)void nmod_mat_invert_cols(nmod_mat_t mat, slong * perm)Reverses the order of the rows (columns) of mat, that is, swaps rows (columns) and for , where is the number of rows (columns). If perm is not NULL, the same permutation is applied to it.
void nmod_mat_permute_rows(nmod_mat_t mat, const slong * perm_act, slong * perm_store)Replaces row of mat by the old row perm_act[i], for every , where perm_act is a permutation of the row indices. If perm_store is not NULL, it is updated in the same way: perm_store[i] becomes the old perm_store[perm_act[i]].
Addition and scalar multiplication#
These functions allow the output to be aliased with any input.
void nmod_mat_add(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)void nmod_mat_sub(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets , respectively . The three matrices must have the same dimensions.
void nmod_mat_neg(nmod_mat_t B, const nmod_mat_t A)Sets . The matrices must have the same dimensions.
void nmod_mat_scalar_mul(nmod_mat_t B, const nmod_mat_t A, ulong c)Sets . Requires .
Morevoid nmod_mat_scalar_mul_fmpz(nmod_mat_t B, const nmod_mat_t A, const fmpz_t c)Sets for any integer , which is first reduced modulo .
void nmod_mat_scalar_addmul_ui(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B, const ulong c)Sets . Unlike nmod_mat_scalar_mul, may be any word; it is reduced modulo first. Uses Shoup multiplication under the same conditions as nmod_mat_scalar_mul.
Matrix multiplication#
nmod_mat_mul is the function to use: it selects the fastest of the methods below for the dimensions, the modulus, the number of threads and the instruction set. The other functions are the individual methods, documented for testing, benchmarking and special needs. The kernels that return an int return 0, without touching , when they do not apply. All methods work for any modulus within their range, prime or not.
nmod_mat_mul chooses among them.
void nmod_mat_mul(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets , where is , is and is . may be aliased with or .
Full documentationvoid nmod_mat_addmul(nmod_mat_t D, const nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)void nmod_mat_submul(nmod_mat_t D, const nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets , respectively . may be aliased with but not with or . The product is either computed by classical multiplication fused with the addition, or with nmod_mat_mul and then added; see Adding a product.
void nmod_mat_mul_classical(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets by classical multiplication, computing each entry as a dot product with a single reduction. must not be aliased with or .
Morevoid nmod_mat_mul_classical_threaded(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)The same as nmod_mat_mul_classical, with the rows of distributed over the threads of FLINT's thread pool. Dimensions below 20 are handled by the serial code. must not be aliased with or .
void nmod_mat_mul_strassen(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets by one level of the Strassen–Winograd algorithm: seven products of half-size blocks, each computed by nmod_mat_mul (which may recurse), and 15 block additions. must not be aliased with or .
int nmod_mat_mul_blas(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets by floating-point matrix multiplication with flint_sgemm or flint_dgemm, which use an external BLAS if FLINT was built with one and FLINT's own kernels otherwise. Returns 1 on success. Returns 0, and does nothing, if a dimension is 0 or exceeds INT_MAX, if the inner dimension is so large that no suitable set of at most 12 moduli exists, or on 32-bit machines. may be aliased with or .
void nmod_mat_mul_u8(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets for a modulus (checked only by FLINT_ASSERT) using kernels for entries stored in bytes. may be aliased with or . Uses several threads when available.
void _nmod_mat_mul_u8(uint8_t * C, slong Cstride, const uint8_t * A, slong Astride, const uint8_t * B, slong Bstride, slong m, slong k, slong n, nmod_t mod)The multiplication of nmod_mat_mul_u8 on byte arrays: sets the array to , where is and is , each stored by rows with the given row strides (in bytes), with entries reduced modulo mod.n, which must be at most 255. may be equal to or (same pointer) but must not otherwise overlap them.
int nmod_mat_mul_u32(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets for a modulus with an integer SIMD kernel (AVX-512, AVX2, NEON, or portable C), and returns 1. Returns 0 if or on 32-bit machines. may be aliased with or . Uses several threads when available.
Moreint _nmod_mat_mul_u32(uint32_t * C, slong Cstride, const uint32_t * A, slong Astride, const uint32_t * B, slong Bstride, slong m, slong k, slong n, nmod_t mod)The multiplication of nmod_mat_mul_u32 on arrays of 32-bit entries: is , is and is , each stored by rows with the given row strides, with entries reduced modulo mod.n. Returns 0 if mod.n or on 32-bit machines and 1 otherwise. may be equal to or (same pointer and stride) but must not otherwise overlap them.
int nmod_mat_mul_u52(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets for a modulus with the AVX512-IFMA instructions, and returns 1. Returns 0 if , or if FLINT was not compiled for a processor with AVX512-IFMA (or on 32-bit machines). may be aliased with or . Uses several threads when available.
Moreint nmod_mat_mul_k52(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets for a modulus with integer SIMD instructions (AVX-512, AVX2, NEON, or portable C), and returns 1. Returns 0 if , on 32-bit machines, and for the portable C code compiled by MSVC. may be aliased with or . Uses several threads when available.
Moreint nmod_mat_mul_fp50(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B)Sets for a modulus in double precision, and returns
- Returns 0 if , on 32-bit machines, and for the portable C code compiled by MSVC. may be aliased with or . Uses several threads when available.
Matrix-vector products#
void nmod_mat_mul_nmod_vec(ulong * c, const nmod_mat_t A, const ulong * b, slong blen)void nmod_mat_mul_nmod_vec_ptr(ulong * const * c, const nmod_mat_t A, const ulong * const * b, slong blen)Sets , where is and is the vector of length blen, truncated or extended by zeros to length . The entries of are written. In the _ptr version, entry of and is *b[i] and *c[i]. Each entry of is a dot product with one reduction. must not overlap , except in the _ptr version, which copies.
void nmod_mat_nmod_vec_mul(ulong * c, const ulong * a, slong alen, const nmod_mat_t B)void nmod_mat_nmod_vec_mul_ptr(ulong * const * c, const ulong * const * a, slong alen, const nmod_mat_t B)Sets , where is and is the vector of length alen, truncated or extended by zeros to length . The entries of are written. In the _ptr version, entry of and is *a[i] and *c[i]. must not overlap , except in the _ptr version, which copies.
Powers and trace#
void nmod_mat_pow(nmod_mat_t dest, const nmod_mat_t mat, ulong pow)void _nmod_mat_pow(nmod_mat_t dest, const nmod_mat_t mat, ulong pow)Sets dest to mat raised to the power pow, by binary exponentiation. The matrix must be square; the power 0 gives the identity matrix. nmod_mat_pow allows dest to be aliased with mat; _nmod_mat_pow does not.
ulong nmod_mat_trace(const nmod_mat_t mat)Returns the sum of the diagonal entries of the square matrix mat.
Triangular solving#
These functions solve or for a square triangular matrix with rows and an matrix , or, for the _right versions, or for a matrix . Only the relevant triangular part and, if unit is 0, the diagonal of or are read, so they may be stored in a matrix holding other data, such as the output of nmod_mat_lu. If unit is nonzero the diagonal is taken to be 1. Otherwise every diagonal entry must be invertible modulo , or a FLINT_IMPINV exception is raised. may be aliased with , but no other aliasing is allowed.
void nmod_mat_solve_tril(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Sets for lower triangular , respectively for upper triangular . Uses substitution if has fewer than 64 rows or fewer than 64 columns, and the recursive algorithm otherwise.
void nmod_mat_solve_tril_classical(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu_classical(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Forward, respectively back, substitution, for an triangular matrix. If has at least columns ( for , or with 32-bit words), the rows of are computed one after the other, each as the row of minus a linear combination of the rows already computed, with delayed reductions: the products are accumulated by vectors in one, two or three words and each entry is reduced once (or a few times, for some moduli below ). Otherwise each column of is computed entry by entry, each entry with one dot product and one reduction, which is faster with few long columns. The inverses of the diagonal entries are computed once.
void nmod_mat_solve_tril_recursive(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu_recursive(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Splits (or ) into blocks of and rows and solves recursively, reducing the work to matrix multiplications.
Morevoid nmod_mat_solve_tril_right(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu_right(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Sets for lower triangular , respectively for upper triangular . Uses substitution if has fewer than 64 rows or fewer than 64 columns, and the recursive algorithm otherwise.
void nmod_mat_solve_tril_right_classical(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu_right_classical(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Substitution, for an triangular matrix, with three methods. If has at least rows ( for , or with 32-bit words), as nmod_mat_solve_tril_classical (nmod_mat_solve_triu_classical) with delayed reductions on the transposed system, being transposed by blocks of 256 rows. Otherwise, if ( for these larger moduli) or has at most 4 rows, each row of is computed from the last entry to the first for (from the first to the last for ): once is known, times the row of the triangular matrix is added to the unreduced sums of the remaining entries, each reduced once. Otherwise (a large triangular matrix and a few rows), each entry is computed with one dot product and one reduction, the columns of the triangular matrix being copied to rows 64 at a time so that the dot products read contiguous memory. The inverses of the diagonal entries are computed once.
void nmod_mat_solve_tril_right_recursive(nmod_mat_t X, const nmod_mat_t L, const nmod_mat_t B, int unit)void nmod_mat_solve_triu_right_recursive(nmod_mat_t X, const nmod_mat_t U, const nmod_mat_t B, int unit)Splits (or ) into blocks of and rows and columns and solves recursively, reducing the work to matrix multiplications.
MoreLU decomposition#
AlgorithmGaussian elimination and LU decompositionLU decomposition with row pivoting over in its classical, delayed-reduction and recursive forms, and how FLINT derives triangular solving, linear system solving, inverses, determinants, ranks, echelon forms and nullspaces from it; plus division-free determinants and the Howell form over .slong nmod_mat_lu(slong * P, nmod_mat_t A, int rank_check)slong nmod_mat_lu_classical(slong * P, nmod_mat_t A, int rank_check)slong nmod_mat_lu_classical_delayed(slong * P, nmod_mat_t A, int rank_check)slong nmod_mat_lu_recursive(slong * P, nmod_mat_t A, int rank_check)Computes an LU decomposition with row pivoting of the matrix modulo a prime, overwriting with and , and returns the rank . On return, row of is row P[i] of the original , where P is an array of length (it need not be initialised). is in row echelon form with nonzero rows, and is unit lower triangular. If rank_check is nonzero, the function may stop as soon as it finds that the rank is less than , and then returns 0 and leaves undefined.
slong nmod_mat_lu_with_pivots(slong * P, slong * pivots_nonpivots, nmod_mat_t A)The same as nmod_mat_lu with rank_check 0, and in addition writes to pivots_nonpivots, an array of length , the indices of the pivot columns of in increasing order followed by the indices of the other columns in increasing order.
PLE decomposition and rank profiles#
AlgorithmGaussian elimination and LU decompositionLU decomposition with row pivoting over in its classical, delayed-reduction and recursive forms, and how FLINT derives triangular solving, linear system solving, inverses, determinants, ranks, echelon forms and nullspaces from it; plus division-free determinants and the Howell form over .slong nmod_mat_ple(slong * P, slong * pivots_nonpivots, nmod_mat_t A, int flags)slong nmod_mat_ple_classical(slong * P, slong * pivots_nonpivots, nmod_mat_t A, int flags)slong nmod_mat_ple_classical_delayed(slong * P, slong * pivots_nonpivots, nmod_mat_t A, int flags)slong nmod_mat_ple_crout(slong * P, slong * pivots_nonpivots, nmod_mat_t A, int flags)slong nmod_mat_ple_recursive(slong * P, slong * pivots_nonpivots, nmod_mat_t A, int flags)Computes the PLE decomposition of the matrix modulo a prime that reveals its rank profile matrix, overwrites with and in the storage of nmod_mat_lu, and returns the rank . Row of is row P[i] of the original (P has length ). The array pivots_nonpivots, of length , receives the pivot columns of followed by the other columns, both in increasing order; it may be NULL. The rows P[r], ..., P[m-1] are also in increasing order, and the rank profile matrix of has its nonzero entries at (P[k], pivots_nonpivots[k]) for . If flags contains NMOD_MAT_PLE_RANK_CHECK and the rank is less than , the function returns 0, possibly before the end, and leaves A, P and pivots_nonpivots undefined.
void nmod_mat_ple_nullspace(nmod_mat_t X, const nmod_mat_t LU, const slong * pivots_nonpivots, slong rank)void nmod_mat_ple_left_nullspace(nmod_mat_t X, const nmod_mat_t LU, const slong * P, slong rank)Given the output LU, P, pivots_nonpivots and rank of nmod_mat_ple for an matrix , sets the matrix to the basis of the right nullspace computed by nmod_mat_nullspace, respectively the matrix to the basis of the left nullspace computed by nmod_mat_left_nullspace. must have exactly these dimensions.
void nmod_mat_ple_nullspace_compact(nmod_mat_t X, const nmod_mat_t LU, const slong * pivots_nonpivots, slong rank)void nmod_mat_ple_left_nullspace_compact(nmod_mat_t X, slong * rows, const nmod_mat_t LU, const slong * P, slong rank)The same bases without their identity matrix. For the right nullspace, is and receives : its row gives the entries in position pivots_nonpivots[j] and its column corresponds to the vector with a 1 in position pivots_nonpivots[r+k]. For the left nullspace, is , rows (length ) receives the row rank profile of in increasing order followed by the other rows in increasing order, and receives the columns of sorted accordingly: its column gives the entries in position rows[j] and its row corresponds to the vector with a 1 in position rows[r+k].
Flag for nmod_mat_ple: return 0 as soon as the rank is known to be less than .
Solving linear systems#
These functions require a prime modulus.
int nmod_mat_solve(nmod_mat_t X, const nmod_mat_t A, const nmod_mat_t B)Solves for a square matrix . If is nonsingular, sets to the unique solution and returns 1. Otherwise returns 0 and leaves unchanged. may be aliased with or .
Full documentationint nmod_mat_solve_vec(nn_ptr x, const nmod_mat_t A, nn_srcptr b)Solves for a square matrix and vectors , of length , as nmod_mat_solve. may be equal to .
int nmod_mat_can_solve(nmod_mat_t X, const nmod_mat_t A, const nmod_mat_t B)Decides whether has a solution for an arbitrary matrix and matrix . If so, sets the matrix to a solution and returns 1; otherwise sets to zero and returns 0. Returns 0 if the dimensions are incompatible. may be aliased with but not with .
Full documentationint nmod_mat_can_solve_inner(slong * rank, slong * perm, slong * pivots, nmod_mat_t X, const nmod_mat_t A, const nmod_mat_t B)The same as nmod_mat_can_solve, and in addition, for each pointer that is not NULL, stores the rank of in *rank, the row permutation of the LU decomposition of in perm (length ), and the indices of the pivot columns in the first *rank entries of pivots (length at least ).
Determinant, rank and inverse#
ulong nmod_mat_det(const nmod_mat_t A)Returns the determinant of the square matrix , for any modulus. Throws an exception if is not square.
Full documentationulong nmod_mat_det_howell(const nmod_mat_t A)Returns the determinant of the square matrix , for any modulus, by triangularising with Euclidean row operations. Throws an exception if is not square.
Full documentationslong nmod_mat_rank(const nmod_mat_t A)Returns the rank of , which may have any shape. The modulus must be prime.
Full documentationint nmod_mat_inv(nmod_mat_t B, const nmod_mat_t A)If the square matrix is invertible, sets and returns 1. Otherwise returns 0, and the entries of are unspecified. The modulus must be prime. may be aliased with .
Full documentationRow echelon form and nullspace#
These functions require a prime modulus.
Puts in reduced row echelon form and returns its rank.
Full documentationslong nmod_mat_nullspace(nmod_mat_t X, const nmod_mat_t A)Sets the first columns of to a basis of the right nullspace of the matrix , sets the other entries of to zero, and returns the nullity . must have rows and at least columns; always suffices. may be aliased with . The basis is the one with an identity matrix in the rows of the columns of without pivot, computed with nmod_mat_ple and nmod_mat_ple_nullspace.
slong nmod_mat_left_nullspace(nmod_mat_t X, const nmod_mat_t A)Sets the first rows of to a basis of the left nullspace of the matrix , sets the other entries of to zero, and returns the nullity . must have at least rows and columns; always suffices. The basis is the one with an identity matrix in the columns of the rows of that are not in its row rank profile, computed with nmod_mat_ple and nmod_mat_ple_left_nullspace.
slong nmod_mat_reduce_row(nmod_mat_t M, slong * P, slong * L, slong m)Reduces row of against rows that are already reduced, for incremental Gaussian elimination, and returns the column of its new pivot, or if it reduces to zero.
MoreHowell form#
These functions work for any modulus. For a prime modulus they compute the reduced row echelon form, up to the position of zero rows.
The algorithms are described in Howell form.
Puts in strong echelon form, using the algorithm of [FieHof2014]. must have at least as many rows as columns; add zero rows otherwise.
MorePuts in Howell form [StoMul1998] and returns the number of nonzero rows, which come first. must have at least as many rows as columns.
MoreCharacteristic and minimal polynomials#
These functions are declared in nmod_poly.h. The polynomial must be initialised with the same modulus as the matrix.
void nmod_mat_charpoly(nmod_poly_t p, const nmod_mat_t M)void nmod_mat_charpoly_berkowitz(nmod_poly_t p, const nmod_mat_t M)int nmod_mat_charpoly_danilevsky(nmod_poly_t p, const nmod_mat_t M)Sets to the characteristic polynomial of the square matrix . An exception is thrown if is not square. nmod_mat_charpoly and the division-free _berkowitz work for any modulus. _danilevsky returns 1 on success and 0 if it needs an inverse that does not exist, which cannot happen for a prime modulus. For the result is the zero polynomial.
void nmod_mat_minpoly(nmod_poly_t p, const nmod_mat_t M)void nmod_mat_minpoly_with_gens(nmod_poly_t p, const nmod_mat_t M, ulong * P)Sets to the minimal polynomial of the square matrix , the monic polynomial of least degree with , and throws an exception if is not square. The modulus must be prime. If P is not NULL, nmod_mat_minpoly_with_gens sets P[j] to 1 for each index such that the unit vector was used as a Krylov generator, and leaves the other entries of the array (of length ) unchanged.
void nmod_mat_similarity(nmod_mat_t M, slong r, ulong d)Replaces the square matrix by , where is the identity matrix with the entries in row and every column replaced by . Requires .
MoreTuning parameters#
These macros are defined in nmod_mat.h. The parameters of nmod_mat_mul are in flint-mparam.h; see How the method is chosen.
The dimension (20) from which classical multiplication transposes before forming dot products, and below which the threaded classical multiplication runs serially.
The triangular solving functions use substitution when the right-hand side has fewer than NMOD_MAT_SOLVE_TRI_ROWS_CUTOFF (64) rows or fewer than NMOD_MAT_SOLVE_TRI_COLS_CUTOFF (64) columns, and the recursive algorithm otherwise.
A suggested bit size, FLINT_BITS - 5, for the primes of multimodular algorithms that rely on matrix multiplication, used for example by fmpz_mat_mul_multi_mod and the Dixon solver of fmpz_mat. It was chosen when classical multiplication with two-word dot products was the fastest method; with the SIMD kernels, primes of at most 52 bits can be cheaper per bit of modulus.
Internal functions#
These functions are used by the functions above and by other modules.
void _nmod_mat_mul_classical_op(nmod_mat_t D, const nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B, int op)Sets if op is 0, if op is 1 and if op is , by the classical algorithm of nmod_mat_mul_classical. may be aliased with but not with or . is not read if op is 0.
void _nmod_mat_mul_classical_threaded_pool_op(nmod_mat_t D, const nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B, int op, thread_pool_handle * threads, slong num_threads)The threaded version of _nmod_mat_mul_classical_op, using the num_threads threads in threads, obtained from flint_request_threads, in addition to the calling thread. If or the modulus is 1, is not written.
void _nmod_mat_scalar_mul_generic(nmod_mat_t B, const nmod_mat_t A, ulong c)void _nmod_mat_scalar_mul_precomp(nmod_mat_t B, const nmod_mat_t A, ulong c, ulong c_pr)Sets with nmod_mul, respectively with n_mulmod_shoup and c_pr = n_mulmod_precomp_shoup(c, n), which requires . Both require .
void _nmod_mat_scalar_addmul_ui_generic(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B, const ulong c)void _nmod_mat_scalar_addmul_ui_precomp(nmod_mat_t C, const nmod_mat_t A, const nmod_mat_t B, const ulong c, const ulong c_pr)Sets , as the two functions above. Both require .
Returns the determinant of the square matrix modulo a prime, computed by nmod_mat_lu, which destroys .
Returns the determinant of the square matrix for any modulus, as nmod_mat_det_howell, destroying .
slong _nmod_mat_rref(nmod_mat_t A, slong * pivots_nonpivots, slong * P)Puts in reduced row echelon form and returns the rank , as nmod_mat_rref, and in addition stores in pivots_nonpivots (length the number of columns) the pivot columns followed by the other columns, and in P (length the number of rows) the row permutation of the LU decomposition used.
void _nmod_mat_charpoly_berkowitz(nn_ptr p, const nmod_mat_t M, nmod_t mod)Writes the coefficients of the characteristic polynomial of the matrix to p, by Berkowitz's algorithm. Works for any modulus.
References#
- [FieHof2014] Fieker C. and Hofmann T.: "Computing in quotients of rings of integers" LMS Journal of Computation and Mathematics, 17(A), 349-365
- [StoMul1998] Storjohann, Arne and Mulders, Thom : Fast algorithms for linear algebra modulo :math: : Algorithms—{ESA} '98 (Venice), Lecture Notes in Comput. Sci. 1461 139–150
The FLINT team, “nmod_mat.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nmod_mat/index.html (generated 2026-11-02).
@misc{flint-doc-nmod-mat-index,
author = {{The FLINT team}},
title = {{nmod\_mat.h (module overview)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nmod_mat/index.html},
note = {Generated 2026-11-02}
}