fmpz_mat – matrices over integers

class flint.fmpz_mat

The fmpz_mat type represents dense matrices over the integers.

An fmpz_mat can be constructed empty, from a list of entries in row-major order, from a list of lists, or from an existing matrix:

>>> fmpz_mat(2, 4)
[0, 0, 0, 0]
[0, 0, 0, 0]
>>> A = fmpz_mat(2, 4, range(8))
>>> A
[0, 1, 2, 3]
[4, 5, 6, 7]
>>> fmpz_mat(A) == A
True
>>> fmpz_mat([[1,2,3],[4,5,6]])
[1, 2, 3]
[4, 5, 6]

Entries can be accessed and set:

>>> A[0,1]
1
>>> A[1,3] = 8
>>> A
[0, 1, 2, 3]
[4, 5, 6, 8]

Arithmetic operations are supported:

>>> A * 3
[ 0,  3,  6,  9]
[12, 15, 18, 24]
>>> A + (-A)
[0, 0, 0, 0]
[0, 0, 0, 0]
>>> A * fmpz_mat(4, 3, range(12))
[ 42,  48,  54]
[123, 146, 169]
>>> A * fmpz_mat(3, 3, range(9))
Traceback (most recent call last):
  ...
ValueError: incompatible shapes for matrix multiplication

Disabling pretty-printing:

>>> ctx.pretty = False
>>> fmpz_mat([[1,2,3],[4,5,6]])
fmpz_mat(2, 3, [1, 2, 3, 4, 5, 6])
>>> ctx.pretty = True
det(self)

Returns the determinant of self as an fmpz.

>>> A = fmpz_mat(3, 3, range(9))
>>> A.det()
0
>>> A[2,2] = 10
>>> A.det()
-6
>>> (A * A).det()
36
>>> fmpz_mat(0, 0).det()
1
entries(self)
hadamard(type cls, ulong n)

Attempts to construct a Hadamard matrix of size n. Raises ValueError if no such Hadamard matrix exists. The method can also raise ValueError if it fails to construct a Hadamard matrix of the specified size, even if one exists. It always succeeds if n is a power of two.

>>> fmpz_mat.hadamard(1)
[1]
>>> fmpz_mat.hadamard(2)
[1,  1]
[1, -1]
>>> fmpz_mat.hadamard(4)
[1,  1,  1,  1]
[1, -1,  1, -1]
[1,  1, -1, -1]
[1, -1, -1,  1]
>>> fmpz_mat.hadamard(12)
[ 1, -1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1]
[-1, -1,  1, -1,  1, -1,  1, -1,  1, -1,  1, -1]
[ 1,  1,  1, -1,  1,  1, -1, -1, -1, -1,  1,  1]
[ 1, -1, -1, -1,  1, -1, -1,  1, -1,  1,  1, -1]
[ 1,  1,  1,  1,  1, -1,  1,  1, -1, -1, -1, -1]
[ 1, -1,  1, -1, -1, -1,  1, -1, -1,  1, -1,  1]
[ 1,  1, -1, -1,  1,  1,  1, -1,  1,  1, -1, -1]
[ 1, -1, -1,  1,  1, -1, -1, -1,  1, -1, -1,  1]
[ 1,  1, -1, -1, -1, -1,  1,  1,  1, -1,  1,  1]
[ 1, -1, -1,  1, -1,  1,  1, -1, -1, -1,  1, -1]
[ 1,  1,  1,  1, -1, -1, -1, -1,  1,  1,  1, -1]
[ 1, -1,  1, -1, -1,  1, -1,  1,  1, -1, -1, -1]
>>> fmpz_mat.hadamard(10)
Traceback (most recent call last):
  ...
ValueError: unable to construct Hadamard matrix of size 10
hnf(self, bool transform=False)

Returns the Hermite normal form of self, optionally with a transformation matrix.

>>> A = fmpz_mat(3,4,range(12))
>>> A.hnf()
[4, 0, -4, -8]
[0, 1,  2,  3]
[0, 0,  0,  0]
>>> H, T = A.hnf(transform=True)
>>> H == T * A
True
inv(self, bool integer=False)

Returns the inverse matrix of self, which by default will be of type fmpq_mat:

>>> fmpz_mat(3,3,[1,2,4,0,1,1,2,-1,0]).inv()
[-1/3,  4/3,  2/3]
[-2/3,  8/3,  1/3]
[ 2/3, -5/3, -1/3]

If integer is set, returns the inverse as an fmpz_mat, or raises an exception if the matrix is not invertible over the integers.

>>> fmpz_mat([[5,1],[19,4]]).inv(integer=True)
[  4, -1]
[-19,  5]
>>> fmpz_mat([[5,1],[19,5]]).inv(integer=True)
Traceback (most recent call last):
  ...
ValueError: matrix is not invertible over the integers
is_hadamard(self)

Determines whether self is a Hadamard matrix.

>>> (fmpz_mat.hadamard(20) * -1).is_hadamard()
True
>>> (fmpz_mat.hadamard(20) * 2).is_hadamard()
False
is_hnf(self)

Determines whether self is in Hermite normal form.

