Note
Go to the end to download the full example code.
12.3.10.2.6. Rank and nullspace demo#
This demo shows an example on how to use numpy
in itom
.
import numpy as np
from numpy.linalg import svd
from numpy.typing import ArrayLike
Function to estimate the rank (i.e. the dimension of the nullspace) of a matrix.
def rank(A: ArrayLike, atol: float = 1e-13, rtol: int = 0) -> int:
"""Estimate the rank (i.e. the dimension of the nullspace) of a matrix.
The algorithm used by this function is based on the singular value
decomposition of `A`.
If both `atol` and `rtol` are positive, the combined tolerance is the
maximum of the two; that is::
tol = max(atol, rtol * smax)
Singular values smaller than `tol` are considered to be zero.
Args:
A (ArrayLike): A should be at most 2-D. A 1-D array with length n will be treated
as a 2-D with shape (1, n)
atol (float, optional): The absolute tolerance for a zero singular value. Singular values
smaller than `atol` are considered to be zero.
rtol (int, optional): The relative tolerance. Singular values less than rtol*smax are
considered to be zero, where smax is the largest singular value.
Returns:
int: The estimated rank of the matrix.
See also
--------
numpy.linalg.matrix_rank
matrix_rank is basically the same as this function, but it does not
provide the option of the absolute tolerance."""
A = np.atleast_2d(A)
s = svd(A, compute_uv=False)
tol = max(atol, rtol * s[0])
rank = int((s >= tol).sum())
return rank
Function to compute an approximate basis for the nullspace of A.
def nullspace(A: ArrayLike, atol: float = 1e-13, rtol: int = 0) -> ArrayLike:
"""Compute an approximate basis for the nullspace of A.
The algorithm used by this function is based on the singular value
decomposition of `A`.
If both `atol` and `rtol` are positive, the combined tolerance is the
maximum of the two; that is::
tol = max(atol, rtol * smax)
Singular values smaller than `tol` are considered to be zero.
Args:
A (ArrayLike): A should be at most 2-D. A 1-D array with length k will be treated
as a 2-D with shape (1, k)
atol (float, optional): The absolute tolerance for a zero singular value. Singular values
smaller than `atol` are considered to be zero.
rtol (int, optional): The relative tolerance. Singular values less than rtol*smax are
considered to be zero, where smax is the largest singular value.
Returns:
ArrayLike: If `A` is an array with shape (m, k), then `ns` will be an array
with shape (k, n), where n is the estimated dimension of the
nullspace of `A`. The columns of `ns` are a basis for the
nullspace; each element in numpy.dot(A, ns) will be approximately
zero.
"""
A = np.atleast_2d(A)
u, s, vh = svd(A)
tol = max(atol, rtol * s[0])
nnz = (s >= tol).sum()
ns = vh[nnz:].conj().T
return ns
Function to check rank and nullspace of the matrix.
def checkit(mat):
"""This method calculates the rank and nullspace of matrix mat. The results
are printed."""
print("mat:")
print(mat)
r = rank(mat)
print("rank is", r)
ns = nullspace(mat)
print("nullspace:")
print(ns)
if ns.size > 0:
res = np.abs(np.dot(mat, ns)).max()
print("max residual is", res)
print("-" * 25)
# checks rank and nulllspace of a. The rank is limited since the 3rd row
# is equal to 2x the 2nd row minus 1x the 1st row.
a = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
checkit(a)
b = 2
print("-" * 25)
# full rank matrix
a = np.array([[0.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
checkit(a)
print("-" * 25)
# the rank is 2 since the matrix has only two rows
a = np.array([[0.0, 1.0, 2.0, 4.0], [1.0, 2.0, 3.0, 4.0]])
checkit(a)
print("-" * 25)
# check the rank and nullspace of a complex matrix
a = np.array(
[
[1.0, 1.0j, 2.0 + 2.0j],
[1.0j, -1.0, -2.0 + 2.0j],
[0.5, 0.5j, 1.0 + 1.0j],
]
)
checkit(a)
print("-" * 25)
-------------------------
mat:
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
rank is 2
nullspace:
[[-0.40824829]
[ 0.81649658]
[-0.40824829]]
max residual is 9.43689570931383e-16
-------------------------
mat:
[[0. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
rank is 3
nullspace:
[]
-------------------------
mat:
[[0. 1. 2. 4.]
[1. 2. 3. 4.]]
rank is 2
nullspace:
[[-0.48666474 -0.61177492]
[-0.27946883 0.76717915]
[ 0.76613356 -0.15540423]
[-0.31319957 -0.11409267]]
max residual is 8.881784197001252e-16
-------------------------
mat:
[[ 1. +0.j 0. +1.j 2. +2.j ]
[ 0. +1.j -1. +0.j -2. +2.j ]
[ 0.5+0.j 0. +0.5j 1. +1.j ]]
rank is 1
nullspace:
[[ 0. -0.j -0.9486833 -0.j ]
[ 0.13333333+0.93333333j 0. -0.10540926j]
[ 0.2 -0.26666667j 0.21081851-0.21081851j]]
max residual is 9.930136612989092e-16
-------------------------
Total running time of the script: (0 minutes 0.010 seconds)