Trajectree 0.0.1__py3-none-any.whl → 0.0.2__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.
Files changed (122) hide show
  1. trajectree/__init__.py +0 -3
  2. trajectree/fock_optics/devices.py +1 -1
  3. trajectree/fock_optics/light_sources.py +2 -2
  4. trajectree/fock_optics/measurement.py +3 -3
  5. trajectree/fock_optics/utils.py +6 -6
  6. trajectree/trajectory.py +2 -2
  7. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/METADATA +2 -3
  8. trajectree-0.0.2.dist-info/RECORD +16 -0
  9. trajectree/quimb/docs/_pygments/_pygments_dark.py +0 -118
  10. trajectree/quimb/docs/_pygments/_pygments_light.py +0 -118
  11. trajectree/quimb/docs/conf.py +0 -158
  12. trajectree/quimb/docs/examples/ex_mpi_expm_evo.py +0 -62
  13. trajectree/quimb/quimb/__init__.py +0 -507
  14. trajectree/quimb/quimb/calc.py +0 -1491
  15. trajectree/quimb/quimb/core.py +0 -2279
  16. trajectree/quimb/quimb/evo.py +0 -712
  17. trajectree/quimb/quimb/experimental/__init__.py +0 -0
  18. trajectree/quimb/quimb/experimental/autojittn.py +0 -129
  19. trajectree/quimb/quimb/experimental/belief_propagation/__init__.py +0 -109
  20. trajectree/quimb/quimb/experimental/belief_propagation/bp_common.py +0 -397
  21. trajectree/quimb/quimb/experimental/belief_propagation/d1bp.py +0 -316
  22. trajectree/quimb/quimb/experimental/belief_propagation/d2bp.py +0 -653
  23. trajectree/quimb/quimb/experimental/belief_propagation/hd1bp.py +0 -571
  24. trajectree/quimb/quimb/experimental/belief_propagation/hv1bp.py +0 -775
  25. trajectree/quimb/quimb/experimental/belief_propagation/l1bp.py +0 -316
  26. trajectree/quimb/quimb/experimental/belief_propagation/l2bp.py +0 -537
  27. trajectree/quimb/quimb/experimental/belief_propagation/regions.py +0 -194
  28. trajectree/quimb/quimb/experimental/cluster_update.py +0 -286
  29. trajectree/quimb/quimb/experimental/merabuilder.py +0 -865
  30. trajectree/quimb/quimb/experimental/operatorbuilder/__init__.py +0 -15
  31. trajectree/quimb/quimb/experimental/operatorbuilder/operatorbuilder.py +0 -1631
  32. trajectree/quimb/quimb/experimental/schematic.py +0 -7
  33. trajectree/quimb/quimb/experimental/tn_marginals.py +0 -130
  34. trajectree/quimb/quimb/experimental/tnvmc.py +0 -1483
  35. trajectree/quimb/quimb/gates.py +0 -36
  36. trajectree/quimb/quimb/gen/__init__.py +0 -2
  37. trajectree/quimb/quimb/gen/operators.py +0 -1167
  38. trajectree/quimb/quimb/gen/rand.py +0 -713
  39. trajectree/quimb/quimb/gen/states.py +0 -479
  40. trajectree/quimb/quimb/linalg/__init__.py +0 -6
  41. trajectree/quimb/quimb/linalg/approx_spectral.py +0 -1109
  42. trajectree/quimb/quimb/linalg/autoblock.py +0 -258
  43. trajectree/quimb/quimb/linalg/base_linalg.py +0 -719
  44. trajectree/quimb/quimb/linalg/mpi_launcher.py +0 -397
  45. trajectree/quimb/quimb/linalg/numpy_linalg.py +0 -244
  46. trajectree/quimb/quimb/linalg/rand_linalg.py +0 -514
  47. trajectree/quimb/quimb/linalg/scipy_linalg.py +0 -293
  48. trajectree/quimb/quimb/linalg/slepc_linalg.py +0 -892
  49. trajectree/quimb/quimb/schematic.py +0 -1518
  50. trajectree/quimb/quimb/tensor/__init__.py +0 -401
  51. trajectree/quimb/quimb/tensor/array_ops.py +0 -610
  52. trajectree/quimb/quimb/tensor/circuit.py +0 -4824
  53. trajectree/quimb/quimb/tensor/circuit_gen.py +0 -411
  54. trajectree/quimb/quimb/tensor/contraction.py +0 -336
  55. trajectree/quimb/quimb/tensor/decomp.py +0 -1255
  56. trajectree/quimb/quimb/tensor/drawing.py +0 -1646
  57. trajectree/quimb/quimb/tensor/fitting.py +0 -385
  58. trajectree/quimb/quimb/tensor/geometry.py +0 -583
  59. trajectree/quimb/quimb/tensor/interface.py +0 -114
  60. trajectree/quimb/quimb/tensor/networking.py +0 -1058
  61. trajectree/quimb/quimb/tensor/optimize.py +0 -1818
  62. trajectree/quimb/quimb/tensor/tensor_1d.py +0 -4778
  63. trajectree/quimb/quimb/tensor/tensor_1d_compress.py +0 -1854
  64. trajectree/quimb/quimb/tensor/tensor_1d_tebd.py +0 -662
  65. trajectree/quimb/quimb/tensor/tensor_2d.py +0 -5954
  66. trajectree/quimb/quimb/tensor/tensor_2d_compress.py +0 -96
  67. trajectree/quimb/quimb/tensor/tensor_2d_tebd.py +0 -1230
  68. trajectree/quimb/quimb/tensor/tensor_3d.py +0 -2869
  69. trajectree/quimb/quimb/tensor/tensor_3d_tebd.py +0 -46
  70. trajectree/quimb/quimb/tensor/tensor_approx_spectral.py +0 -60
  71. trajectree/quimb/quimb/tensor/tensor_arbgeom.py +0 -3237
  72. trajectree/quimb/quimb/tensor/tensor_arbgeom_compress.py +0 -565
  73. trajectree/quimb/quimb/tensor/tensor_arbgeom_tebd.py +0 -1138
  74. trajectree/quimb/quimb/tensor/tensor_builder.py +0 -5411
  75. trajectree/quimb/quimb/tensor/tensor_core.py +0 -11179
  76. trajectree/quimb/quimb/tensor/tensor_dmrg.py +0 -1472
  77. trajectree/quimb/quimb/tensor/tensor_mera.py +0 -204
  78. trajectree/quimb/quimb/utils.py +0 -892
  79. trajectree/quimb/tests/__init__.py +0 -0
  80. trajectree/quimb/tests/test_accel.py +0 -501
  81. trajectree/quimb/tests/test_calc.py +0 -788
  82. trajectree/quimb/tests/test_core.py +0 -847
  83. trajectree/quimb/tests/test_evo.py +0 -565
  84. trajectree/quimb/tests/test_gen/__init__.py +0 -0
  85. trajectree/quimb/tests/test_gen/test_operators.py +0 -361
  86. trajectree/quimb/tests/test_gen/test_rand.py +0 -296
  87. trajectree/quimb/tests/test_gen/test_states.py +0 -261
  88. trajectree/quimb/tests/test_linalg/__init__.py +0 -0
  89. trajectree/quimb/tests/test_linalg/test_approx_spectral.py +0 -368
  90. trajectree/quimb/tests/test_linalg/test_base_linalg.py +0 -351
  91. trajectree/quimb/tests/test_linalg/test_mpi_linalg.py +0 -127
  92. trajectree/quimb/tests/test_linalg/test_numpy_linalg.py +0 -84
  93. trajectree/quimb/tests/test_linalg/test_rand_linalg.py +0 -134
  94. trajectree/quimb/tests/test_linalg/test_slepc_linalg.py +0 -283
  95. trajectree/quimb/tests/test_tensor/__init__.py +0 -0
  96. trajectree/quimb/tests/test_tensor/test_belief_propagation/__init__.py +0 -0
  97. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d1bp.py +0 -39
  98. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d2bp.py +0 -67
  99. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hd1bp.py +0 -64
  100. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hv1bp.py +0 -51
  101. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l1bp.py +0 -142
  102. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l2bp.py +0 -101
  103. trajectree/quimb/tests/test_tensor/test_circuit.py +0 -816
  104. trajectree/quimb/tests/test_tensor/test_contract.py +0 -67
  105. trajectree/quimb/tests/test_tensor/test_decomp.py +0 -40
  106. trajectree/quimb/tests/test_tensor/test_mera.py +0 -52
  107. trajectree/quimb/tests/test_tensor/test_optimizers.py +0 -488
  108. trajectree/quimb/tests/test_tensor/test_tensor_1d.py +0 -1171
  109. trajectree/quimb/tests/test_tensor/test_tensor_2d.py +0 -606
  110. trajectree/quimb/tests/test_tensor/test_tensor_2d_tebd.py +0 -144
  111. trajectree/quimb/tests/test_tensor/test_tensor_3d.py +0 -123
  112. trajectree/quimb/tests/test_tensor/test_tensor_arbgeom.py +0 -226
  113. trajectree/quimb/tests/test_tensor/test_tensor_builder.py +0 -441
  114. trajectree/quimb/tests/test_tensor/test_tensor_core.py +0 -2066
  115. trajectree/quimb/tests/test_tensor/test_tensor_dmrg.py +0 -388
  116. trajectree/quimb/tests/test_tensor/test_tensor_spectral_approx.py +0 -63
  117. trajectree/quimb/tests/test_tensor/test_tensor_tebd.py +0 -270
  118. trajectree/quimb/tests/test_utils.py +0 -85
  119. trajectree-0.0.1.dist-info/RECORD +0 -126
  120. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/WHEEL +0 -0
  121. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/licenses/LICENSE +0 -0
  122. {trajectree-0.0.1.dist-info → trajectree-0.0.2.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