>>> fmpz_mat(3,4,range(12)).is_hnf()
False
>>> fmpz_mat(3,4,range(12)).hnf().is_hnf()
True
is_snf(self)

Determines whether self is in Smith normal form.

>>> fmpz_mat(3,4,range(12)).is_snf()
False
>>> fmpz_mat(3,4,range(12)).snf().is_snf()
True
lll(self, bool transform=False, double delta=0.99, double eta=0.51, rep='zbasis', gram='approx')

Returns the LLL reduction of self, optionally along with a transformation matrix.

>>> M = fmpz_mat([[11,17],[13,19]])
>>> M.lll()
[ 2, 2]
[-3, 3]
>>> L, T = M.lll(transform=True)
>>> T * M == L
True
ncols(self) → long

Returns the number of columns of self.

nrows(self) → long

Returns the number of rows of self.

nullspace(self)

Computes a basis for the nullspace of the matrix A represented by self. Returns (X, nullity) where nullity is the rank of the nullspace of A and X is a matrix whose first nullity columns are linearly independent, and such that \(AX = 0\).

>>> A = fmpz_mat(3,5,range(1,16))
>>> X, nullity = A.nullspace()
>>> A.rank(), nullity, X.rank()
(2, 3, 3)
>>> A * X
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
>>> X
[  5,  10,  15, 0, 0]
[-10, -15, -20, 0, 0]
[  5,   0,   0, 0, 0]
[  0,   5,   0, 0, 0]
[  0,   0,   5, 0, 0]
randbits(type cls, ulong m, ulong n, ulong bits)

Returns a random (m, n) matrix with uniformly chosen entries up to the specified number of bits in size.

>>> fmpz_mat.randbits(3, 2, 100)   
[  502804798116524380422349115480, -93136769489619409388141424916]
[-1201505897735399116254292047234, 145439343004100224514654363320]
[ 1183889243483733739229662952032, 632771515833349927306121868518]
randrank(type cls, ulong m, ulong n, ulong rank, ulong bits)

Returns a random sparse (m, n) matrix of the specified rank with entries up to the specified number of bits in size.

>>> fmpz_mat.randrank(3,6,2,20)   
[0, 484749, 0, 0, 0,     0]
[0,      0, 0, 0, 0,     0]
[0,      0, 0, 0, 0, -2048]
randtest(type cls, ulong m, ulong n, ulong bits)

Returns a random (m, n) matrix with non-uniformly chosen entries up to the specified number of bits in size. Small and zero entries are generated with increased probability.

>>> fmpz_mat.randtest(3, 2, 100)   
[        5442103460568216, 1906839377153448]
[-37778931862922801979391,                0]
[                       0,                1]
rank(self)

Returns the rank of self.

>>> A = fmpz_mat(3, 3, range(9))
>>> A.rank()
2
>>> A[2,2] = 10
>>> A.rank()
3
repr(self)
rref(self, inplace=False)

Computes the reduced row echelon form (rref) of self, either returning a new copy or modifying self in-place. Returns (rref, denominator, rank).

>>> ctx.pretty = False
>>> A = fmpz_mat(3,3,range(9))
>>> A.rref()
(fmpz_mat(3, 3, [3, 0, -3, 0, 3, 6, 0, 0, 0]), fmpz(3), 2)
>>> A.rref(inplace=True)
(fmpz_mat(3, 3, [3, 0, -3, 0, 3, 6, 0, 0, 0]), fmpz(3), 2)
>>> A
fmpz_mat(3, 3, [3, 0, -3, 0, 3, 6, 0, 0, 0])
>>> ctx.pretty = True
snf(self)

Returns the Smith normal form of self.

>>> A = fmpz_mat(3,4,range(12))
>>> A.snf()
[1, 0, 0, 0]
[0, 4, 0, 0]
[0, 0, 0, 0]
solve(self, other, bool integer=False)

Given matrices A and B represented by self and other, returns an fmpq_mat X such that \(AX = B\), assuming that A is square and invertible.

If integer is True, returns an fmpz_mat, solving the system only if the system matrix is invertible over the integers. (Warning: solving with integer set to True is currently slow for large matrices.)

>>> A = fmpz_mat(2, 2, [1,4,8,3])
>>> B = fmpz_mat(2, 3, range(6))
>>> A.solve(B)
[12/29, 13/29, 14/29]
[-3/29,  4/29, 11/29]
>>> A.solve(B, integer=True)
Traceback (most recent call last):
  ...
ValueError: matrix is not invertible over the integers
>>> fmpz_mat([[1,2], [3,5]]).solve(B, integer=True)
[ 6,  3, 0]
[-3, -1, 1]
>>> fmpz_mat(2, 2, [1,0,2,0]).solve(B)
Traceback (most recent call last):
  ...
ZeroDivisionError: singular matrix in solve()
>>> A.solve(fmpz_mat(1, 2, [2,3]))
Traceback (most recent call last):
  ...
ValueError: need a square system and compatible right hand side
str(self, *args, **kwargs)
table(self)
tolist()

flint_mat.table(self)

transpose(self)

Returns the transpose of self.

>>> fmpz_mat(2,3,range(6)).transpose()
[0, 3]
[1, 4]
[2, 5]