Trajectree 0.0.1__py3-none-any.whl → 0.0.3__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.
- trajectree/__init__.py +0 -3
- trajectree/fock_optics/devices.py +1 -1
- trajectree/fock_optics/light_sources.py +2 -2
- trajectree/fock_optics/measurement.py +9 -9
- trajectree/fock_optics/outputs.py +10 -6
- trajectree/fock_optics/utils.py +9 -6
- trajectree/sequence/swap.py +5 -4
- trajectree/trajectory.py +5 -4
- {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/METADATA +2 -3
- trajectree-0.0.3.dist-info/RECORD +16 -0
- trajectree/quimb/docs/_pygments/_pygments_dark.py +0 -118
- trajectree/quimb/docs/_pygments/_pygments_light.py +0 -118
- trajectree/quimb/docs/conf.py +0 -158
- trajectree/quimb/docs/examples/ex_mpi_expm_evo.py +0 -62
- trajectree/quimb/quimb/__init__.py +0 -507
- trajectree/quimb/quimb/calc.py +0 -1491
- trajectree/quimb/quimb/core.py +0 -2279
- trajectree/quimb/quimb/evo.py +0 -712
- trajectree/quimb/quimb/experimental/__init__.py +0 -0
- trajectree/quimb/quimb/experimental/autojittn.py +0 -129
- trajectree/quimb/quimb/experimental/belief_propagation/__init__.py +0 -109
- trajectree/quimb/quimb/experimental/belief_propagation/bp_common.py +0 -397
- trajectree/quimb/quimb/experimental/belief_propagation/d1bp.py +0 -316
- trajectree/quimb/quimb/experimental/belief_propagation/d2bp.py +0 -653
- trajectree/quimb/quimb/experimental/belief_propagation/hd1bp.py +0 -571
- trajectree/quimb/quimb/experimental/belief_propagation/hv1bp.py +0 -775
- trajectree/quimb/quimb/experimental/belief_propagation/l1bp.py +0 -316
- trajectree/quimb/quimb/experimental/belief_propagation/l2bp.py +0 -537
- trajectree/quimb/quimb/experimental/belief_propagation/regions.py +0 -194
- trajectree/quimb/quimb/experimental/cluster_update.py +0 -286
- trajectree/quimb/quimb/experimental/merabuilder.py +0 -865
- trajectree/quimb/quimb/experimental/operatorbuilder/__init__.py +0 -15
- trajectree/quimb/quimb/experimental/operatorbuilder/operatorbuilder.py +0 -1631
- trajectree/quimb/quimb/experimental/schematic.py +0 -7
- trajectree/quimb/quimb/experimental/tn_marginals.py +0 -130
- trajectree/quimb/quimb/experimental/tnvmc.py +0 -1483
- trajectree/quimb/quimb/gates.py +0 -36
- trajectree/quimb/quimb/gen/__init__.py +0 -2
- trajectree/quimb/quimb/gen/operators.py +0 -1167
- trajectree/quimb/quimb/gen/rand.py +0 -713
- trajectree/quimb/quimb/gen/states.py +0 -479
- trajectree/quimb/quimb/linalg/__init__.py +0 -6
- trajectree/quimb/quimb/linalg/approx_spectral.py +0 -1109
- trajectree/quimb/quimb/linalg/autoblock.py +0 -258
- trajectree/quimb/quimb/linalg/base_linalg.py +0 -719
- trajectree/quimb/quimb/linalg/mpi_launcher.py +0 -397
- trajectree/quimb/quimb/linalg/numpy_linalg.py +0 -244
- trajectree/quimb/quimb/linalg/rand_linalg.py +0 -514
- trajectree/quimb/quimb/linalg/scipy_linalg.py +0 -293
- trajectree/quimb/quimb/linalg/slepc_linalg.py +0 -892
- trajectree/quimb/quimb/schematic.py +0 -1518
- trajectree/quimb/quimb/tensor/__init__.py +0 -401
- trajectree/quimb/quimb/tensor/array_ops.py +0 -610
- trajectree/quimb/quimb/tensor/circuit.py +0 -4824
- trajectree/quimb/quimb/tensor/circuit_gen.py +0 -411
- trajectree/quimb/quimb/tensor/contraction.py +0 -336
- trajectree/quimb/quimb/tensor/decomp.py +0 -1255
- trajectree/quimb/quimb/tensor/drawing.py +0 -1646
- trajectree/quimb/quimb/tensor/fitting.py +0 -385
- trajectree/quimb/quimb/tensor/geometry.py +0 -583
- trajectree/quimb/quimb/tensor/interface.py +0 -114
- trajectree/quimb/quimb/tensor/networking.py +0 -1058
- trajectree/quimb/quimb/tensor/optimize.py +0 -1818
- trajectree/quimb/quimb/tensor/tensor_1d.py +0 -4778
- trajectree/quimb/quimb/tensor/tensor_1d_compress.py +0 -1854
- trajectree/quimb/quimb/tensor/tensor_1d_tebd.py +0 -662
- trajectree/quimb/quimb/tensor/tensor_2d.py +0 -5954
- trajectree/quimb/quimb/tensor/tensor_2d_compress.py +0 -96
- trajectree/quimb/quimb/tensor/tensor_2d_tebd.py +0 -1230
- trajectree/quimb/quimb/tensor/tensor_3d.py +0 -2869
- trajectree/quimb/quimb/tensor/tensor_3d_tebd.py +0 -46
- trajectree/quimb/quimb/tensor/tensor_approx_spectral.py +0 -60
- trajectree/quimb/quimb/tensor/tensor_arbgeom.py +0 -3237
- trajectree/quimb/quimb/tensor/tensor_arbgeom_compress.py +0 -565
- trajectree/quimb/quimb/tensor/tensor_arbgeom_tebd.py +0 -1138
- trajectree/quimb/quimb/tensor/tensor_builder.py +0 -5411
- trajectree/quimb/quimb/tensor/tensor_core.py +0 -11179
- trajectree/quimb/quimb/tensor/tensor_dmrg.py +0 -1472
- trajectree/quimb/quimb/tensor/tensor_mera.py +0 -204
- trajectree/quimb/quimb/utils.py +0 -892
- trajectree/quimb/tests/__init__.py +0 -0
- trajectree/quimb/tests/test_accel.py +0 -501
- trajectree/quimb/tests/test_calc.py +0 -788
- trajectree/quimb/tests/test_core.py +0 -847
- trajectree/quimb/tests/test_evo.py +0 -565
- trajectree/quimb/tests/test_gen/__init__.py +0 -0
- trajectree/quimb/tests/test_gen/test_operators.py +0 -361
- trajectree/quimb/tests/test_gen/test_rand.py +0 -296
- trajectree/quimb/tests/test_gen/test_states.py +0 -261
- trajectree/quimb/tests/test_linalg/__init__.py +0 -0
- trajectree/quimb/tests/test_linalg/test_approx_spectral.py +0 -368
- trajectree/quimb/tests/test_linalg/test_base_linalg.py +0 -351
- trajectree/quimb/tests/test_linalg/test_mpi_linalg.py +0 -127
- trajectree/quimb/tests/test_linalg/test_numpy_linalg.py +0 -84
- trajectree/quimb/tests/test_linalg/test_rand_linalg.py +0 -134
- trajectree/quimb/tests/test_linalg/test_slepc_linalg.py +0 -283
- trajectree/quimb/tests/test_tensor/__init__.py +0 -0
- trajectree/quimb/tests/test_tensor/test_belief_propagation/__init__.py +0 -0
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d1bp.py +0 -39
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d2bp.py +0 -67
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hd1bp.py +0 -64
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hv1bp.py +0 -51
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l1bp.py +0 -142
- trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l2bp.py +0 -101
- trajectree/quimb/tests/test_tensor/test_circuit.py +0 -816
- trajectree/quimb/tests/test_tensor/test_contract.py +0 -67
- trajectree/quimb/tests/test_tensor/test_decomp.py +0 -40
- trajectree/quimb/tests/test_tensor/test_mera.py +0 -52
- trajectree/quimb/tests/test_tensor/test_optimizers.py +0 -488
- trajectree/quimb/tests/test_tensor/test_tensor_1d.py +0 -1171
- trajectree/quimb/tests/test_tensor/test_tensor_2d.py +0 -606
- trajectree/quimb/tests/test_tensor/test_tensor_2d_tebd.py +0 -144
- trajectree/quimb/tests/test_tensor/test_tensor_3d.py +0 -123
- trajectree/quimb/tests/test_tensor/test_tensor_arbgeom.py +0 -226
- trajectree/quimb/tests/test_tensor/test_tensor_builder.py +0 -441
- trajectree/quimb/tests/test_tensor/test_tensor_core.py +0 -2066
- trajectree/quimb/tests/test_tensor/test_tensor_dmrg.py +0 -388
- trajectree/quimb/tests/test_tensor/test_tensor_spectral_approx.py +0 -63
- trajectree/quimb/tests/test_tensor/test_tensor_tebd.py +0 -270
- trajectree/quimb/tests/test_utils.py +0 -85
- trajectree-0.0.1.dist-info/RECORD +0 -126
- {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/WHEEL +0 -0
- {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/licenses/LICENSE +0 -0
- {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/top_level.txt +0 -0
|
@@ -1,892 +0,0 @@
|
|
|
1
|
-
"""Interface to slepc4py for solving advanced eigenvalue problems.
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
import numpy as np
|
|
5
|
-
import scipy.sparse as sp
|
|
6
|
-
|
|
7
|
-
import quimb as qu
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# --------------------------------------------------------------------------- #
|
|
11
|
-
# LAZY LOAD MPI/PETSc/SLEPc #
|
|
12
|
-
# --------------------------------------------------------------------------- #
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def get_default_comm():
|
|
16
|
-
"""Define the default communicator."""
|
|
17
|
-
from mpi4py import MPI
|
|
18
|
-
|
|
19
|
-
return MPI.COMM_SELF
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class _PetscSlepcHandler:
|
|
23
|
-
"""Helper class for caching the PETSc and SLEPc imports and making sure
|
|
24
|
-
that the MPI comm they use is aligned.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self):
|
|
28
|
-
self._comm = "__UNINITIALIZED__"
|
|
29
|
-
|
|
30
|
-
def init_petsc_slepc(self, comm):
|
|
31
|
-
import os
|
|
32
|
-
|
|
33
|
-
petsc_arch = os.environ.get("PETSC_ARCH", None)
|
|
34
|
-
|
|
35
|
-
import petsc4py
|
|
36
|
-
|
|
37
|
-
petsc4py.init(args=["-no_signal_handler"], arch=petsc_arch, comm=comm)
|
|
38
|
-
import slepc4py
|
|
39
|
-
|
|
40
|
-
slepc4py.init(args=["-no_signal_handler"], arch=petsc_arch)
|
|
41
|
-
|
|
42
|
-
self._comm = comm
|
|
43
|
-
self._PETSc = petsc4py.PETSc
|
|
44
|
-
self._SLEPc = slepc4py.SLEPc
|
|
45
|
-
|
|
46
|
-
def get_petsc(self, comm=None):
|
|
47
|
-
if comm is None:
|
|
48
|
-
comm = get_default_comm()
|
|
49
|
-
|
|
50
|
-
if comm != self._comm:
|
|
51
|
-
self.init_petsc_slepc(comm)
|
|
52
|
-
|
|
53
|
-
return self._PETSc, comm
|
|
54
|
-
|
|
55
|
-
def get_slepc(self, comm=None):
|
|
56
|
-
if comm is None:
|
|
57
|
-
comm = get_default_comm()
|
|
58
|
-
|
|
59
|
-
if comm != self._comm:
|
|
60
|
-
self.init_petsc_slepc(comm)
|
|
61
|
-
|
|
62
|
-
return self._SLEPc, comm
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
_petsc_slepc_handler = _PetscSlepcHandler()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def get_petsc(comm=None):
|
|
69
|
-
global _petsc_slepc_handler
|
|
70
|
-
return _petsc_slepc_handler.get_petsc(comm=comm)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def get_slepc(comm=None):
|
|
74
|
-
global _petsc_slepc_handler
|
|
75
|
-
return _petsc_slepc_handler.get_slepc(comm=comm)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# --------------------------------------------------------------------------- #
|
|
79
|
-
# PETSc FUNCTIONS #
|
|
80
|
-
# --------------------------------------------------------------------------- #
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class PetscLinearOperatorContext:
|
|
84
|
-
def __init__(self, lo):
|
|
85
|
-
self.lo = lo
|
|
86
|
-
self.real = lo.dtype in (float, np.float64)
|
|
87
|
-
|
|
88
|
-
def mult(self, _, xvec, yvec):
|
|
89
|
-
x = xvec.getArray(readonly=True)
|
|
90
|
-
y = self.lo.matvec(x)
|
|
91
|
-
yvec.setArray(y)
|
|
92
|
-
|
|
93
|
-
def multHermitian(self, _, xvec, yvec):
|
|
94
|
-
x = xvec.getArray(readonly=True)
|
|
95
|
-
y = self.lo.rmatvec(x)
|
|
96
|
-
yvec.setArray(y)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def linear_operator_2_petsc_shell(lo, comm=None):
|
|
100
|
-
PETSc, comm = get_petsc(comm=comm)
|
|
101
|
-
context = PetscLinearOperatorContext(lo)
|
|
102
|
-
A = PETSc.Mat().createPython(lo.shape, context, comm=comm)
|
|
103
|
-
A.setUp()
|
|
104
|
-
return A
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def slice_sparse_matrix_to_components(mat, ri, rf):
|
|
108
|
-
"""Slice the matrix `mat` between indices `ri` and `rf` -- for csr or bsr."""
|
|
109
|
-
return (
|
|
110
|
-
mat.indptr[ri : rf + 1] - mat.indptr[ri],
|
|
111
|
-
mat.indices[mat.indptr[ri] : mat.indptr[rf]],
|
|
112
|
-
mat.data[mat.indptr[ri] : mat.indptr[rf]],
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def convert_mat_to_petsc(mat, comm=None):
|
|
117
|
-
"""Convert a matrix to the relevant PETSc type, currently
|
|
118
|
-
only supports csr, bsr and dense matrices formats.
|
|
119
|
-
|
|
120
|
-
Parameters
|
|
121
|
-
----------
|
|
122
|
-
mat : dense, sparse, LinearOperator or Lazy matrix.
|
|
123
|
-
The operator to convert.
|
|
124
|
-
comm : mpi4py.MPI.Comm instance
|
|
125
|
-
The mpi communicator.
|
|
126
|
-
|
|
127
|
-
Returns
|
|
128
|
-
-------
|
|
129
|
-
pmat : petsc4py.PETSc.Mat
|
|
130
|
-
The matrix in petsc form - only the local part if running
|
|
131
|
-
across several mpi processes.
|
|
132
|
-
"""
|
|
133
|
-
if isinstance(mat, sp.linalg.LinearOperator):
|
|
134
|
-
return linear_operator_2_petsc_shell(mat, comm=comm)
|
|
135
|
-
|
|
136
|
-
PETSc, comm = get_petsc(comm=comm)
|
|
137
|
-
mpi_sz = comm.Get_size()
|
|
138
|
-
pmat = PETSc.Mat()
|
|
139
|
-
|
|
140
|
-
# retrieve before mat is possibly built into sliced matrix
|
|
141
|
-
shape = mat.shape
|
|
142
|
-
|
|
143
|
-
pmat.create(comm=comm)
|
|
144
|
-
pmat.setSizes(shape)
|
|
145
|
-
pmat.setFromOptions()
|
|
146
|
-
pmat.setUp()
|
|
147
|
-
ri, rf = pmat.getOwnershipRange()
|
|
148
|
-
|
|
149
|
-
# only consider the operator already sliced if owns whole
|
|
150
|
-
sliced = mpi_sz == 1
|
|
151
|
-
if isinstance(mat, qu.Lazy):
|
|
152
|
-
# operator hasn't been constructed yet
|
|
153
|
-
try:
|
|
154
|
-
# try and and lazily construct with slicing
|
|
155
|
-
mat = mat(ownership=(ri, rf))
|
|
156
|
-
sliced = True
|
|
157
|
-
except TypeError:
|
|
158
|
-
mat = mat()
|
|
159
|
-
|
|
160
|
-
# Sparse compressed or block row matrix
|
|
161
|
-
if sp.issparse(mat):
|
|
162
|
-
mat.sort_indices()
|
|
163
|
-
|
|
164
|
-
if sliced:
|
|
165
|
-
csr = (mat.indptr, mat.indices, mat.data)
|
|
166
|
-
else:
|
|
167
|
-
csr = slice_sparse_matrix_to_components(mat, ri, rf)
|
|
168
|
-
|
|
169
|
-
if sp.isspmatrix_csr(mat):
|
|
170
|
-
pmat.createAIJ(size=shape, nnz=mat.nnz, csr=csr, comm=comm)
|
|
171
|
-
elif sp.isspmatrix_bsr(mat):
|
|
172
|
-
pmat.createBAIJ(
|
|
173
|
-
size=shape,
|
|
174
|
-
bsize=mat.blocksize,
|
|
175
|
-
nnz=mat.nnz,
|
|
176
|
-
csr=csr,
|
|
177
|
-
comm=comm,
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
# Dense matrix
|
|
181
|
-
else:
|
|
182
|
-
if mpi_sz > 1 and not sliced:
|
|
183
|
-
pmat.createDense(size=shape, array=mat[ri:rf, :], comm=comm)
|
|
184
|
-
else:
|
|
185
|
-
pmat.createDense(size=shape, array=mat, comm=comm)
|
|
186
|
-
|
|
187
|
-
pmat.assemble()
|
|
188
|
-
return pmat
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def convert_vec_to_petsc(vec, comm=None):
|
|
192
|
-
"""Convert a vector/array to the PETSc form.
|
|
193
|
-
|
|
194
|
-
Parameters
|
|
195
|
-
----------
|
|
196
|
-
vec : vector-like
|
|
197
|
-
Numpy array, will be unravelled to one dimension.
|
|
198
|
-
comm : mpi4py.MPI.Comm instance
|
|
199
|
-
The mpi communicator.
|
|
200
|
-
|
|
201
|
-
Returns
|
|
202
|
-
-------
|
|
203
|
-
pvec : petsc4py.PETSc.Vec
|
|
204
|
-
The vector in petsc form - only the local part if running
|
|
205
|
-
across several mpi processes.
|
|
206
|
-
"""
|
|
207
|
-
PETSc, comm = get_petsc(comm=comm)
|
|
208
|
-
mpi_sz = comm.Get_size()
|
|
209
|
-
pvec = PETSc.Vec()
|
|
210
|
-
|
|
211
|
-
# get shape before slicing
|
|
212
|
-
size = max(vec.shape)
|
|
213
|
-
|
|
214
|
-
pvec.create(comm=comm)
|
|
215
|
-
pvec.setSizes(size)
|
|
216
|
-
pvec.setFromOptions()
|
|
217
|
-
pvec.setUp()
|
|
218
|
-
ri, rf = pvec.getOwnershipRange()
|
|
219
|
-
|
|
220
|
-
# only consider the vector already sliced if owns whole
|
|
221
|
-
sliced = mpi_sz == 1
|
|
222
|
-
if isinstance(vec, qu.Lazy):
|
|
223
|
-
# vector hasn't been constructed yet
|
|
224
|
-
try:
|
|
225
|
-
# try and and lazily construct with slicing
|
|
226
|
-
vec = vec(ownership=(ri, rf))
|
|
227
|
-
sliced = True
|
|
228
|
-
except TypeError:
|
|
229
|
-
vec = vec()
|
|
230
|
-
|
|
231
|
-
array = np.asarray(vec).reshape(-1)
|
|
232
|
-
|
|
233
|
-
if not sliced:
|
|
234
|
-
array = array[ri:rf]
|
|
235
|
-
|
|
236
|
-
pvec.createWithArray(array, comm=comm)
|
|
237
|
-
return pvec
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
def new_petsc_vec(d, comm=None):
|
|
241
|
-
"""Create an empty petsc vector of size `d`.
|
|
242
|
-
|
|
243
|
-
Parameters
|
|
244
|
-
----------
|
|
245
|
-
d : int
|
|
246
|
-
Dimension of vector, i.e. the global size.
|
|
247
|
-
comm : mpi4py.MPI.Comm instance
|
|
248
|
-
The mpi communicator.
|
|
249
|
-
|
|
250
|
-
Returns
|
|
251
|
-
-------
|
|
252
|
-
pvec : petsc4py.PETSc.Vec
|
|
253
|
-
An empty vector in petsc form - only the local part if running
|
|
254
|
-
across several mpi processes.
|
|
255
|
-
"""
|
|
256
|
-
PETSc, comm = get_petsc(comm=comm)
|
|
257
|
-
pvec = PETSc.Vec()
|
|
258
|
-
pvec.create(comm=comm)
|
|
259
|
-
pvec.setSizes(d)
|
|
260
|
-
pvec.setFromOptions()
|
|
261
|
-
pvec.setUp()
|
|
262
|
-
return pvec
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
def gather_petsc_array(x, comm, out_shape=None):
|
|
266
|
-
"""Gather the petsc vector/matrix `x` to a single array on the master
|
|
267
|
-
process, assuming that owernership is sliced along the first dimension.
|
|
268
|
-
|
|
269
|
-
Parameters
|
|
270
|
-
----------
|
|
271
|
-
x : petsc4py.PETSc Mat or Vec
|
|
272
|
-
Distributed petsc array to gather.
|
|
273
|
-
comm : mpi4py.MPI.COMM
|
|
274
|
-
MPI communicator
|
|
275
|
-
out_shape : tuple, optional
|
|
276
|
-
If not None, reshape the output array to this.
|
|
277
|
-
|
|
278
|
-
Returns
|
|
279
|
-
-------
|
|
280
|
-
gathered : np.array master, None on workers (rank > 0)
|
|
281
|
-
"""
|
|
282
|
-
# get local numpy array
|
|
283
|
-
lx = x.getArray()
|
|
284
|
-
ox = np.empty(2, dtype=int)
|
|
285
|
-
ox[:] = x.getOwnershipRange()
|
|
286
|
-
|
|
287
|
-
# master only
|
|
288
|
-
if comm.Get_rank() == 0:
|
|
289
|
-
# create total array
|
|
290
|
-
ax = np.empty(x.getSize(), dtype=lx.dtype)
|
|
291
|
-
# set master's portion
|
|
292
|
-
ax[ox[0] : ox[1], ...] = lx
|
|
293
|
-
|
|
294
|
-
# get ownership ranges and data from worker processes
|
|
295
|
-
for i in range(1, comm.Get_size()):
|
|
296
|
-
comm.Recv(ox, source=i, tag=11)
|
|
297
|
-
|
|
298
|
-
# receive worker's part of ouput vector
|
|
299
|
-
comm.Recv(ax[ox[0] : ox[1], ...], source=i, tag=42)
|
|
300
|
-
|
|
301
|
-
if out_shape is not None:
|
|
302
|
-
ax = ax.reshape(*out_shape)
|
|
303
|
-
|
|
304
|
-
# Worker only
|
|
305
|
-
else:
|
|
306
|
-
# send ownership range
|
|
307
|
-
comm.Send(ox, dest=0, tag=11)
|
|
308
|
-
# send local portion of eigenvectors as buffer
|
|
309
|
-
comm.Send(lx, dest=0, tag=42)
|
|
310
|
-
ax = None
|
|
311
|
-
|
|
312
|
-
return ax
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
def normalize_real_part(vecs, transposed=False):
|
|
316
|
-
"""Take the real part of a set of vectors and normalize it. This is used
|
|
317
|
-
for returning real eigenvectors even when the PETSc scalar type is complex.
|
|
318
|
-
"""
|
|
319
|
-
k = vecs.shape[0] if transposed else vecs.shape[1]
|
|
320
|
-
|
|
321
|
-
vecs = np.ascontiguousarray(vecs.real)
|
|
322
|
-
for i in range(k):
|
|
323
|
-
where = (i, Ellipsis) if transposed else (Ellipsis, i)
|
|
324
|
-
qu.nmlz(vecs[where], inplace=True)
|
|
325
|
-
|
|
326
|
-
return vecs
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
# --------------------------------------------------------------------------- #
|
|
330
|
-
# SLEPc FUNCTIONS #
|
|
331
|
-
# --------------------------------------------------------------------------- #
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
def _init_krylov_subspace(
|
|
335
|
-
comm=None,
|
|
336
|
-
tol=None,
|
|
337
|
-
maxiter=None,
|
|
338
|
-
KSPType="preonly",
|
|
339
|
-
PCType="lu",
|
|
340
|
-
PCFactorSolverType="mumps",
|
|
341
|
-
):
|
|
342
|
-
"""Initialise a krylov subspace and preconditioner."""
|
|
343
|
-
PETSc, comm = get_petsc(comm=comm)
|
|
344
|
-
K = PETSc.KSP().create(comm=comm)
|
|
345
|
-
K.setType(KSPType)
|
|
346
|
-
K.setTolerances(rtol=tol, max_it=maxiter)
|
|
347
|
-
|
|
348
|
-
if PCType:
|
|
349
|
-
PC = K.getPC()
|
|
350
|
-
PC.setType(PCType)
|
|
351
|
-
if PCFactorSolverType:
|
|
352
|
-
PC.setFactorSolverType(PCFactorSolverType)
|
|
353
|
-
PC.setFactorShift(PETSc.Mat.FactorShiftType.POSITIVE_DEFINITE)
|
|
354
|
-
PC.setFromOptions()
|
|
355
|
-
K.setPC(PC)
|
|
356
|
-
|
|
357
|
-
K.setFromOptions()
|
|
358
|
-
return K
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
def _init_spectral_inverter(
|
|
362
|
-
STType="sinvert",
|
|
363
|
-
KSPType="preonly",
|
|
364
|
-
PCType="lu",
|
|
365
|
-
PCFactorSolverType="mumps",
|
|
366
|
-
comm=None,
|
|
367
|
-
):
|
|
368
|
-
"""Create a slepc spectral transformation object with specified solver."""
|
|
369
|
-
SLEPc, comm = get_slepc(comm=comm)
|
|
370
|
-
S = SLEPc.ST().create(comm=comm)
|
|
371
|
-
S.setType(STType)
|
|
372
|
-
# set the krylov subspace and preconditioner.
|
|
373
|
-
if KSPType:
|
|
374
|
-
K = _init_krylov_subspace(
|
|
375
|
-
KSPType=KSPType,
|
|
376
|
-
PCType=PCType,
|
|
377
|
-
comm=comm,
|
|
378
|
-
PCFactorSolverType=PCFactorSolverType,
|
|
379
|
-
)
|
|
380
|
-
S.setKSP(K)
|
|
381
|
-
S.setFromOptions()
|
|
382
|
-
return S
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
_WHICH_SCIPY_TO_SLEPC = {
|
|
386
|
-
"LM": "LARGEST_MAGNITUDE",
|
|
387
|
-
"SM": "SMALLEST_MAGNITUDE",
|
|
388
|
-
"LR": "LARGEST_REAL",
|
|
389
|
-
"LA": "LARGEST_REAL",
|
|
390
|
-
"SR": "SMALLEST_REAL",
|
|
391
|
-
"SA": "SMALLEST_REAL",
|
|
392
|
-
"LI": "LARGEST_IMAGINARY",
|
|
393
|
-
"SI": "SMALLEST_IMAGINARY",
|
|
394
|
-
"TM": "TARGET_MAGNITUDE",
|
|
395
|
-
"TR": "TARGET_REAL",
|
|
396
|
-
"TI": "TARGET_IMAGINARY",
|
|
397
|
-
"ALL": "ALL",
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
def _which_scipy_to_slepc(which):
|
|
402
|
-
SLEPc = get_slepc()[0]
|
|
403
|
-
return getattr(SLEPc.EPS.Which, _WHICH_SCIPY_TO_SLEPC[which.upper()])
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
def _init_eigensolver(
|
|
407
|
-
k=6,
|
|
408
|
-
which="LM",
|
|
409
|
-
sigma=None,
|
|
410
|
-
isherm=True,
|
|
411
|
-
isgen=False,
|
|
412
|
-
EPSType=None,
|
|
413
|
-
st_opts=None,
|
|
414
|
-
tol=None,
|
|
415
|
-
A_is_linop=False,
|
|
416
|
-
B_is_linop=False,
|
|
417
|
-
maxiter=None,
|
|
418
|
-
ncv=None,
|
|
419
|
-
l_win=None,
|
|
420
|
-
comm=None,
|
|
421
|
-
):
|
|
422
|
-
"""Create an advanced eigensystem solver
|
|
423
|
-
|
|
424
|
-
Parameters
|
|
425
|
-
----------
|
|
426
|
-
sigma :
|
|
427
|
-
Target eigenvalue.
|
|
428
|
-
isherm :
|
|
429
|
-
Whether problem is hermitian or not.
|
|
430
|
-
|
|
431
|
-
Returns
|
|
432
|
-
-------
|
|
433
|
-
SLEPc solver ready to be called.
|
|
434
|
-
"""
|
|
435
|
-
SLEPc, comm = get_slepc(comm=comm)
|
|
436
|
-
|
|
437
|
-
eigensolver = SLEPc.EPS().create(comm=comm)
|
|
438
|
-
|
|
439
|
-
if st_opts is None:
|
|
440
|
-
st_opts = {}
|
|
441
|
-
|
|
442
|
-
if l_win is not None:
|
|
443
|
-
EPSType = {"ciss": "ciss", None: "ciss"}[EPSType]
|
|
444
|
-
which = "ALL"
|
|
445
|
-
rg = eigensolver.getRG()
|
|
446
|
-
rg.setType(SLEPc.RG.Type.INTERVAL)
|
|
447
|
-
rg.setIntervalEndpoints(*l_win, -0.1, 0.1)
|
|
448
|
-
else:
|
|
449
|
-
eigensolver.setDimensions(k, ncv)
|
|
450
|
-
|
|
451
|
-
internal = (sigma is not None) or (l_win is not None)
|
|
452
|
-
|
|
453
|
-
# pick right backend
|
|
454
|
-
if EPSType is None:
|
|
455
|
-
if (isgen and B_is_linop) or (internal and A_is_linop):
|
|
456
|
-
EPSType = "gd"
|
|
457
|
-
else:
|
|
458
|
-
EPSType = "krylovschur"
|
|
459
|
-
|
|
460
|
-
# set some preconditioning defaults for 'gd' and 'lobpcg'
|
|
461
|
-
if EPSType in ("gd", "lobpcg", "blopex", "primme"):
|
|
462
|
-
st_opts.setdefault("STType", "precond")
|
|
463
|
-
st_opts.setdefault("KSPType", "preonly")
|
|
464
|
-
st_opts.setdefault("PCType", "none")
|
|
465
|
-
|
|
466
|
-
# set some preconditioning defaults for 'jd'
|
|
467
|
-
elif EPSType == "jd":
|
|
468
|
-
st_opts.setdefault("STType", "precond")
|
|
469
|
-
st_opts.setdefault("KSPType", "bcgs")
|
|
470
|
-
st_opts.setdefault("PCType", "none")
|
|
471
|
-
|
|
472
|
-
# set the spectral inverter / preconditioner.
|
|
473
|
-
if st_opts or internal:
|
|
474
|
-
st = _init_spectral_inverter(comm=comm, **st_opts)
|
|
475
|
-
eigensolver.setST(st)
|
|
476
|
-
|
|
477
|
-
# NB: `setTarget` must be called *after* `setST`.
|
|
478
|
-
if sigma is not None:
|
|
479
|
-
which = "TR"
|
|
480
|
-
eigensolver.setTarget(sigma)
|
|
481
|
-
|
|
482
|
-
if A_is_linop:
|
|
483
|
-
st.setMatMode(SLEPc.ST.MatMode.SHELL)
|
|
484
|
-
|
|
485
|
-
_EPS_PROB_TYPES = {
|
|
486
|
-
(False, False): SLEPc.EPS.ProblemType.NHEP,
|
|
487
|
-
(True, False): SLEPc.EPS.ProblemType.HEP,
|
|
488
|
-
(False, True): SLEPc.EPS.ProblemType.GNHEP,
|
|
489
|
-
(True, True): SLEPc.EPS.ProblemType.GHEP,
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
eigensolver.setType(EPSType)
|
|
493
|
-
eigensolver.setProblemType(_EPS_PROB_TYPES[(isherm, isgen)])
|
|
494
|
-
eigensolver.setWhichEigenpairs(_which_scipy_to_slepc(which))
|
|
495
|
-
eigensolver.setConvergenceTest(SLEPc.EPS.Conv.REL)
|
|
496
|
-
eigensolver.setTolerances(tol=tol, max_it=maxiter)
|
|
497
|
-
eigensolver.setFromOptions()
|
|
498
|
-
return eigensolver
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
def eigs_slepc(
|
|
502
|
-
A,
|
|
503
|
-
k,
|
|
504
|
-
*,
|
|
505
|
-
B=None,
|
|
506
|
-
which=None,
|
|
507
|
-
sigma=None,
|
|
508
|
-
isherm=True,
|
|
509
|
-
P=None,
|
|
510
|
-
v0=None,
|
|
511
|
-
ncv=None,
|
|
512
|
-
return_vecs=True,
|
|
513
|
-
sort=True,
|
|
514
|
-
EPSType=None,
|
|
515
|
-
return_all_conv=False,
|
|
516
|
-
st_opts=None,
|
|
517
|
-
tol=None,
|
|
518
|
-
maxiter=None,
|
|
519
|
-
l_win=None,
|
|
520
|
-
comm=None,
|
|
521
|
-
):
|
|
522
|
-
"""Solve a matrix using the advanced eigensystem solver
|
|
523
|
-
|
|
524
|
-
Parameters
|
|
525
|
-
----------
|
|
526
|
-
A : dense-matrix, sparse-matrix, LinearOperator or callable
|
|
527
|
-
Operator to solve.
|
|
528
|
-
k : int, optional
|
|
529
|
-
Number of requested eigenpairs.
|
|
530
|
-
B : dense-matrix, sparse-matrix, LinearOperator or callable
|
|
531
|
-
The RHS operator defining a generalized eigenproblem.
|
|
532
|
-
which : {"LM": "SM", "LR", "LA", "SR", "SA", "LI", "SI", "TM", "TR", "TI"}
|
|
533
|
-
Which eigenpairs to target. See :func:`scipy.sparse.linalg.eigs`.
|
|
534
|
-
sigma : float, optional
|
|
535
|
-
Target eigenvalue, implies ``which='TR'`` if this is not set but
|
|
536
|
-
``sigma`` is.
|
|
537
|
-
isherm : bool, optional
|
|
538
|
-
Whether problem is hermitian or not.
|
|
539
|
-
P : dense-matrix, sparse-matrix, LinearOperator or callable
|
|
540
|
-
Perform the eigensolve in the subspace defined by this projector.
|
|
541
|
-
v0 : 1D-array like, optional
|
|
542
|
-
Initial iteration vector, e.g., informed guess at eigenvector.
|
|
543
|
-
ncv : int, optional
|
|
544
|
-
Subspace size, defaults to ``min(20, 2 * k)``.
|
|
545
|
-
return_vecs : bool, optional
|
|
546
|
-
Whether to return the eigenvectors.
|
|
547
|
-
sort : bool, optional
|
|
548
|
-
Whether to sort the eigenpairs in ascending real value.
|
|
549
|
-
EPSType : {"krylovschur", 'gd', 'lobpcg', 'jd', 'ciss'}, optional
|
|
550
|
-
SLEPc eigensolver type to use, see slepc4py.EPSType.
|
|
551
|
-
return_all_conv : bool, optional
|
|
552
|
-
Whether to return converged eigenpairs beyond requested subspace size
|
|
553
|
-
st_opts : dict, optional
|
|
554
|
-
options to send to the eigensolver internal inverter.
|
|
555
|
-
tol : float, optional
|
|
556
|
-
Tolerance.
|
|
557
|
-
maxiter : int, optional
|
|
558
|
-
Maximum number of iterations.
|
|
559
|
-
comm : mpi4py communicator, optional
|
|
560
|
-
MPI communicator, defaults to ``COMM_SELF`` for a single process solve.
|
|
561
|
-
|
|
562
|
-
Returns
|
|
563
|
-
-------
|
|
564
|
-
lk : (k,) array
|
|
565
|
-
The eigenvalues.
|
|
566
|
-
vk : (m, k) array
|
|
567
|
-
Corresponding eigenvectors (if ``return_vecs=True``).
|
|
568
|
-
"""
|
|
569
|
-
if comm is None:
|
|
570
|
-
comm = get_default_comm()
|
|
571
|
-
|
|
572
|
-
A_is_linop = isinstance(A, sp.linalg.LinearOperator)
|
|
573
|
-
B_is_linop = isinstance(B, sp.linalg.LinearOperator)
|
|
574
|
-
isgen = B is not None
|
|
575
|
-
|
|
576
|
-
eigensolver = _init_eigensolver(
|
|
577
|
-
which=(
|
|
578
|
-
"SA"
|
|
579
|
-
if (which is None) and (sigma is None)
|
|
580
|
-
else "TR"
|
|
581
|
-
if (which is None) and (sigma is not None)
|
|
582
|
-
else which
|
|
583
|
-
),
|
|
584
|
-
EPSType=EPSType,
|
|
585
|
-
k=k,
|
|
586
|
-
sigma=sigma,
|
|
587
|
-
isherm=isherm,
|
|
588
|
-
tol=tol,
|
|
589
|
-
ncv=ncv,
|
|
590
|
-
maxiter=maxiter,
|
|
591
|
-
st_opts=st_opts,
|
|
592
|
-
comm=comm,
|
|
593
|
-
l_win=l_win,
|
|
594
|
-
isgen=isgen,
|
|
595
|
-
A_is_linop=A_is_linop,
|
|
596
|
-
B_is_linop=B_is_linop,
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
# set up the initial operators and solver
|
|
600
|
-
pA = convert_mat_to_petsc(A, comm=comm)
|
|
601
|
-
pB = convert_mat_to_petsc(B, comm=comm) if isgen else None
|
|
602
|
-
|
|
603
|
-
if P is not None:
|
|
604
|
-
pP = convert_mat_to_petsc(P, comm=comm)
|
|
605
|
-
pA = pP.transposeMatMult(pA.matMult(pP))
|
|
606
|
-
|
|
607
|
-
eigensolver.setOperators(pA, pB)
|
|
608
|
-
if v0 is not None:
|
|
609
|
-
eigensolver.setInitialSpace(convert_vec_to_petsc(v0, comm=comm))
|
|
610
|
-
eigensolver.solve()
|
|
611
|
-
|
|
612
|
-
# work out how many eigenpairs to retrieve
|
|
613
|
-
nconv = eigensolver.getConverged()
|
|
614
|
-
k = nconv if (return_all_conv or l_win is not None) else k
|
|
615
|
-
if nconv < k:
|
|
616
|
-
raise RuntimeError(
|
|
617
|
-
"SLEPC eigs did not find enough eigenpairs, "
|
|
618
|
-
f"wanted: {k}, found: {nconv}."
|
|
619
|
-
)
|
|
620
|
-
|
|
621
|
-
# get eigenvalues
|
|
622
|
-
rank = comm.Get_rank()
|
|
623
|
-
if rank == 0:
|
|
624
|
-
lk = np.asarray([eigensolver.getEigenvalue(i) for i in range(k)])
|
|
625
|
-
lk = lk.real if isherm else lk
|
|
626
|
-
else:
|
|
627
|
-
res = None
|
|
628
|
-
|
|
629
|
-
# gather eigenvectors
|
|
630
|
-
if return_vecs:
|
|
631
|
-
pvec = pA.getVecLeft()
|
|
632
|
-
|
|
633
|
-
def get_vecs_local():
|
|
634
|
-
for i in range(k):
|
|
635
|
-
eigensolver.getEigenvector(i, pvec)
|
|
636
|
-
|
|
637
|
-
if P is not None:
|
|
638
|
-
pvecP = pP.getVecLeft()
|
|
639
|
-
pP.mult(pvec, pvecP)
|
|
640
|
-
|
|
641
|
-
yield gather_petsc_array(
|
|
642
|
-
pvecP if P is not None else pvec,
|
|
643
|
-
comm=comm,
|
|
644
|
-
out_shape=(-1, 1),
|
|
645
|
-
)
|
|
646
|
-
|
|
647
|
-
lvecs = tuple(get_vecs_local())
|
|
648
|
-
if rank == 0:
|
|
649
|
-
vk = np.concatenate(lvecs, axis=1)
|
|
650
|
-
if sort:
|
|
651
|
-
sortinds = np.argsort(lk)
|
|
652
|
-
lk, vk = lk[sortinds], vk[:, sortinds]
|
|
653
|
-
|
|
654
|
-
# check if input matrix was real -> use real output when
|
|
655
|
-
# petsc compiled with complex scalars and thus outputs complex
|
|
656
|
-
convert = (
|
|
657
|
-
isherm
|
|
658
|
-
and np.issubdtype(A.dtype, np.floating)
|
|
659
|
-
and np.issubdtype(vk.dtype, np.complexfloating)
|
|
660
|
-
)
|
|
661
|
-
if convert:
|
|
662
|
-
vk = normalize_real_part(vk)
|
|
663
|
-
|
|
664
|
-
res = lk, qu.qarray(vk)
|
|
665
|
-
elif rank == 0:
|
|
666
|
-
res = np.sort(lk) if sort else lk
|
|
667
|
-
|
|
668
|
-
eigensolver.destroy()
|
|
669
|
-
return res
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
# ----------------------------------- SVD ----------------------------------- #
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
def _init_svd_solver(
|
|
676
|
-
nsv=6, SVDType="cross", tol=None, maxiter=None, ncv=None, comm=None
|
|
677
|
-
):
|
|
678
|
-
SLEPc, comm = get_slepc(comm=comm)
|
|
679
|
-
svd_solver = SLEPc.SVD().create(comm=comm)
|
|
680
|
-
svd_solver.setType(SVDType)
|
|
681
|
-
svd_solver.setTolerances(tol=tol, max_it=maxiter)
|
|
682
|
-
svd_solver.setDimensions(nsv=nsv, ncv=ncv)
|
|
683
|
-
svd_solver.setFromOptions()
|
|
684
|
-
return svd_solver
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
def svds_slepc(
|
|
688
|
-
A,
|
|
689
|
-
k=6,
|
|
690
|
-
ncv=None,
|
|
691
|
-
return_vecs=True,
|
|
692
|
-
SVDType="cross",
|
|
693
|
-
return_all_conv=False,
|
|
694
|
-
tol=None,
|
|
695
|
-
maxiter=None,
|
|
696
|
-
comm=None,
|
|
697
|
-
):
|
|
698
|
-
"""Find the singular values for sparse matrix `a`.
|
|
699
|
-
|
|
700
|
-
Parameters
|
|
701
|
-
----------
|
|
702
|
-
A : sparse matrix in csr format
|
|
703
|
-
The matrix to solve.
|
|
704
|
-
k : int
|
|
705
|
-
Number of requested singular values.
|
|
706
|
-
method : {"cross", "cyclic", "lanczos", "trlanczos"}
|
|
707
|
-
Solver method to use.
|
|
708
|
-
|
|
709
|
-
Returns
|
|
710
|
-
-------
|
|
711
|
-
U : (m, k) array
|
|
712
|
-
Left singular vectors (if ``return_vecs=True``) as columns.
|
|
713
|
-
s : (k,) array
|
|
714
|
-
Singular values.
|
|
715
|
-
VH : (k, n) array
|
|
716
|
-
Right singular vectors (if ``return_vecs=True``) as rows.
|
|
717
|
-
"""
|
|
718
|
-
if comm is None:
|
|
719
|
-
comm = get_default_comm()
|
|
720
|
-
|
|
721
|
-
pA = convert_mat_to_petsc(A, comm=comm)
|
|
722
|
-
|
|
723
|
-
svd_solver = _init_svd_solver(
|
|
724
|
-
nsv=k, SVDType=SVDType, tol=tol, maxiter=maxiter, ncv=ncv, comm=comm
|
|
725
|
-
)
|
|
726
|
-
svd_solver.setOperator(pA)
|
|
727
|
-
svd_solver.solve()
|
|
728
|
-
|
|
729
|
-
nconv = svd_solver.getConverged()
|
|
730
|
-
k = nconv if return_all_conv else k
|
|
731
|
-
if nconv < k:
|
|
732
|
-
raise RuntimeError(
|
|
733
|
-
"SLEPC svds did not find enough singular triplets, "
|
|
734
|
-
f"wanted: {k}, found: {nconv}."
|
|
735
|
-
)
|
|
736
|
-
|
|
737
|
-
rank = comm.Get_rank()
|
|
738
|
-
|
|
739
|
-
if return_vecs:
|
|
740
|
-
|
|
741
|
-
def usv_getter():
|
|
742
|
-
v, u = pA.createVecs()
|
|
743
|
-
for i in range(k):
|
|
744
|
-
s = svd_solver.getSingularTriplet(i, u, v)
|
|
745
|
-
lu = gather_petsc_array(u, comm=comm, out_shape=(-1, 1))
|
|
746
|
-
lv = gather_petsc_array(v, comm=comm, out_shape=(1, -1))
|
|
747
|
-
yield lu, s, lv
|
|
748
|
-
|
|
749
|
-
lus, sk, lvs = zip(*usv_getter())
|
|
750
|
-
sk = np.asarray(sk)
|
|
751
|
-
|
|
752
|
-
if rank == 0:
|
|
753
|
-
uk = qu.qarray(np.concatenate(lus, axis=1))
|
|
754
|
-
vtk = qu.qarray(np.concatenate(lvs, axis=0).conjugate())
|
|
755
|
-
|
|
756
|
-
# # check if input matrix was real -> use real output when
|
|
757
|
-
# # petsc compiled with complex scalars and thus outputs complex
|
|
758
|
-
# convert = (np.issubdtype(A.dtype, np.floating) and
|
|
759
|
-
# np.issubdtype(uk.dtype, np.complexfloating))
|
|
760
|
-
# if convert:
|
|
761
|
-
# uk = normalize_real_part(uk)
|
|
762
|
-
# vtk = normalize_real_part(uk, transposed=True)
|
|
763
|
-
|
|
764
|
-
res = uk, sk, vtk
|
|
765
|
-
else:
|
|
766
|
-
res = np.asarray([svd_solver.getValue(i) for i in range(k)])
|
|
767
|
-
|
|
768
|
-
svd_solver.destroy()
|
|
769
|
-
return res if rank == 0 else None
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
# ------------------------ matrix multiply function ------------------------- #
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
def mfn_multiply_slepc(
|
|
776
|
-
mat, vec, fntype="exp", MFNType="AUTO", comm=None, isherm=False
|
|
777
|
-
):
|
|
778
|
-
"""Compute the action of ``func(mat) @ vec``.
|
|
779
|
-
|
|
780
|
-
Parameters
|
|
781
|
-
----------
|
|
782
|
-
mat : operator
|
|
783
|
-
Operator to compute function action of.
|
|
784
|
-
vec : vector-like
|
|
785
|
-
Vector to compute matrix function action on.
|
|
786
|
-
func : {'exp', 'sqrt', 'log'}, optional
|
|
787
|
-
Function to use.
|
|
788
|
-
MFNType : {'krylov', 'expokit'}, optional
|
|
789
|
-
Method of computing the matrix function action, 'expokit' is only
|
|
790
|
-
available for func='exp'.
|
|
791
|
-
comm : mpi4py.MPI.Comm instance, optional
|
|
792
|
-
The mpi communicator.
|
|
793
|
-
isherm : bool, optional
|
|
794
|
-
If `mat` is known to be hermitian, this might speed things up in
|
|
795
|
-
some circumstances.
|
|
796
|
-
|
|
797
|
-
Returns
|
|
798
|
-
-------
|
|
799
|
-
fvec : array
|
|
800
|
-
The vector output of ``func(mat) @ vec``.
|
|
801
|
-
"""
|
|
802
|
-
SLEPc, comm = get_slepc(comm=comm)
|
|
803
|
-
|
|
804
|
-
mat = convert_mat_to_petsc(mat, comm=comm)
|
|
805
|
-
|
|
806
|
-
if isherm:
|
|
807
|
-
mat.setOption(mat.Option.HERMITIAN, True)
|
|
808
|
-
|
|
809
|
-
vec = convert_vec_to_petsc(vec, comm=comm)
|
|
810
|
-
out = new_petsc_vec(vec.size, comm=comm)
|
|
811
|
-
|
|
812
|
-
if MFNType.upper() == "AUTO":
|
|
813
|
-
if (fntype == "exp") and (vec.size <= 2**16):
|
|
814
|
-
MFNType = "EXPOKIT"
|
|
815
|
-
else:
|
|
816
|
-
MFNType = "KRYLOV"
|
|
817
|
-
|
|
818
|
-
# set up the matrix function options and objects
|
|
819
|
-
mfn = SLEPc.MFN().create(comm=comm)
|
|
820
|
-
mfn.setType(getattr(SLEPc.MFN.Type, MFNType.upper()))
|
|
821
|
-
mfn_fn = mfn.getFN()
|
|
822
|
-
mfn_fn.setType(getattr(SLEPc.FN.Type, fntype.upper()))
|
|
823
|
-
mfn_fn.setScale(1.0, 1.0)
|
|
824
|
-
mfn.setFromOptions()
|
|
825
|
-
|
|
826
|
-
mfn.setOperator(mat)
|
|
827
|
-
# 'solve' / perform the matrix function
|
|
828
|
-
mfn.solve(vec, out)
|
|
829
|
-
|
|
830
|
-
# --> gather the (distributed) petsc vector to a numpy matrix on master
|
|
831
|
-
all_out = gather_petsc_array(out, comm=comm, out_shape=(-1, 1))
|
|
832
|
-
|
|
833
|
-
mfn.destroy()
|
|
834
|
-
return all_out
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
# -------------------- solve linear system of equations --------------------- #
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
def lookup_ksp_error(i):
|
|
841
|
-
"""Look up PETSc error to print when raising after not converging."""
|
|
842
|
-
PETSc = get_petsc()
|
|
843
|
-
_KSP_DIVERGED_REASONS = {
|
|
844
|
-
i: error
|
|
845
|
-
for error, i in PETSc.KSP.ConvergedReason.__dict__.items()
|
|
846
|
-
if isinstance(i, int)
|
|
847
|
-
}
|
|
848
|
-
return _KSP_DIVERGED_REASONS[i]
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
def ssolve_slepc(
|
|
852
|
-
A,
|
|
853
|
-
y,
|
|
854
|
-
isherm=True,
|
|
855
|
-
comm=None,
|
|
856
|
-
maxiter=None,
|
|
857
|
-
tol=None,
|
|
858
|
-
KSPType="preonly",
|
|
859
|
-
PCType="lu",
|
|
860
|
-
PCFactorSolverType="mumps",
|
|
861
|
-
):
|
|
862
|
-
if comm is None:
|
|
863
|
-
comm = get_default_comm()
|
|
864
|
-
A = convert_mat_to_petsc(A, comm=comm)
|
|
865
|
-
if isherm:
|
|
866
|
-
A.setOption(A.Option.HERMITIAN, isherm)
|
|
867
|
-
x = A.createVecRight()
|
|
868
|
-
out_shape = y.shape
|
|
869
|
-
y = convert_vec_to_petsc(y, comm=comm)
|
|
870
|
-
|
|
871
|
-
ksp = _init_krylov_subspace(
|
|
872
|
-
KSPType=KSPType,
|
|
873
|
-
PCType=PCType,
|
|
874
|
-
comm=comm,
|
|
875
|
-
maxiter=maxiter,
|
|
876
|
-
tol=tol,
|
|
877
|
-
PCFactorSolverType=PCFactorSolverType,
|
|
878
|
-
)
|
|
879
|
-
|
|
880
|
-
ksp.setOperators(A)
|
|
881
|
-
ksp.solve(y, x)
|
|
882
|
-
|
|
883
|
-
converged_reason = ksp.getConvergedReason()
|
|
884
|
-
if converged_reason < 0:
|
|
885
|
-
raise RuntimeError(
|
|
886
|
-
"PETSc KSP solve did not converge, reason: "
|
|
887
|
-
f"{lookup_ksp_error(converged_reason)}"
|
|
888
|
-
)
|
|
889
|
-
|
|
890
|
-
x = gather_petsc_array(x, comm=comm, out_shape=out_shape)
|
|
891
|
-
ksp.destroy()
|
|
892
|
-
return x
|