Coverage for src/cvx/linalg/solve/inv.py: 100%
21 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 18:56 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 18:56 +0000
1"""Matrix inversion helpers that ignore rows and columns with non-finite diagonals."""
3from __future__ import annotations
5import numpy as np
7from ..core.exceptions import (
8 DEFAULT_COND_THRESHOLD,
9 NonSquareMatrixError,
10 SingularMatrixError,
11)
12from ..core.exceptions import (
13 check_and_warn_condition as _check_and_warn_condition,
14)
15from ..core.types import Matrix
16from ..core.valid import valid
19def inv(
20 matrix: Matrix,
21 cond_threshold: float = DEFAULT_COND_THRESHOLD,
22) -> Matrix:
23 """Invert a matrix restricted to the valid submatrix.
25 Rows and columns with non-finite diagonal entries are excluded from the
26 inversion; the corresponding rows and columns in the result are set to NaN.
27 When the condition number of the valid sub-matrix exceeds *cond_threshold*,
28 an ``IllConditionedMatrixWarning`` is emitted.
30 Args:
31 matrix: Square matrix to invert.
32 cond_threshold: Condition-number threshold above which a warning is
33 emitted. Defaults to ``1e12``.
35 Returns:
36 An inverted matrix with the same shape as *matrix*. Rows and columns
37 mapped to invalid entries are returned as ``NaN``.
39 Raises:
40 NonSquareMatrixError: If the matrix is not square.
41 SingularMatrixError: If the valid sub-matrix is singular.
43 Example:
44 >>> import numpy as np
45 >>> from cvx.linalg import inv
46 >>> np.allclose(inv(np.eye(2)), np.eye(2))
47 True
49 NaN-masked entries are skipped:
51 >>> matrix = np.array([[4.0, 0.0], [0.0, np.nan]])
52 >>> result = inv(matrix)
53 >>> float(result[0, 0])
54 0.25
55 >>> bool(np.isnan(result[0, 1]) and np.isnan(result[1, 0]) and np.isnan(result[1, 1]))
56 True
57 """
58 if matrix.shape[0] != matrix.shape[1]:
59 raise NonSquareMatrixError(matrix.shape[0], matrix.shape[1])
61 n = matrix.shape[0]
62 result = np.full((n, n), np.nan)
63 mask, submatrix = valid(matrix)
65 if mask.any():
66 _check_and_warn_condition(submatrix, cond_threshold)
67 try:
68 sub_inv = np.linalg.inv(submatrix)
69 except np.linalg.LinAlgError as exc:
70 raise SingularMatrixError(str(exc)) from exc
72 idx = np.where(mask)[0]
73 result[np.ix_(idx, idx)] = sub_inv
75 return result