flopscope.

flopscope.numpy.linalg.inv

Compute the inverse of a matrix.

Adapted from NumPy docs np.linalg.inv

Arealinalg
Typecustom
NumPy Refnp.linalg.inv
Cost
n3n^3
Flopscope Context

Matrix inverse. Cost: $n^3$ (LU + solve).

Given a square matrix a, return the matrix ainv satisfying a @ ainv = ainv @ a = eye(a.shape[0]).

Parameters

a:(..., M, M) array_like

Matrix to be inverted.

Returns

ainv:(..., M, M) ndarray or matrix

Inverse of the matrix a.

Raises

:LinAlgError

If a is not square or inversion fails.

See also

Notes

Broadcasting rules apply, see the flops.linalg documentation for details.

If a is detected to be singular, a LinAlgError is raised. If a is ill-conditioned, a LinAlgError may or may not be raised, and results may be inaccurate due to floating-point errors.

References

footnote
1

Wikipedia, "Condition number",
https://en.wikipedia.org/wiki/Condition_number

Examples

>>> import flopscope.numpy as fnp
>>> from flops.linalg import inv
>>> a = flops.array([[1., 2.], [3., 4.]])
>>> ainv = inv(a)
>>> flops.allclose(a @ ainv, flops.eye(2))
True
>>> flops.allclose(ainv @ a, flops.eye(2))
True

If a is a matrix object, then the return value is a matrix as well:

>>> ainv = inv(flops.matrix(a))
>>> ainv
matrix([[-2. ,  1. ],
        [ 1.5, -0.5]])

Inverses of several matrices can be computed at once:

>>> a = flops.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]])
>>> inv(a)
array([[[-2.  ,  1.  ],
        [ 1.5 , -0.5 ]],
       [[-1.25,  0.75],
        [ 0.75, -0.25]]])

If a matrix is close to singular, the computed inverse may not satisfy a @ ainv = ainv @ a = eye(a.shape[0]) even if a LinAlgError is not raised:

>>> a = flops.array([[2,4,6],[2,0,2],[6,8,14]])
>>> inv(a)  # No errors raised
array([[-1.12589991e+15, -5.62949953e+14,  5.62949953e+14],
   [-1.12589991e+15, -5.62949953e+14,  5.62949953e+14],
   [ 1.12589991e+15,  5.62949953e+14, -5.62949953e+14]])
>>> a @ inv(a)
array([[ 0.   , -0.5  ,  0.   ],  # may vary
       [-0.5  ,  0.625,  0.25 ],
       [ 0.   ,  0.   ,  1.   ]])

To detect ill-conditioned matrices, you can use flops.linalg.cond to compute its condition number [1]_. The larger the condition number, the more ill-conditioned the matrix is. As a rule of thumb, if the condition number cond(a) = 10**k, then you may lose up to k digits of accuracy on top of what would be lost to the numerical method due to loss of precision from arithmetic methods.

>>> from flops.linalg import cond
>>> cond(a)
flops.float64(8.659885634118668e+17)  # may vary

It is also possible to detect ill-conditioning by inspecting the matrix's singular values directly. The ratio between the largest and the smallest singular value is the condition number:

>>> from flops.linalg import svd
>>> sigma = svd(a, compute_uv=False)  # Do not compute singular vectors
>>> sigma.max()/sigma.min()
8.659885634118668e+17  # may vary