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