# acb_mat – matrices over complex numbers¶

class flint.acb_mat

Represents a matrix over the complex numbers.

>>> A = acb_mat([[1,2+1j],[3,4]]) ** 2 / 5
[1.4000 + 0.60000j,  2.0000 + 1.0000j]
[           3.0000, 4.4000 + 0.60000j]

charpoly(s)

Returns the characteristic polynomial of s as an acb_poly.

>>> print(acb_mat(2, 2, [1, 1, 1, 0]).charpoly())
1.00000000000000*x^2 + (-1.00000000000000)*x + (-1.00000000000000)

chop(s, tol)

Returns a copy of s where real and imaginary parts of entries that are bounded by tol in magnitude have been replaced by exact zeros.

>>> A = acb_mat([[1, 1+1e-20j], [1e-20+1j, 1e-20+1e-20j]])
>>> A.chop(1e-6)
[ 1.00000000000000, 1.00000000000000]
[1.00000000000000j,                0]

conjugate(s)

Returns the entrywise conjugate (not the conjugate transpose) of s.

>>> acb_mat([[1-2j, 1+3j]]).conjugate()
[1.00000000000000 + 2.00000000000000j, 1.00000000000000 - 3.00000000000000j]

contains(s, t)

Returns whether t is contained in s (in the sense of balls).

>>> A = acb_mat([[1,2],[3,4]])
>>> ((A / 3) * 3).contains(A)
True
>>> A.contains((A / 3) * 3)
False
>>> ((A / 3) * 3).contains(fmpz_mat([[1,2],[3,4]]))
True
>>> ((A / 3) * 3).contains(fmpz_mat([[1,2],[3,5]]))
False
>>> (A / 3).contains(fmpq_mat([[1,2],[3,4]]) / 3)
True
>>> ((A / 3) * 3).contains(arb_mat([[1,2],[3,4]]))
True

convert(type cls, x)

Attempts to convert x to an acb_mat, raising TypeError if unsuccessful.

convert_operand(type cls, x)

Attempts to convert x to an acb_mat, returning NotImplemented if unsuccessful.

det(s)

Returns the determinant of the square matrix s as an acb.

>>> A = acb_mat(3, 3, range(9))
>>> showgood(lambda: A.det(), dps=25)    # singular
0
>>> A[2,2] = 10
>>> showgood(lambda: A.det(), dps=25)
-6.000000000000000000000000
>>> showgood(lambda: (A * A).det())
36.0000000000000
>>> print(acb_mat(0, 0).det())
1.00000000000000

dft(type cls, long n, long m=-1)

Returns the size n by n DFT matrix (optionally a separate number of columns m can be given in which case the periodic extension of the smaller dimension is used).

>>> print(acb_mat.dft(3).str(5, radius=False))
[0.57735,             0.57735,             0.57735]
[0.57735, -0.28868 - 0.50000j, -0.28868 + 0.50000j]
[0.57735, -0.28868 + 0.50000j, -0.28868 - 0.50000j]

eig(s, bool left=False, bool right=False, multiple=False, algorithm=None, tol=None, long maxiter=0, bool nonstop=False)

Computes eigenvalues and optionally eigenvectors of this matrix. Returns either E, (E, L), (E, R) or (E, L, R) depending on whether the flags left and right are set, where E is a list of the eigenvalues, L is a matrix with the left eigenvectors as rows, and R is a matrix with the right eigenvectors as columns.

The algorithm can be “rump”, “vdhoeven_mourrain”, or None to use a default algorithm. Typically “rump” is slower and more accurate while “vdhoeven_mourrain” (the current default) is faster and less accurate.

>>> A = acb_mat([[2,3,5],[7,11,13],[17,19,23]])
>>> for c in A.eig(): print(c)
...
[1.105299634957 +/- 6.34e-13] + [+/- 1.83e-13]j
[-1.917027627441 +/- 2.64e-13] + [+/- 1.83e-13]j
[36.811727992483 +/- 6.97e-13] + [+/- 1.83e-13]j
>>> for c in A.eig(algorithm="rump"): print(c)
...
[1.10529963495745 +/- 4.71e-15] + [+/- 2.92e-15]j
[-1.91702762744092 +/- 8.45e-15] + [+/- 3.86e-15]j
[36.8117279924835 +/- 4.72e-14] + [+/- 9.07e-15]j


With the left and right eigenvector matrices, a complete diagonalization of the matrix is produced:

>>> A = acb_mat([[2,3,5],[7,11,13],[17,19,23]])
>>> E, L, R = A.eig(left=True, right=True)
>>> D = acb_mat(3,3)
>>> for i in range(3): D[i,i] = E[i]
...
>>> (L*A*R - D).contains(acb_mat(3,3))
True
>>> (R*D*L - A).contains(acb_mat(3,3))
True


Ill-conditioned or large matrices may require high precision to isolate the eigenvalues:

>>> sum(acb_mat(arb_mat.hilbert(20,20)).eig())
Traceback (most recent call last):
...
ValueError: failed to isolate eigenvalues (try higher prec, multiple=True for multiple eigenvalues, or nonstop=True to avoid the exception)
>>> sum(acb_mat(arb_mat.hilbert(20,20)).eig(nonstop=True))
nan + nanj
>>> showgood(lambda: sum(acb_mat(arb_mat.hilbert(20,20)).eig(nonstop=True)), parts=False)
2.47967321036454 + [+/- 1.48e-56]j


With default options, the method only succeeds if all eigenvalues can be isolated. Multiple (overlapping) eigenvalues can be handled by setting multiple = True.

