Trajectree 0.0.0__py3-none-any.whl → 0.0.1__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 +3 -0
  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/quimb/docs/_pygments/_pygments_dark.py +118 -0
  7. trajectree/quimb/docs/_pygments/_pygments_light.py +118 -0
  8. trajectree/quimb/docs/conf.py +158 -0
  9. trajectree/quimb/docs/examples/ex_mpi_expm_evo.py +62 -0
  10. trajectree/quimb/quimb/__init__.py +507 -0
  11. trajectree/quimb/quimb/calc.py +1491 -0
  12. trajectree/quimb/quimb/core.py +2279 -0
  13. trajectree/quimb/quimb/evo.py +712 -0
  14. trajectree/quimb/quimb/experimental/__init__.py +0 -0
  15. trajectree/quimb/quimb/experimental/autojittn.py +129 -0
  16. trajectree/quimb/quimb/experimental/belief_propagation/__init__.py +109 -0
  17. trajectree/quimb/quimb/experimental/belief_propagation/bp_common.py +397 -0
  18. trajectree/quimb/quimb/experimental/belief_propagation/d1bp.py +316 -0
  19. trajectree/quimb/quimb/experimental/belief_propagation/d2bp.py +653 -0
  20. trajectree/quimb/quimb/experimental/belief_propagation/hd1bp.py +571 -0
  21. trajectree/quimb/quimb/experimental/belief_propagation/hv1bp.py +775 -0
  22. trajectree/quimb/quimb/experimental/belief_propagation/l1bp.py +316 -0
  23. trajectree/quimb/quimb/experimental/belief_propagation/l2bp.py +537 -0
  24. trajectree/quimb/quimb/experimental/belief_propagation/regions.py +194 -0
  25. trajectree/quimb/quimb/experimental/cluster_update.py +286 -0
  26. trajectree/quimb/quimb/experimental/merabuilder.py +865 -0
  27. trajectree/quimb/quimb/experimental/operatorbuilder/__init__.py +15 -0
  28. trajectree/quimb/quimb/experimental/operatorbuilder/operatorbuilder.py +1631 -0
  29. trajectree/quimb/quimb/experimental/schematic.py +7 -0
  30. trajectree/quimb/quimb/experimental/tn_marginals.py +130 -0
  31. trajectree/quimb/quimb/experimental/tnvmc.py +1483 -0
  32. trajectree/quimb/quimb/gates.py +36 -0
  33. trajectree/quimb/quimb/gen/__init__.py +2 -0
  34. trajectree/quimb/quimb/gen/operators.py +1167 -0
  35. trajectree/quimb/quimb/gen/rand.py +713 -0
  36. trajectree/quimb/quimb/gen/states.py +479 -0
  37. trajectree/quimb/quimb/linalg/__init__.py +6 -0
  38. trajectree/quimb/quimb/linalg/approx_spectral.py +1109 -0
  39. trajectree/quimb/quimb/linalg/autoblock.py +258 -0
  40. trajectree/quimb/quimb/linalg/base_linalg.py +719 -0
  41. trajectree/quimb/quimb/linalg/mpi_launcher.py +397 -0
  42. trajectree/quimb/quimb/linalg/numpy_linalg.py +244 -0
  43. trajectree/quimb/quimb/linalg/rand_linalg.py +514 -0
  44. trajectree/quimb/quimb/linalg/scipy_linalg.py +293 -0
  45. trajectree/quimb/quimb/linalg/slepc_linalg.py +892 -0
  46. trajectree/quimb/quimb/schematic.py +1518 -0
  47. trajectree/quimb/quimb/tensor/__init__.py +401 -0
  48. trajectree/quimb/quimb/tensor/array_ops.py +610 -0
  49. trajectree/quimb/quimb/tensor/circuit.py +4824 -0
  50. trajectree/quimb/quimb/tensor/circuit_gen.py +411 -0
  51. trajectree/quimb/quimb/tensor/contraction.py +336 -0
  52. trajectree/quimb/quimb/tensor/decomp.py +1255 -0
  53. trajectree/quimb/quimb/tensor/drawing.py +1646 -0
  54. trajectree/quimb/quimb/tensor/fitting.py +385 -0
  55. trajectree/quimb/quimb/tensor/geometry.py +583 -0
  56. trajectree/quimb/quimb/tensor/interface.py +114 -0
  57. trajectree/quimb/quimb/tensor/networking.py +1058 -0
  58. trajectree/quimb/quimb/tensor/optimize.py +1818 -0
  59. trajectree/quimb/quimb/tensor/tensor_1d.py +4778 -0
  60. trajectree/quimb/quimb/tensor/tensor_1d_compress.py +1854 -0
  61. trajectree/quimb/quimb/tensor/tensor_1d_tebd.py +662 -0
  62. trajectree/quimb/quimb/tensor/tensor_2d.py +5954 -0
  63. trajectree/quimb/quimb/tensor/tensor_2d_compress.py +96 -0
  64. trajectree/quimb/quimb/tensor/tensor_2d_tebd.py +1230 -0
  65. trajectree/quimb/quimb/tensor/tensor_3d.py +2869 -0
  66. trajectree/quimb/quimb/tensor/tensor_3d_tebd.py +46 -0
  67. trajectree/quimb/quimb/tensor/tensor_approx_spectral.py +60 -0
  68. trajectree/quimb/quimb/tensor/tensor_arbgeom.py +3237 -0
  69. trajectree/quimb/quimb/tensor/tensor_arbgeom_compress.py +565 -0
  70. trajectree/quimb/quimb/tensor/tensor_arbgeom_tebd.py +1138 -0
  71. trajectree/quimb/quimb/tensor/tensor_builder.py +5411 -0
  72. trajectree/quimb/quimb/tensor/tensor_core.py +11179 -0
  73. trajectree/quimb/quimb/tensor/tensor_dmrg.py +1472 -0
  74. trajectree/quimb/quimb/tensor/tensor_mera.py +204 -0
  75. trajectree/quimb/quimb/utils.py +892 -0
  76. trajectree/quimb/tests/__init__.py +0 -0
  77. trajectree/quimb/tests/test_accel.py +501 -0
  78. trajectree/quimb/tests/test_calc.py +788 -0
  79. trajectree/quimb/tests/test_core.py +847 -0
  80. trajectree/quimb/tests/test_evo.py +565 -0
  81. trajectree/quimb/tests/test_gen/__init__.py +0 -0
  82. trajectree/quimb/tests/test_gen/test_operators.py +361 -0
  83. trajectree/quimb/tests/test_gen/test_rand.py +296 -0
  84. trajectree/quimb/tests/test_gen/test_states.py +261 -0
  85. trajectree/quimb/tests/test_linalg/__init__.py +0 -0
  86. trajectree/quimb/tests/test_linalg/test_approx_spectral.py +368 -0
  87. trajectree/quimb/tests/test_linalg/test_base_linalg.py +351 -0
  88. trajectree/quimb/tests/test_linalg/test_mpi_linalg.py +127 -0
  89. trajectree/quimb/tests/test_linalg/test_numpy_linalg.py +84 -0
  90. trajectree/quimb/tests/test_linalg/test_rand_linalg.py +134 -0
  91. trajectree/quimb/tests/test_linalg/test_slepc_linalg.py +283 -0
  92. trajectree/quimb/tests/test_tensor/__init__.py +0 -0
  93. trajectree/quimb/tests/test_tensor/test_belief_propagation/__init__.py +0 -0
  94. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d1bp.py +39 -0
  95. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d2bp.py +67 -0
  96. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hd1bp.py +64 -0
  97. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hv1bp.py +51 -0
  98. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l1bp.py +142 -0
  99. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l2bp.py +101 -0
  100. trajectree/quimb/tests/test_tensor/test_circuit.py +816 -0
  101. trajectree/quimb/tests/test_tensor/test_contract.py +67 -0
  102. trajectree/quimb/tests/test_tensor/test_decomp.py +40 -0
  103. trajectree/quimb/tests/test_tensor/test_mera.py +52 -0
  104. trajectree/quimb/tests/test_tensor/test_optimizers.py +488 -0
  105. trajectree/quimb/tests/test_tensor/test_tensor_1d.py +1171 -0
  106. trajectree/quimb/tests/test_tensor/test_tensor_2d.py +606 -0
  107. trajectree/quimb/tests/test_tensor/test_tensor_2d_tebd.py +144 -0
  108. trajectree/quimb/tests/test_tensor/test_tensor_3d.py +123 -0
  109. trajectree/quimb/tests/test_tensor/test_tensor_arbgeom.py +226 -0
  110. trajectree/quimb/tests/test_tensor/test_tensor_builder.py +441 -0
  111. trajectree/quimb/tests/test_tensor/test_tensor_core.py +2066 -0
  112. trajectree/quimb/tests/test_tensor/test_tensor_dmrg.py +388 -0
  113. trajectree/quimb/tests/test_tensor/test_tensor_spectral_approx.py +63 -0
  114. trajectree/quimb/tests/test_tensor/test_tensor_tebd.py +270 -0
  115. trajectree/quimb/tests/test_utils.py +85 -0
  116. trajectree/trajectory.py +2 -2
  117. {trajectree-0.0.0.dist-info → trajectree-0.0.1.dist-info}/METADATA +2 -2
  118. trajectree-0.0.1.dist-info/RECORD +126 -0
  119. trajectree-0.0.0.dist-info/RECORD +0 -16
  120. {trajectree-0.0.0.dist-info → trajectree-0.0.1.dist-info}/WHEEL +0 -0
  121. {trajectree-0.0.0.dist-info → trajectree-0.0.1.dist-info}/licenses/LICENSE +0 -0
  122. {trajectree-0.0.0.dist-info → trajectree-0.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,361 @@
1
+ import numpy as np
2
+ import pytest
3
+ from numpy.testing import assert_allclose
4
+
5
+ import quimb as qu
6
+
7
+
8
+ @pytest.mark.parametrize("sparse", [False, True])
9
+ @pytest.mark.parametrize("stype", ["csr", "csc"])
10
+ @pytest.mark.parametrize(
11
+ "dtype", ["don't pass", None, np.float64, np.complex128]
12
+ )
13
+ def test_hamiltonian_builder(sparse, stype, dtype):
14
+ from quimb.gen.operators import hamiltonian_builder
15
+
16
+ @hamiltonian_builder
17
+ def simple_ham(sparse=None, stype=None, dtype=None):
18
+ H = qu.qu(
19
+ [[0.0, 1.0], [1.0, 0.0]], sparse=True, stype="csr", dtype=dtype
20
+ )
21
+ return H
22
+
23
+ @hamiltonian_builder
24
+ def simple_ham_complex(sparse=None, stype=None, dtype=None):
25
+ H = qu.qu(
26
+ [[0.0, 1.0j], [-1.0j, 0.0]], sparse=True, stype="csr", dtype=dtype
27
+ )
28
+ return H
29
+
30
+ if dtype == "don't pass":
31
+ H = simple_ham(sparse=sparse, stype=stype)
32
+ else:
33
+ H = simple_ham(sparse=sparse, stype=stype, dtype=dtype)
34
+
35
+ if dtype == "don't pass" or dtype is None:
36
+ # check that passng no actual dtype keeps it as float
37
+ assert H.dtype == np.float64
38
+ else:
39
+ # check that explicit dtypes are respected
40
+ assert H.dtype == dtype
41
+ assert qu.issparse(H) == sparse
42
+ assert qu.isdense(H) != sparse
43
+ if sparse:
44
+ assert H.format == stype
45
+
46
+ with pytest.raises(ValueError): # check immutability
47
+ H[0, 0] = 100
48
+
49
+ if dtype == "don't pass":
50
+ H = simple_ham_complex(sparse=sparse, stype=stype)
51
+ elif dtype is np.float64:
52
+ with pytest.warns(np.exceptions.ComplexWarning):
53
+ H = simple_ham_complex(sparse=sparse, stype=stype, dtype=dtype)
54
+ else:
55
+ H = simple_ham_complex(sparse=sparse, stype=stype, dtype=dtype)
56
+ if dtype == "don't pass" or dtype is None:
57
+ # check that passng no actual dtype keeps it as float
58
+ assert H.dtype == np.complex128
59
+ else:
60
+ # check that explicit dtypes are respected
61
+ assert H.dtype == dtype
62
+ assert qu.issparse(H) == sparse
63
+ assert qu.isdense(H) != sparse
64
+ if sparse:
65
+ assert H.format == stype
66
+
67
+ with pytest.raises(ValueError): # check immutability
68
+ H[0, 0] = 100
69
+
70
+ return
71
+
72
+
73
+ class TestSpinOperator:
74
+ def test_spin_half(self):
75
+ Sx = qu.spin_operator("x", 1 / 2)
76
+ assert_allclose(Sx, [[0.0, 0.5], [0.5, 0.0]])
77
+
78
+ Sy = qu.spin_operator("y", 1 / 2)
79
+ assert_allclose(Sy, [[0.0, -0.5j], [0.5j, 0.0]])
80
+
81
+ Sz = qu.spin_operator("z", 1 / 2)
82
+ assert_allclose(Sz, [[0.5, 0.0], [0.0, -0.5]])
83
+
84
+ Sp = qu.spin_operator("+", 1 / 2)
85
+ assert_allclose(Sp, [[0.0, 1.0], [0.0, 0.0]])
86
+
87
+ Sm = qu.spin_operator("-", 1 / 2)
88
+ assert_allclose(Sm, [[0.0, 0.0], [1.0, 0.0]])
89
+
90
+ SI = qu.spin_operator("I", 1 / 2)
91
+ assert_allclose(SI, [[1.0, 0.0], [0.0, 1.0]])
92
+
93
+ @pytest.mark.parametrize("label", ("x", "y", "z"))
94
+ @pytest.mark.parametrize("S", [1, 3 / 2, 2, 5 / 2])
95
+ def test_spin_high(self, label, S):
96
+ D = int(2 * S + 1)
97
+ op = qu.spin_operator(label, S)
98
+ assert_allclose(qu.eigvalsh(op), np.linspace(-S, S, D), atol=1e-13)
99
+
100
+
101
+ class TestPauli:
102
+ def test_pauli_dim2(self):
103
+ for dir in (1, "x", "X", 2, "y", "Y", 3, "z", "Z"):
104
+ x = qu.pauli(dir)
105
+ assert_allclose(qu.eigvalsh(x), [-1, 1])
106
+
107
+ def test_pauli_dim3(self):
108
+ for dir in (1, "x", "X", 2, "y", "Y", 3, "z", "Z"):
109
+ x = qu.pauli(dir, dim=3)
110
+ assert_allclose(qu.eigvalsh(x), [-1, 0, 1], atol=1e-15)
111
+
112
+ def test_pauli_bad_dim(self):
113
+ with pytest.raises(KeyError):
114
+ qu.pauli("x", 4)
115
+
116
+ def test_pauli_bad_dir(self):
117
+ with pytest.raises(KeyError):
118
+ qu.pauli("w", 2)
119
+
120
+
121
+ class TestControlledZ:
122
+ def test_controlled_z_dense(self):
123
+ cz = qu.controlled("z")
124
+ assert_allclose(cz, np.diag([1, 1, 1, -1]))
125
+
126
+ def test_controlled_z_sparse(self):
127
+ cz = qu.controlled("z", sparse=True)
128
+ assert qu.issparse(cz)
129
+ assert_allclose(cz.toarray(), np.diag([1, 1, 1, -1]))
130
+
131
+
132
+ class TestGates:
133
+ @pytest.mark.parametrize(
134
+ "gate",
135
+ [
136
+ "Rx",
137
+ "Ry",
138
+ "Rz",
139
+ "T_gate",
140
+ "S_gate",
141
+ "CNOT",
142
+ "cX",
143
+ "cY",
144
+ "cZ",
145
+ "hadamard",
146
+ "phase_gate",
147
+ "iswap",
148
+ "swap",
149
+ "U_gate",
150
+ "fsim",
151
+ "fsimg",
152
+ ],
153
+ )
154
+ @pytest.mark.parametrize("dtype", [np.complex64, np.complex128])
155
+ @pytest.mark.parametrize("sparse", [False, True])
156
+ def test_construct(self, gate, dtype, sparse):
157
+ if gate in {"Rx", "Ry", "Rz", "phase_gate"}:
158
+ args = (0.43827,)
159
+ elif gate in {"U_gate"}:
160
+ args = (0.1, 0.2, 0.3)
161
+ elif gate in {"fsim"}:
162
+ args = (-1.3, 5.4)
163
+ elif gate in {"fsimg"}:
164
+ args = (-1.3, 5.4, 2.0, 3.0, 4.0)
165
+ else:
166
+ args = ()
167
+ G = getattr(qu, gate)(*args, dtype=dtype, sparse=sparse)
168
+ assert G.dtype == dtype
169
+ assert qu.issparse(G) is sparse
170
+ psi = qu.rand_ket(G.shape[0])
171
+ Gpsi = G @ psi
172
+ assert qu.expec(Gpsi, Gpsi) == pytest.approx(1.0)
173
+
174
+ def test_gates_import(self):
175
+ from quimb.gates import Z
176
+
177
+ assert_allclose(Z, [[1, 0], [0, -1]])
178
+
179
+ def test_fsim(self):
180
+ assert_allclose(qu.fsim(-qu.pi / 2, 0.0), qu.iswap(), atol=1e-12)
181
+
182
+ def test_fsimg(self):
183
+ assert_allclose(
184
+ qu.fsimg(-qu.pi / 2, 0.0, 0.0, 0.0, 0.0), qu.iswap(), atol=1e-12
185
+ )
186
+
187
+
188
+ class TestHamHeis:
189
+ def test_ham_heis_2(self):
190
+ h = qu.ham_heis(2, cyclic=False)
191
+ evals = qu.eigvalsh(h)
192
+ assert_allclose(evals, [-0.75, 0.25, 0.25, 0.25])
193
+ gs = qu.groundstate(h)
194
+ assert_allclose(qu.expec(gs, qu.singlet()), 1.0)
195
+
196
+ @pytest.mark.parametrize("parallel", [False, True])
197
+ def test_ham_heis_sparse_cyclic_4(self, parallel):
198
+ h = qu.ham_heis(4, sparse=True, cyclic=True, parallel=parallel)
199
+ lk = qu.eigvalsh(h, k=4)
200
+ assert_allclose(lk, [-2, -1, -1, -1])
201
+
202
+ def test_ham_heis_bz(self):
203
+ h = qu.ham_heis(2, cyclic=False, b=1)
204
+ evals = qu.eigvalsh(h)
205
+ assert_allclose(evals, [-3 / 4, -3 / 4, 1 / 4, 5 / 4])
206
+
207
+ @pytest.mark.parametrize("stype", ["coo", "csr", "csc", "bsr"])
208
+ def test_sformat_construct(self, stype):
209
+ h = qu.ham_heis(4, sparse=True, stype=stype)
210
+ assert h.format == stype
211
+
212
+
213
+ class TestHamJ1J2:
214
+ def test_ham_j1j2_3_dense(self):
215
+ h = qu.ham_j1j2(3, j2=1.0, cyclic=False)
216
+ h2 = qu.ham_heis(3, cyclic=True)
217
+ assert_allclose(h, h2)
218
+
219
+ def test_ham_j1j2_6_sparse_cyc(self):
220
+ h = qu.ham_j1j2(6, j2=0.5, sparse=True, cyclic=True)
221
+ lk = qu.eigvalsh(h, k=5)
222
+ assert_allclose(lk, [-9 / 4, -9 / 4, -7 / 4, -7 / 4, -7 / 4])
223
+
224
+ def test_ham_j1j2_4_bz(self):
225
+ h = qu.ham_j1j2(4, j2=0.5, cyclic=True, bz=0)
226
+ lk = qu.eigvalsh(h, k=11)
227
+ assert_allclose(
228
+ lk,
229
+ [-1.5, -1.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5],
230
+ )
231
+ h = qu.ham_j1j2(4, j2=0.5, cyclic=True, bz=0.05)
232
+ lk = qu.eigvalsh(h, k=11)
233
+ assert_allclose(
234
+ lk,
235
+ [
236
+ -1.5,
237
+ -1.5,
238
+ -0.55,
239
+ -0.55,
240
+ -0.55,
241
+ -0.5,
242
+ -0.5,
243
+ -0.5,
244
+ -0.45,
245
+ -0.45,
246
+ -0.45,
247
+ ],
248
+ )
249
+
250
+
251
+ class TestHamMBL:
252
+ @pytest.mark.parametrize("cyclic", [False, True])
253
+ @pytest.mark.parametrize("sparse", [False, True])
254
+ @pytest.mark.parametrize("dh_dim", [1, 2, 3, "y", "xz"])
255
+ @pytest.mark.parametrize("dh_dist", ["s", "g"])
256
+ def test_construct(self, cyclic, sparse, dh_dim, dh_dist):
257
+ qu.ham_mbl(
258
+ n=3,
259
+ dh=3,
260
+ cyclic=cyclic,
261
+ sparse=sparse,
262
+ dh_dim=dh_dim,
263
+ dh_dist=dh_dist,
264
+ )
265
+
266
+ @pytest.mark.parametrize("cyclic", [False, True])
267
+ @pytest.mark.parametrize("sparse", [False, True])
268
+ def test_construct_qp(self, cyclic, sparse):
269
+ qu.ham_mbl(n=3, dh=3, cyclic=cyclic, sparse=sparse, dh_dist="qp")
270
+
271
+
272
+ class TestHamHeis2D:
273
+ @pytest.mark.parametrize("cyclic", [False, True])
274
+ @pytest.mark.parametrize("sparse", [False, True])
275
+ @pytest.mark.parametrize("parallel", [False, True])
276
+ @pytest.mark.parametrize("bz", [0.0, 0.7])
277
+ def test_construct(self, cyclic, sparse, parallel, bz):
278
+ qu.ham_heis_2D(
279
+ 2, 3, cyclic=cyclic, sparse=sparse, parallel=parallel, bz=bz
280
+ )
281
+
282
+
283
+ class TestSpinZProjector:
284
+ @pytest.mark.parametrize("sz", [-2, -1, 0, 1, 2])
285
+ def test_works(self, sz):
286
+ prj = qu.zspin_projector(4, sz)
287
+ h = qu.ham_heis(4)
288
+ h0 = prj.T @ h @ prj
289
+ v0s = qu.eigvecsh(h0)
290
+ for i in range(v0s.shape[1]):
291
+ v0 = v0s[:, [i]]
292
+ vf = prj @ v0
293
+ prjv = vf @ vf.H
294
+ # Check reconstructed full eigenvectors commute with full ham
295
+ assert_allclose(prjv @ h, h @ prjv, atol=1e-13)
296
+ if sz == 0:
297
+ # Groundstate must be in most symmetric subspace
298
+ gs = qu.groundstate(h)
299
+ gs0 = prj @ v0s[:, [0]]
300
+ assert_allclose(qu.expec(gs, gs0), 1.0)
301
+ assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
302
+
303
+ def test_raises(self):
304
+ with pytest.raises(ValueError):
305
+ qu.zspin_projector(5, 0)
306
+ with pytest.raises(ValueError):
307
+ qu.zspin_projector(4, 1 / 2)
308
+
309
+ @pytest.mark.parametrize("sz", [(-1 / 2, 1 / 2), (3 / 2, 5 / 2)])
310
+ def test_spin_half_double_space(self, sz):
311
+ prj = qu.zspin_projector(5, sz)
312
+ h = qu.ham_heis(5)
313
+ h0 = prj.T @ h @ prj
314
+ v0s = qu.eigvecsh(h0)
315
+ for i in range(v0s.shape[1]):
316
+ v0 = v0s[:, [i]]
317
+ vf = prj @ v0
318
+ prjv = vf @ vf.H
319
+ # Check reconstructed full eigenvectors commute with full ham
320
+ assert_allclose(prjv @ h, h @ prjv, atol=1e-13)
321
+ if sz == 0:
322
+ # Groundstate must be in most symmetric subspace
323
+ gs = qu.groundstate(h)
324
+ gs0 = prj @ v0s[:, [0]]
325
+ assert_allclose(qu.expec(gs, gs0), 1.0)
326
+ assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
327
+
328
+
329
+ class TestSwap:
330
+ @pytest.mark.parametrize("sparse", [False, True])
331
+ def test_swap_qubits(self, sparse):
332
+ a = qu.up() & qu.down()
333
+ s = qu.swap(2, sparse=sparse)
334
+ assert_allclose(s @ a, qu.down() & qu.up())
335
+
336
+ @pytest.mark.parametrize("sparse", [False, True])
337
+ def test_swap_higher_dim(self, sparse):
338
+ a = qu.rand_ket(9)
339
+ s = qu.swap(3, sparse=sparse)
340
+ assert_allclose(s @ a, a.reshape([3, 3]).T.reshape([9, 1]))
341
+
342
+
343
+ @pytest.mark.parametrize("sparse", [False, True])
344
+ def test_3qubit_gates(sparse):
345
+ psi = qu.rand_ket(8)
346
+ psi = qu.toffoli(sparse=sparse) @ psi
347
+ psi = qu.ccY(sparse=sparse) @ psi
348
+ psi = qu.fredkin(sparse=sparse) @ psi
349
+ psi = qu.ccZ(sparse=sparse) @ psi
350
+ assert qu.expec(psi, psi) == pytest.approx(1.0)
351
+
352
+
353
+ class TestHubbardSpinless:
354
+ def test_half_filling_groundstate(self):
355
+ H = qu.ham_hubbard_hardcore(8, t=0.5, V=1.0, mu=1.0, cyclic=True)
356
+ gs = qu.groundstate(H)
357
+ dims = [2] * 8
358
+ cn = qu.num(2)
359
+ ens = [qu.expec(cn, qu.ptr(gs, dims, i)) for i in range(8)]
360
+ for en in ens:
361
+ assert en == pytest.approx(0.5, rel=1e-6)
@@ -0,0 +1,296 @@
1
+ import pytest
2
+ from numpy.testing import assert_allclose
3
+ import numpy as np
4
+ import scipy.sparse as sp
5
+
6
+ import quimb as qu
7
+
8
+
9
+ dtypes = [np.float32, np.float64, np.complex128, np.complex64]
10
+
11
+
12
+ class TestRandn:
13
+ @pytest.mark.parametrize(
14
+ "dtype",
15
+ dtypes
16
+ + [
17
+ float,
18
+ complex,
19
+ "f8",
20
+ "f4",
21
+ "c8",
22
+ "c16",
23
+ "float32",
24
+ "float64",
25
+ "complex64",
26
+ "complex128",
27
+ ],
28
+ )
29
+ def test_basic(self, dtype):
30
+ x = qu.randn((2, 3, 4), dtype=dtype)
31
+ assert x.shape == (2, 3, 4)
32
+ assert x.dtype == np.dtype(dtype)
33
+
34
+ @pytest.mark.parametrize("num_threads", [2, 3])
35
+ @pytest.mark.parametrize("dist", ["uniform", "normal", "exp"])
36
+ def test_multithreaded(self, num_threads, dist):
37
+ x = qu.randn((2, 3, 4), dist=dist, num_threads=num_threads, seed=42)
38
+ y = qu.randn((2, 3, 4), dist=dist, num_threads=num_threads, seed=42)
39
+ assert_allclose(x, y)
40
+
41
+ def test_can_seed(self):
42
+ assert_allclose(qu.randn(5, seed=42), qu.randn(5, seed=42))
43
+
44
+ def test_scale_and_loc(self):
45
+ x = qu.randn(1000, scale=100, loc=50, dtype=float, seed=42)
46
+ assert_allclose(np.mean(x), 50, rtol=1e-1)
47
+ assert_allclose(np.std(x), 100, rtol=1e-1)
48
+
49
+ @pytest.mark.parametrize(
50
+ "dtype,tol",
51
+ [
52
+ ("complex64", 1e-5),
53
+ ("complex128", 1e-11),
54
+ ],
55
+ )
56
+ def test_rand_phase(self, dtype, tol):
57
+ x = qu.gen.rand.rand_phase(10, dtype=dtype)
58
+ assert x.dtype == dtype
59
+ assert_allclose(np.abs(x), np.ones(10), rtol=tol)
60
+
61
+ @pytest.mark.parametrize(
62
+ "dtype", ["float32", "float64", "complex64", "complex128"]
63
+ )
64
+ def test_rand_rademacher(self, dtype):
65
+ x = qu.gen.rand.rand_rademacher(10, dtype=dtype)
66
+ assert x.dtype == dtype
67
+ assert_allclose(np.abs(x), np.ones(10))
68
+
69
+ @pytest.mark.parametrize(
70
+ "bitgen",
71
+ [
72
+ "MT19937",
73
+ "PCG64",
74
+ "Philox",
75
+ "SFC64",
76
+ ],
77
+ )
78
+ def test_set_bitgen(self, bitgen):
79
+ x0 = qu.randn(3, seed=42)
80
+ qu.set_rand_bitgen(bitgen)
81
+ x1 = qu.randn(3, seed=42)
82
+ assert not np.allclose(x0, x1) or bitgen == "PCG64" # <- default
83
+ x2 = qu.randn(3, seed=42)
84
+ assert_allclose(x1, x2)
85
+ qu.set_rand_bitgen(None)
86
+ x3 = qu.randn(3, seed=42)
87
+ assert_allclose(x0, x3)
88
+
89
+
90
+ @pytest.mark.parametrize("dtype", dtypes)
91
+ class TestRandMatrix:
92
+ def test_rand_matrix(self, dtype):
93
+ a = qu.rand_matrix(3, scaled=True, dtype=dtype)
94
+ assert a.shape == (3, 3)
95
+ assert type(a) == qu.qarray
96
+ assert a.dtype == dtype
97
+
98
+ def test_rand_matrix_sparse(self, dtype):
99
+ a = qu.rand_matrix(3, sparse=True, dtype=dtype)
100
+ assert a.shape == (3, 3)
101
+ assert type(a) == sp.csr_matrix
102
+ assert a.dtype == dtype
103
+
104
+ def test_rand_matrix_sparse_density(self, dtype):
105
+ a = qu.rand_matrix(3, sparse=True, density=1 / 9, dtype=dtype)
106
+ assert a.nnz == 1
107
+ a = qu.rand_matrix(3, sparse=True, density=7 / 9, dtype=dtype)
108
+ assert a.nnz == 7
109
+
110
+ def test_rand_matrix_bsr(self, dtype):
111
+ a = qu.rand_matrix(
112
+ 10, sparse=True, density=0.2, stype="bsr", dtype=dtype
113
+ )
114
+ assert a.shape == (10, 10)
115
+ assert type(a) == sp.bsr_matrix
116
+ assert a.dtype == dtype
117
+
118
+ @pytest.mark.parametrize("sparse", [False, True])
119
+ def test_seed(self, dtype, sparse):
120
+ a = qu.rand_matrix(10, sparse=sparse, dtype=dtype, seed=42)
121
+ b = qu.rand_matrix(10, sparse=sparse, dtype=dtype, seed=42)
122
+ if sparse:
123
+ assert_allclose(a.data, b.data)
124
+ else:
125
+ assert_allclose(a, b)
126
+
127
+
128
+ @pytest.mark.parametrize("dtype", dtypes)
129
+ class TestRandHerm:
130
+ def test_rand_herm(self, dtype):
131
+ a = qu.rand_herm(3, dtype=dtype)
132
+ assert a.shape == (3, 3)
133
+ assert type(a) == qu.qarray
134
+ assert a.dtype == dtype
135
+ assert_allclose(a, a.H)
136
+ evals = qu.eigvalsh(a)
137
+ assert_allclose(evals.imag, [0, 0, 0], atol=1e-14)
138
+
139
+ def test_rand_herm_sparse(self, dtype):
140
+ a = qu.rand_herm(3, sparse=True, density=0.3, dtype=dtype)
141
+ assert a.shape == (3, 3)
142
+ assert type(a) == sp.csr_matrix
143
+ assert qu.isherm(a)
144
+ assert a.dtype == dtype
145
+ evals = qu.eigvalsh(a.toarray())
146
+ assert_allclose(evals.imag, [0, 0, 0], atol=1e-14)
147
+
148
+
149
+ @pytest.mark.parametrize("dtype", dtypes)
150
+ class TestRandPos:
151
+ def test_rand_pos(self, dtype):
152
+ a = qu.rand_pos(3, dtype=dtype)
153
+ assert qu.ispos(a)
154
+ assert a.shape == (3, 3)
155
+ assert type(a) == qu.qarray
156
+ assert a.dtype == dtype
157
+ evals = qu.eigvalsh(a)
158
+ assert_allclose(evals.imag, [0, 0, 0], atol=1e-7)
159
+ assert np.all(evals.real >= 0)
160
+
161
+ def test_rand_pos_sparse(self, dtype):
162
+ a = qu.rand_pos(3, sparse=True, density=0.3, dtype=dtype)
163
+ assert a.shape == (3, 3)
164
+ assert type(a) == sp.csr_matrix
165
+ assert a.dtype == dtype
166
+ evals = qu.eigvalsh(a.toarray())
167
+ assert_allclose(evals.imag, [0, 0, 0], atol=1e-7)
168
+ assert np.all(evals.real >= -1e-15)
169
+
170
+
171
+ @pytest.mark.parametrize("dtype", dtypes)
172
+ class TestRandRho:
173
+ def test_rand_rho(self, dtype):
174
+ rho = qu.rand_rho(3, dtype=dtype)
175
+ assert rho.shape == (3, 3)
176
+ assert type(rho) == qu.qarray
177
+ assert rho.dtype == dtype
178
+ assert_allclose(qu.tr(rho), 1.0)
179
+
180
+ def test_rand_rho_sparse(self, dtype):
181
+ rho = qu.rand_rho(3, sparse=True, density=0.3, dtype=dtype)
182
+ assert rho.shape == (3, 3)
183
+ assert type(rho) == sp.csr_matrix
184
+ assert rho.dtype == dtype
185
+ assert_allclose(qu.tr(rho), 1.0)
186
+
187
+
188
+ @pytest.mark.parametrize("dtype", dtypes)
189
+ class TestRandUni:
190
+ def test_rand_uni(self, dtype):
191
+ u = qu.rand_uni(3, dtype=dtype)
192
+ assert u.shape == (3, 3)
193
+ assert type(u) == qu.qarray
194
+ assert u.dtype == dtype
195
+ # low tolerances for float32 etc
196
+ assert_allclose(qu.eye(3), u @ u.H, atol=1e-7, rtol=1e-5)
197
+ assert_allclose(qu.eye(3), u.H @ u, atol=1e-7, rtol=1e-5)
198
+
199
+
200
+ class TestRandKet:
201
+ def test_rand_ket(self):
202
+ ket = qu.rand_ket(3)
203
+ assert ket.shape == (3, 1)
204
+ assert type(ket) == qu.qarray
205
+ assert_allclose(qu.tr(ket.H @ ket), 1.0)
206
+
207
+
208
+ class TestRandHaarState:
209
+ def test_rand_haar_state(self):
210
+ ket = qu.rand_haar_state(3)
211
+ assert ket.shape == (3, 1)
212
+ assert type(ket) == qu.qarray
213
+ assert_allclose(qu.tr(ket.H @ ket), 1.0)
214
+
215
+ def test_gen_rand_haar_states(self):
216
+ kets = [*qu.gen_rand_haar_states(3, 6)]
217
+ for ket in kets:
218
+ assert ket.shape == (3, 1)
219
+ assert type(ket) == qu.qarray
220
+ assert_allclose(qu.tr(ket.H @ ket), 1.0)
221
+
222
+
223
+ class TestRandMix:
224
+ @pytest.mark.parametrize("mode", ["rand", "haar"])
225
+ def test_rand_mix(self, mode):
226
+ rho = qu.rand_mix(3, mode=mode)
227
+ assert rho.shape == (3, 3)
228
+ assert type(rho) == qu.qarray
229
+ assert_allclose(qu.tr(rho), 1.0)
230
+ mixedness = qu.tr(rho @ rho)
231
+ assert mixedness < 1.0
232
+
233
+
234
+ class TestRandProductState:
235
+ def test_rand_product_state(self):
236
+ a = qu.rand_product_state(3)
237
+ assert a.shape[0] == 2**3
238
+ assert (a.H @ a)[0, 0].real == pytest.approx(1.0)
239
+ assert qu.mutinf(a, [2, 2, 2], 0, 1) == pytest.approx(0.0)
240
+ assert qu.mutinf(a, [2, 2, 2], 1, 2) == pytest.approx(0.0)
241
+ assert qu.mutinf(a, [2, 2, 2], 0, 2) == pytest.approx(0.0)
242
+
243
+
244
+ class TestRandMPS:
245
+ @pytest.mark.parametrize("cyclic", (True, False))
246
+ @pytest.mark.parametrize(
247
+ "d_n_b_e",
248
+ [
249
+ (2, 4, 5, 16),
250
+ (2, 4, 1, 16),
251
+ (3, 3, 7, 27),
252
+ ],
253
+ )
254
+ def test_shape(self, d_n_b_e, cyclic):
255
+ d, n, b, e = d_n_b_e
256
+ psi = qu.rand_matrix_product_state(n, b, d, cyclic=cyclic)
257
+ assert psi.shape == (e, 1)
258
+
259
+ assert_allclose(qu.expec(psi, psi), 1.0)
260
+
261
+ @pytest.mark.parametrize("cyclic", (True, False))
262
+ @pytest.mark.parametrize("bond_dim", (1, 2, 3))
263
+ def test_rank(self, bond_dim, cyclic):
264
+ psi = qu.rand_matrix_product_state(10, bond_dim, cyclic=cyclic)
265
+ rhoa = qu.ptr(psi, [2] * 10, [0, 1, 2, 3])
266
+ el = qu.eigvalsh(rhoa)
267
+ # bond_dim squared as cyclic mps is generated
268
+ assert sum(el > 1e-12) == bond_dim ** (2 if cyclic else 1)
269
+
270
+
271
+ class TestRandSeperable:
272
+ def test_entanglement(self):
273
+ rho = qu.rand_seperable([2, 3, 2], 10)
274
+ assert_allclose(qu.tr(rho), 1.0)
275
+ assert qu.isherm(rho)
276
+
277
+ assert qu.logneg(rho, [2, 6]) < 1e-12
278
+ assert qu.logneg(rho, [6, 2]) < 1e-12
279
+
280
+ rho_a = qu.ptr(rho, [2, 3, 2], 1)
281
+
282
+ el = qu.eigvalsh(rho_a)
283
+ assert np.all(el < 1 - 1e-12)
284
+ assert np.all(el > 1e-12)
285
+
286
+
287
+ class TestRandMERA:
288
+ @pytest.mark.parametrize("invariant", [False, True])
289
+ @pytest.mark.parametrize(
290
+ "dtype", ["float32", "float64", "complex64", "complex128"]
291
+ )
292
+ def test_simple(self, invariant, dtype):
293
+ m = qu.rand_mera(8, invariant=invariant, dtype=dtype)
294
+ assert m.dtype == dtype
295
+ assert m.H @ m == pytest.approx(1.0)
296
+ assert m.shape == (256, 1)