pygeoinf 1.0.9__py3-none-any.whl → 1.1.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.
- pygeoinf/__init__.py +5 -1
- pygeoinf/direct_sum.py +101 -75
- pygeoinf/forward_problem.py +33 -32
- pygeoinf/gaussian_measure.py +97 -71
- pygeoinf/hilbert_space.py +517 -241
- pygeoinf/inversion.py +16 -4
- pygeoinf/linear_bayesian.py +57 -36
- pygeoinf/linear_forms.py +169 -0
- pygeoinf/linear_optimisation.py +34 -23
- pygeoinf/linear_solvers.py +74 -247
- pygeoinf/operators.py +175 -36
- pygeoinf/random_matrix.py +36 -32
- pygeoinf/symmetric_space/circle.py +347 -202
- pygeoinf/symmetric_space/sphere.py +335 -448
- pygeoinf/symmetric_space/symmetric_space.py +330 -142
- {pygeoinf-1.0.9.dist-info → pygeoinf-1.1.0.dist-info}/METADATA +1 -2
- pygeoinf-1.1.0.dist-info/RECORD +20 -0
- pygeoinf/forms.py +0 -128
- pygeoinf/symmetric_space/line.py +0 -384
- pygeoinf-1.0.9.dist-info/RECORD +0 -21
- {pygeoinf-1.0.9.dist-info → pygeoinf-1.1.0.dist-info}/LICENSE +0 -0
- {pygeoinf-1.0.9.dist-info → pygeoinf-1.1.0.dist-info}/WHEEL +0 -0
pygeoinf/operators.py
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Defines a class hierarchy for operators between Hilbert spaces.
|
|
3
|
+
|
|
4
|
+
This module provides the tools for defining and manipulating mappings between
|
|
5
|
+
`HilbertSpace` objects. It distinguishes between general non-linear operators
|
|
6
|
+
and the more structured linear operators, which are the primary focus and
|
|
7
|
+
support a rich algebra.
|
|
8
|
+
|
|
9
|
+
Key Classes
|
|
10
|
+
-----------
|
|
11
|
+
- `Operator`: A general, potentially non-linear operator defined by a simple
|
|
12
|
+
mapping function.
|
|
13
|
+
- `LinearOperator`: The main workhorse for linear algebra. It represents a
|
|
14
|
+
linear map and provides rich functionality, including composition (`@`),
|
|
15
|
+
adjoints (`.adjoint`), duals (`.dual`), and matrix representations (`.matrix`).
|
|
16
|
+
It includes numerous factory methods for convenient construction.
|
|
17
|
+
- `DiagonalLinearOperator`: A specialized, efficient implementation for linear
|
|
18
|
+
operators that are diagonal in their component representation, which supports
|
|
19
|
+
functional calculus.
|
|
3
20
|
"""
|
|
4
21
|
|
|
5
22
|
from __future__ import annotations
|
|
@@ -9,8 +26,7 @@ import numpy as np
|
|
|
9
26
|
from scipy.sparse.linalg import LinearOperator as ScipyLinOp
|
|
10
27
|
from scipy.sparse import diags
|
|
11
28
|
|
|
12
|
-
|
|
13
|
-
# For a local package structure, you might use from ..random_matrix import ...
|
|
29
|
+
|
|
14
30
|
from .random_matrix import (
|
|
15
31
|
fixed_rank_random_range,
|
|
16
32
|
variable_rank_random_range,
|
|
@@ -22,7 +38,7 @@ from .random_matrix import (
|
|
|
22
38
|
# This block only runs for type checkers, not at runtime
|
|
23
39
|
if TYPE_CHECKING:
|
|
24
40
|
from .hilbert_space import HilbertSpace, EuclideanSpace
|
|
25
|
-
from .
|
|
41
|
+
from .linear_forms import LinearForm
|
|
26
42
|
|
|
27
43
|
|
|
28
44
|
class Operator:
|
|
@@ -83,8 +99,14 @@ class LinearOperator(Operator):
|
|
|
83
99
|
"""
|
|
84
100
|
A linear operator between two Hilbert spaces.
|
|
85
101
|
|
|
86
|
-
This class is the primary workhorse for linear algebraic operations
|
|
87
|
-
|
|
102
|
+
This class is the primary workhorse for linear algebraic operations. An
|
|
103
|
+
operator can be defined "on the fly" from a callable mapping. The class
|
|
104
|
+
automatically derives the associated `adjoint` and `dual` operators,
|
|
105
|
+
which are fundamental for solving linear systems and for optimization.
|
|
106
|
+
|
|
107
|
+
It supports a rich algebra, including composition (`@`), addition (`+`),
|
|
108
|
+
and scalar multiplication (`*`). Operators can also be represented as
|
|
109
|
+
dense or matrix-free (`scipy`) matrices for use with numerical solvers.
|
|
88
110
|
"""
|
|
89
111
|
|
|
90
112
|
def __init__(
|
|
@@ -96,7 +118,6 @@ class LinearOperator(Operator):
|
|
|
96
118
|
*,
|
|
97
119
|
dual_mapping: Optional[Callable[[Any], Any]] = None,
|
|
98
120
|
adjoint_mapping: Optional[Callable[[Any], Any]] = None,
|
|
99
|
-
formal_adjoint_mapping: Optional[Callable[[Any], Any]] = None,
|
|
100
121
|
thread_safe: bool = False,
|
|
101
122
|
dual_base: Optional[LinearOperator] = None,
|
|
102
123
|
adjoint_base: Optional[LinearOperator] = None,
|
|
@@ -110,7 +131,6 @@ class LinearOperator(Operator):
|
|
|
110
131
|
mapping (callable): The function defining the linear mapping.
|
|
111
132
|
dual_mapping (callable, optional): The action of the dual operator.
|
|
112
133
|
adjoint_mapping (callable, optional): The action of the adjoint.
|
|
113
|
-
formal_adjoint_mapping (callable, optional): The formal adjoint.
|
|
114
134
|
thread_safe (bool, optional): True if the mapping is thread-safe.
|
|
115
135
|
dual_base (LinearOperator, optional): Internal use for duals.
|
|
116
136
|
adjoint_base (LinearOperator, optional): Internal use for adjoints.
|
|
@@ -119,17 +139,12 @@ class LinearOperator(Operator):
|
|
|
119
139
|
self._dual_base: Optional[LinearOperator] = dual_base
|
|
120
140
|
self._adjoint_base: Optional[LinearOperator] = adjoint_base
|
|
121
141
|
self._thread_safe: bool = thread_safe
|
|
122
|
-
self.__formal_adjoint_mapping: Optional[Callable[[Any], Any]]
|
|
123
142
|
self.__adjoint_mapping: Callable[[Any], Any]
|
|
124
143
|
self.__dual_mapping: Callable[[Any], Any]
|
|
125
144
|
|
|
126
145
|
if dual_mapping is None:
|
|
127
146
|
if adjoint_mapping is None:
|
|
128
|
-
|
|
129
|
-
self.__dual_mapping = self._dual_mapping_default
|
|
130
|
-
else:
|
|
131
|
-
self.__formal_adjoint_mapping = formal_adjoint_mapping
|
|
132
|
-
self.__dual_mapping = self._dual_mapping_from_formal_adjoint
|
|
147
|
+
self.__dual_mapping = self._dual_mapping_default
|
|
133
148
|
self.__adjoint_mapping = self._adjoint_mapping_from_dual
|
|
134
149
|
else:
|
|
135
150
|
self.__adjoint_mapping = adjoint_mapping
|
|
@@ -156,11 +171,76 @@ class LinearOperator(Operator):
|
|
|
156
171
|
return LinearOperator(domain, domain, mapping, adjoint_mapping=mapping)
|
|
157
172
|
|
|
158
173
|
@staticmethod
|
|
159
|
-
def
|
|
160
|
-
domain: "HilbertSpace",
|
|
174
|
+
def from_formal_adjoint(
|
|
175
|
+
domain: "HilbertSpace", codomain: "HilbertSpace", operator: LinearOperator
|
|
161
176
|
) -> LinearOperator:
|
|
162
|
-
"""
|
|
163
|
-
|
|
177
|
+
"""
|
|
178
|
+
Constructs an operator on weighted spaces from one on the underlying spaces.
|
|
179
|
+
|
|
180
|
+
This is a key method for working with `MassWeightedHilbertSpace`. It takes
|
|
181
|
+
an operator `A` that is defined on the simple, unweighted underlying spaces
|
|
182
|
+
and "lifts" it to be a proper operator on the mass-weighted spaces. It
|
|
183
|
+
correctly defines the new operator's adjoint with respect to the
|
|
184
|
+
weighted inner products.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
domain: The (potentially) mass-weighted domain of the new operator.
|
|
188
|
+
codomain: The (potentially) mass-weighted codomain of the new operator.
|
|
189
|
+
operator: The original operator defined on the underlying,
|
|
190
|
+
unweighted spaces.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
A new `LinearOperator` that acts between the mass-weighted spaces.
|
|
194
|
+
"""
|
|
195
|
+
from .hilbert_space import MassWeightedHilbertSpace
|
|
196
|
+
|
|
197
|
+
if isinstance(domain, MassWeightedHilbertSpace):
|
|
198
|
+
domain_base = domain.underlying_space
|
|
199
|
+
domain_inverse_mass_operator = domain.inverse_mass_operator
|
|
200
|
+
else:
|
|
201
|
+
domain_base = domain
|
|
202
|
+
domain_inverse_mass_operator = domain.identity_operator()
|
|
203
|
+
|
|
204
|
+
if isinstance(codomain, MassWeightedHilbertSpace):
|
|
205
|
+
codomain_base = codomain.underlying_space
|
|
206
|
+
codomain_mass_operator = codomain.mass_operator
|
|
207
|
+
else:
|
|
208
|
+
codomain_base = codomain
|
|
209
|
+
codomain_mass_operator = codomain.identity_operator()
|
|
210
|
+
|
|
211
|
+
if domain_base != operator.domain:
|
|
212
|
+
raise ValueError("Domain mismatch")
|
|
213
|
+
if codomain_base != operator.codomain:
|
|
214
|
+
raise ValueError("Codomain mismatch")
|
|
215
|
+
|
|
216
|
+
return LinearOperator(
|
|
217
|
+
domain,
|
|
218
|
+
codomain,
|
|
219
|
+
operator,
|
|
220
|
+
adjoint_mapping=domain_inverse_mass_operator
|
|
221
|
+
@ operator.adjoint
|
|
222
|
+
@ codomain_mass_operator,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def from_formally_self_adjoint(
|
|
227
|
+
domain: "HilbertSpace", operator: LinearOperator
|
|
228
|
+
) -> LinearOperator:
|
|
229
|
+
"""
|
|
230
|
+
Method to construct LinearOperators on MassWeightedHilbertSpaces
|
|
231
|
+
that are self-adjoint on the underlying space.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
domain (MassWeightedHilbertSpace): The domain of the operator.
|
|
235
|
+
operator (LinearOperator): The operator to be converted
|
|
236
|
+
|
|
237
|
+
Notes:
|
|
238
|
+
If the domain is not a MassWeightedHilbertSpace, the underlying
|
|
239
|
+
domain is taken to be the domain, and the mass operator the identity.
|
|
240
|
+
In such cases the method is well-defined but pointless as the output
|
|
241
|
+
operator is identical to the input operator.
|
|
242
|
+
"""
|
|
243
|
+
return LinearOperator.from_formal_adjoint(domain, domain, operator)
|
|
164
244
|
|
|
165
245
|
@staticmethod
|
|
166
246
|
def from_linear_forms(forms: List["LinearForm"]) -> LinearOperator:
|
|
@@ -203,15 +283,48 @@ class LinearOperator(Operator):
|
|
|
203
283
|
galerkin: bool = False,
|
|
204
284
|
) -> LinearOperator:
|
|
205
285
|
"""
|
|
206
|
-
Creates
|
|
286
|
+
Creates a LinearOperator from its matrix representation.
|
|
287
|
+
|
|
288
|
+
This factory method allows you to define a `LinearOperator` using a
|
|
289
|
+
concrete matrix (like a `numpy.ndarray`) that acts on the component
|
|
290
|
+
vectors of the abstract Hilbert space vectors. The `galerkin` flag
|
|
291
|
+
determines how this matrix action is interpreted.
|
|
207
292
|
|
|
208
293
|
Args:
|
|
209
|
-
domain: The operator's domain.
|
|
210
|
-
codomain: The operator's codomain.
|
|
211
|
-
matrix: The matrix representation
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
294
|
+
domain (HilbertSpace): The operator's domain.
|
|
295
|
+
codomain (HilbertSpace): The operator's codomain.
|
|
296
|
+
matrix (MatrixLike): The matrix representation, which can be a dense
|
|
297
|
+
NumPy array or a SciPy LinearOperator. Its shape must be
|
|
298
|
+
(codomain.dim, domain.dim).
|
|
299
|
+
galerkin (bool): Specifies the interpretation of the matrix.
|
|
300
|
+
|
|
301
|
+
- **`galerkin=False` (Default): Standard Component Mapping**
|
|
302
|
+
This is the most direct interpretation. The matrix `M` maps the
|
|
303
|
+
component vector `c_x` of an input vector `x` directly to the
|
|
304
|
+
component vector `c_y` of the output vector `y`.
|
|
305
|
+
|
|
306
|
+
- **`galerkin=True`: Galerkin (or "Weak Form") Representation**
|
|
307
|
+
This interpretation is standard in the finite element method (FEM)
|
|
308
|
+
and other variational techniques. The matrix `M` maps the component
|
|
309
|
+
vector `c_x` of an input `x` to the component vector `c_yp` of the
|
|
310
|
+
*dual* of the output vector `y`.
|
|
311
|
+
|
|
312
|
+
- **Matrix Entries**: The matrix elements are defined by inner
|
|
313
|
+
products with basis vectors: `M_ij = inner_product(A(b_j), b_i)`,
|
|
314
|
+
where `b_j` are domain basis vectors and `b_i` are codomain
|
|
315
|
+
basis vectors.
|
|
316
|
+
- **Use Case**: This is critically important for preserving the
|
|
317
|
+
mathematical properties of an operator. For example, if an operator
|
|
318
|
+
`A` is self-adjoint, its Galerkin matrix `M` will be **symmetric**
|
|
319
|
+
(`M.T == M`). This allows the use of highly efficient numerical
|
|
320
|
+
methods like the Conjugate Gradient solver or Cholesky
|
|
321
|
+
factorization, which rely on symmetry. The standard component
|
|
322
|
+
matrix of a self-adjoint operator is generally not symmetric
|
|
323
|
+
unless the basis is orthonormal.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
LinearOperator: A new `LinearOperator` instance whose action is
|
|
327
|
+
defined by the provided matrix and interpretation.
|
|
215
328
|
"""
|
|
216
329
|
assert matrix.shape == (codomain.dim, domain.dim)
|
|
217
330
|
|
|
@@ -361,11 +474,44 @@ class LinearOperator(Operator):
|
|
|
361
474
|
"""
|
|
362
475
|
Returns a matrix representation of the operator.
|
|
363
476
|
|
|
364
|
-
|
|
477
|
+
This method provides a concrete matrix that represents the abstract
|
|
478
|
+
linear operator's action on the underlying component vectors.
|
|
365
479
|
|
|
366
480
|
Args:
|
|
367
|
-
dense:
|
|
368
|
-
|
|
481
|
+
dense (bool): Determines the format of the returned matrix.
|
|
482
|
+
- If `True`, this method computes and returns a dense `numpy.ndarray`.
|
|
483
|
+
Be aware that this can be very memory-intensive for
|
|
484
|
+
high-dimensional spaces.
|
|
485
|
+
- If `False` (default), it returns a matrix-free
|
|
486
|
+
`scipy.sparse.linalg.LinearOperator`. This object encapsulates
|
|
487
|
+
the operator's action (`matvec`) and its transpose action
|
|
488
|
+
(`rmatvec`) without ever explicitly forming the full matrix in memory,
|
|
489
|
+
making it ideal for large-scale problems.
|
|
490
|
+
|
|
491
|
+
galerkin (bool): Specifies the interpretation of the matrix representation. This
|
|
492
|
+
flag is crucial for correctly using the matrix with numerical solvers.
|
|
493
|
+
|
|
494
|
+
- **`galerkin=False` (Default): Standard Component Mapping**
|
|
495
|
+
The returned matrix `M` performs a standard component-to-component
|
|
496
|
+
mapping.
|
|
497
|
+
- **`matvec` action**: Takes the component vector `c_x` of an input `x`
|
|
498
|
+
and returns the component vector `c_y` of the output `y`.
|
|
499
|
+
- **`rmatvec` action**: Corresponds to the matrix of the **dual operator**, `A'`.
|
|
500
|
+
|
|
501
|
+
- **`galerkin=True`: Galerkin (or "Weak Form") Representation**
|
|
502
|
+
The returned matrix `M` represents the operator in a weak form, mapping
|
|
503
|
+
components of a vector to components of a dual vector.
|
|
504
|
+
- **`matvec` action**: Takes the component vector `c_x` of an input `x`
|
|
505
|
+
and returns the component vector `c_yp` of the *dual* of the output `y`.
|
|
506
|
+
- **`rmatvec` action**: Corresponds to the matrix of the **adjoint operator**, `A*`.
|
|
507
|
+
- **Key Property**: This representation is designed to preserve fundamental
|
|
508
|
+
mathematical properties. For instance, if the `LinearOperator` is
|
|
509
|
+
self-adjoint, its Galerkin matrix will be **symmetric**, which is a
|
|
510
|
+
prerequisite for algorithms like the Conjugate Gradient method.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
Union[ScipyLinOp, np.ndarray]: The matrix representation of the
|
|
514
|
+
operator, either as a dense array or a matrix-free object.
|
|
369
515
|
"""
|
|
370
516
|
if dense:
|
|
371
517
|
return self._compute_dense_matrix(galerkin)
|
|
@@ -552,7 +698,7 @@ class LinearOperator(Operator):
|
|
|
552
698
|
)
|
|
553
699
|
|
|
554
700
|
def _dual_mapping_default(self, yp: Any) -> "LinearForm":
|
|
555
|
-
from .
|
|
701
|
+
from .linear_forms import LinearForm
|
|
556
702
|
|
|
557
703
|
return LinearForm(self.domain, mapping=lambda x: yp(self(x)))
|
|
558
704
|
|
|
@@ -561,13 +707,6 @@ class LinearOperator(Operator):
|
|
|
561
707
|
x = self.__adjoint_mapping(y)
|
|
562
708
|
return self.domain.to_dual(x)
|
|
563
709
|
|
|
564
|
-
def _dual_mapping_from_formal_adjoint(self, yp: Any) -> Any:
|
|
565
|
-
cyp = self.codomain.dual.to_components(yp)
|
|
566
|
-
y = self.codomain.from_components(cyp)
|
|
567
|
-
x = self.__formal_adjoint_mapping(y)
|
|
568
|
-
cx = self.domain.to_components(x)
|
|
569
|
-
return self.domain.dual.from_components(cx)
|
|
570
|
-
|
|
571
710
|
def _adjoint_mapping_from_dual(self, y: Any) -> Any:
|
|
572
711
|
yp = self.codomain.to_dual(y)
|
|
573
712
|
xp = self.__dual_mapping(yp)
|
pygeoinf/random_matrix.py
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
This module provides functions for computing low-rank matrix
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
Implements randomized algorithms for low-rank matrix factorizations.
|
|
3
|
+
|
|
4
|
+
This module provides functions for computing approximate, low-rank matrix
|
|
5
|
+
factorizations (SVD, Cholesky, Eigendecomposition) using randomized methods.
|
|
6
|
+
These algorithms are particularly effective for large, high-dimensional matrices
|
|
7
|
+
where deterministic methods would be computationally prohibitive. They work by
|
|
8
|
+
finding a low-dimensional subspace that captures most of the "action" of the
|
|
9
|
+
matrix.
|
|
10
|
+
|
|
11
|
+
The implementations are based on the seminal work of Halko, Martinsson, and
|
|
12
|
+
Tropp, "Finding structure with randomness: Probabilistic algorithms for
|
|
13
|
+
constructing approximate matrix decompositions" (2011).
|
|
8
14
|
"""
|
|
9
15
|
|
|
16
|
+
from typing import Tuple, Union
|
|
17
|
+
|
|
10
18
|
import numpy as np
|
|
11
19
|
from scipy.linalg import (
|
|
12
20
|
cho_factor,
|
|
@@ -16,7 +24,7 @@ from scipy.linalg import (
|
|
|
16
24
|
qr,
|
|
17
25
|
)
|
|
18
26
|
from scipy.sparse.linalg import LinearOperator as ScipyLinOp
|
|
19
|
-
|
|
27
|
+
|
|
20
28
|
|
|
21
29
|
# A type for objects that act like matrices (numpy arrays or SciPy LinearOperators)
|
|
22
30
|
MatrixLike = Union[np.ndarray, ScipyLinOp]
|
|
@@ -26,29 +34,24 @@ def fixed_rank_random_range(
|
|
|
26
34
|
matrix: MatrixLike, rank: int, power: int = 0
|
|
27
35
|
) -> np.ndarray:
|
|
28
36
|
"""
|
|
29
|
-
Computes an orthonormal basis for a fixed-rank approximation
|
|
30
|
-
range of a matrix using a randomized method.
|
|
37
|
+
Computes an orthonormal basis for a fixed-rank approximation of a matrix's range.
|
|
31
38
|
|
|
32
|
-
This
|
|
33
|
-
|
|
39
|
+
This randomized algorithm finds a low-dimensional subspace that captures
|
|
40
|
+
most of the action of the matrix.
|
|
34
41
|
|
|
35
42
|
Args:
|
|
36
|
-
matrix
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
accuracy of the approximation.
|
|
43
|
+
matrix: An (m, n) matrix or scipy.LinearOperator whose range is to be approximated.
|
|
44
|
+
rank: The desired rank for the approximation.
|
|
45
|
+
power: The number of power iterations to perform. Power iterations
|
|
46
|
+
(multiplying by `A*A`) improves the accuracy of the approximation by
|
|
47
|
+
amplifying the dominant singular values, but adds to the computational cost.
|
|
42
48
|
|
|
43
49
|
Returns:
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
An (m, rank) matrix with orthonormal columns whose span approximates
|
|
51
|
+
the range of the input matrix.
|
|
46
52
|
|
|
47
53
|
Notes:
|
|
48
|
-
|
|
49
|
-
`matmat` and `rmatmat` methods implemented.
|
|
50
|
-
|
|
51
|
-
This method is based on Algorithm 4.4 in Halko et al. 2011.
|
|
54
|
+
Based on Algorithm 4.4 in Halko et al. 2011.
|
|
52
55
|
"""
|
|
53
56
|
|
|
54
57
|
m, n = matrix.shape
|
|
@@ -143,19 +146,20 @@ def random_svd(
|
|
|
143
146
|
matrix: MatrixLike, qr_factor: np.ndarray
|
|
144
147
|
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
145
148
|
"""
|
|
146
|
-
Computes an approximate
|
|
147
|
-
|
|
149
|
+
Computes an approximate SVD from a low-rank range approximation.
|
|
150
|
+
|
|
151
|
+
This function takes the original matrix and an orthonormal basis for its
|
|
152
|
+
approximate range (the `qr_factor`) and projects the problem into a smaller
|
|
153
|
+
subspace where a deterministic SVD is cheap to compute.
|
|
148
154
|
|
|
149
155
|
Args:
|
|
150
|
-
matrix
|
|
151
|
-
qr_factor
|
|
152
|
-
|
|
153
|
-
`random_range` function.
|
|
156
|
+
matrix: The original (m, n) matrix or LinearOperator.
|
|
157
|
+
qr_factor: An (m, k) orthonormal basis for the approximate range,
|
|
158
|
+
typically from a `random_range` function.
|
|
154
159
|
|
|
155
160
|
Returns:
|
|
156
|
-
(
|
|
157
|
-
|
|
158
|
-
S is a 1D array of singular values.
|
|
161
|
+
A tuple `(U, S, Vh)` containing the approximate SVD factors, where S is
|
|
162
|
+
a 1D array of singular values.
|
|
159
163
|
|
|
160
164
|
Notes:
|
|
161
165
|
Based on Algorithm 5.1 of Halko et al. 2011.
|