>>> acb_mat.dft(4).eig()
Traceback (most recent call last):
...
ValueError: failed to isolate eigenvalues (try higher prec, multiple=True for multiple eigenvalues, or nonstop=True to avoid the exception)
>>> acb_mat.dft(4).eig(nonstop=True)
[nan + nanj, nan + nanj, nan + nanj, nan + nanj]
>>> acb_mat.dft(4).eig(multiple=True)
[[-1.0000000000000 +/- 2.26e-15] + [+/- 1.23e-15]j, [+/- 4.96e-16] + [-1.00000000000000 +/- 3.72e-16]j, [1.00000000000000 +/- 4.98e-16] + [+/- 3.42e-16]j, [1.00000000000000 +/- 4.98e-16] + [+/- 3.42e-16]j]


At this time, computing the eigenvectors is not supported with multiple eigenvalues:

>>> acb_mat.dft(4).eig(multiple=True, right=True)
Traceback (most recent call last):
...
NotImplementedError: eigenvectors not supported with multiple=True


The algorithm can also be set to “approx” to compute approximate eigenvalues and/or eigenvectors without error bounds.

>>> for c in acb_mat.dft(4).eig(algorithm="approx"): print(c.str(radius=False))
...
-0.999999999999999 - 7.85046229341892e-17j
-2.35513868802566e-16 - 1.00000000000000j
1.00000000000000 - 6.64346650360854e-17j
0.999999999999999 - 5.14675360671472e-17j


If algorithm is set to “approx”, then multiple has no effect, and both eigenvalues and eigenvectors can be computed regardless of overlap.

>>> E = acb_mat.dft(4).eig(algorithm="approx")
>>> E, R = acb_mat.dft(4).eig(right=True, algorithm="approx")
>>> E, L = acb_mat.dft(4).eig(left=True, algorithm="approx")
>>> E, L, R = acb_mat.dft(4).eig(left=True, right=True, algorithm="approx")

entries(self)
exp(s)

Returns the matrix exponential of s.

>>> print(acb_mat(2, 2, [1, 4, -2, 1]).exp())
[ [-2.58607310345045 +/- 5.06e-15],  [1.18429895089106 +/- 1.15e-15]]
[[-0.592149475445530 +/- 5.73e-16], [-2.58607310345045 +/- 5.06e-15]]

imag

Entrywise imaginary part of this matrix as an arb_mat.

>>> print(acb_mat.dft(3).imag.str(5, radius=False))
[0,        0,        0]
[0, -0.50000,  0.50000]
[0,  0.50000, -0.50000]

inv(s, bool nonstop=False)

Returns the inverse matrix of the square matrix s.

If s is numerically singular, raises ZeroDivisionError unless nonstop is set in which case a matrix with NaN entries is returned.

>>> A = acb_mat(2, 2, [1, 5, 2, 4])
>>> print(A * A.inv())
[[1.00000000000000 +/- 6.11e-16],                  [+/- 3.34e-16]]
[                 [+/- 4.45e-16], [1.00000000000000 +/- 5.56e-16]]
>>> A = acb_mat(2, 2, [1, 5, 2, 10])
>>> A.inv()
Traceback (most recent call last):
...
ZeroDivisionError: matrix is singular
>>> A.inv(nonstop=True)
[nan + nanj, nan + nanj]
[nan + nanj, nan + nanj]

mid(s)

Returns the matrix consisting of the midpoints of the entries of s.

>>> acb_mat([["1.5 +/- 0.1", 3]]).mid()
[1.50000000000000, 3.00000000000000]

ncols(s) → long

Returns the number of columns of s.

nrows(s) → long

Returns the number of rows of s.

overlaps(s, acb_mat t)

Returns whether s and t overlap (in the sense of balls).

>>> A = acb_mat([[1,2],[3,4]])
>>> ((A / 3) * 3).overlaps(A)
True
>>> ((A / 3) * 3 + 0.0001).overlaps(A)
False

real

Entrywise real part of this matrix as an arb_mat.

>>> print(acb_mat.dft(3).real.str(5, radius=False))
[0.57735,  0.57735,  0.57735]
[0.57735, -0.28868, -0.28868]
[0.57735, -0.28868, -0.28868]

repr(self)
solve(s, t, bool nonstop=False, algorithm=None)

Solves $$AX = B$$ where A is a square matrix given by s and $$B$$ is a matrix given by t.

If A is numerically singular, raises ZeroDivisionError unless nonstop is set in which case a matrix with NaN entries is returned.

>>> A = acb_mat(2, 2, [1, 2, 3, 4])
>>> X = acb_mat(2, 3, range(6))
>>> B = A * X
>>> print(A.solve(B))
[                 [+/- 4.74e-15], [1.00000000000000 +/- 4.78e-15], [2.00000000000000 +/- 8.52e-15]]
[[3.00000000000000 +/- 3.56e-15], [4.00000000000000 +/- 3.59e-15], [5.00000000000000 +/- 6.28e-15]]
>>> acb_mat([[1,1],[0,0]]).solve(acb_mat(2,3), nonstop=True)
[nan + nanj, nan + nanj, nan + nanj]
[nan + nanj, nan + nanj, nan + nanj]


The optional algorithm can be None (default), “lu”, or “precond”. It can also be set to “approx” in which case an approximate floating-point solution (warning: without error bounds!) is returned.

str(self, *args, **kwargs)
table(self)
tolist()

flint_mat.table(self)

trace(s)

Returns the trace of the square matrix s as an acb.

>>> acb_mat([[3,4],[5,7]]).trace()
10.0000000000000

transpose(s)

Returns the transpose of s.