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,719 +0,0 @@
1
- """Backend agnostic functions for solving matrices either fully or partially.
2
- """
3
- import functools
4
- import warnings
5
-
6
- import numpy as np
7
- import scipy.linalg as sla
8
- import scipy.sparse.linalg as spla
9
-
10
- from ..utils import raise_cant_find_library_function
11
- from ..core import qarray, dag, issparse, isdense, vdot, ldmul
12
- from .numpy_linalg import (
13
- eig_numpy,
14
- eigs_numpy,
15
- svds_numpy,
16
- )
17
-
18
- from .scipy_linalg import (
19
- eigs_scipy,
20
- eigs_lobpcg,
21
- eigs_primme,
22
- svds_scipy,
23
- svds_primme,
24
- )
25
- from . import SLEPC4PY_FOUND
26
-
27
- if SLEPC4PY_FOUND:
28
- from .mpi_launcher import (
29
- eigs_slepc_spawn,
30
- mfn_multiply_slepc_spawn,
31
- svds_slepc_spawn,
32
- )
33
- from .slepc_linalg import eigs_slepc, svds_slepc, mfn_multiply_slepc
34
- else: # pragma: no cover
35
- eigs_slepc = raise_cant_find_library_function("slepc4py")
36
- eigs_slepc_spawn = raise_cant_find_library_function("slepc4py")
37
- svds_slepc = raise_cant_find_library_function("slepc4py")
38
- svds_slepc_spawn = raise_cant_find_library_function("slepc4py")
39
- mfn_multiply_slepc = raise_cant_find_library_function("slepc4py")
40
- mfn_multiply_slepc_spawn = raise_cant_find_library_function("slepc4py")
41
-
42
-
43
- # --------------------------------------------------------------------------- #
44
- # Partial eigendecomposition #
45
- # --------------------------------------------------------------------------- #
46
-
47
-
48
- def choose_backend(A, k, int_eps=False, B=None):
49
- """Pick a backend automatically for partial decompositions."""
50
- # LinOps -> not possible to simply convert to dense or use MPI processes
51
- A_is_linop = isinstance(A, spla.LinearOperator)
52
- B_is_linop = isinstance(B, spla.LinearOperator)
53
-
54
- # small array or large part of subspace requested
55
- small_d_big_k = A.shape[0] ** 2 / k < (10000 if int_eps else 2000)
56
-
57
- if small_d_big_k and not (A_is_linop or B_is_linop):
58
- return "NUMPY"
59
-
60
- # slepc seems faster for sparse, dense and LinearOperators
61
- if SLEPC4PY_FOUND and not B_is_linop:
62
- # only spool up an mpi pool for big sparse matrices though
63
- if issparse(A) and A.nnz > 10000:
64
- return "SLEPC"
65
-
66
- return "SLEPC-NOMPI"
67
-
68
- return "SCIPY"
69
-
70
-
71
- _EIGS_METHODS = {
72
- "NUMPY": eigs_numpy,
73
- "SCIPY": eigs_scipy,
74
- "PRIMME": eigs_primme,
75
- "LOBPCG": eigs_lobpcg,
76
- "SLEPC": eigs_slepc_spawn,
77
- "SLEPC-NOMPI": eigs_slepc,
78
- }
79
-
80
-
81
- def eigensystem_partial(
82
- A,
83
- k,
84
- isherm,
85
- *,
86
- B=None,
87
- which=None,
88
- return_vecs=True,
89
- sigma=None,
90
- ncv=None,
91
- tol=None,
92
- v0=None,
93
- sort=True,
94
- backend=None,
95
- fallback_to_scipy=False,
96
- **backend_opts,
97
- ):
98
- """Return a few eigenpairs from an operator.
99
-
100
- Parameters
101
- ----------
102
- A : sparse, dense or linear operator
103
- The operator to solve for.
104
- k : int
105
- Number of eigenpairs to return.
106
- isherm : bool
107
- Whether to use hermitian solve or not.
108
- B : sparse, dense or linear operator, optional
109
- If given, the RHS operator defining a generalized eigen problem.
110
- which : {'SA', 'LA', 'LM', 'SM', 'TR'}
111
- Where in spectrum to take eigenvalues from (see
112
- :func:``scipy.sparse.linalg.eigsh``)
113
- return_vecs : bool, optional
114
- Whether to return the eigenvectors.
115
- sigma : float, optional
116
- Which part of spectrum to target, implies which='TR' if which is None.
117
- ncv : int, optional
118
- number of lanczos vectors, can use to optimise speed
119
- tol : None or float
120
- Tolerance with which to find eigenvalues.
121
- v0 : None or 1D-array like
122
- An initial vector guess to iterate with.
123
- sort : bool, optional
124
- Whether to explicitly sort by ascending eigenvalue order.
125
- backend : {'AUTO', 'NUMPY', 'SCIPY',
126
- 'LOBPCG', 'SLEPC', 'SLEPC-NOMPI'}, optional
127
- Which solver to use.
128
- fallback_to_scipy : bool, optional
129
- If an error occurs and scipy is not being used, try using scipy.
130
- backend_opts
131
- Supplied to the backend solver.
132
-
133
- Returns
134
- -------
135
- elk : (k,) array
136
- The ``k`` eigenvalues.
137
- evk : (d, k) array
138
- Array with ``k`` eigenvectors as columns if ``return_vecs``.
139
- """
140
- settings = {
141
- "k": k,
142
- "B": B,
143
- "which": (
144
- "SA"
145
- if (which is None) and (sigma is None)
146
- else "TR"
147
- if (which is None) and (sigma is not None)
148
- else which
149
- ),
150
- "return_vecs": return_vecs,
151
- "sigma": sigma,
152
- "isherm": isherm,
153
- "ncv": ncv,
154
- "sort": sort,
155
- "tol": tol,
156
- "v0": v0,
157
- }
158
-
159
- # Choose backend to perform the decompostion
160
- bkd = "AUTO" if backend is None else backend.upper()
161
- if bkd == "AUTO":
162
- bkd = choose_backend(A, k, sigma is not None, B=B)
163
-
164
- try:
165
- return _EIGS_METHODS[bkd](A, **settings, **backend_opts)
166
-
167
- # sometimes e.g. lobpcg fails, worth trying scipy
168
- except Exception as e: # pragma: no cover
169
- if fallback_to_scipy and (bkd != "SCIPY"):
170
- warnings.warn(
171
- f"`eigensystem_partial` with backend '{bkd}' failed, trying "
172
- "again with scipy. Set ``fallback_to_scipy=False`` to avoid "
173
- "this and see the full error."
174
- )
175
-
176
- return eigs_scipy(A, **settings, **backend_opts)
177
- else:
178
- raise e
179
-
180
-
181
- # --------------------------------------------------------------------------- #
182
- # Full eigendecomposition #
183
- # --------------------------------------------------------------------------- #
184
-
185
-
186
- def eigensystem(A, isherm, *, k=-1, sort=True, return_vecs=True, **kwargs):
187
- """Find all or some eigenpairs of an operator.
188
-
189
- Parameters
190
- ----------
191
- A : operator
192
- The operator to decompose.
193
- isherm : bool
194
- Whether the operator is assumed to be hermitian or not.
195
- k : int, optional
196
- If negative, find all eigenpairs, else perform partial
197
- eigendecomposition and find ``k`` pairs. See
198
- :func:`~quimb.linalg.base_linalg.eigensystem_partial`.
199
- sort : bool, optional
200
- Whether to sort the eigenpairs in ascending eigenvalue order.
201
- kwargs
202
- Supplied to the backend function.
203
-
204
- Returns
205
- -------
206
- el : (k,) array
207
- Eigenvalues.
208
- ev : (d, k) array
209
- Corresponding eigenvectors as columns of array, such that
210
- ``ev @ diag(el) @ ev.H == A``.
211
- """
212
- if k < 0:
213
- return eig_numpy(
214
- A, isherm=isherm, sort=sort, return_vecs=return_vecs, **kwargs
215
- )
216
-
217
- return eigensystem_partial(
218
- A, k=k, isherm=isherm, sort=sort, return_vecs=return_vecs, **kwargs
219
- )
220
-
221
-
222
- eig = functools.partial(eigensystem, isherm=False, return_vecs=True)
223
- eigh = functools.partial(eigensystem, isherm=True, return_vecs=True)
224
- eigvals = functools.partial(eigensystem, isherm=False, return_vecs=False)
225
- eigvalsh = functools.partial(eigensystem, isherm=True, return_vecs=False)
226
-
227
-
228
- @functools.wraps(eigensystem)
229
- def eigenvectors(A, isherm, *, sort=True, **kwargs):
230
- return eigensystem(A, isherm=isherm, sort=sort, **kwargs)[1]
231
-
232
-
233
- eigvecs = functools.partial(eigenvectors, isherm=False)
234
- eigvecsh = functools.partial(eigenvectors, isherm=True)
235
-
236
-
237
- def groundstate(ham, **kwargs):
238
- """Alias for finding lowest eigenvector only."""
239
- return eigvecsh(ham, k=1, which="SA", **kwargs)
240
-
241
-
242
- def groundenergy(ham, **kwargs):
243
- """Alias for finding lowest eigenvalue only."""
244
- return eigvalsh(ham, k=1, which="SA", **kwargs)[0]
245
-
246
-
247
- def bound_spectrum(A, backend="auto", **kwargs):
248
- """Return the smallest and largest eigenvalue of hermitian operator ``A``."""
249
- el_min = eigvalsh(A, k=1, which="SA", backend=backend, **kwargs)[0]
250
- el_max = eigvalsh(A, k=1, which="LA", backend=backend, **kwargs)[0]
251
- return el_min, el_max
252
-
253
-
254
- def _rel_window_to_abs_window(el_min, el_max, w_0, w_sz=None):
255
- """Convert min/max eigenvalues and relative window to absolute values.
256
-
257
- Parameters
258
- ----------
259
- el_min : float
260
- Smallest eigenvalue.
261
- el_max : float
262
- Largest eigenvalue.
263
- w_0 : float [0.0 - 1.0]
264
- Relative window centre.
265
- w_sz : float, optional
266
- Relative window width.
267
-
268
- Returns
269
- -------
270
- l_0[, l_min, l_max]:
271
- Absolute value of centre of window, lower and upper intervals if a
272
- window size is specified.
273
- """
274
- el_range = el_max - el_min
275
- el_w_0 = el_min + w_0 * el_range
276
- if w_sz is not None:
277
- el_w_min = el_w_0 - w_sz * el_range / 2
278
- el_w_max = el_w_0 + w_sz * el_range / 2
279
- return el_w_0, el_w_min, el_w_max
280
- return el_w_0
281
-
282
-
283
- def eigh_window(
284
- A,
285
- w_0,
286
- k,
287
- w_sz=None,
288
- backend="AUTO",
289
- return_vecs=True,
290
- offset_const=1 / 104729,
291
- **kwargs,
292
- ):
293
- """Return mid-spectrum eigenpairs from a hermitian operator.
294
-
295
- Parameters
296
- ----------
297
- A : (d, d) operator
298
- Operator to retrieve eigenpairs from.
299
- w_0 : float [0.0, 1.0]
300
- Relative window centre to retrieve eigenpairs from.
301
- k : int
302
- Target number of eigenpairs to retrieve.
303
- w_sz : float, optional
304
- Relative maximum window width within which to keep eigenpairs.
305
- backend : str, optional
306
- Which :func:`~quimb.eigh` backend to use.
307
- return_vecs : bool, optional
308
- Whether to return eigenvectors as well.
309
- offset_const : float, optional
310
- Small fudge factor (relative to window range) to avoid 1 / 0 issues.
311
-
312
- Returns
313
- -------
314
- el : (k,) array
315
- Eigenvalues around w_0.
316
- ev : (d, k) array
317
- The eigenvectors, if ``return_vecs=True``.
318
- """
319
- w_sz = w_sz if w_sz is not None else 1.1
320
-
321
- if isdense(A) or backend.upper() == "NUMPY":
322
- if return_vecs:
323
- lk, vk = eigh(A.toarray() if issparse(A) else A, **kwargs)
324
- else:
325
- lk = eigvalsh(A.toarray() if issparse(A) else A, **kwargs)
326
-
327
- lmin, lmax = lk[0], lk[-1]
328
- l_w0, l_wmin, l_wmax = _rel_window_to_abs_window(lmin, lmax, w_0, w_sz)
329
-
330
- else:
331
- lmin, lmax = bound_spectrum(A, backend=backend, **kwargs)
332
- l_w0, l_wmin, l_wmax = _rel_window_to_abs_window(lmin, lmax, w_0, w_sz)
333
- l_w0 += (lmax - lmin) * offset_const # for 1/0 issues
334
-
335
- if return_vecs:
336
- lk, vk = eigh(A, k=k, sigma=l_w0, backend=backend, **kwargs)
337
- else:
338
- lk = eigvalsh(A, k=k, sigma=l_w0, backend=backend, **kwargs)
339
-
340
- # Trim eigenpairs from beyond window
341
- in_window = (lk > l_wmin) & (lk < l_wmax)
342
-
343
- if return_vecs:
344
- return lk[in_window], vk[:, in_window]
345
-
346
- return lk[in_window]
347
-
348
-
349
- def eigvalsh_window(*args, **kwargs):
350
- """Alias for only finding the eigenvalues in a relative window."""
351
- return eigh_window(*args, return_vecs=False, **kwargs)
352
-
353
-
354
- def eigvecsh_window(*args, **kwargs):
355
- """Alias for only finding the eigenvectors in a relative window."""
356
- return eigh_window(*args, return_vecs=True, **kwargs)[1]
357
-
358
-
359
- # -------------------------------------------------------------------------- #
360
- # Partial singular value decomposition #
361
- # -------------------------------------------------------------------------- #
362
-
363
-
364
- def svd(A, return_vecs=True):
365
- """Compute full singular value decomposition of an operator, using numpy.
366
-
367
- Parameters
368
- ----------
369
- A : (m, n) array
370
- The operator.
371
- return_vecs : bool, optional
372
- Whether to return the singular vectors.
373
-
374
- Returns
375
- -------
376
- U : (m, k) array
377
- Left singular vectors (if ``return_vecs=True``) as columns.
378
- s : (k,) array
379
- Singular values.
380
- VH : (k, n) array
381
- Right singular vectors (if ``return_vecs=True``) as rows.
382
- """
383
- try:
384
- return np.linalg.svd(A, full_matrices=False, compute_uv=return_vecs)
385
-
386
- except np.linalg.linalg.LinAlgError: # pragma: no cover
387
- warnings.warn("Numpy SVD failed, trying again with different driver.")
388
- return sla.svd(
389
- A,
390
- full_matrices=False,
391
- compute_uv=return_vecs,
392
- lapack_driver="gesvd",
393
- )
394
-
395
-
396
- _SVDS_METHODS = {
397
- "SLEPC": svds_slepc_spawn,
398
- "SLEPC-NOMPI": svds_slepc,
399
- "NUMPY": svds_numpy,
400
- "SCIPY": svds_scipy,
401
- "PRIMME": svds_primme,
402
- }
403
-
404
-
405
- def svds(A, k, ncv=None, return_vecs=True, backend="AUTO", **kwargs):
406
- """Compute the partial singular value decomposition of an operator.
407
-
408
- Parameters
409
- ----------
410
- A : dense, sparse or linear operator
411
- The operator to decompose.
412
- k : int, optional
413
- number of singular value (triplets) to retrieve
414
- ncv : int, optional
415
- Number of lanczos vectors to use performing decomposition.
416
- return_vecs : bool, optional
417
- Whether to return the left and right vectors
418
- backend : {'AUTO', 'SCIPY', 'SLEPC', 'SLEPC-NOMPI', 'NUMPY'}, optional
419
- Which solver to use to perform decomposition.
420
-
421
- Returns
422
- -------
423
- (Uk,) sk (, VHk) :
424
- Singular value(s) (and vectors) such that ``Uk @ np.diag(sk) @ VHk``
425
- approximates ``A``.
426
- """
427
- settings = {"k": k, "ncv": ncv, "return_vecs": return_vecs}
428
-
429
- bkd = (
430
- choose_backend(A, k, False)
431
- if backend in {"auto", "AUTO"}
432
- else backend.upper()
433
- )
434
- svds_func = _SVDS_METHODS[bkd.upper()]
435
-
436
- return svds_func(A, **settings, **kwargs)
437
-
438
-
439
- # -------------------------------------------------------------------------- #
440
- # Norms and other quantities based on decompositions #
441
- # -------------------------------------------------------------------------- #
442
-
443
-
444
- def norm_2(A, **kwargs):
445
- """Return the 2-norm of operator, ``A``, i.e. the largest singular value."""
446
- return svds(A, k=1, return_vecs=False, **kwargs)[0]
447
-
448
-
449
- def norm_fro_dense(A):
450
- """Frobenius norm for dense matrices"""
451
- return vdot(A, A).real ** 0.5
452
-
453
-
454
- def norm_fro_sparse(A):
455
- return vdot(A.data, A.data).real ** 0.5
456
-
457
-
458
- def norm_trace_dense(A, isherm=False):
459
- """Returns the trace norm of operator ``A``, that is,
460
- the sum of the absolute eigenvalues.
461
- """
462
- if isherm:
463
- return abs(eigvalsh(A)).sum()
464
- else:
465
- return svd(A, return_vecs=False).sum()
466
-
467
-
468
- def norm(A, ntype=2, **kwargs):
469
- """Operator norms.
470
-
471
- Parameters
472
- ----------
473
- A : operator
474
- The operator to find norm of.
475
- ntype : str
476
- Norm to calculate, if any of:
477
-
478
- - {2, '2', 'spectral'}: largest singular value
479
- - {'f', 'fro'}: frobenius norm
480
- - {'t', 'nuc', 'tr', 'trace'}: sum of singular values
481
-
482
- Returns
483
- -------
484
- x : float
485
- The operator norm.
486
- """
487
- types = {
488
- "2": "2",
489
- 2: "2",
490
- "spectral": "2",
491
- "f": "f",
492
- "fro": "f",
493
- "t": "t",
494
- "trace": "t",
495
- "nuc": "t",
496
- "tr": "t",
497
- }
498
- methods = {
499
- ("2", 0): norm_2,
500
- ("2", 1): norm_2,
501
- ("t", 0): norm_trace_dense,
502
- ("f", 0): norm_fro_dense,
503
- ("f", 1): norm_fro_sparse,
504
- }
505
- return methods[(types[ntype], issparse(A))](A, **kwargs)
506
-
507
-
508
- # --------------------------------------------------------------------------- #
509
- # Matrix functions #
510
- # --------------------------------------------------------------------------- #
511
-
512
-
513
- def expm(A, herm=False):
514
- """Matrix exponential, can be accelerated if explicitly hermitian.
515
-
516
- Parameters
517
- ----------
518
- A : dense or sparse operator
519
- Operator to exponentiate.
520
- herm : bool, optional
521
- If True (not default), and ``A`` is dense, digonalize the matrix
522
- in order to perform the exponential.
523
- """
524
- if issparse(A):
525
- # convert to and from csc to suppress scipy warning
526
- return spla.expm(A.tocsc()).tocsr()
527
- elif not herm:
528
- return qarray(spla.expm(A))
529
- else:
530
- evals, evecs = eigh(A)
531
- return evecs @ ldmul(np.exp(evals), dag(evecs))
532
-
533
-
534
- _EXPM_MULTIPLY_METHODS = {
535
- "SCIPY": spla.expm_multiply,
536
- "SLEPC": functools.partial(mfn_multiply_slepc_spawn, fntype="exp"),
537
- "SLEPC-KRYLOV": functools.partial(
538
- mfn_multiply_slepc_spawn, fntype="exp", MFNType="KRYLOV"
539
- ),
540
- "SLEPC-EXPOKIT": functools.partial(
541
- mfn_multiply_slepc_spawn, fntype="exp", MFNType="EXPOKIT"
542
- ),
543
- "SLEPC-NOMPI": functools.partial(mfn_multiply_slepc, fntype="exp"),
544
- }
545
-
546
-
547
- def expm_multiply(mat, vec, backend="AUTO", **kwargs):
548
- """Compute the action of ``expm(mat)`` on ``vec``.
549
-
550
- Parameters
551
- ----------
552
- mat : operator
553
- Operator with which to act with exponential on ``vec``.
554
- vec : vector-like
555
- Vector to act with exponential of operator on.
556
- backend : {'AUTO', 'SCIPY', 'SLEPC', 'SLEPC-KRYLOV', 'SLEPC-EXPOKIT'}
557
- Which backend to use.
558
- kwargs
559
- Supplied to backend function.
560
-
561
- Returns
562
- -------
563
- vector
564
- Result of ``expm(mat) @ vec``.
565
- """
566
- if backend == "AUTO":
567
- if SLEPC4PY_FOUND and vec.size > 2**10:
568
- backend = "SLEPC"
569
- else:
570
- backend = "SCIPY"
571
-
572
- return _EXPM_MULTIPLY_METHODS[backend.upper()](mat, vec, **kwargs)
573
-
574
-
575
- def sqrtm(A, herm=True):
576
- """Matrix square root, can be accelerated if explicitly hermitian.
577
-
578
- Parameters
579
- ----------
580
- A : dense array
581
- Operator to take square root of.
582
- herm : bool, optional
583
- If True (the default), and ``A`` is dense, digonalize the matrix
584
- in order to take the square root.
585
-
586
- Returns
587
- -------
588
- array
589
- """
590
- if issparse(A):
591
- raise NotImplementedError("No sparse sqrtm available.")
592
- elif not herm:
593
- return qarray(sla.sqrtm(A))
594
- else:
595
- evals, evecs = eigh(A)
596
- return evecs @ ldmul(np.sqrt(evals.astype(complex)), dag(evecs))
597
-
598
-
599
- class IdentityLinearOperator(spla.LinearOperator):
600
- """Get a ``LinearOperator`` representation of the identity operator,
601
- scaled by ``factor``.
602
-
603
- Parameters
604
- ----------
605
- size : int
606
- The size of the identity.
607
- factor : float
608
- The coefficient of the identity.
609
-
610
- Examples
611
- --------
612
-
613
- >>> I3 = IdentityLinearOperator(100, 1/3)
614
- >>> p = rand_ket(100)
615
- >>> np.allclose(I3 @ p, p / 3)
616
- True
617
- """
618
-
619
- def __init__(self, size, factor=1):
620
- self.factor = factor
621
- super().__init__(dtype=np.array(factor).dtype, shape=(size, size))
622
-
623
- def _matvec(self, vec):
624
- return self.factor * vec
625
-
626
- def _rmatvec(self, vec):
627
- return self.factor * vec
628
-
629
- def _matmat(self, mat):
630
- return self.factor * mat
631
-
632
-
633
- class Lazy:
634
- """A simple class representing an unconstructed matrix. This can be passed
635
- to, for example, MPI workers, who can then construct the matrix themselves.
636
- The main function ``fn`` should ideally take an ``ownership`` keyword to
637
- avoid forming every row.
638
-
639
- This is essentially like using ``functools.partial`` and assigning the
640
- ``shape`` attribute.
641
-
642
- Parameters
643
- ----------
644
- fn : callable
645
- A function that constructs an operator.
646
- shape :
647
- Shape of the constructed operator.
648
- args
649
- Supplied to ``fn``.
650
- kwargs
651
- Supplied to ``fn``.
652
-
653
- Returns
654
- -------
655
- Lazy : callable
656
-
657
- Examples
658
- --------
659
- Setup the lazy operator:
660
-
661
- >>> H_lazy = Lazy(ham_heis, n=10, shape=(2**10, 2**10), sparse=True)
662
- >>> H_lazy
663
- <Lazy(ham_heis, shape=(1024, 1024), dtype=None)>
664
-
665
- Build a matrix slice (usually done automatically by e.g. ``eigs``):
666
-
667
- >>> H_lazy(ownership=(256, 512))
668
- <256x1024 sparse matrix of type '<class 'numpy.float64'>'
669
- with 1664 stored elements in Compressed Sparse Row format>
670
- """
671
-
672
- def __init__(self, fn, *args, shape=None, factor=None, **kwargs):
673
- if shape is None:
674
- raise TypeError("`shape` must be specified.")
675
- self.fn = fn
676
- self.args = args
677
- self.kwargs = kwargs
678
- self.shape = shape
679
- self.factor = factor
680
- self.dtype = None
681
-
682
- def __imul__(self, x):
683
- if self.factor is None:
684
- self.factor = x
685
- else:
686
- self.factor = self.factor * x
687
-
688
- def __mul__(self, x):
689
- if self.factor is not None:
690
- x = x * self.factor
691
- return Lazy(
692
- self.fn, *self.args, shape=self.shape, factor=x, **self.kwargs
693
- )
694
-
695
- def __rmul__(self, x):
696
- return self.__mul__(x)
697
-
698
- def __call__(self, **kwargs):
699
- A = self.fn(*self.args, **self.kwargs, **kwargs)
700
-
701
- # check if any prefactors have been set
702
- if self.factor is not None:
703
- # try inplace first
704
- try:
705
- A *= self.factor
706
- except (ValueError, TypeError):
707
- A = self.factor * A
708
-
709
- # helpful to store dtype once constructed
710
- self.dtype = A.dtype
711
- return A
712
-
713
- def __repr__(self):
714
- s = "<Lazy({}, shape={}{}{})>"
715
-
716
- s_dtype = f", dtype={self.dtype}" if self.dtype is not None else ""
717
- s_factor = f", factor={self.factor}" if self.factor is not None else ""
718
-
719
- return s.format(self.fn.__name__, self.shape, s_dtype, s_factor)