pynumerics 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynumerics/__init__.py +73 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.LICENSE.txt +27 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.dll +0 -0
- pynumerics/_bin/Numerics.dll +0 -0
- pynumerics/_bin/pynumerics.runtimeconfig.json +15 -0
- pynumerics/_coverage.py +3825 -0
- pynumerics/_util.py +237 -0
- pynumerics/_version.py +40 -0
- pynumerics/bootstrap.py +593 -0
- pynumerics/callbacks.py +791 -0
- pynumerics/copulas.py +910 -0
- pynumerics/data.py +2233 -0
- pynumerics/differentiation.py +348 -0
- pynumerics/distributions.py +4043 -0
- pynumerics/download.py +623 -0
- pynumerics/enums.py +119 -0
- pynumerics/errors.py +245 -0
- pynumerics/functions.py +1142 -0
- pynumerics/goodness_of_fit.py +699 -0
- pynumerics/graphs.py +556 -0
- pynumerics/hypothesis_tests.py +445 -0
- pynumerics/identity.py +144 -0
- pynumerics/integration.py +677 -0
- pynumerics/linalg.py +1408 -0
- pynumerics/machine_learning.py +1335 -0
- pynumerics/marshal.py +733 -0
- pynumerics/mathematics.py +1053 -0
- pynumerics/mcmc.py +1406 -0
- pynumerics/multivariate.py +1539 -0
- pynumerics/ode.py +156 -0
- pynumerics/optimization.py +1736 -0
- pynumerics/probability.py +966 -0
- pynumerics/py.typed +0 -0
- pynumerics/regional.py +522 -0
- pynumerics/roots.py +274 -0
- pynumerics/runtime.py +384 -0
- pynumerics/sampling.py +1758 -0
- pynumerics/special.py +1079 -0
- pynumerics/statistics.py +1958 -0
- pynumerics/timeseries.py +1326 -0
- pynumerics-2.3.0.dist-info/METADATA +142 -0
- pynumerics-2.3.0.dist-info/RECORD +46 -0
- pynumerics-2.3.0.dist-info/WHEEL +5 -0
- pynumerics-2.3.0.dist-info/licenses/LICENSE +10 -0
- pynumerics-2.3.0.dist-info/top_level.txt +1 -0
pynumerics/linalg.py
ADDED
|
@@ -0,0 +1,1408 @@
|
|
|
1
|
+
"""Matrices, vectors and decompositions from ``Numerics.Mathematics.LinearAlgebra``.
|
|
2
|
+
|
|
3
|
+
:class:`Matrix` and :class:`Vector` hold a .NET ``Matrix`` or ``Vector`` (``.net``) and expose
|
|
4
|
+
its members; matrix-valued results stay in .NET as new wrappers, and ``numpy.asarray`` copies
|
|
5
|
+
the values out. The decompositions (:class:`CholeskyDecomposition`, :class:`LUDecomposition`,
|
|
6
|
+
:class:`QRDecomposition`, :class:`SingularValueDecomposition` and
|
|
7
|
+
:class:`EigenValueDecomposition`) take any 2-D array or a :class:`Matrix` and return their
|
|
8
|
+
factors and solutions as NumPy arrays. :func:`regularize` and :func:`make_symmetric_positive_definite`
|
|
9
|
+
wrap ``MatrixRegularization``. Every array crosses in one bulk copy each way, bit for bit.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Callable, Sequence
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from pynumerics._util import cached_overload, net_enum, overload
|
|
20
|
+
from pynumerics.callbacks import scalar_function
|
|
21
|
+
from pynumerics.enums import NetEnum
|
|
22
|
+
from pynumerics.errors import translate_public
|
|
23
|
+
from pynumerics.marshal import (
|
|
24
|
+
_construct,
|
|
25
|
+
_linear_algebra,
|
|
26
|
+
_numerics_matrix,
|
|
27
|
+
_numerics_vector,
|
|
28
|
+
to_net_doubles,
|
|
29
|
+
to_net_matrix,
|
|
30
|
+
to_numpy_doubles,
|
|
31
|
+
to_numpy_matrix,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _numpy_matrix(net: Any) -> np.ndarray:
|
|
36
|
+
"""Copy a .NET ``Matrix`` into a new 2-D float64 array."""
|
|
37
|
+
return to_numpy_matrix(net.Array)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _numpy_vector(net: Any) -> np.ndarray:
|
|
41
|
+
"""Copy a .NET ``Vector`` into a new 1-D float64 array."""
|
|
42
|
+
return to_numpy_doubles(net.Array)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _is_matrix_operand(values: Any) -> bool:
|
|
46
|
+
"""Return whether an operand is a :class:`Matrix` or a 2-D array (otherwise a vector)."""
|
|
47
|
+
return isinstance(values, Matrix) or (not isinstance(values, Vector) and np.ndim(values) == 2)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _solve(net: Any, b: Any, *extra: float) -> np.ndarray:
|
|
51
|
+
"""Call ``Solve`` with a vector or a matrix right-hand side and copy the solution out."""
|
|
52
|
+
if _is_matrix_operand(b):
|
|
53
|
+
return _numpy_matrix(net.Solve(_numerics_matrix(b, unwrap=True), *extra))
|
|
54
|
+
return _numpy_vector(net.Solve(_numerics_vector(b, unwrap=True), *extra))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class DecompositionMethod(NetEnum):
|
|
58
|
+
"""Matrix decomposition choices (``Numerics.Mathematics.LinearAlgebra.DecompositionMethod``)."""
|
|
59
|
+
|
|
60
|
+
CHOLESKY = "Cholesky"
|
|
61
|
+
SINGULAR_VALUE = "SingularValue"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class EigenSolverMethod(NetEnum):
|
|
65
|
+
"""Symmetric eigen-decomposition algorithms (``Numerics.Mathematics.LinearAlgebra.EigenSolverMethod``)."""
|
|
66
|
+
|
|
67
|
+
JACOBI = "Jacobi"
|
|
68
|
+
QL = "QL"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Matrix:
|
|
72
|
+
"""A dense matrix of doubles (``Numerics.Mathematics.LinearAlgebra.Matrix``).
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
values : array_like or int or Vector
|
|
77
|
+
A 2-D array; a 1-D array or a :class:`Vector` (a single column); or the number of rows
|
|
78
|
+
of a zero matrix (square unless ``columns`` is given). With ``by_column``, a sequence of
|
|
79
|
+
1-D arrays.
|
|
80
|
+
columns : int, optional
|
|
81
|
+
The number of columns of a zero matrix.
|
|
82
|
+
by_column : bool, optional
|
|
83
|
+
Build from a sequence of 1-D arrays, as columns (True) or rows (False).
|
|
84
|
+
|
|
85
|
+
Attributes
|
|
86
|
+
----------
|
|
87
|
+
net : Numerics.Mathematics.LinearAlgebra.Matrix
|
|
88
|
+
The wrapped .NET matrix.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, values: Any, columns: int | None = None, *, by_column: bool | None = None) -> None:
|
|
92
|
+
la = _linear_algebra()
|
|
93
|
+
if isinstance(values, Vector):
|
|
94
|
+
self.net = la.Matrix(values.net)
|
|
95
|
+
elif isinstance(values, (int, np.integer)) and not isinstance(values, bool):
|
|
96
|
+
self.net = la.Matrix(int(values)) if columns is None else la.Matrix(int(values), int(columns))
|
|
97
|
+
elif by_column is not None:
|
|
98
|
+
import System # noqa: PLC0415 - started by _linear_algebra()
|
|
99
|
+
from System.Collections.Generic import List # noqa: PLC0415
|
|
100
|
+
|
|
101
|
+
arrays = List[System.Array[System.Double]]()
|
|
102
|
+
for item in values:
|
|
103
|
+
arrays.Add(to_net_doubles(item))
|
|
104
|
+
self.net = la.Matrix(arrays, bool(by_column))
|
|
105
|
+
elif np.ndim(values) == 1:
|
|
106
|
+
self.net = la.Matrix(to_net_doubles(values))
|
|
107
|
+
else:
|
|
108
|
+
self.net = _construct("Matrix", to_net_matrix(values))
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_net(cls, net: Any) -> Matrix:
|
|
112
|
+
"""Wrap an existing .NET matrix without copying it.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
net : Numerics.Mathematics.LinearAlgebra.Matrix
|
|
117
|
+
The .NET matrix.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
Matrix
|
|
122
|
+
The wrapper.
|
|
123
|
+
"""
|
|
124
|
+
matrix = cls.__new__(cls)
|
|
125
|
+
matrix.net = net
|
|
126
|
+
return matrix
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def from_xml(cls, xml: str) -> Matrix:
|
|
130
|
+
"""Read a matrix written by :meth:`to_xml` (the ``Matrix(XElement)`` constructor).
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
xml : str
|
|
135
|
+
The ``<Matrix>`` element text.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
Matrix
|
|
140
|
+
The matrix.
|
|
141
|
+
"""
|
|
142
|
+
from System.Xml.Linq import XElement # noqa: PLC0415
|
|
143
|
+
|
|
144
|
+
_linear_algebra()
|
|
145
|
+
return cls.from_net(_linear_algebra().Matrix(XElement.Parse(str(xml))))
|
|
146
|
+
|
|
147
|
+
def __array__(self, dtype: Any = None, copy: Any = None) -> np.ndarray:
|
|
148
|
+
values = _numpy_matrix(self.net)
|
|
149
|
+
return values if dtype is None else values.astype(dtype)
|
|
150
|
+
|
|
151
|
+
def __getitem__(self, index: tuple[int, int]) -> float:
|
|
152
|
+
row, column = index
|
|
153
|
+
return float(self.net[int(row), int(column)])
|
|
154
|
+
|
|
155
|
+
def __setitem__(self, index: tuple[int, int], value: float) -> None:
|
|
156
|
+
row, column = index
|
|
157
|
+
self.net[int(row), int(column)] = float(value)
|
|
158
|
+
|
|
159
|
+
def __repr__(self) -> str:
|
|
160
|
+
return f"Matrix({self.to_array()!r})"
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def number_of_rows(self) -> int:
|
|
164
|
+
"""The number of rows (``NumberOfRows``)."""
|
|
165
|
+
return int(self.net.NumberOfRows)
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def number_of_columns(self) -> int:
|
|
169
|
+
"""The number of columns (``NumberOfColumns``)."""
|
|
170
|
+
return int(self.net.NumberOfColumns)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def shape(self) -> tuple[int, int]:
|
|
174
|
+
"""``(number_of_rows, number_of_columns)``."""
|
|
175
|
+
return self.number_of_rows, self.number_of_columns
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def header(self) -> list[str] | None:
|
|
179
|
+
"""The column header text (``Header``)."""
|
|
180
|
+
header = self.net.Header
|
|
181
|
+
return None if header is None else [str(h) for h in header]
|
|
182
|
+
|
|
183
|
+
@header.setter
|
|
184
|
+
def header(self, value: Sequence[str] | None) -> None:
|
|
185
|
+
import System # noqa: PLC0415 - the matrix exists, so the runtime is running
|
|
186
|
+
|
|
187
|
+
self.net.Header = None if value is None else System.Array[System.String]([str(v) for v in value])
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def is_symmetric(self) -> bool:
|
|
191
|
+
"""Whether every pair agrees to 1e-12 times the largest magnitude (``IsSymmetric``)."""
|
|
192
|
+
return bool(self.net.IsSymmetric)
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def is_square(self) -> bool:
|
|
196
|
+
"""Whether the matrix is square (``IsSquare``)."""
|
|
197
|
+
return bool(self.net.IsSquare)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def array(self) -> np.ndarray:
|
|
201
|
+
"""A copy of the underlying ``double[,]`` (``Array``)."""
|
|
202
|
+
return _numpy_matrix(self.net)
|
|
203
|
+
|
|
204
|
+
def to_array(self) -> np.ndarray:
|
|
205
|
+
"""Return the values as a new 2-D array (``ToArray``).
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
numpy.ndarray
|
|
210
|
+
The values.
|
|
211
|
+
"""
|
|
212
|
+
return to_numpy_matrix(self.net.ToArray())
|
|
213
|
+
|
|
214
|
+
def to_xml(self) -> str:
|
|
215
|
+
"""Return the matrix as XML text (``ToXElement``).
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
str
|
|
220
|
+
The ``<Matrix>`` element, values written with round-trip precision.
|
|
221
|
+
"""
|
|
222
|
+
return str(self.net.ToXElement().ToString())
|
|
223
|
+
|
|
224
|
+
def clone(self) -> Matrix:
|
|
225
|
+
"""Return a copy (``Clone``).
|
|
226
|
+
|
|
227
|
+
Returns
|
|
228
|
+
-------
|
|
229
|
+
Matrix
|
|
230
|
+
The copy.
|
|
231
|
+
"""
|
|
232
|
+
return Matrix.from_net(self.net.Clone())
|
|
233
|
+
|
|
234
|
+
def row(self, index: int) -> np.ndarray:
|
|
235
|
+
"""Return a copy of a row (``Row``).
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
index : int
|
|
240
|
+
The zero-based row index.
|
|
241
|
+
|
|
242
|
+
Returns
|
|
243
|
+
-------
|
|
244
|
+
numpy.ndarray
|
|
245
|
+
The row.
|
|
246
|
+
"""
|
|
247
|
+
return to_numpy_doubles(self.net.Row(int(index)))
|
|
248
|
+
|
|
249
|
+
def column(self, index: int) -> np.ndarray:
|
|
250
|
+
"""Return a copy of a column (``Column``).
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
index : int
|
|
255
|
+
The zero-based column index.
|
|
256
|
+
|
|
257
|
+
Returns
|
|
258
|
+
-------
|
|
259
|
+
numpy.ndarray
|
|
260
|
+
The column.
|
|
261
|
+
"""
|
|
262
|
+
return to_numpy_doubles(self.net.Column(int(index)))
|
|
263
|
+
|
|
264
|
+
def diagonal(self) -> np.ndarray:
|
|
265
|
+
"""Return the min(rows, columns) diagonal elements (``Diagonal()``).
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
numpy.ndarray
|
|
270
|
+
The diagonal.
|
|
271
|
+
"""
|
|
272
|
+
return to_numpy_doubles(self.net.Diagonal())
|
|
273
|
+
|
|
274
|
+
@staticmethod
|
|
275
|
+
def diagonal_matrix(values: Any) -> Matrix:
|
|
276
|
+
"""Return a diagonal matrix (the static ``Matrix.Diagonal``).
|
|
277
|
+
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
values : Matrix or Vector or array_like
|
|
281
|
+
A square matrix (its diagonal is kept) or a 1-D array of diagonal entries.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
Matrix
|
|
286
|
+
The diagonal matrix.
|
|
287
|
+
"""
|
|
288
|
+
la = _linear_algebra()
|
|
289
|
+
if _is_matrix_operand(values):
|
|
290
|
+
return Matrix.from_net(la.Matrix.Diagonal.Overloads[la.Matrix](_numerics_matrix(values, unwrap=True)))
|
|
291
|
+
return Matrix.from_net(la.Matrix.Diagonal.Overloads[la.Vector](_numerics_vector(values, unwrap=True)))
|
|
292
|
+
|
|
293
|
+
def upper_triangle(self) -> Matrix:
|
|
294
|
+
"""Return the upper triangle, with zeros below the diagonal (``UpperTriangle``).
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
Matrix
|
|
299
|
+
The upper-triangular matrix.
|
|
300
|
+
"""
|
|
301
|
+
return Matrix.from_net(self.net.UpperTriangle())
|
|
302
|
+
|
|
303
|
+
def lower_triangle(self) -> Matrix:
|
|
304
|
+
"""Return the lower triangle, with zeros above the diagonal (``LowerTriangle``).
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
Matrix
|
|
309
|
+
The lower-triangular matrix.
|
|
310
|
+
"""
|
|
311
|
+
return Matrix.from_net(self.net.LowerTriangle())
|
|
312
|
+
|
|
313
|
+
def determinant(self) -> float:
|
|
314
|
+
"""Return the determinant, by LU decomposition (``Determinant``).
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
float
|
|
319
|
+
The determinant det(A).
|
|
320
|
+
"""
|
|
321
|
+
return float(self.net.Determinant())
|
|
322
|
+
|
|
323
|
+
def inverse(self) -> Matrix:
|
|
324
|
+
"""Return the inverse, by LU decomposition (``Inverse``).
|
|
325
|
+
|
|
326
|
+
Returns
|
|
327
|
+
-------
|
|
328
|
+
Matrix
|
|
329
|
+
A^-1.
|
|
330
|
+
"""
|
|
331
|
+
return Matrix.from_net(self.net.Inverse())
|
|
332
|
+
|
|
333
|
+
def transpose(self) -> Matrix:
|
|
334
|
+
"""Return the transpose (``Transpose``).
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
Matrix
|
|
339
|
+
A^T.
|
|
340
|
+
"""
|
|
341
|
+
return Matrix.from_net(self.net.Transpose())
|
|
342
|
+
|
|
343
|
+
def trace(self) -> float:
|
|
344
|
+
"""Return the sum of the diagonal (``Trace``).
|
|
345
|
+
|
|
346
|
+
Returns
|
|
347
|
+
-------
|
|
348
|
+
float
|
|
349
|
+
The trace tr(A).
|
|
350
|
+
"""
|
|
351
|
+
return float(self.net.Trace())
|
|
352
|
+
|
|
353
|
+
@staticmethod
|
|
354
|
+
def identity(size: int) -> Matrix:
|
|
355
|
+
"""Return the identity matrix (``Identity``).
|
|
356
|
+
|
|
357
|
+
Parameters
|
|
358
|
+
----------
|
|
359
|
+
size : int
|
|
360
|
+
The number of rows and columns.
|
|
361
|
+
|
|
362
|
+
Returns
|
|
363
|
+
-------
|
|
364
|
+
Matrix
|
|
365
|
+
I.
|
|
366
|
+
"""
|
|
367
|
+
return Matrix.from_net(_linear_algebra().Matrix.Identity(int(size)))
|
|
368
|
+
|
|
369
|
+
@staticmethod
|
|
370
|
+
def outer(x: Any, y: Any) -> Matrix:
|
|
371
|
+
"""Return the outer product x y^T (``Outer``).
|
|
372
|
+
|
|
373
|
+
Parameters
|
|
374
|
+
----------
|
|
375
|
+
x, y : Vector or array_like
|
|
376
|
+
1-D operands.
|
|
377
|
+
|
|
378
|
+
Returns
|
|
379
|
+
-------
|
|
380
|
+
Matrix
|
|
381
|
+
The ``len(x)`` by ``len(y)`` product.
|
|
382
|
+
"""
|
|
383
|
+
return Matrix.from_net(_linear_algebra().Matrix.Outer(_numerics_vector(x, unwrap=True),
|
|
384
|
+
_numerics_vector(y, unwrap=True)))
|
|
385
|
+
|
|
386
|
+
def column_means(self) -> np.ndarray:
|
|
387
|
+
"""Return the mean of each column (``ColumnMeans``).
|
|
388
|
+
|
|
389
|
+
Returns
|
|
390
|
+
-------
|
|
391
|
+
numpy.ndarray
|
|
392
|
+
One mean per column.
|
|
393
|
+
"""
|
|
394
|
+
return _numpy_vector(self.net.ColumnMeans())
|
|
395
|
+
|
|
396
|
+
def apply(self, func: Callable[[float], float] | str) -> None:
|
|
397
|
+
"""Replace every element ``a`` by ``func(a)`` in place (``Apply``).
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
----------
|
|
401
|
+
func : callable or str
|
|
402
|
+
A Python callable (one crossing per element) or C# lambda source compiled with
|
|
403
|
+
Roslyn (no crossing per element), as :func:`pynumerics.callbacks.scalar_function`
|
|
404
|
+
accepts.
|
|
405
|
+
"""
|
|
406
|
+
self.net.Apply(scalar_function(func))
|
|
407
|
+
|
|
408
|
+
def sqrt(self) -> None:
|
|
409
|
+
"""Take the square root of every element in place (``Sqrt``)."""
|
|
410
|
+
self.net.Sqrt()
|
|
411
|
+
|
|
412
|
+
def sqr(self) -> None:
|
|
413
|
+
"""Square every element in place (``Sqr``)."""
|
|
414
|
+
self.net.Sqr()
|
|
415
|
+
|
|
416
|
+
def log(self) -> None:
|
|
417
|
+
"""Take the natural logarithm of every element in place (``Log``)."""
|
|
418
|
+
self.net.Log()
|
|
419
|
+
|
|
420
|
+
def exp(self) -> None:
|
|
421
|
+
"""Exponentiate every element in place (``Exp``)."""
|
|
422
|
+
self.net.Exp()
|
|
423
|
+
|
|
424
|
+
def sum(self) -> float:
|
|
425
|
+
"""Return the sum of every element (``Sum``).
|
|
426
|
+
|
|
427
|
+
Returns
|
|
428
|
+
-------
|
|
429
|
+
float
|
|
430
|
+
The sum.
|
|
431
|
+
"""
|
|
432
|
+
return float(self.net.Sum())
|
|
433
|
+
|
|
434
|
+
def multiply(self, other: Any) -> Matrix | Vector:
|
|
435
|
+
"""Return the product with a matrix, a vector or a scalar (``Multiply``).
|
|
436
|
+
|
|
437
|
+
Parameters
|
|
438
|
+
----------
|
|
439
|
+
other : Matrix or Vector or array_like or float
|
|
440
|
+
A matrix (or 2-D array), a vector (or 1-D array) or a scalar.
|
|
441
|
+
|
|
442
|
+
Returns
|
|
443
|
+
-------
|
|
444
|
+
Matrix or Vector
|
|
445
|
+
A B or A s (a :class:`Matrix`), or A x (a :class:`Vector`).
|
|
446
|
+
"""
|
|
447
|
+
if _is_matrix_operand(other):
|
|
448
|
+
member = cached_overload("Matrix.Multiply(Matrix)",
|
|
449
|
+
lambda: _linear_algebra().Matrix.Multiply.Overloads[_linear_algebra().Matrix])
|
|
450
|
+
return Matrix.from_net(member(self.net, _numerics_matrix(other, unwrap=True)))
|
|
451
|
+
if isinstance(other, Vector) or np.ndim(other) == 1:
|
|
452
|
+
member = cached_overload("Matrix.Multiply(Vector)",
|
|
453
|
+
lambda: _linear_algebra().Matrix.Multiply.Overloads[_linear_algebra().Vector])
|
|
454
|
+
return Vector.from_net(member(self.net, _numerics_vector(other, unwrap=True)))
|
|
455
|
+
return Matrix.from_net(overload(self.net.Multiply, "Double")(float(other)))
|
|
456
|
+
|
|
457
|
+
def transpose_multiply(self, other: Any) -> Matrix:
|
|
458
|
+
"""Return A^T B without forming the transpose (``TransposeMultiply``).
|
|
459
|
+
|
|
460
|
+
Parameters
|
|
461
|
+
----------
|
|
462
|
+
other : Matrix or array_like
|
|
463
|
+
B, with as many rows as this matrix.
|
|
464
|
+
|
|
465
|
+
Returns
|
|
466
|
+
-------
|
|
467
|
+
Matrix
|
|
468
|
+
A^T B; exactly symmetric when B is A.
|
|
469
|
+
"""
|
|
470
|
+
return Matrix.from_net(self.net.TransposeMultiply(_numerics_matrix(other, unwrap=True)))
|
|
471
|
+
|
|
472
|
+
def divide(self, scalar: float) -> Matrix:
|
|
473
|
+
"""Return the matrix divided by a scalar (``Divide``).
|
|
474
|
+
|
|
475
|
+
Parameters
|
|
476
|
+
----------
|
|
477
|
+
scalar : float
|
|
478
|
+
The divisor.
|
|
479
|
+
|
|
480
|
+
Returns
|
|
481
|
+
-------
|
|
482
|
+
Matrix
|
|
483
|
+
A / s.
|
|
484
|
+
"""
|
|
485
|
+
return Matrix.from_net(self.net.Divide(float(scalar)))
|
|
486
|
+
|
|
487
|
+
def add(self, other: Any) -> Matrix:
|
|
488
|
+
"""Return the elementwise sum (``Add``).
|
|
489
|
+
|
|
490
|
+
Parameters
|
|
491
|
+
----------
|
|
492
|
+
other : Matrix or array_like
|
|
493
|
+
A matrix of the same shape.
|
|
494
|
+
|
|
495
|
+
Returns
|
|
496
|
+
-------
|
|
497
|
+
Matrix
|
|
498
|
+
A + B.
|
|
499
|
+
"""
|
|
500
|
+
return Matrix.from_net(self.net.Add(_numerics_matrix(other, unwrap=True)))
|
|
501
|
+
|
|
502
|
+
def subtract(self, other: Any) -> Matrix:
|
|
503
|
+
"""Return the elementwise difference (``Subtract``).
|
|
504
|
+
|
|
505
|
+
Parameters
|
|
506
|
+
----------
|
|
507
|
+
other : Matrix or array_like
|
|
508
|
+
A matrix of the same shape.
|
|
509
|
+
|
|
510
|
+
Returns
|
|
511
|
+
-------
|
|
512
|
+
Matrix
|
|
513
|
+
A - B.
|
|
514
|
+
"""
|
|
515
|
+
return Matrix.from_net(self.net.Subtract(_numerics_matrix(other, unwrap=True)))
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
class Vector:
|
|
519
|
+
"""A dense vector of doubles (``Numerics.Mathematics.LinearAlgebra.Vector``).
|
|
520
|
+
|
|
521
|
+
Parameters
|
|
522
|
+
----------
|
|
523
|
+
values : array_like or int
|
|
524
|
+
The 1-D values, or the length of a new vector.
|
|
525
|
+
fill : float, optional
|
|
526
|
+
The value of every element of a new vector of length ``values``; None gives zeros.
|
|
527
|
+
|
|
528
|
+
Attributes
|
|
529
|
+
----------
|
|
530
|
+
net : Numerics.Mathematics.LinearAlgebra.Vector
|
|
531
|
+
The wrapped .NET vector.
|
|
532
|
+
"""
|
|
533
|
+
|
|
534
|
+
def __init__(self, values: Any, fill: float | None = None) -> None:
|
|
535
|
+
la = _linear_algebra()
|
|
536
|
+
if isinstance(values, (int, np.integer)) and not isinstance(values, bool):
|
|
537
|
+
self.net = la.Vector(int(values)) if fill is None else la.Vector(int(values), float(fill))
|
|
538
|
+
else:
|
|
539
|
+
self.net = _construct("Vector", to_net_doubles(values))
|
|
540
|
+
|
|
541
|
+
@classmethod
|
|
542
|
+
def from_net(cls, net: Any) -> Vector:
|
|
543
|
+
"""Wrap an existing .NET vector without copying it.
|
|
544
|
+
|
|
545
|
+
Parameters
|
|
546
|
+
----------
|
|
547
|
+
net : Numerics.Mathematics.LinearAlgebra.Vector
|
|
548
|
+
The .NET vector.
|
|
549
|
+
|
|
550
|
+
Returns
|
|
551
|
+
-------
|
|
552
|
+
Vector
|
|
553
|
+
The wrapper.
|
|
554
|
+
"""
|
|
555
|
+
vector = cls.__new__(cls)
|
|
556
|
+
vector.net = net
|
|
557
|
+
return vector
|
|
558
|
+
|
|
559
|
+
def __array__(self, dtype: Any = None, copy: Any = None) -> np.ndarray:
|
|
560
|
+
values = _numpy_vector(self.net)
|
|
561
|
+
return values if dtype is None else values.astype(dtype)
|
|
562
|
+
|
|
563
|
+
def __len__(self) -> int:
|
|
564
|
+
return int(self.net.Length)
|
|
565
|
+
|
|
566
|
+
def __getitem__(self, index: int) -> float:
|
|
567
|
+
return float(self.net[int(index)])
|
|
568
|
+
|
|
569
|
+
def __setitem__(self, index: int, value: float) -> None:
|
|
570
|
+
self.net[int(index)] = float(value)
|
|
571
|
+
|
|
572
|
+
def __repr__(self) -> str:
|
|
573
|
+
return f"Vector({self.to_array()!r})"
|
|
574
|
+
|
|
575
|
+
@property
|
|
576
|
+
def length(self) -> int:
|
|
577
|
+
"""The number of elements (``Length``)."""
|
|
578
|
+
return int(self.net.Length)
|
|
579
|
+
|
|
580
|
+
@property
|
|
581
|
+
def header(self) -> str | None:
|
|
582
|
+
"""The header text (``Header``)."""
|
|
583
|
+
header = self.net.Header
|
|
584
|
+
return None if header is None else str(header)
|
|
585
|
+
|
|
586
|
+
@header.setter
|
|
587
|
+
def header(self, value: str | None) -> None:
|
|
588
|
+
self.net.Header = None if value is None else str(value)
|
|
589
|
+
|
|
590
|
+
@property
|
|
591
|
+
def array(self) -> np.ndarray:
|
|
592
|
+
"""A copy of the underlying ``double[]`` (``Array``)."""
|
|
593
|
+
return _numpy_vector(self.net)
|
|
594
|
+
|
|
595
|
+
def to_array(self) -> np.ndarray:
|
|
596
|
+
"""Return the values as a new 1-D array (``ToArray``).
|
|
597
|
+
|
|
598
|
+
Returns
|
|
599
|
+
-------
|
|
600
|
+
numpy.ndarray
|
|
601
|
+
The values.
|
|
602
|
+
"""
|
|
603
|
+
return to_numpy_doubles(self.net.ToArray())
|
|
604
|
+
|
|
605
|
+
def to_list(self) -> list[float]:
|
|
606
|
+
"""Return the values as a Python list (``ToList``).
|
|
607
|
+
|
|
608
|
+
Returns
|
|
609
|
+
-------
|
|
610
|
+
list of float
|
|
611
|
+
The values.
|
|
612
|
+
"""
|
|
613
|
+
return to_numpy_doubles(self.net.ToList()).tolist()
|
|
614
|
+
|
|
615
|
+
def clone(self) -> Vector:
|
|
616
|
+
"""Return a copy (``Clone``).
|
|
617
|
+
|
|
618
|
+
Returns
|
|
619
|
+
-------
|
|
620
|
+
Vector
|
|
621
|
+
The copy.
|
|
622
|
+
"""
|
|
623
|
+
return Vector.from_net(self.net.Clone())
|
|
624
|
+
|
|
625
|
+
def clear(self) -> None:
|
|
626
|
+
"""Set every element to zero in place (``Clear``)."""
|
|
627
|
+
self.net.Clear()
|
|
628
|
+
|
|
629
|
+
def copy_from(self, other: Any) -> None:
|
|
630
|
+
"""Overwrite the elements with those of another vector of the same length (``CopyFrom``).
|
|
631
|
+
|
|
632
|
+
Parameters
|
|
633
|
+
----------
|
|
634
|
+
other : Vector or array_like
|
|
635
|
+
The source.
|
|
636
|
+
"""
|
|
637
|
+
self.net.CopyFrom(_numerics_vector(other, unwrap=True))
|
|
638
|
+
|
|
639
|
+
def sum(self) -> float:
|
|
640
|
+
"""Return the sum of the elements (``Sum``).
|
|
641
|
+
|
|
642
|
+
Returns
|
|
643
|
+
-------
|
|
644
|
+
float
|
|
645
|
+
The sum.
|
|
646
|
+
"""
|
|
647
|
+
return float(self.net.Sum())
|
|
648
|
+
|
|
649
|
+
def norm(self) -> float:
|
|
650
|
+
"""Return the Euclidean norm (``Norm``).
|
|
651
|
+
|
|
652
|
+
Returns
|
|
653
|
+
-------
|
|
654
|
+
float
|
|
655
|
+
||v||.
|
|
656
|
+
"""
|
|
657
|
+
return float(self.net.Norm())
|
|
658
|
+
|
|
659
|
+
def norm_squared(self) -> float:
|
|
660
|
+
"""Return the squared Euclidean norm (``NormSquared``).
|
|
661
|
+
|
|
662
|
+
Returns
|
|
663
|
+
-------
|
|
664
|
+
float
|
|
665
|
+
||v||**2.
|
|
666
|
+
"""
|
|
667
|
+
return float(self.net.NormSquared())
|
|
668
|
+
|
|
669
|
+
@staticmethod
|
|
670
|
+
def distance(a: Any, b: Any) -> float:
|
|
671
|
+
"""Return the Euclidean distance ||a - b|| (``Distance``).
|
|
672
|
+
|
|
673
|
+
Parameters
|
|
674
|
+
----------
|
|
675
|
+
a, b : Vector or array_like
|
|
676
|
+
Equal-length vectors.
|
|
677
|
+
|
|
678
|
+
Returns
|
|
679
|
+
-------
|
|
680
|
+
float
|
|
681
|
+
The distance.
|
|
682
|
+
"""
|
|
683
|
+
return float(_linear_algebra().Vector.Distance(_numerics_vector(a, unwrap=True),
|
|
684
|
+
_numerics_vector(b, unwrap=True)))
|
|
685
|
+
|
|
686
|
+
@staticmethod
|
|
687
|
+
def dot_product(a: Any, b: Any) -> float:
|
|
688
|
+
"""Return the dot product a . b (``DotProduct``).
|
|
689
|
+
|
|
690
|
+
Parameters
|
|
691
|
+
----------
|
|
692
|
+
a, b : Vector or array_like
|
|
693
|
+
Equal-length vectors.
|
|
694
|
+
|
|
695
|
+
Returns
|
|
696
|
+
-------
|
|
697
|
+
float
|
|
698
|
+
The dot product.
|
|
699
|
+
"""
|
|
700
|
+
return float(_linear_algebra().Vector.DotProduct(_numerics_vector(a, unwrap=True),
|
|
701
|
+
_numerics_vector(b, unwrap=True)))
|
|
702
|
+
|
|
703
|
+
@staticmethod
|
|
704
|
+
def project(a: Any, b: Any) -> Vector:
|
|
705
|
+
"""Return the projection of a onto b, (a . b / b . b) b (``Project``).
|
|
706
|
+
|
|
707
|
+
Parameters
|
|
708
|
+
----------
|
|
709
|
+
a, b : Vector or array_like
|
|
710
|
+
Equal-length vectors.
|
|
711
|
+
|
|
712
|
+
Returns
|
|
713
|
+
-------
|
|
714
|
+
Vector
|
|
715
|
+
The projection.
|
|
716
|
+
"""
|
|
717
|
+
return Vector.from_net(_linear_algebra().Vector.Project(_numerics_vector(a, unwrap=True),
|
|
718
|
+
_numerics_vector(b, unwrap=True)))
|
|
719
|
+
|
|
720
|
+
def add(self, other: Any) -> Vector:
|
|
721
|
+
"""Return the elementwise sum (``Add``).
|
|
722
|
+
|
|
723
|
+
Parameters
|
|
724
|
+
----------
|
|
725
|
+
other : Vector or array_like
|
|
726
|
+
An equal-length vector.
|
|
727
|
+
|
|
728
|
+
Returns
|
|
729
|
+
-------
|
|
730
|
+
Vector
|
|
731
|
+
The sum v + w.
|
|
732
|
+
"""
|
|
733
|
+
if isinstance(other, Vector):
|
|
734
|
+
return Vector.from_net(self.net.Add.Overloads[_linear_algebra().Vector](other.net))
|
|
735
|
+
return Vector.from_net(overload(self.net.Add, "Double[]")(to_net_doubles(other)))
|
|
736
|
+
|
|
737
|
+
def subtract(self, other: Any) -> Vector:
|
|
738
|
+
"""Return the elementwise difference (``Subtract``).
|
|
739
|
+
|
|
740
|
+
Parameters
|
|
741
|
+
----------
|
|
742
|
+
other : Vector or array_like
|
|
743
|
+
An equal-length vector.
|
|
744
|
+
|
|
745
|
+
Returns
|
|
746
|
+
-------
|
|
747
|
+
Vector
|
|
748
|
+
The difference v - w.
|
|
749
|
+
"""
|
|
750
|
+
if isinstance(other, Vector):
|
|
751
|
+
return Vector.from_net(self.net.Subtract.Overloads[_linear_algebra().Vector](other.net))
|
|
752
|
+
return Vector.from_net(overload(self.net.Subtract, "Double[]")(to_net_doubles(other)))
|
|
753
|
+
|
|
754
|
+
def multiply(self, other: Any) -> Vector:
|
|
755
|
+
"""Return a matrix times this vector, the elementwise product, or the scaled vector (``Multiply``).
|
|
756
|
+
|
|
757
|
+
Parameters
|
|
758
|
+
----------
|
|
759
|
+
other : Matrix or Vector or array_like or float
|
|
760
|
+
A matrix M (or 2-D array) whose column count is the vector length, for M v; a vector
|
|
761
|
+
(or 1-D array) for the elementwise product; or a scalar.
|
|
762
|
+
|
|
763
|
+
Returns
|
|
764
|
+
-------
|
|
765
|
+
Vector
|
|
766
|
+
The product.
|
|
767
|
+
"""
|
|
768
|
+
la = _linear_algebra()
|
|
769
|
+
if _is_matrix_operand(other):
|
|
770
|
+
return Vector.from_net(self.net.Multiply.Overloads[la.Matrix](_numerics_matrix(other, unwrap=True)))
|
|
771
|
+
if isinstance(other, Vector):
|
|
772
|
+
return Vector.from_net(self.net.Multiply.Overloads[la.Vector](other.net))
|
|
773
|
+
if np.ndim(other) == 1:
|
|
774
|
+
return Vector.from_net(overload(self.net.Multiply, "Double[]")(to_net_doubles(other)))
|
|
775
|
+
return Vector.from_net(overload(self.net.Multiply, "Double")(float(other)))
|
|
776
|
+
|
|
777
|
+
def divide(self, scalar: float) -> Vector:
|
|
778
|
+
"""Return the vector divided by a scalar (``Divide``).
|
|
779
|
+
|
|
780
|
+
Parameters
|
|
781
|
+
----------
|
|
782
|
+
scalar : float
|
|
783
|
+
The divisor.
|
|
784
|
+
|
|
785
|
+
Returns
|
|
786
|
+
-------
|
|
787
|
+
Vector
|
|
788
|
+
The quotient v / s.
|
|
789
|
+
"""
|
|
790
|
+
return Vector.from_net(self.net.Divide(float(scalar)))
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
class CholeskyDecomposition:
|
|
794
|
+
"""The Cholesky factorization A = L L^T of a symmetric positive-definite matrix (``CholeskyDecomposition``).
|
|
795
|
+
|
|
796
|
+
Only the upper triangle and the diagonal of A are read. A pivot is rejected when it is at or
|
|
797
|
+
below ``relative_tolerance`` times the corresponding diagonal entry.
|
|
798
|
+
|
|
799
|
+
Parameters
|
|
800
|
+
----------
|
|
801
|
+
matrix : Matrix or array_like
|
|
802
|
+
The symmetric positive-definite matrix.
|
|
803
|
+
relative_tolerance : float, optional
|
|
804
|
+
The scale-relative pivot tolerance in [0, 1); None uses
|
|
805
|
+
:meth:`default_relative_tolerance` of the dimension.
|
|
806
|
+
|
|
807
|
+
Attributes
|
|
808
|
+
----------
|
|
809
|
+
net : Numerics.Mathematics.LinearAlgebra.CholeskyDecomposition
|
|
810
|
+
The wrapped .NET decomposition.
|
|
811
|
+
|
|
812
|
+
Raises
|
|
813
|
+
------
|
|
814
|
+
RuntimeError
|
|
815
|
+
If the matrix is not positive definite (raised by Numerics).
|
|
816
|
+
ValueError
|
|
817
|
+
If the matrix is not square or the tolerance is outside [0, 1) (raised by Numerics).
|
|
818
|
+
"""
|
|
819
|
+
|
|
820
|
+
def __init__(self, matrix: Any, relative_tolerance: float | None = None) -> None:
|
|
821
|
+
la = _linear_algebra()
|
|
822
|
+
self.net = (la.CholeskyDecomposition(_numerics_matrix(matrix, unwrap=True)) if relative_tolerance is None
|
|
823
|
+
else la.CholeskyDecomposition(_numerics_matrix(matrix, unwrap=True), float(relative_tolerance)))
|
|
824
|
+
|
|
825
|
+
@classmethod
|
|
826
|
+
def try_decompose(cls, matrix: Any, minimum_relative_jitter: float | None = None,
|
|
827
|
+
maximum_relative_jitter: float | None = None) -> tuple[bool, CholeskyDecomposition | None,
|
|
828
|
+
float]:
|
|
829
|
+
"""Factor A, retrying on A + jitter I with an escalating jitter (``TryCholesky``).
|
|
830
|
+
|
|
831
|
+
The jitters are s * minimum * 10**k up to s * maximum, with s the mean diagonal of A
|
|
832
|
+
(or 1); the defaults are the Numerics ones, 1e-10 and 1e-2.
|
|
833
|
+
|
|
834
|
+
Parameters
|
|
835
|
+
----------
|
|
836
|
+
matrix : Matrix or array_like
|
|
837
|
+
The symmetric matrix.
|
|
838
|
+
minimum_relative_jitter, maximum_relative_jitter : float, optional
|
|
839
|
+
The jitter range relative to s; give both or neither.
|
|
840
|
+
|
|
841
|
+
Returns
|
|
842
|
+
-------
|
|
843
|
+
success : bool
|
|
844
|
+
Whether A or a jittered A was factored.
|
|
845
|
+
decomposition : CholeskyDecomposition or None
|
|
846
|
+
The factorization of A + jitter I on success.
|
|
847
|
+
jitter : float
|
|
848
|
+
The absolute jitter added: 0 when A factors as given, NaN on failure.
|
|
849
|
+
"""
|
|
850
|
+
member = _linear_algebra().CholeskyDecomposition.TryCholesky
|
|
851
|
+
if minimum_relative_jitter is None and maximum_relative_jitter is None:
|
|
852
|
+
ok, net, jitter = member(_numerics_matrix(matrix, unwrap=True), None, 0.0)
|
|
853
|
+
else:
|
|
854
|
+
ok, net, jitter = member(_numerics_matrix(matrix, unwrap=True), float(minimum_relative_jitter),
|
|
855
|
+
float(maximum_relative_jitter), None, 0.0)
|
|
856
|
+
if not ok:
|
|
857
|
+
return False, None, float(jitter)
|
|
858
|
+
decomposition = cls.__new__(cls)
|
|
859
|
+
decomposition.net = net
|
|
860
|
+
return True, decomposition, float(jitter)
|
|
861
|
+
|
|
862
|
+
@staticmethod
|
|
863
|
+
def default_relative_tolerance(dimension: int) -> float:
|
|
864
|
+
"""Return the default pivot tolerance for a dimension (``DefaultRelativeTolerance``).
|
|
865
|
+
|
|
866
|
+
Parameters
|
|
867
|
+
----------
|
|
868
|
+
dimension : int
|
|
869
|
+
The matrix order n.
|
|
870
|
+
|
|
871
|
+
Returns
|
|
872
|
+
-------
|
|
873
|
+
float
|
|
874
|
+
The tolerance (2 n eps).
|
|
875
|
+
"""
|
|
876
|
+
return float(_linear_algebra().CholeskyDecomposition.DefaultRelativeTolerance(int(dimension)))
|
|
877
|
+
|
|
878
|
+
@property
|
|
879
|
+
def relative_tolerance(self) -> float:
|
|
880
|
+
"""The pivot tolerance used (``RelativeTolerance``)."""
|
|
881
|
+
return float(self.net.RelativeTolerance)
|
|
882
|
+
|
|
883
|
+
@property
|
|
884
|
+
def l(self) -> np.ndarray: # noqa: E743 - the factor's conventional name
|
|
885
|
+
"""The lower-triangular factor L (``L``)."""
|
|
886
|
+
return _numpy_matrix(self.net.L)
|
|
887
|
+
|
|
888
|
+
@property
|
|
889
|
+
def a(self) -> np.ndarray:
|
|
890
|
+
"""The decomposed matrix (``A``; A + jitter I after :meth:`try_decompose`)."""
|
|
891
|
+
return _numpy_matrix(self.net.A)
|
|
892
|
+
|
|
893
|
+
@property
|
|
894
|
+
def is_positive_definite(self) -> bool:
|
|
895
|
+
"""Whether the factorization succeeded (``IsPositiveDefinite``)."""
|
|
896
|
+
return bool(self.net.IsPositiveDefinite)
|
|
897
|
+
|
|
898
|
+
def solve(self, b: Any) -> np.ndarray:
|
|
899
|
+
"""Solve A x = b (``Solve``).
|
|
900
|
+
|
|
901
|
+
Parameters
|
|
902
|
+
----------
|
|
903
|
+
b : Vector or array_like
|
|
904
|
+
The right-hand side.
|
|
905
|
+
|
|
906
|
+
Returns
|
|
907
|
+
-------
|
|
908
|
+
numpy.ndarray
|
|
909
|
+
The solution x.
|
|
910
|
+
"""
|
|
911
|
+
return _numpy_vector(self.net.Solve(_numerics_vector(b, unwrap=True)))
|
|
912
|
+
|
|
913
|
+
def forward(self, b: Any) -> np.ndarray:
|
|
914
|
+
"""Solve L y = b by forward substitution (``Forward``).
|
|
915
|
+
|
|
916
|
+
Parameters
|
|
917
|
+
----------
|
|
918
|
+
b : Vector or array_like
|
|
919
|
+
The right-hand side.
|
|
920
|
+
|
|
921
|
+
Returns
|
|
922
|
+
-------
|
|
923
|
+
numpy.ndarray
|
|
924
|
+
The solution y.
|
|
925
|
+
"""
|
|
926
|
+
return _numpy_vector(self.net.Forward(_numerics_vector(b, unwrap=True)))
|
|
927
|
+
|
|
928
|
+
def backward(self, y: Any) -> np.ndarray:
|
|
929
|
+
"""Solve L^T x = y by back substitution (``Backward``).
|
|
930
|
+
|
|
931
|
+
Parameters
|
|
932
|
+
----------
|
|
933
|
+
y : Vector or array_like
|
|
934
|
+
The right-hand side.
|
|
935
|
+
|
|
936
|
+
Returns
|
|
937
|
+
-------
|
|
938
|
+
numpy.ndarray
|
|
939
|
+
The solution x.
|
|
940
|
+
"""
|
|
941
|
+
return _numpy_vector(self.net.Backward(_numerics_vector(y, unwrap=True)))
|
|
942
|
+
|
|
943
|
+
def inverse(self) -> np.ndarray:
|
|
944
|
+
"""Return A^-1 from the factor (``InverseA``).
|
|
945
|
+
|
|
946
|
+
Returns
|
|
947
|
+
-------
|
|
948
|
+
numpy.ndarray
|
|
949
|
+
The inverse.
|
|
950
|
+
"""
|
|
951
|
+
return _numpy_matrix(self.net.InverseA())
|
|
952
|
+
|
|
953
|
+
def determinant(self) -> float:
|
|
954
|
+
"""Return det(A) from the factor (``Determinant``).
|
|
955
|
+
|
|
956
|
+
Returns
|
|
957
|
+
-------
|
|
958
|
+
float
|
|
959
|
+
The determinant.
|
|
960
|
+
"""
|
|
961
|
+
return float(self.net.Determinant())
|
|
962
|
+
|
|
963
|
+
def log_determinant(self) -> float:
|
|
964
|
+
"""Return ln det(A) = 2 sum ln L[i, i] (``LogDeterminant``).
|
|
965
|
+
|
|
966
|
+
Returns
|
|
967
|
+
-------
|
|
968
|
+
float
|
|
969
|
+
The log determinant.
|
|
970
|
+
"""
|
|
971
|
+
return float(self.net.LogDeterminant())
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
class LUDecomposition:
|
|
975
|
+
"""The LU decomposition with partial pivoting of a square matrix (``LUDecomposition``).
|
|
976
|
+
|
|
977
|
+
Parameters
|
|
978
|
+
----------
|
|
979
|
+
matrix : Matrix or array_like
|
|
980
|
+
The square matrix; it is copied, not modified.
|
|
981
|
+
|
|
982
|
+
Attributes
|
|
983
|
+
----------
|
|
984
|
+
net : Numerics.Mathematics.LinearAlgebra.LUDecomposition
|
|
985
|
+
The wrapped .NET decomposition.
|
|
986
|
+
|
|
987
|
+
Raises
|
|
988
|
+
------
|
|
989
|
+
ValueError
|
|
990
|
+
If the matrix is not square (raised by Numerics).
|
|
991
|
+
"""
|
|
992
|
+
|
|
993
|
+
def __init__(self, matrix: Any) -> None:
|
|
994
|
+
self.net = _linear_algebra().LUDecomposition(_numerics_matrix(matrix, unwrap=True))
|
|
995
|
+
|
|
996
|
+
@property
|
|
997
|
+
def lu(self) -> np.ndarray:
|
|
998
|
+
"""The packed factors of the row-permuted matrix (``LU``; unit diagonal of L implied)."""
|
|
999
|
+
return _numpy_matrix(self.net.LU)
|
|
1000
|
+
|
|
1001
|
+
@property
|
|
1002
|
+
def a(self) -> np.ndarray:
|
|
1003
|
+
"""The decomposed matrix (``A``)."""
|
|
1004
|
+
return _numpy_matrix(self.net.A)
|
|
1005
|
+
|
|
1006
|
+
def solve(self, b: Any) -> np.ndarray:
|
|
1007
|
+
"""Solve A x = b for a vector or a matrix of right-hand sides (``Solve``).
|
|
1008
|
+
|
|
1009
|
+
Parameters
|
|
1010
|
+
----------
|
|
1011
|
+
b : Vector or Matrix or array_like
|
|
1012
|
+
A 1-D right-hand side or a 2-D array of them (one per column).
|
|
1013
|
+
|
|
1014
|
+
Returns
|
|
1015
|
+
-------
|
|
1016
|
+
numpy.ndarray
|
|
1017
|
+
The solution x, shaped like ``b``.
|
|
1018
|
+
"""
|
|
1019
|
+
return _solve(self.net, b)
|
|
1020
|
+
|
|
1021
|
+
def inverse(self) -> np.ndarray:
|
|
1022
|
+
"""Return A^-1 (``InverseA``).
|
|
1023
|
+
|
|
1024
|
+
Returns
|
|
1025
|
+
-------
|
|
1026
|
+
numpy.ndarray
|
|
1027
|
+
The inverse.
|
|
1028
|
+
"""
|
|
1029
|
+
return _numpy_matrix(self.net.InverseA())
|
|
1030
|
+
|
|
1031
|
+
def determinant(self) -> float:
|
|
1032
|
+
"""Return det(A) (``Determinant``).
|
|
1033
|
+
|
|
1034
|
+
Returns
|
|
1035
|
+
-------
|
|
1036
|
+
float
|
|
1037
|
+
The determinant.
|
|
1038
|
+
"""
|
|
1039
|
+
return float(self.net.Determinant())
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
class QRDecomposition:
|
|
1043
|
+
"""The Householder QR decomposition A = Q R of an m-by-n matrix (``QRDecomposition``).
|
|
1044
|
+
|
|
1045
|
+
Parameters
|
|
1046
|
+
----------
|
|
1047
|
+
matrix : Matrix or array_like
|
|
1048
|
+
The matrix.
|
|
1049
|
+
|
|
1050
|
+
Attributes
|
|
1051
|
+
----------
|
|
1052
|
+
net : Numerics.Mathematics.LinearAlgebra.QRDecomposition
|
|
1053
|
+
The wrapped .NET decomposition.
|
|
1054
|
+
"""
|
|
1055
|
+
|
|
1056
|
+
def __init__(self, matrix: Any) -> None:
|
|
1057
|
+
self.net = _linear_algebra().QRDecomposition(_numerics_matrix(matrix, unwrap=True))
|
|
1058
|
+
|
|
1059
|
+
@property
|
|
1060
|
+
def q(self) -> np.ndarray:
|
|
1061
|
+
"""The orthogonal factor Q (``Q``)."""
|
|
1062
|
+
return _numpy_matrix(self.net.Q)
|
|
1063
|
+
|
|
1064
|
+
@property
|
|
1065
|
+
def r(self) -> np.ndarray:
|
|
1066
|
+
"""The upper-triangular factor R (``RMatrix``)."""
|
|
1067
|
+
return _numpy_matrix(self.net.RMatrix)
|
|
1068
|
+
|
|
1069
|
+
def solve(self, b: Any) -> np.ndarray:
|
|
1070
|
+
"""Solve A x = b (least squares when m > n) for a vector or a matrix (``Solve``).
|
|
1071
|
+
|
|
1072
|
+
Parameters
|
|
1073
|
+
----------
|
|
1074
|
+
b : Vector or Matrix or array_like
|
|
1075
|
+
A 1-D right-hand side or a 2-D array of them.
|
|
1076
|
+
|
|
1077
|
+
Returns
|
|
1078
|
+
-------
|
|
1079
|
+
numpy.ndarray
|
|
1080
|
+
The solution x.
|
|
1081
|
+
|
|
1082
|
+
Raises
|
|
1083
|
+
------
|
|
1084
|
+
ValueError
|
|
1085
|
+
If ``b`` does not match A or A is numerically rank-deficient (raised by Numerics).
|
|
1086
|
+
"""
|
|
1087
|
+
return _solve(self.net, b)
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
class SingularValueDecomposition:
|
|
1091
|
+
"""The singular value decomposition A = U diag(W) V^T (``SingularValueDecomposition``).
|
|
1092
|
+
|
|
1093
|
+
A ``threshold`` argument below zero, the Numerics default, means the roundoff-based
|
|
1094
|
+
:attr:`threshold`; singular values below the threshold count as zero.
|
|
1095
|
+
|
|
1096
|
+
Parameters
|
|
1097
|
+
----------
|
|
1098
|
+
matrix : Matrix or array_like
|
|
1099
|
+
The m-by-n matrix.
|
|
1100
|
+
|
|
1101
|
+
Attributes
|
|
1102
|
+
----------
|
|
1103
|
+
net : Numerics.Mathematics.LinearAlgebra.SingularValueDecomposition
|
|
1104
|
+
The wrapped .NET decomposition.
|
|
1105
|
+
"""
|
|
1106
|
+
|
|
1107
|
+
def __init__(self, matrix: Any) -> None:
|
|
1108
|
+
self.net = _linear_algebra().SingularValueDecomposition(_numerics_matrix(matrix, unwrap=True))
|
|
1109
|
+
|
|
1110
|
+
@property
|
|
1111
|
+
def a(self) -> np.ndarray:
|
|
1112
|
+
"""The decomposed matrix (``A``)."""
|
|
1113
|
+
return _numpy_matrix(self.net.A)
|
|
1114
|
+
|
|
1115
|
+
@property
|
|
1116
|
+
def u(self) -> np.ndarray:
|
|
1117
|
+
"""The m-by-n column-orthogonal factor U (``U``)."""
|
|
1118
|
+
return _numpy_matrix(self.net.U)
|
|
1119
|
+
|
|
1120
|
+
@property
|
|
1121
|
+
def v(self) -> np.ndarray:
|
|
1122
|
+
"""The n-by-n orthogonal factor V, so A = U diag(w) V^T (``V``)."""
|
|
1123
|
+
return _numpy_matrix(self.net.V)
|
|
1124
|
+
|
|
1125
|
+
@property
|
|
1126
|
+
def w(self) -> np.ndarray:
|
|
1127
|
+
"""The singular values, in decreasing order (``W``)."""
|
|
1128
|
+
return _numpy_vector(self.net.W)
|
|
1129
|
+
|
|
1130
|
+
@property
|
|
1131
|
+
def threshold(self) -> float:
|
|
1132
|
+
"""The default zero threshold 0.5 sqrt(m + n + 1) w[0] eps (``Threshold``)."""
|
|
1133
|
+
return float(self.net.Threshold)
|
|
1134
|
+
|
|
1135
|
+
@property
|
|
1136
|
+
def inverse_condition(self) -> float:
|
|
1137
|
+
"""The reciprocal condition number w[-1] / w[0] (``InverseCondition``)."""
|
|
1138
|
+
return float(self.net.InverseCondition)
|
|
1139
|
+
|
|
1140
|
+
def rank(self, threshold: float = -1.0) -> int:
|
|
1141
|
+
"""Return the number of singular values above the threshold (``Rank``).
|
|
1142
|
+
|
|
1143
|
+
Parameters
|
|
1144
|
+
----------
|
|
1145
|
+
threshold : float, optional
|
|
1146
|
+
The zero threshold; negative (default) uses :attr:`threshold`.
|
|
1147
|
+
|
|
1148
|
+
Returns
|
|
1149
|
+
-------
|
|
1150
|
+
int
|
|
1151
|
+
The rank.
|
|
1152
|
+
"""
|
|
1153
|
+
return int(self.net.Rank(float(threshold)))
|
|
1154
|
+
|
|
1155
|
+
def nullity(self, threshold: float = -1.0) -> int:
|
|
1156
|
+
"""Return the number of singular values at or below the threshold (``Nullity``).
|
|
1157
|
+
|
|
1158
|
+
Parameters
|
|
1159
|
+
----------
|
|
1160
|
+
threshold : float, optional
|
|
1161
|
+
The zero threshold; negative (default) uses :attr:`threshold`.
|
|
1162
|
+
|
|
1163
|
+
Returns
|
|
1164
|
+
-------
|
|
1165
|
+
int
|
|
1166
|
+
The nullity.
|
|
1167
|
+
"""
|
|
1168
|
+
return int(self.net.Nullity(float(threshold)))
|
|
1169
|
+
|
|
1170
|
+
def range(self, threshold: float = -1.0) -> np.ndarray:
|
|
1171
|
+
"""Return an orthonormal basis of the range of A, one vector per column (``Range``).
|
|
1172
|
+
|
|
1173
|
+
Parameters
|
|
1174
|
+
----------
|
|
1175
|
+
threshold : float, optional
|
|
1176
|
+
The zero threshold; negative (default) uses :attr:`threshold`.
|
|
1177
|
+
|
|
1178
|
+
Returns
|
|
1179
|
+
-------
|
|
1180
|
+
numpy.ndarray
|
|
1181
|
+
The m-by-rank basis.
|
|
1182
|
+
"""
|
|
1183
|
+
return _numpy_matrix(self.net.Range(float(threshold)))
|
|
1184
|
+
|
|
1185
|
+
def nullspace(self, threshold: float = -1.0) -> np.ndarray:
|
|
1186
|
+
"""Return an orthonormal basis of the null space of A, one vector per column (``Nullspace``).
|
|
1187
|
+
|
|
1188
|
+
Parameters
|
|
1189
|
+
----------
|
|
1190
|
+
threshold : float, optional
|
|
1191
|
+
The zero threshold; negative (default) uses :attr:`threshold`.
|
|
1192
|
+
|
|
1193
|
+
Returns
|
|
1194
|
+
-------
|
|
1195
|
+
numpy.ndarray
|
|
1196
|
+
The n-by-nullity basis.
|
|
1197
|
+
"""
|
|
1198
|
+
return _numpy_matrix(self.net.Nullspace(float(threshold)))
|
|
1199
|
+
|
|
1200
|
+
def solve(self, b: Any, threshold: float = -1.0) -> np.ndarray:
|
|
1201
|
+
"""Return the pseudo-inverse solution of A x = b for a vector or a matrix (``Solve``).
|
|
1202
|
+
|
|
1203
|
+
The matrix overload of Numerics requires ``b`` to have as many rows as A has columns and
|
|
1204
|
+
reads its first m rows, so a matrix right-hand side is meaningful for a square A only.
|
|
1205
|
+
|
|
1206
|
+
Parameters
|
|
1207
|
+
----------
|
|
1208
|
+
b : Vector or Matrix or array_like
|
|
1209
|
+
A 1-D right-hand side of length m, or a 2-D array of them (square A).
|
|
1210
|
+
threshold : float, optional
|
|
1211
|
+
The zero threshold; negative (default) uses :attr:`threshold`.
|
|
1212
|
+
|
|
1213
|
+
Returns
|
|
1214
|
+
-------
|
|
1215
|
+
numpy.ndarray
|
|
1216
|
+
The solution x.
|
|
1217
|
+
"""
|
|
1218
|
+
return _solve(self.net, b, float(threshold))
|
|
1219
|
+
|
|
1220
|
+
def log_determinant(self) -> float:
|
|
1221
|
+
"""Return the sum of the logs of the singular values, ln abs(det A) (``LogDeterminant``).
|
|
1222
|
+
|
|
1223
|
+
Returns
|
|
1224
|
+
-------
|
|
1225
|
+
float
|
|
1226
|
+
The log absolute determinant.
|
|
1227
|
+
"""
|
|
1228
|
+
return float(self.net.LogDeterminant())
|
|
1229
|
+
|
|
1230
|
+
def log_pseudo_determinant(self, threshold: float | None = None) -> float:
|
|
1231
|
+
"""Return the sum of the logs of the nonzero singular values (``LogPseudoDeterminant``).
|
|
1232
|
+
|
|
1233
|
+
Parameters
|
|
1234
|
+
----------
|
|
1235
|
+
threshold : float, optional
|
|
1236
|
+
None (the no-argument overload) drops only singular values exactly equal to zero; a
|
|
1237
|
+
value drops those below it, and a negative value uses :attr:`threshold`, matching
|
|
1238
|
+
:meth:`rank`.
|
|
1239
|
+
|
|
1240
|
+
Returns
|
|
1241
|
+
-------
|
|
1242
|
+
float
|
|
1243
|
+
The log pseudo-determinant.
|
|
1244
|
+
"""
|
|
1245
|
+
if threshold is None:
|
|
1246
|
+
return float(self.net.LogPseudoDeterminant())
|
|
1247
|
+
return float(self.net.LogPseudoDeterminant(float(threshold)))
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
class EigenValueDecomposition:
|
|
1251
|
+
"""The eigen-decomposition A = V diag(lambda) V^T of a symmetric matrix (``EigenValueDecomposition``).
|
|
1252
|
+
|
|
1253
|
+
``method="jacobi"`` (the default) uses cyclic Jacobi rotations and leaves the eigenvalues in
|
|
1254
|
+
diagonal order, not sorted. ``method="ql"`` uses Householder tridiagonalization and implicit QL
|
|
1255
|
+
iterations, returns the eigenvalues in ascending order as ``numpy.linalg.eigh`` does, and is
|
|
1256
|
+
many times faster for large matrices.
|
|
1257
|
+
|
|
1258
|
+
Parameters
|
|
1259
|
+
----------
|
|
1260
|
+
matrix : Matrix or array_like
|
|
1261
|
+
The symmetric matrix.
|
|
1262
|
+
method : EigenSolverMethod or str, optional
|
|
1263
|
+
``"jacobi"`` (default) or ``"ql"``.
|
|
1264
|
+
|
|
1265
|
+
Attributes
|
|
1266
|
+
----------
|
|
1267
|
+
net : Numerics.Mathematics.LinearAlgebra.EigenValueDecomposition
|
|
1268
|
+
The wrapped .NET decomposition.
|
|
1269
|
+
|
|
1270
|
+
Raises
|
|
1271
|
+
------
|
|
1272
|
+
ValueError
|
|
1273
|
+
If the matrix is not square, not symmetric or not finite (raised by Numerics), or
|
|
1274
|
+
``method`` names no method.
|
|
1275
|
+
"""
|
|
1276
|
+
|
|
1277
|
+
def __init__(self, matrix: Any, method: EigenSolverMethod | str = EigenSolverMethod.JACOBI) -> None:
|
|
1278
|
+
la = _linear_algebra()
|
|
1279
|
+
kind = EigenSolverMethod(method)
|
|
1280
|
+
a = _numerics_matrix(matrix, unwrap=True)
|
|
1281
|
+
if kind is EigenSolverMethod.JACOBI:
|
|
1282
|
+
self.net = la.EigenValueDecomposition(a)
|
|
1283
|
+
return
|
|
1284
|
+
self.net = la.EigenValueDecomposition(a, net_enum(la.EigenSolverMethod, kind))
|
|
1285
|
+
|
|
1286
|
+
@property
|
|
1287
|
+
def a(self) -> np.ndarray:
|
|
1288
|
+
"""The decomposed matrix (``A``)."""
|
|
1289
|
+
return _numpy_matrix(self.net.A)
|
|
1290
|
+
|
|
1291
|
+
@property
|
|
1292
|
+
def eigenvalues(self) -> np.ndarray:
|
|
1293
|
+
"""The eigenvalues (``EigenValues``)."""
|
|
1294
|
+
return _numpy_vector(self.net.EigenValues)
|
|
1295
|
+
|
|
1296
|
+
@property
|
|
1297
|
+
def eigenvectors(self) -> np.ndarray:
|
|
1298
|
+
"""The orthonormal eigenvectors, one per column (``EigenVectors``)."""
|
|
1299
|
+
return _numpy_matrix(self.net.EigenVectors)
|
|
1300
|
+
|
|
1301
|
+
@property
|
|
1302
|
+
def is_converged(self) -> bool:
|
|
1303
|
+
"""Whether every off-diagonal element fell to 1e-12 of the largest (``IsConverged``)."""
|
|
1304
|
+
return bool(self.net.IsConverged)
|
|
1305
|
+
|
|
1306
|
+
def effective_sample_size(self) -> float:
|
|
1307
|
+
"""Return Dutilleul's effective sample size (sum lambda)**2 / sum lambda**2 (``EffectiveSampleSize``).
|
|
1308
|
+
|
|
1309
|
+
Returns
|
|
1310
|
+
-------
|
|
1311
|
+
float
|
|
1312
|
+
The effective sample size, or 0 for an all-zero spectrum.
|
|
1313
|
+
"""
|
|
1314
|
+
return float(self.net.EffectiveSampleSize())
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
def gauss_jordan_solve(a: Any, b: Any) -> tuple[np.ndarray, np.ndarray]:
|
|
1318
|
+
"""Solve A X = B by Gauss-Jordan elimination with full pivoting (``GaussJordanElimination.Solve``).
|
|
1319
|
+
|
|
1320
|
+
Parameters
|
|
1321
|
+
----------
|
|
1322
|
+
a : Matrix or array_like
|
|
1323
|
+
The square matrix A; a :class:`Matrix` is not modified (a copy is eliminated).
|
|
1324
|
+
b : Matrix or array_like
|
|
1325
|
+
The right-hand sides, one per column (2-D) or a single 1-D one.
|
|
1326
|
+
|
|
1327
|
+
Returns
|
|
1328
|
+
-------
|
|
1329
|
+
inverse : numpy.ndarray
|
|
1330
|
+
A^-1.
|
|
1331
|
+
solution : numpy.ndarray
|
|
1332
|
+
X, shaped like ``b``.
|
|
1333
|
+
|
|
1334
|
+
Raises
|
|
1335
|
+
------
|
|
1336
|
+
ValueError
|
|
1337
|
+
If A is not square, B has a different number of rows, or A is not finite (raised by Numerics).
|
|
1338
|
+
"""
|
|
1339
|
+
rhs = np.asarray(b, dtype=np.float64)
|
|
1340
|
+
column = rhs.ndim == 1
|
|
1341
|
+
net_a = _numerics_matrix(a, unwrap=True).Clone()
|
|
1342
|
+
net_b = _numerics_matrix(rhs.reshape(-1, 1) if column else rhs) if not isinstance(b, Matrix) else b.net.Clone()
|
|
1343
|
+
inverse, solution = _linear_algebra().GaussJordanElimination.Solve(net_a, net_b)
|
|
1344
|
+
out = _numpy_matrix(solution)
|
|
1345
|
+
return _numpy_matrix(inverse), out.ravel() if column else out
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
def regularize(matrix: Any, eps: float = 1e-6, cap_multiplier: float = 50.0) -> np.ndarray:
|
|
1349
|
+
"""Return a positive semi-definite version of a symmetric matrix (``MatrixRegularization.Regularize``).
|
|
1350
|
+
|
|
1351
|
+
The matrix is symmetrized and eigen-decomposed, its eigenvalues are floored at
|
|
1352
|
+
eps * trace / p (eps when the trace is not positive) and capped at cap_multiplier times
|
|
1353
|
+
their median, and it is rebuilt as Q diag(lambda) Q^T.
|
|
1354
|
+
|
|
1355
|
+
Parameters
|
|
1356
|
+
----------
|
|
1357
|
+
matrix : array_like
|
|
1358
|
+
The (approximately) symmetric matrix.
|
|
1359
|
+
eps : float, optional
|
|
1360
|
+
The relative eigenvalue floor; default 1e-6.
|
|
1361
|
+
cap_multiplier : float, optional
|
|
1362
|
+
The eigenvalue cap as a multiple of the median; default 50.
|
|
1363
|
+
|
|
1364
|
+
Returns
|
|
1365
|
+
-------
|
|
1366
|
+
numpy.ndarray
|
|
1367
|
+
The regularized matrix.
|
|
1368
|
+
"""
|
|
1369
|
+
values = np.asarray(matrix.to_array() if isinstance(matrix, Matrix) else matrix, dtype=np.float64)
|
|
1370
|
+
return to_numpy_matrix(_linear_algebra().MatrixRegularization.Regularize(to_net_matrix(values), float(eps),
|
|
1371
|
+
float(cap_multiplier)))
|
|
1372
|
+
|
|
1373
|
+
|
|
1374
|
+
def make_symmetric_positive_definite(matrix: Any) -> np.ndarray:
|
|
1375
|
+
"""Return the nearest Cholesky-accepted symmetric matrix (``MatrixRegularization.MakeSymmetricPositiveDefinite``).
|
|
1376
|
+
|
|
1377
|
+
The symmetric part when its Cholesky factor exists, otherwise the symmetric part plus
|
|
1378
|
+
the smallest trace-scaled decade ridge whose factor exists.
|
|
1379
|
+
|
|
1380
|
+
Parameters
|
|
1381
|
+
----------
|
|
1382
|
+
matrix : Matrix or array_like
|
|
1383
|
+
A finite square matrix.
|
|
1384
|
+
|
|
1385
|
+
Returns
|
|
1386
|
+
-------
|
|
1387
|
+
numpy.ndarray
|
|
1388
|
+
The regularized matrix.
|
|
1389
|
+
|
|
1390
|
+
Raises
|
|
1391
|
+
------
|
|
1392
|
+
ValueError
|
|
1393
|
+
If the matrix is not square or holds non-finite entries (raised by Numerics).
|
|
1394
|
+
RuntimeError
|
|
1395
|
+
If no ridge on the ladder yields a factor (raised by Numerics).
|
|
1396
|
+
"""
|
|
1397
|
+
regularized = _linear_algebra().MatrixRegularization.MakeSymmetricPositiveDefinite(
|
|
1398
|
+
_numerics_matrix(matrix, unwrap=True))
|
|
1399
|
+
return _numpy_matrix(regularized)
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
__all__ = [
|
|
1403
|
+
"CholeskyDecomposition", "DecompositionMethod", "EigenSolverMethod", "EigenValueDecomposition", "LUDecomposition",
|
|
1404
|
+
"Matrix", "QRDecomposition", "SingularValueDecomposition", "Vector", "gauss_jordan_solve",
|
|
1405
|
+
"make_symmetric_positive_definite", "regularize",
|
|
1406
|
+
]
|
|
1407
|
+
|
|
1408
|
+
translate_public(globals())
|