1"""Dense real-matrix utilities backed by the C++ ``RealMatrix`` type.
3This module provides a Python-friendly wrapper around the C++ dense matrix
4implementation used throughout the statistics and copula stack. Inputs and
5outputs are converted to native Python containers, while heavy linear-algebra
6operations are delegated to the C++ backend.
9from __future__
import annotations
11from dataclasses
import dataclass
12from typing
import List, Optional, Sequence, Tuple, Union
14from pyhyperiso.phyperiso.pyhyperiso
import math
as ma
17Number = Union[int, float]
18NestedList = Sequence[Sequence[Number]]
21@dataclass(frozen=True)
23 """Signed logarithmic determinant.
26 logdet: Natural logarithm of the determinant absolute value.
27 sign: Determinant sign, usually ``-1``, ``0``, or ``1``.
35 """Python wrapper for the C++ ``RealMatrix`` class.
37 The wrapper accepts common Python matrix representations and exposes Python
38 arithmetic operators. Matrix-matrix multiplication is also mapped to the
42 data: Optional nested sequence representing a dense matrix.
43 rows: Number of rows for an empty matrix or flat initialization.
44 cols: Number of columns for an empty matrix or flat initialization.
45 flat: Optional row-major flat values. Requires ``rows`` and ``cols``.
48 ValueError: If constructor arguments are incomplete or inconsistent.
51 >>> A = Matrix([[1.0, 2.0], [3.0, 4.0]])
54 [[1.0, 2.0], [3.0, 4.0]]
57 __slots__ = (
"_cpp_obj",)
61 data: Optional[NestedList] =
None,
63 rows: Optional[int] =
None,
64 cols: Optional[int] =
None,
65 flat: Optional[Sequence[Number]] =
None,
68 self.
_cpp_obj = ma.matrix.RealMatrix([[float(x)
for x
in row]
for row
in data])
72 if rows
is None or cols
is None:
73 raise ValueError(
"When using flat=..., you must also provide rows=... and cols=...")
74 self.
_cpp_obj = ma.matrix.RealMatrix([float(x)
for x
in flat], int(rows), int(cols))
77 if rows
is not None or cols
is not None:
78 if rows
is None or cols
is None:
79 raise ValueError(
"Provide both rows and cols.")
80 self.
_cpp_obj = ma.matrix.RealMatrix(int(rows), int(cols))
83 self.
_cpp_obj = ma.matrix.RealMatrix()
87 """Wrap an existing C++ ``RealMatrix`` object.
90 cpp_obj: Bound C++ matrix object.
93 Matrix: Python wrapper sharing the provided C++ object.
95 inst = cls.__new__(cls)
96 inst._cpp_obj = cpp_obj
101 """Public alias for wrapping a C++ ``RealMatrix`` object."""
106 """Number of matrix rows."""
111 """Number of matrix columns."""
116 """Matrix shape as ``(rows, cols)``."""
118 return int(r), int(c)
121 """Return a nested Python list copy of the matrix.
124 list[list[float]]: Row-major matrix values.
129 """Return a compact representation containing the matrix shape."""
131 return f
"Matrix(shape=({r}, {c}))"
134 """Return one matrix entry using ``matrix[i, j]`` indexing."""
136 return float(self.
_cpp_obj[(int(i), int(j))])
138 def __setitem__(self, idx: Tuple[int, int], value: Number) ->
None:
139 """Set one matrix entry using ``matrix[i, j] = value`` indexing."""
141 self.
_cpp_obj[(int(i), int(j))] = float(value)
144 """Return whether the C++ backend considers the matrix symmetric."""
147 def T(self) -> "Matrix":
148 """Return the transpose of the matrix.
151 Matrix: Transposed matrix.
153 return Matrix._from_cpp(self.
_cpp_obj.transpose())
155 def inv(self) -> "Matrix":
156 """Return the matrix inverse.
159 Matrix: Inverse matrix computed by C++.
162 RuntimeError: Propagated from the C++ backend if inversion fails.
167 """Compute the signed logarithmic determinant.
170 SignedLogDet: Determinant sign and log-absolute determinant.
173 return SignedLogDet(logdet=float(s.logdet), sign=int(s.sign))
175 def eig(self) -> Tuple["Matrix", "Matrix"]:
176 """Compute the eigensystem of the matrix.
179 tuple[Matrix, Matrix]: ``(D, P)``, where ``D`` is a diagonal matrix
180 of eigenvalues and ``P`` contains eigenvectors as returned by C++.
183 return Matrix._from_cpp(es.D), Matrix._from_cpp(es.P)
186 """Return the wrapped C++ matrix object."""
190 def _as_cpp(other: Union[
"Matrix", NestedList]):
191 """Convert a Python matrix-like object to a C++ ``RealMatrix``."""
192 if isinstance(other, Matrix):
193 return other._cpp_obj
194 return ma.matrix.RealMatrix([[float(x)
for x
in row]
for row
in other])
197 """Return ``-self``."""
198 return Matrix._from_cpp(-self.
_cpp_obj)
200 def __add__(self, other: Union[
"Matrix", NestedList]) ->
"Matrix":
201 """Return matrix addition with another matrix-like object."""
204 def __sub__(self, other: Union[
"Matrix", NestedList]) ->
"Matrix":
205 """Return matrix subtraction with another matrix-like object."""
208 def __mul__(self, other: Union[
"Matrix", NestedList, Number]) ->
"Matrix":
209 """Return C++ multiplication by a scalar or matrix-like object."""
210 if isinstance(other, (int, float)):
211 return Matrix._from_cpp(self.
_cpp_obj * float(other))
215 """Return scalar multiplication from the left."""
216 if not isinstance(other, (int, float)):
217 return NotImplemented
218 return Matrix._from_cpp(float(other) * self.
_cpp_obj)
221 """Return division by a scalar."""
222 if not isinstance(other, (int, float)):
223 return NotImplemented
224 return Matrix._from_cpp(self.
_cpp_obj / float(other))
226 def __matmul__(self, other: Union[
"Matrix", NestedList]) ->
"Matrix":
227 """Return matrix multiplication using the Python ``@`` operator."""
232 """Create an identity matrix.
238 Matrix: ``n x n`` identity matrix.
240 return Matrix._from_cpp(ma.matrix.eye(int(n)))
243def nearest_psd(R: Union[Matrix, NestedList], thr: float = 1e-12) -> Matrix:
244 """Project a matrix to the nearest positive semidefinite matrix.
246 This helper is used by copula construction to regularize correlation
247 matrices before decomposition.
250 R: Input matrix or nested list.
251 thr: Numerical threshold used by the C++ routine.
254 Matrix: Regularized positive-semidefinite matrix.
258 if isinstance(R, Matrix)
259 else ma.matrix.RealMatrix([[float(x)
for x
in row]
for row
in R])
261 return Matrix._from_cpp(ma.matrix.nearest_psd(cpp_R, float(thr)))
265 """Compute the lower Cholesky factor of a matrix.
268 R: Input symmetric positive-semidefinite matrix.
271 Matrix: Lower triangular Cholesky factor as returned by C++.
275 if isinstance(R, Matrix)
276 else ma.matrix.RealMatrix([[float(x)
for x
in row]
for row
in R])
278 return Matrix._from_cpp(ma.matrix.cholesky_L(cpp_R))
281__all__ = [
"Matrix",
"SignedLogDet",
"eye",
"nearest_psd",
"cholesky_L"]
Tuple["Matrix", "Matrix"] eig(self)
"Matrix" __add__(self, Union["Matrix", NestedList] other)
"Matrix" __sub__(self, Union["Matrix", NestedList] other)
Tuple[int, int] shape(self)
"Matrix" __rmul__(self, Number other)
List[List[float]] to_list(self)
None __setitem__(self, Tuple[int, int] idx, Number value)
"Matrix" __truediv__(self, Number other)
"Matrix" __mul__(self, Union["Matrix", NestedList, Number] other)
"Matrix" from_cpp(cls, cpp_obj)
__init__(self, Optional[NestedList] data=None, *Optional[int] rows=None, Optional[int] cols=None, Optional[Sequence[Number]] flat=None)
"Matrix" _from_cpp(cls, cpp_obj)
"Matrix" __matmul__(self, Union["Matrix", NestedList] other)
SignedLogDet slogdet(self)
float __getitem__(self, Tuple[int, int] idx)
_as_cpp(Union["Matrix", NestedList] other)
Matrix cholesky_L(Union[Matrix, NestedList] R)
Matrix nearest_psd(Union[Matrix, NestedList] R, float thr=1e-12)