pyMOTO 1.3.0__py3-none-any.whl → 1.5.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.
- {pyMOTO-1.3.0.dist-info → pyMOTO-1.5.0.dist-info}/METADATA +7 -8
- pyMOTO-1.5.0.dist-info/RECORD +29 -0
- {pyMOTO-1.3.0.dist-info → pyMOTO-1.5.0.dist-info}/WHEEL +1 -1
- pymoto/__init__.py +17 -11
- pymoto/common/domain.py +61 -5
- pymoto/common/dyadcarrier.py +87 -29
- pymoto/common/mma.py +142 -129
- pymoto/core_objects.py +129 -117
- pymoto/modules/aggregation.py +209 -0
- pymoto/modules/assembly.py +250 -10
- pymoto/modules/complex.py +3 -3
- pymoto/modules/filter.py +171 -24
- pymoto/modules/generic.py +12 -1
- pymoto/modules/io.py +85 -12
- pymoto/modules/linalg.py +92 -120
- pymoto/modules/scaling.py +5 -4
- pymoto/routines.py +34 -9
- pymoto/solvers/__init__.py +14 -0
- pymoto/solvers/auto_determine.py +108 -0
- pymoto/{common/solvers_dense.py → solvers/dense.py} +90 -70
- pymoto/solvers/iterative.py +361 -0
- pymoto/solvers/matrix_checks.py +60 -0
- pymoto/solvers/solvers.py +253 -0
- pymoto/{common/solvers_sparse.py → solvers/sparse.py} +42 -29
- pyMOTO-1.3.0.dist-info/RECORD +0 -24
- pymoto/common/solvers.py +0 -236
- {pyMOTO-1.3.0.dist-info → pyMOTO-1.5.0.dist-info}/LICENSE +0 -0
- {pyMOTO-1.3.0.dist-info → pyMOTO-1.5.0.dist-info}/top_level.txt +0 -0
- {pyMOTO-1.3.0.dist-info → pyMOTO-1.5.0.dist-info}/zip-safe +0 -0
@@ -2,7 +2,8 @@ import warnings
|
|
2
2
|
import numpy as np
|
3
3
|
import scipy.sparse as sps
|
4
4
|
from scipy.sparse import SparseEfficiencyWarning
|
5
|
-
from .
|
5
|
+
from .matrix_checks import matrix_is_hermitian, matrix_is_complex, matrix_is_symmetric
|
6
|
+
from .solvers import LinearSolver
|
6
7
|
|
7
8
|
# ------------------------------------ Pardiso Solver -----------------------------------
|
8
9
|
try:
|
@@ -125,27 +126,33 @@ class SolverSparsePardiso(LinearSolver):
|
|
125
126
|
self._pardiso_solver = PyPardisoSolver(mtype=self._mtype)
|
126
127
|
|
127
128
|
self._pardiso_solver.factorize(A)
|
129
|
+
self._pardiso_solver.set_phase(33)
|
128
130
|
|
129
|
-
def solve(self, b):
|
131
|
+
def solve(self, b, x0=None, trans='N'):
|
130
132
|
""" solve Ax=b for x
|
131
133
|
|
132
134
|
Args:
|
133
135
|
A (scipy.sparse.csr.csr_matrix): sparse square CSR matrix , CSC matrix also possible
|
134
136
|
b (numpy.ndarray): right-hand side(s), b.shape[0] needs to be the same as A.shape[0]
|
137
|
+
x0 (unused)
|
138
|
+
trans (optional): Indicate which system to solve (Normal, Transposed, or Hermitian transposed)
|
135
139
|
|
136
140
|
Returns:
|
137
141
|
Solution of the system of linear equations, same shape as input b
|
138
142
|
"""
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
143
|
+
if trans == 'N':
|
144
|
+
return self._pardiso_solver.solve(self.A, b)
|
145
|
+
elif trans == 'T' or trans == 'H':
|
146
|
+
# T and H are the same, because only real matrix is supported
|
147
|
+
# Cannot use _pardiso_solver.solve because it changes flag 12 internally
|
148
|
+
iparm_prev = self._pardiso_solver.get_iparm(12)
|
149
|
+
self._pardiso_solver.set_iparm(12, int(not iparm_prev)) # Adjoint solver (transpose)
|
150
|
+
b = self._pardiso_solver._check_b(self.A, b)
|
151
|
+
x = self._pardiso_solver._call_pardiso(self.A, b)
|
152
|
+
self._pardiso_solver.set_iparm(12, iparm_prev) # Revert back to normal solver
|
153
|
+
return x
|
154
|
+
else:
|
155
|
+
raise TypeError("Only N, T, or H transposition is possible")
|
149
156
|
|
150
157
|
def _print_iparm(self):
|
151
158
|
""" Print all iparm settings to console """
|
@@ -219,17 +226,16 @@ class SolverSparseLU(LinearSolver):
|
|
219
226
|
self.inv = splu(A)
|
220
227
|
return self
|
221
228
|
|
222
|
-
def solve(self, rhs):
|
229
|
+
def solve(self, rhs, x0=None, trans='N'):
|
223
230
|
r""" Solves the linear system of equations :math:`\mathbf{A} \mathbf{x} = \mathbf{b}` by forward and backward
|
224
231
|
substitution of :math:`\mathbf{x} = \mathbf{U}^{-1}\mathbf{L}^{-1}\mathbf{b}`.
|
225
|
-
"""
|
226
|
-
return self.inv.solve(rhs)
|
227
232
|
|
228
|
-
|
229
|
-
|
230
|
-
backward substitution of :math:`\mathbf{x} = \mathbf{L}^{-\text{H}}\mathbf{U}^{-\text{H}}\mathbf{b}`.
|
233
|
+
Adjoint system solves the linear system of equations :math:`\mathbf{A}^\text{H}\mathbf{x} = \mathbf{b}` by
|
234
|
+
forward and backward substitution of :math:`\mathbf{x} = \mathbf{L}^{-\text{H}}\mathbf{U}^{-\text{H}}\mathbf{b}`
|
231
235
|
"""
|
232
|
-
|
236
|
+
if trans not in ['N', 'T', 'H']:
|
237
|
+
raise TypeError("Only N, T, or H transposition is possible")
|
238
|
+
return self.inv.solve(rhs, trans=trans)
|
233
239
|
|
234
240
|
|
235
241
|
# ------------------------------------ Cholesky Solver scikit-sparse -----------------------------------
|
@@ -281,7 +287,7 @@ class SolverSparseCholeskyScikit(LinearSolver):
|
|
281
287
|
|
282
288
|
return self
|
283
289
|
|
284
|
-
def solve(self, rhs):
|
290
|
+
def solve(self, rhs, x0=None, trans='N'):
|
285
291
|
r""" Solves the linear system of equations :math:`\mathbf{A} \mathbf{x} = \mathbf{b}` by forward and backward
|
286
292
|
substitution of :math:`\mathbf{x} = \mathbf{L}^{-\text{H}}\mathbf{L}^{-1}\mathbf{b}` in case of an
|
287
293
|
Hermitian matrix.
|
@@ -290,10 +296,12 @@ class SolverSparseCholeskyScikit(LinearSolver):
|
|
290
296
|
:math:`\mathbf{A}` and ``K`` is the number of right-hand sides.
|
291
297
|
|
292
298
|
"""
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
299
|
+
if trans not in ['N', 'T', 'H']:
|
300
|
+
raise TypeError("Only N, T, or H transposition is possible")
|
301
|
+
if trans == 'T':
|
302
|
+
return self.inv(rhs.conj()).conj()
|
303
|
+
else:
|
304
|
+
return self.inv(rhs)
|
297
305
|
|
298
306
|
|
299
307
|
# ------------------------------------ Cholesky Solver cvxopt -----------------------------------
|
@@ -344,15 +352,20 @@ class SolverSparseCholeskyCVXOPT(LinearSolver):
|
|
344
352
|
|
345
353
|
return self
|
346
354
|
|
347
|
-
def solve(self, rhs):
|
355
|
+
def solve(self, rhs, x0=None, trans='N'):
|
348
356
|
r""" Solves the linear system of equations :math:`\mathbf{A} \mathbf{x} = \mathbf{b}` by forward and backward
|
349
357
|
substitution of :math:`\mathbf{x} = \mathbf{L}^{-\text{H}}\mathbf{L}^{-1}\mathbf{b}`. """
|
358
|
+
if trans not in ['N', 'T', 'H']:
|
359
|
+
raise TypeError("Only N, T, or H transposition is possible")
|
350
360
|
if rhs.dtype != self._dtype:
|
351
361
|
warnings.warn(f"{type(self).__name__}: Type warning: rhs value type ({rhs.dtype}) is converted to {self._dtype}")
|
352
|
-
|
362
|
+
if trans == 'T':
|
363
|
+
B = cvxopt.matrix(rhs.conj().astype(self._dtype))
|
364
|
+
else:
|
365
|
+
B = cvxopt.matrix(rhs.astype(self._dtype))
|
353
366
|
nrhs = 1 if rhs.ndim == 1 else rhs.shape[1]
|
367
|
+
|
354
368
|
cvxopt.cholmod.solve(self.inv, B, nrhs=nrhs)
|
355
|
-
return np.array(B).flatten() if nrhs == 1 else np.array(B)
|
356
369
|
|
357
|
-
|
358
|
-
return
|
370
|
+
x = np.array(B).flatten() if rhs.ndim == 1 else np.array(B)
|
371
|
+
return x.conj() if trans == 'T' else x
|
pyMOTO-1.3.0.dist-info/RECORD
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
pymoto/__init__.py,sha256=Uy-TOgGg2Ztv2B-HfznVYApXYyvJ3k6a6gm2o3I_5Rg,2232
|
2
|
-
pymoto/core_objects.py,sha256=9TjGunvGVwa-LqM2tmE1XlWnqHDscZLeqbKFBZ7ZroU,25111
|
3
|
-
pymoto/routines.py,sha256=zcwAlq3ytfjhPJqzvHdvW4nTyzmjdgoVSX5j5vDRExw,14638
|
4
|
-
pymoto/utils.py,sha256=YJ-PNLJLc12Yx6TYCrEechS2aaBRx0o4mTM1soeeyz0,1122
|
5
|
-
pymoto/common/domain.py,sha256=79BNR3PKOGOJbUZVyKlnQUbctAbHetO3hRV4vPSl17A,15899
|
6
|
-
pymoto/common/dyadcarrier.py,sha256=VwLJnOq1omfMX2udG6DMHOkD3AsIB05LTpDY7veYXcc,17136
|
7
|
-
pymoto/common/mma.py,sha256=W1Z0h5f3a9BP8nFIlCdahDCIHT4XrcDcDyE6Y1Brq3k,23318
|
8
|
-
pymoto/common/solvers.py,sha256=U7XNMSyHhp0fiZ8ASo1guUb-CHGygik7A4lfLOnh07c,8316
|
9
|
-
pymoto/common/solvers_dense.py,sha256=vuBUp3y4qJLwmsXbFQ_tEb-7LqqCEemFunTn1z_Qu0U,9901
|
10
|
-
pymoto/common/solvers_sparse.py,sha256=QVbGTwGtbhOqRUyg2gHmY-K5haiPbskGA6uj_g-dKz8,15776
|
11
|
-
pymoto/modules/assembly.py,sha256=0jRSFbfhEQtOW7GPLObXAOQEjC91LeZ9spdK25vD6lA,12953
|
12
|
-
pymoto/modules/autodiff.py,sha256=WAfoAOHBSozf7jbr9gQz9Vw4a_2G9wGJxLMMqUQP0Co,1684
|
13
|
-
pymoto/modules/complex.py,sha256=vwzqRo5W319mVf_RqbB7LpYe7jXruVxa3ZV560Iq39k,4421
|
14
|
-
pymoto/modules/filter.py,sha256=8A-dmWSFEqFyQcutjFv__pfgAwszCVZeZgLxuG9hi0g,18840
|
15
|
-
pymoto/modules/generic.py,sha256=27EuDMfUtWkkwEqkfbHMCRlHkt6wcV40aUQKfhL2xKI,9783
|
16
|
-
pymoto/modules/io.py,sha256=4k5S-YQHKhw_HwmqOoYQWFEzdcL5nMJ5fVD2FJFqpFg,10532
|
17
|
-
pymoto/modules/linalg.py,sha256=y9KO7GVnoxpGpJLTMUNZhK4jVUTpWGTnOWI3RBfBeuE,23942
|
18
|
-
pymoto/modules/scaling.py,sha256=hK3sfCoAoseabjqdn5VXe6aGA_fV-MRmMtiv4uIg_I4,2252
|
19
|
-
pyMOTO-1.3.0.dist-info/LICENSE,sha256=ZXMC2Txpzs-dBwz9Me4_1rQCSVl4P1B27MomNi43F30,1072
|
20
|
-
pyMOTO-1.3.0.dist-info/METADATA,sha256=KJvLKj58DMxrc_mJKTy5ZwyU3reFi76MeILIRynh4JY,4907
|
21
|
-
pyMOTO-1.3.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
22
|
-
pyMOTO-1.3.0.dist-info/top_level.txt,sha256=EdvAUSmFMaiqhuEZW8jxANMiK-LdPtlmDWL6SfmCdUU,7
|
23
|
-
pyMOTO-1.3.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
24
|
-
pyMOTO-1.3.0.dist-info/RECORD,,
|
pymoto/common/solvers.py
DELETED
@@ -1,236 +0,0 @@
|
|
1
|
-
import numpy as np
|
2
|
-
import scipy.sparse as sps
|
3
|
-
try:
|
4
|
-
import cvxopt
|
5
|
-
_has_cvxopt = True
|
6
|
-
except ImportError:
|
7
|
-
_has_cvxopt = False
|
8
|
-
|
9
|
-
|
10
|
-
def is_cvxopt_spmatrix(A):
|
11
|
-
""" Checks if the argument is a cvxopt sparse matrix """
|
12
|
-
return isinstance(A, cvxopt.spmatrix) if _has_cvxopt else False
|
13
|
-
|
14
|
-
|
15
|
-
def matrix_is_complex(A):
|
16
|
-
""" Checks if the matrix is complex """
|
17
|
-
if is_cvxopt_spmatrix(A):
|
18
|
-
return A.typecode == 'z'
|
19
|
-
else:
|
20
|
-
return np.iscomplexobj(A)
|
21
|
-
|
22
|
-
|
23
|
-
def matrix_is_diagonal(A):
|
24
|
-
""" Checks if the matrix is diagonal"""
|
25
|
-
if sps.issparse(A):
|
26
|
-
if isinstance(A, sps.dia_matrix):
|
27
|
-
return len(A.offsets) == 1 and A.offsets[0] == 0
|
28
|
-
else:
|
29
|
-
return np.allclose((A - sps.spdiags(A.diagonal(), 0, *A.shape)).data, 0.0)
|
30
|
-
elif is_cvxopt_spmatrix(A):
|
31
|
-
return max(abs(A.I - A.J)) == 0
|
32
|
-
else:
|
33
|
-
return np.allclose(A, np.diag(np.diag(A)))
|
34
|
-
|
35
|
-
|
36
|
-
def matrix_is_symmetric(A):
|
37
|
-
""" Checks whether a matrix is numerically symmetric """
|
38
|
-
if sps.issparse(A):
|
39
|
-
return np.allclose((A-A.T).data, 0)
|
40
|
-
elif is_cvxopt_spmatrix(A):
|
41
|
-
return np.isclose(max(abs(A-A.T)), 0.0)
|
42
|
-
else:
|
43
|
-
return np.allclose(A, A.T)
|
44
|
-
|
45
|
-
|
46
|
-
def matrix_is_hermitian(A):
|
47
|
-
""" Checks whether a matrix is numerically Hermitian """
|
48
|
-
if matrix_is_complex(A):
|
49
|
-
if sps.issparse(A):
|
50
|
-
return np.allclose((A-A.T.conj()).data, 0)
|
51
|
-
elif is_cvxopt_spmatrix(A):
|
52
|
-
return np.isclose(max(abs(A-A.ctrans())), 0.0)
|
53
|
-
else:
|
54
|
-
return np.allclose(A, A.T.conj())
|
55
|
-
else:
|
56
|
-
return matrix_is_symmetric(A)
|
57
|
-
|
58
|
-
|
59
|
-
class LinearSolver:
|
60
|
-
""" Base class of all linear solvers
|
61
|
-
|
62
|
-
Keyword Args:
|
63
|
-
A (matrix): Optionally provide a matrix, which is used in :method:`update` right away.
|
64
|
-
|
65
|
-
Attributes:
|
66
|
-
defined (bool): Flag if the solver is able to run, e.g. false if some dependent library is not available
|
67
|
-
"""
|
68
|
-
|
69
|
-
defined = True
|
70
|
-
_err_msg = ""
|
71
|
-
|
72
|
-
def __init__(self, A=None):
|
73
|
-
if A is not None:
|
74
|
-
self.update(A)
|
75
|
-
|
76
|
-
def update(self, A):
|
77
|
-
""" Updates with a new matrix of the same structure
|
78
|
-
|
79
|
-
Args:
|
80
|
-
A (matrix): The new matrix of size ``(N, N)``
|
81
|
-
|
82
|
-
Returns:
|
83
|
-
self
|
84
|
-
"""
|
85
|
-
raise NotImplementedError(f"Solver not implemented {self._err_msg}")
|
86
|
-
|
87
|
-
def solve(self, rhs):
|
88
|
-
r""" Solves the linear system of equations :math:`\mathbf{A} \mathbf{x} = \mathbf{b}`
|
89
|
-
|
90
|
-
Args:
|
91
|
-
rhs: Right hand side :math:`\mathbf{b}` of shape ``(N)`` or ``(N, K)`` for multiple right-hand-sides
|
92
|
-
|
93
|
-
Returns:
|
94
|
-
Solution vector :math:`\mathbf{x}` of same shape as :math:`\mathbf{b}`
|
95
|
-
"""
|
96
|
-
raise NotImplementedError(f"Solver not implemented {self._err_msg}")
|
97
|
-
|
98
|
-
def adjoint(self, rhs):
|
99
|
-
r""" Solves the adjoint linear system of equations
|
100
|
-
|
101
|
-
The system of equations is :math:`\mathbf{A}^\text{H} \mathbf{x} = \mathbf{b}` (conjugate transpose) in case of
|
102
|
-
complex matrix or :math:`\mathbf{A}^\text{T} \mathbf{x} = \mathbf{b}` for a real-valued matrix.
|
103
|
-
|
104
|
-
Args:
|
105
|
-
rhs: Right hand side :math:`\mathbf{b}` of shape ``(N)`` or ``(N, K)`` for multiple right-hand-sides
|
106
|
-
|
107
|
-
Returns:
|
108
|
-
Solution vector :math:`\mathbf{x}` of same shape as :math:`\mathbf{b}`
|
109
|
-
"""
|
110
|
-
raise NotImplementedError(f"Solver not implemented {self._err_msg}")
|
111
|
-
|
112
|
-
@staticmethod
|
113
|
-
def residual(A, x, b):
|
114
|
-
r""" Calculates the (relative) residual of the linear system of equations
|
115
|
-
|
116
|
-
The residual is calculated as
|
117
|
-
:math:`r = \frac{\left| \mathbf{A} \mathbf{x} - \mathbf{b} \right|}{\left| \mathbf{b} \right|}`
|
118
|
-
|
119
|
-
Args:
|
120
|
-
A: The matrix
|
121
|
-
x: Solution vector
|
122
|
-
b: Right-hand side
|
123
|
-
|
124
|
-
Returns:
|
125
|
-
Residual value
|
126
|
-
"""
|
127
|
-
return np.linalg.norm(A@x - b) / np.linalg.norm(b)
|
128
|
-
|
129
|
-
|
130
|
-
class LDAWrapper(LinearSolver):
|
131
|
-
r""" Linear dependency aware solver (LDAS)
|
132
|
-
|
133
|
-
This solver uses previous solutions of the system :math:`\mathbf{A} \mathbf{x} = \mathbf{b}` to reduce computational
|
134
|
-
effort. In case the solution :math:`\mathbf{x}` is linearly dependent on the previous solutions, the solution
|
135
|
-
will be nearly free of cost.
|
136
|
-
|
137
|
-
Args:
|
138
|
-
solver: The internal solver to be used
|
139
|
-
tol (optional): Residual tolerance above which the internal solver is used to add a new solution vector.
|
140
|
-
A (optional): The matrix :math:`\mathbf{A}`
|
141
|
-
|
142
|
-
References:
|
143
|
-
|
144
|
-
Koppen, S., van der Kolk, M., van den Boom, S., & Langelaar, M. (2022).
|
145
|
-
Efficient computation of states and sensitivities for compound structural optimisation problems using a Linear Dependency Aware Solver (LDAS).
|
146
|
-
Structural and Multidisciplinary Optimization, 65(9), 273.
|
147
|
-
DOI: 10.1007/s00158-022-03378-8
|
148
|
-
"""
|
149
|
-
def __init__(self, solver: LinearSolver, tol=1e-8, A=None, hermitian=False, symmetric=False):
|
150
|
-
self.solver = solver
|
151
|
-
self.tol = tol
|
152
|
-
self.x_stored = []
|
153
|
-
self.b_stored = []
|
154
|
-
self.xadj_stored = []
|
155
|
-
self.badj_stored = []
|
156
|
-
self.A = None
|
157
|
-
self._did_solve = False # For debugging purposes
|
158
|
-
self._last_rtol = 0.
|
159
|
-
self.hermitian = hermitian
|
160
|
-
self.symmetric = symmetric
|
161
|
-
super().__init__(A)
|
162
|
-
|
163
|
-
def update(self, A):
|
164
|
-
""" Clear the internal stored solution vectors and update the internal ``solver`` """
|
165
|
-
self.A = A
|
166
|
-
self.x_stored.clear()
|
167
|
-
self.b_stored.clear()
|
168
|
-
self.xadj_stored.clear()
|
169
|
-
self.badj_stored.clear()
|
170
|
-
self.solver.update(A)
|
171
|
-
|
172
|
-
def _do_solve_1rhs(self, A, rhs, x_data, b_data, solve_fn):
|
173
|
-
rhs_loc = rhs.copy()
|
174
|
-
sol = 0
|
175
|
-
|
176
|
-
# Check linear dependencies in the rhs using modified Gram-Schmidt
|
177
|
-
for (x, b) in zip(x_data, b_data):
|
178
|
-
alpha = rhs_loc.conj() @ b / (b.conj() @ b)
|
179
|
-
rhs_loc -= alpha * b
|
180
|
-
sol += alpha * x
|
181
|
-
|
182
|
-
# Check tolerance
|
183
|
-
self._last_rtol = 1.0 if len(x_data) == 0 else self.residual(A, sol, rhs)
|
184
|
-
|
185
|
-
if self._last_rtol > self.tol:
|
186
|
-
# Calculate a new solution
|
187
|
-
xnew = solve_fn(rhs_loc)
|
188
|
-
x_data.append(xnew)
|
189
|
-
b_data.append(rhs_loc)
|
190
|
-
sol += xnew
|
191
|
-
self._did_solve = True
|
192
|
-
else:
|
193
|
-
self._did_solve = False
|
194
|
-
|
195
|
-
return sol
|
196
|
-
|
197
|
-
def _solve_1x(self, b):
|
198
|
-
return self._do_solve_1rhs(self.A, b, self.x_stored, self.b_stored, self.solver.solve)
|
199
|
-
|
200
|
-
def _adjoint_1x(self, b):
|
201
|
-
return self._do_solve_1rhs(self.A.conj().T, b, self.xadj_stored, self.badj_stored, self.solver.adjoint)
|
202
|
-
|
203
|
-
def solve(self, rhs):
|
204
|
-
r""" Solves the linear system of equations :math:`\mathbf{A} \mathbf{x} = \mathbf{b}` by performing a modified
|
205
|
-
Gram-Schmidt over the previously calculated solutions :math:`\mathbf{U}` and corresponding right-hand-sides
|
206
|
-
:math:`\mathbf{F}`. This is used to construct an approximate solution
|
207
|
-
:math:`\tilde{\mathbf{x}} = \sum_k \alpha_k \mathbf{u}_k` in the subspace of :math:`\mathbf{U}`.
|
208
|
-
If the residual of :math:`\mathbf{A} \tilde{\mathbf{x}} = \mathbf{b}` is above the tolerance, a new solution
|
209
|
-
:math:`\mathbf{u}_{k+1}` will be added to the database such that
|
210
|
-
:math:`\mathbf{x} = \tilde{\mathbf{x}}+\mathbf{u}_{k+1}` is the solution to the system
|
211
|
-
:math:`\mathbf{A} \mathbf{x} = \mathbf{b}`.
|
212
|
-
|
213
|
-
The right-hand-side :math:`\mathbf{b}` can be of size ``(N)`` or ``(N, K)``, where ``N`` is the size of matrix
|
214
|
-
:math:`\mathbf{A}` and ``K`` is the number of right-hand sides.
|
215
|
-
"""
|
216
|
-
if rhs.ndim == 1:
|
217
|
-
return self._solve_1x(rhs)
|
218
|
-
else: # Multiple rhs
|
219
|
-
sol = []
|
220
|
-
for i in range(rhs.shape[-1]):
|
221
|
-
sol.append(self._solve_1x(rhs[..., i]))
|
222
|
-
return np.stack(sol, axis=-1)
|
223
|
-
|
224
|
-
def adjoint(self, rhs):
|
225
|
-
if self.hermitian:
|
226
|
-
return self.solve(rhs)
|
227
|
-
elif self.symmetric:
|
228
|
-
return self.solve(rhs.conj()).conj()
|
229
|
-
else:
|
230
|
-
if rhs.ndim == 1:
|
231
|
-
return self._adjoint_1x(rhs)
|
232
|
-
else: # Multiple rhs
|
233
|
-
sol = []
|
234
|
-
for i in range(rhs.shape[-1]):
|
235
|
-
sol.append(self._adjoint_1x(rhs[..., i]))
|
236
|
-
return np.stack(sol, axis=-1)
|
File without changes
|
File without changes
|
File without changes
|