Trajectree 0.0.1__py3-none-any.whl → 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. trajectree/__init__.py +0 -3
  2. trajectree/fock_optics/devices.py +1 -1
  3. trajectree/fock_optics/light_sources.py +2 -2
  4. trajectree/fock_optics/measurement.py +3 -3
  5. trajectree/fock_optics/utils.py +6 -6
  6. trajectree/trajectory.py +2 -2
  7. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/METADATA +2 -3
  8. trajectree-0.0.2.dist-info/RECORD +16 -0
  9. trajectree/quimb/docs/_pygments/_pygments_dark.py +0 -118
  10. trajectree/quimb/docs/_pygments/_pygments_light.py +0 -118
  11. trajectree/quimb/docs/conf.py +0 -158
  12. trajectree/quimb/docs/examples/ex_mpi_expm_evo.py +0 -62
  13. trajectree/quimb/quimb/__init__.py +0 -507
  14. trajectree/quimb/quimb/calc.py +0 -1491
  15. trajectree/quimb/quimb/core.py +0 -2279
  16. trajectree/quimb/quimb/evo.py +0 -712
  17. trajectree/quimb/quimb/experimental/__init__.py +0 -0
  18. trajectree/quimb/quimb/experimental/autojittn.py +0 -129
  19. trajectree/quimb/quimb/experimental/belief_propagation/__init__.py +0 -109
  20. trajectree/quimb/quimb/experimental/belief_propagation/bp_common.py +0 -397
  21. trajectree/quimb/quimb/experimental/belief_propagation/d1bp.py +0 -316
  22. trajectree/quimb/quimb/experimental/belief_propagation/d2bp.py +0 -653
  23. trajectree/quimb/quimb/experimental/belief_propagation/hd1bp.py +0 -571
  24. trajectree/quimb/quimb/experimental/belief_propagation/hv1bp.py +0 -775
  25. trajectree/quimb/quimb/experimental/belief_propagation/l1bp.py +0 -316
  26. trajectree/quimb/quimb/experimental/belief_propagation/l2bp.py +0 -537
  27. trajectree/quimb/quimb/experimental/belief_propagation/regions.py +0 -194
  28. trajectree/quimb/quimb/experimental/cluster_update.py +0 -286
  29. trajectree/quimb/quimb/experimental/merabuilder.py +0 -865
  30. trajectree/quimb/quimb/experimental/operatorbuilder/__init__.py +0 -15
  31. trajectree/quimb/quimb/experimental/operatorbuilder/operatorbuilder.py +0 -1631
  32. trajectree/quimb/quimb/experimental/schematic.py +0 -7
  33. trajectree/quimb/quimb/experimental/tn_marginals.py +0 -130
  34. trajectree/quimb/quimb/experimental/tnvmc.py +0 -1483
  35. trajectree/quimb/quimb/gates.py +0 -36
  36. trajectree/quimb/quimb/gen/__init__.py +0 -2
  37. trajectree/quimb/quimb/gen/operators.py +0 -1167
  38. trajectree/quimb/quimb/gen/rand.py +0 -713
  39. trajectree/quimb/quimb/gen/states.py +0 -479
  40. trajectree/quimb/quimb/linalg/__init__.py +0 -6
  41. trajectree/quimb/quimb/linalg/approx_spectral.py +0 -1109
  42. trajectree/quimb/quimb/linalg/autoblock.py +0 -258
  43. trajectree/quimb/quimb/linalg/base_linalg.py +0 -719
  44. trajectree/quimb/quimb/linalg/mpi_launcher.py +0 -397
  45. trajectree/quimb/quimb/linalg/numpy_linalg.py +0 -244
  46. trajectree/quimb/quimb/linalg/rand_linalg.py +0 -514
  47. trajectree/quimb/quimb/linalg/scipy_linalg.py +0 -293
  48. trajectree/quimb/quimb/linalg/slepc_linalg.py +0 -892
  49. trajectree/quimb/quimb/schematic.py +0 -1518
  50. trajectree/quimb/quimb/tensor/__init__.py +0 -401
  51. trajectree/quimb/quimb/tensor/array_ops.py +0 -610
  52. trajectree/quimb/quimb/tensor/circuit.py +0 -4824
  53. trajectree/quimb/quimb/tensor/circuit_gen.py +0 -411
  54. trajectree/quimb/quimb/tensor/contraction.py +0 -336
  55. trajectree/quimb/quimb/tensor/decomp.py +0 -1255
  56. trajectree/quimb/quimb/tensor/drawing.py +0 -1646
  57. trajectree/quimb/quimb/tensor/fitting.py +0 -385
  58. trajectree/quimb/quimb/tensor/geometry.py +0 -583
  59. trajectree/quimb/quimb/tensor/interface.py +0 -114
  60. trajectree/quimb/quimb/tensor/networking.py +0 -1058
  61. trajectree/quimb/quimb/tensor/optimize.py +0 -1818
  62. trajectree/quimb/quimb/tensor/tensor_1d.py +0 -4778
  63. trajectree/quimb/quimb/tensor/tensor_1d_compress.py +0 -1854
  64. trajectree/quimb/quimb/tensor/tensor_1d_tebd.py +0 -662
  65. trajectree/quimb/quimb/tensor/tensor_2d.py +0 -5954
  66. trajectree/quimb/quimb/tensor/tensor_2d_compress.py +0 -96
  67. trajectree/quimb/quimb/tensor/tensor_2d_tebd.py +0 -1230
  68. trajectree/quimb/quimb/tensor/tensor_3d.py +0 -2869
  69. trajectree/quimb/quimb/tensor/tensor_3d_tebd.py +0 -46
  70. trajectree/quimb/quimb/tensor/tensor_approx_spectral.py +0 -60
  71. trajectree/quimb/quimb/tensor/tensor_arbgeom.py +0 -3237
  72. trajectree/quimb/quimb/tensor/tensor_arbgeom_compress.py +0 -565
  73. trajectree/quimb/quimb/tensor/tensor_arbgeom_tebd.py +0 -1138
  74. trajectree/quimb/quimb/tensor/tensor_builder.py +0 -5411
  75. trajectree/quimb/quimb/tensor/tensor_core.py +0 -11179
  76. trajectree/quimb/quimb/tensor/tensor_dmrg.py +0 -1472
  77. trajectree/quimb/quimb/tensor/tensor_mera.py +0 -204
  78. trajectree/quimb/quimb/utils.py +0 -892
  79. trajectree/quimb/tests/__init__.py +0 -0
  80. trajectree/quimb/tests/test_accel.py +0 -501
  81. trajectree/quimb/tests/test_calc.py +0 -788
  82. trajectree/quimb/tests/test_core.py +0 -847
  83. trajectree/quimb/tests/test_evo.py +0 -565
  84. trajectree/quimb/tests/test_gen/__init__.py +0 -0
  85. trajectree/quimb/tests/test_gen/test_operators.py +0 -361
  86. trajectree/quimb/tests/test_gen/test_rand.py +0 -296
  87. trajectree/quimb/tests/test_gen/test_states.py +0 -261
  88. trajectree/quimb/tests/test_linalg/__init__.py +0 -0
  89. trajectree/quimb/tests/test_linalg/test_approx_spectral.py +0 -368
  90. trajectree/quimb/tests/test_linalg/test_base_linalg.py +0 -351
  91. trajectree/quimb/tests/test_linalg/test_mpi_linalg.py +0 -127
  92. trajectree/quimb/tests/test_linalg/test_numpy_linalg.py +0 -84
  93. trajectree/quimb/tests/test_linalg/test_rand_linalg.py +0 -134
  94. trajectree/quimb/tests/test_linalg/test_slepc_linalg.py +0 -283
  95. trajectree/quimb/tests/test_tensor/__init__.py +0 -0
  96. trajectree/quimb/tests/test_tensor/test_belief_propagation/__init__.py +0 -0
  97. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d1bp.py +0 -39
  98. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d2bp.py +0 -67
  99. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hd1bp.py +0 -64
  100. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hv1bp.py +0 -51
  101. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l1bp.py +0 -142
  102. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l2bp.py +0 -101
  103. trajectree/quimb/tests/test_tensor/test_circuit.py +0 -816
  104. trajectree/quimb/tests/test_tensor/test_contract.py +0 -67
  105. trajectree/quimb/tests/test_tensor/test_decomp.py +0 -40
  106. trajectree/quimb/tests/test_tensor/test_mera.py +0 -52
  107. trajectree/quimb/tests/test_tensor/test_optimizers.py +0 -488
  108. trajectree/quimb/tests/test_tensor/test_tensor_1d.py +0 -1171
  109. trajectree/quimb/tests/test_tensor/test_tensor_2d.py +0 -606
  110. trajectree/quimb/tests/test_tensor/test_tensor_2d_tebd.py +0 -144
  111. trajectree/quimb/tests/test_tensor/test_tensor_3d.py +0 -123
  112. trajectree/quimb/tests/test_tensor/test_tensor_arbgeom.py +0 -226
  113. trajectree/quimb/tests/test_tensor/test_tensor_builder.py +0 -441
  114. trajectree/quimb/tests/test_tensor/test_tensor_core.py +0 -2066
  115. trajectree/quimb/tests/test_tensor/test_tensor_dmrg.py +0 -388
  116. trajectree/quimb/tests/test_tensor/test_tensor_spectral_approx.py +0 -63
  117. trajectree/quimb/tests/test_tensor/test_tensor_tebd.py +0 -270
  118. trajectree/quimb/tests/test_utils.py +0 -85
  119. trajectree-0.0.1.dist-info/RECORD +0 -126
  120. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/WHEEL +0 -0
  121. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/licenses/LICENSE +0 -0
  122. {trajectree-0.0.1.dist-info → trajectree-0.0.2.dist-info}/top_level.txt +0 -0
@@ -1,1171 +0,0 @@
1
- import numpy as np
2
- import pytest
3
- from numpy.testing import assert_allclose
4
-
5
- import quimb as qu
6
- import quimb.tensor as qtn
7
-
8
- dtypes = ["float32", "float64", "complex64", "complex128"]
9
-
10
-
11
- class TestMatrixProductState:
12
- def test_matrix_product_state(self):
13
- tensors = (
14
- [np.random.rand(5, 2)]
15
- + [np.random.rand(5, 5, 2) for _ in range(3)]
16
- + [np.random.rand(5, 2)]
17
- )
18
- mps = qtn.MatrixProductState(tensors)
19
- mps.check()
20
- assert len(mps.tensors) == 5
21
- nmps = mps.reindex_sites("foo{}", inplace=False, where=slice(0, 3))
22
- assert nmps.site_ind_id == "k{}"
23
- assert isinstance(nmps, qtn.MatrixProductState)
24
- assert set(nmps.outer_inds()) == {"foo0", "foo1", "foo2", "k3", "k4"}
25
- assert set(mps.outer_inds()) == {"k0", "k1", "k2", "k3", "k4"}
26
- mps.site_ind_id = "foo{}"
27
- assert set(mps.outer_inds()) == {
28
- "foo0",
29
- "foo1",
30
- "foo2",
31
- "foo3",
32
- "foo4",
33
- }
34
- assert mps.site_inds == ("foo0", "foo1", "foo2", "foo3", "foo4")
35
- assert mps.site_ind_id == "foo{}"
36
- mps.show()
37
-
38
- @pytest.mark.parametrize(
39
- "dtype", [float, complex, np.complex128, np.float64, "raise"]
40
- )
41
- def test_rand_mps_dtype(self, dtype):
42
- if dtype == "raise":
43
- with pytest.raises(TypeError):
44
- qtn.MPS_rand_state(10, 7, dtype=dtype)
45
- else:
46
- p = qtn.MPS_rand_state(10, 7, dtype=dtype)
47
- assert p[0].dtype == dtype
48
- assert p[7].dtype == dtype
49
-
50
- def test_trans_invar(self):
51
- with pytest.raises(ValueError):
52
- psi = qtn.MPS_rand_state(10, 7, cyclic=False, trans_invar=True)
53
-
54
- psi = qtn.MPS_rand_state(10, 7, cyclic=True, trans_invar=True)
55
- z0 = psi.expec(psi.gate(qu.pauli("Z"), 0, contract=True))
56
- z3 = psi.expec(psi.gate(qu.pauli("Z"), 0, contract=True))
57
- z7 = psi.expec(psi.gate(qu.pauli("Z"), 0, contract=True))
58
-
59
- assert_allclose(z0, z3)
60
- assert_allclose(z3, z7)
61
-
62
- def test_from_dense(self):
63
- L = 8
64
- psi = qu.rand_ket(2**L)
65
- mps = qtn.MatrixProductState.from_dense(psi)
66
- assert mps.tags == qtn.oset(f"I{i}" for i in range(L))
67
- assert mps.site_inds == tuple(f"k{i}" for i in range(L))
68
- assert mps.L == L
69
- assert mps.bond_sizes() == [2, 4, 8, 16, 8, 4, 2]
70
- mpod = mps.to_qarray()
71
- assert qu.expec(mpod, psi) == pytest.approx(1)
72
-
73
- def test_from_dense_low_rank(self):
74
- L = 6
75
- psi = qu.ghz_state(L)
76
- mps = qtn.MatrixProductState.from_dense(psi, dims=[2] * L)
77
- assert mps.tags == qtn.oset(f"I{i}" for i in range(L))
78
- assert mps.site_inds == tuple(f"k{i}" for i in range(L))
79
- assert mps.L == L
80
- assert mps.bond_sizes() == [2, 2, 2, 2, 2]
81
- mpod = mps.to_qarray()
82
- assert qu.expec(mpod, psi) == pytest.approx(1)
83
-
84
- def test_left_canonize_site(self):
85
- a = np.random.randn(7, 2) + 1.0j * np.random.randn(7, 2)
86
- b = np.random.randn(7, 7, 2) + 1.0j * np.random.randn(7, 7, 2)
87
- c = np.random.randn(7, 2) + 1.0j * np.random.randn(7, 2)
88
- mps = qtn.MatrixProductState([a, b, c], site_tag_id="I{}")
89
-
90
- mps.left_canonize_site(0)
91
- assert mps["I0"].shape == (2, 2)
92
- assert mps["I0"].tags == qtn.oset(("I0",))
93
- assert mps["I1"].tags == qtn.oset(("I1",))
94
-
95
- U = mps["I0"].data
96
- assert_allclose(U.conj().T @ U, np.eye(2), atol=1e-13)
97
- assert_allclose(U @ U.conj().T, np.eye(2), atol=1e-13)
98
-
99
- # combined two site contraction is identity also
100
- mps.left_canonize_site(1)
101
- ptn = (mps.H & mps) ^ ["I0", "I1"]
102
- assert_allclose(ptn["I1"].data, np.eye(4), atol=1e-13)
103
-
104
- # try normalizing the state
105
- mps["I2"] /= mps["I2"].norm()
106
-
107
- assert_allclose(abs(mps.H @ mps), 1.0)
108
-
109
- def test_right_canonize_site(self):
110
- a = np.random.randn(7, 2) + 1.0j * np.random.randn(7, 2)
111
- b = np.random.randn(7, 7, 2) + 1.0j * np.random.randn(7, 7, 2)
112
- c = np.random.randn(7, 2) + 1.0j * np.random.randn(7, 2)
113
- mps = qtn.MatrixProductState([a, b, c], site_tag_id="I{}")
114
-
115
- mps.right_canonize_site(2)
116
- assert mps["I2"].shape == (2, 2)
117
- assert mps["I2"].tags == qtn.oset(("I2",))
118
- assert mps["I1"].tags == qtn.oset(("I1",))
119
-
120
- U = mps["I2"].data
121
- assert_allclose(U.conj().T @ U, np.eye(2), atol=1e-13)
122
- assert_allclose(U @ U.conj().T, np.eye(2), atol=1e-13)
123
-
124
- # combined two site contraction is identity also
125
- mps.right_canonize_site(1)
126
- ptn = (mps.H & mps) ^ ["I1", "I2"]
127
- assert_allclose(ptn["I1"].data, np.eye(4), atol=1e-13)
128
-
129
- # try normalizing the state
130
- mps["I0"] /= mps["I0"].norm()
131
-
132
- assert_allclose(mps.H @ mps, 1)
133
-
134
- def test_rand_mps_left_canonize(self):
135
- n = 10
136
- k = qtn.MPS_rand_state(
137
- n, 10, site_tag_id="foo{}", tags="bar", normalize=False
138
- )
139
- k.left_canonicalize_(normalize=True)
140
-
141
- assert k.count_canonized() == (9, 0)
142
-
143
- assert_allclose(k.H @ k, 1)
144
- p_tn = (k.H & k) ^ slice(0, 9)
145
- assert_allclose(p_tn["foo8"].data, np.eye(10), atol=1e-13)
146
-
147
- def test_rand_mps_left_canonize_with_bra(self):
148
- n = 10
149
- k = qtn.MPS_rand_state(
150
- n, 10, site_tag_id="foo{}", tags="bar", normalize=False
151
- )
152
- b = k.H
153
- k.left_canonicalize_(normalize=True, bra=b)
154
- assert_allclose(b @ k, 1)
155
- p_tn = (b & k) ^ slice(0, 9)
156
- assert_allclose(p_tn["foo8"].data, np.eye(10), atol=1e-13)
157
-
158
- def test_rand_mps_right_canonize(self):
159
- n = 10
160
- k = qtn.MPS_rand_state(
161
- n, 10, site_tag_id="foo{}", tags="bar", normalize=False
162
- )
163
- k.right_canonicalize_(normalize=True)
164
- assert_allclose(k.H @ k, 1)
165
- p_tn = (k.H & k) ^ slice(..., 0, -1)
166
- assert_allclose(p_tn["foo1"].data, np.eye(10), atol=1e-13)
167
-
168
- def test_rand_mps_right_canonize_with_bra(self):
169
- n = 10
170
- k = qtn.MPS_rand_state(
171
- n, 10, site_tag_id="foo{}", tags="bar", normalize=False
172
- )
173
- b = k.H
174
- k.right_canonicalize_(normalize=True, bra=b)
175
- assert_allclose(b @ k, 1)
176
- p_tn = (b & k) ^ slice(..., 0, -1)
177
- assert_allclose(p_tn["foo1"].data, np.eye(10), atol=1e-13)
178
-
179
- def test_rand_mps_mixed_canonize(self):
180
- n = 10
181
- rmps = qtn.MPS_rand_state(
182
- n, 10, site_tag_id="foo{}", tags="bar", normalize=True
183
- )
184
-
185
- # move to the center
186
- rmps.canonicalize_(4)
187
- assert rmps.count_canonized() == (4, 5)
188
- assert_allclose(rmps.H @ rmps, 1)
189
- p_tn = (rmps.H & rmps) ^ slice(0, 4) ^ slice(..., 4, -1)
190
- assert_allclose(p_tn["foo3"].data, np.eye(10), atol=1e-13)
191
- assert_allclose(p_tn["foo5"].data, np.eye(10), atol=1e-13)
192
-
193
- # try shifting to the right
194
- rmps.shift_orthogonality_center(current=4, new=8)
195
- assert_allclose(rmps.H @ rmps, 1)
196
- p_tn = (rmps.H & rmps) ^ slice(0, 8) ^ slice(..., 8, -1)
197
- assert_allclose(p_tn["foo7"].data, np.eye(4), atol=1e-13)
198
- assert_allclose(p_tn["foo9"].data, np.eye(2), atol=1e-13)
199
-
200
- # try shifting to the left
201
- rmps.shift_orthogonality_center(current=8, new=6)
202
- assert_allclose(rmps.H @ rmps, 1)
203
- p_tn = (rmps.H & rmps) ^ slice(0, 6) ^ slice(..., 6, -1)
204
- assert_allclose(p_tn["foo5"].data, np.eye(10), atol=1e-13)
205
- assert_allclose(p_tn["foo7"].data, np.eye(8), atol=1e-13)
206
-
207
- @pytest.mark.parametrize("dtype", dtypes)
208
- def test_canonize_and_calc_current_orthog_center(self, dtype):
209
- p = qtn.MPS_rand_state(20, 3, dtype=dtype)
210
- co = p.calc_current_orthog_center()
211
- assert co == (0, 19)
212
- p.canonicalize_((5, 15), co)
213
- co = p.calc_current_orthog_center()
214
- assert co == (5, 15)
215
- p.canonicalize_((8, 11), co)
216
- co = p.calc_current_orthog_center()
217
- assert co == (8, 11)
218
- assert p.dtype == dtype
219
-
220
- def test_can_change_data(self):
221
- p = qtn.MPS_rand_state(3, 10)
222
- assert_allclose(p.H @ p, 1)
223
- p[1].modify(data=np.random.randn(10, 10, 2))
224
- assert abs(p.H @ p - 1) > 1e-13
225
-
226
- def test_can_change_data_using_subnetwork(self):
227
- p = qtn.MPS_rand_state(3, 10)
228
- pH = p.H
229
- p.add_tag("__ket__")
230
- pH.add_tag("__bra__")
231
- tn = p | pH
232
- assert_allclose((tn ^ ...), 1)
233
- assert_allclose(
234
- tn[("__ket__", "I1")].data, tn[("__bra__", "I1")].data.conj()
235
- )
236
- p[1].modify(data=np.random.randn(10, 10, 2))
237
- assert abs((tn ^ ...) - 1) > 1e-13
238
- assert not np.allclose(
239
- tn[("__ket__", "I1")].data, tn[("__bra__", "I1")].data.conj()
240
- )
241
-
242
- def test_adding_mps(self):
243
- p = qtn.MPS_rand_state(10, 7)
244
- assert max(p["I4"].shape) == 7
245
- p2 = p + p
246
- assert max(p2["I4"].shape) == 14
247
- assert_allclose(p2.H @ p, 2)
248
- p += p
249
- assert max(p["I4"].shape) == 14
250
- assert_allclose(p.H @ p, 4)
251
-
252
- @pytest.mark.parametrize("method", ["svd", "eig"])
253
- @pytest.mark.parametrize("cutoff_mode", ["abs", "rel", "sum2"])
254
- def test_compress_mps(self, method, cutoff_mode):
255
- n = 10
256
- chi = 7
257
- p = qtn.MPS_rand_state(n, chi)
258
- assert max(p["I4"].shape) == chi
259
- p2 = p + p
260
- assert max(p2["I4"].shape) == chi * 2
261
- assert_allclose(p2.H @ p, 2)
262
- p2.left_compress(method=method, cutoff=1e-6, cutoff_mode=cutoff_mode)
263
- assert max(p2["I4"].shape) == chi
264
- assert_allclose(p2.H @ p, 2)
265
- assert p2.count_canonized() == (n - 1, 0)
266
-
267
- def test_compress_mps_right(self):
268
- p = qtn.MPS_rand_state(10, 7)
269
- assert max(p["I4"].shape) == 7
270
- p2 = p + p
271
- assert max(p2["I4"].shape) == 14
272
- assert_allclose(p2.H @ p, 2)
273
- p2.right_compress()
274
- assert max(p2["I4"].shape) == 7
275
- assert_allclose(p2.H @ p, 2)
276
-
277
- @pytest.mark.parametrize("method", ["svd", "eig"])
278
- def test_compress_trim_max_bond(self, method):
279
- p0 = qtn.MPS_rand_state(20, 20)
280
- p = p0.copy()
281
- p.compress(method=method, renorm=True)
282
- assert max(p["I4"].shape) == 20
283
- p.compress(max_bond=13, method=method, renorm=True)
284
- assert max(p["I4"].shape) == 13
285
- assert_allclose(p.H @ p, p0.H @ p0)
286
-
287
- def test_compress_form(self):
288
- p = qtn.MPS_rand_state(20, 20)
289
- p.compress("left")
290
- assert p.count_canonized() == (19, 0)
291
- p.compress("right")
292
- assert p.count_canonized() == (0, 19)
293
- p.compress(7)
294
- assert p.count_canonized() == (7, 12)
295
- p = qtn.MPS_rand_state(20, 20)
296
- p.compress("flat", absorb="left")
297
- assert p.count_canonized() == (0, 0)
298
-
299
- def test_compress_site(self):
300
- psi = qtn.MPS_rand_state(10, 7)
301
- psi.compress_site(3, max_bond=1)
302
- assert psi.bond_sizes() == [2, 4, 1, 1, 7, 7, 7, 4, 2]
303
- assert psi.calc_current_orthog_center() == (3, 3)
304
-
305
- psi = qtn.MPS_rand_state(10, 7)
306
- psi.compress_site(0, max_bond=1)
307
- assert psi.bond_sizes() == [1, 7, 7, 7, 7, 7, 7, 4, 2]
308
- assert psi.calc_current_orthog_center() == (0, 0)
309
-
310
- psi = qtn.MPS_rand_state(10, 7)
311
- psi.compress_site(9, max_bond=1)
312
- assert psi.bond_sizes() == [2, 4, 7, 7, 7, 7, 7, 7, 1]
313
- assert psi.calc_current_orthog_center() == (9, 9)
314
-
315
- @pytest.mark.parametrize("method", ["svd", "eig"])
316
- @pytest.mark.parametrize("form", ["left", "right", "raise"])
317
- def test_add_and_compress_mps(self, method, form):
318
- p = qtn.MPS_rand_state(10, 7)
319
- assert max(p["I4"].shape) == 7
320
-
321
- if form == "raise":
322
- with pytest.raises(ValueError):
323
- p.add_MPS(
324
- p, compress=True, method=method, form=form, cutoff=1e-6
325
- )
326
- return
327
-
328
- p2 = p.add_MPS(p, compress=True, method=method, form=form, cutoff=1e-6)
329
- assert max(p2["I4"].shape) == 7
330
- assert_allclose(p2.H @ p, 2, rtol=1e-5)
331
-
332
- def test_subtract(self):
333
- a, b, c = (qtn.MPS_rand_state(10, 7) for _ in "abc")
334
- ab = a.H @ b
335
- ac = a.H @ c
336
- abmc = a.H @ (b - c)
337
- assert_allclose(ab - ac, abmc)
338
-
339
- def test_subtract_inplace(self):
340
- a, b, c = (qtn.MPS_rand_state(10, 7) for _ in "abc")
341
- ab = a.H @ b
342
- ac = a.H @ c
343
- b -= c
344
- abmc = a.H @ b
345
- assert_allclose(ab - ac, abmc)
346
-
347
- def test_amplitude(self):
348
- mps = qtn.MPS_rand_state(10, 7)
349
- k = mps.to_qarray()
350
- idx = np.random.randint(0, k.shape[0])
351
- c_b = mps.amplitude(f"{idx:0>10b}")
352
- assert k[idx, 0] == pytest.approx(c_b)
353
-
354
- def test_schmidt_values_entropy_gap_simple(self):
355
- n = 12
356
- p = qtn.MPS_rand_state(n, 16)
357
- p.right_canonicalize_()
358
- svns = []
359
- sgs = []
360
- info = {}
361
- for i in range(1, n):
362
- sgs.append(p.schmidt_gap(i, info=info))
363
- svns.append(p.entropy(i, info=info))
364
-
365
- pd = p.to_qarray()
366
- ex_svns = [
367
- qu.entropy_subsys(pd, [2] * n, range(i)) for i in range(1, n)
368
- ]
369
- ex_sgs = [qu.schmidt_gap(pd, [2] * n, range(i)) for i in range(1, n)]
370
- assert_allclose(ex_svns, svns)
371
- assert_allclose(ex_sgs, sgs)
372
-
373
- def test_magnetization(self):
374
- binary = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
375
- p = qtn.MPS_computational_state(binary)
376
- mzs = [p.magnetization(i) for i in range(len(binary))]
377
- assert_allclose(mzs, 0.5 - np.array(binary))
378
-
379
- @pytest.mark.parametrize("rescale", [False, True])
380
- @pytest.mark.parametrize(
381
- "keep", [(2, 3, 4, 6, 8), slice(-2, 4), slice(3, -1, -1), [1]]
382
- )
383
- def test_partial_trace(self, rescale, keep):
384
- n = 10
385
- p = qtn.MPS_rand_state(n, 7)
386
- r = p.partial_trace_to_mpo(
387
- keep=keep, upper_ind_id="u{}", rescale_sites=rescale
388
- )
389
- rd = r.to_qarray()
390
- if isinstance(keep, slice):
391
- keep = p.slice2sites(keep)
392
- else:
393
- if rescale:
394
- if keep == [1]:
395
- assert r.lower_inds_present == ("u0",)
396
- assert r.upper_inds_present == ("k0",)
397
- else:
398
- assert r.lower_inds_present == (
399
- "u0",
400
- "u1",
401
- "u2",
402
- "u3",
403
- "u4",
404
- )
405
- assert r.upper_inds_present == (
406
- "k0",
407
- "k1",
408
- "k2",
409
- "k3",
410
- "k4",
411
- )
412
- else:
413
- if keep == [1]:
414
- assert r.lower_inds_present == ("u1",)
415
- assert r.upper_inds_present == ("k1",)
416
- else:
417
- assert r.lower_inds_present == (
418
- "u2",
419
- "u3",
420
- "u4",
421
- "u6",
422
- "u8",
423
- )
424
- assert r.upper_inds_present == (
425
- "k2",
426
- "k3",
427
- "k4",
428
- "k6",
429
- "k8",
430
- )
431
- assert_allclose(r.trace(), 1.0)
432
- assert qu.isherm(rd)
433
- pd = p.to_qarray()
434
- rdd = pd.ptr([2] * n, keep=keep)
435
- assert_allclose(rd, rdd)
436
-
437
- def test_bipartite_schmidt_state(self):
438
- psi = qtn.MPS_rand_state(16, 5)
439
- psid = psi.to_qarray()
440
- eln = qu.logneg(psid, [2**7, 2**9])
441
-
442
- s_d_ket = psi.bipartite_schmidt_state(7, get="ket-dense")
443
- ln_d_ket = qu.logneg(s_d_ket, [5, 5])
444
- assert_allclose(eln, ln_d_ket, rtol=1e-5)
445
-
446
- s_d_rho = psi.bipartite_schmidt_state(7, get="rho-dense")
447
- ln_d_rho = qu.logneg(s_d_rho, [5, 5])
448
- assert_allclose(eln, ln_d_rho, rtol=1e-5)
449
-
450
- T_s_ket = psi.bipartite_schmidt_state(7, get="ket")
451
- assert set(T_s_ket.inds) == {"kA", "kB"}
452
- assert_allclose(T_s_ket.H @ T_s_ket, 1.0)
453
-
454
- T_s_rho = psi.bipartite_schmidt_state(7, get="rho")
455
- assert set(T_s_rho.outer_inds()) == {"kA", "kB", "bA", "bB"}
456
- assert_allclose(T_s_rho.H @ T_s_rho, 1.0)
457
-
458
- @pytest.mark.parametrize(
459
- "method", ["isvd", "svds", ("isvd", "eigsh"), ("isvd", "cholesky")]
460
- )
461
- @pytest.mark.parametrize("cyclic", [True, False])
462
- @pytest.mark.parametrize(
463
- "sysa", [range(0, 10), range(10, 20), range(20, 30), range(0, 30)]
464
- )
465
- @pytest.mark.parametrize(
466
- "sysb", [range(30, 40), range(40, 50), range(50, 60), range(30, 60)]
467
- )
468
- def test_partial_trace_compress(self, method, cyclic, sysa, sysb):
469
- k = qtn.MPS_rand_state(60, 5, cyclic=cyclic)
470
- kws = dict(sysa=sysa, sysb=sysb, eps=1e-6, method=method, verbosity=2)
471
- rhoc_ab = k.partial_trace_compress(**kws)
472
- assert set(rhoc_ab.outer_inds()) == {"kA", "kB", "bA", "bB"}
473
- inds = ["kA", "kB"], ["bA", "bB"]
474
- x = rhoc_ab.trace(*inds)
475
- assert_allclose(1.0, x, rtol=1e-3)
476
-
477
- @pytest.mark.parametrize("cyclic", [True, False])
478
- def test_known_bad_case(self, cyclic):
479
- k = qtn.MPS_rand_state(5, 10, cyclic=cyclic)
480
- rhoc_ab = k.partial_trace_compress(sysa=range(2), sysb=range(2, 4))
481
- inds = ["kA", "kB"], ["bA", "bB"]
482
- x = rhoc_ab.trace(*inds)
483
- assert_allclose(1.0, x, rtol=1e-3)
484
-
485
- @pytest.mark.parametrize(
486
- "block",
487
- [
488
- 0,
489
- 20,
490
- 39,
491
- slice(0, 5),
492
- slice(20, 25),
493
- slice(35, 40),
494
- slice(38, 42),
495
- slice(-3, 2),
496
- ],
497
- )
498
- @pytest.mark.parametrize("dtype", [float, complex])
499
- def test_canonize_cyclic(self, dtype, block):
500
- k = qtn.MPS_rand_state(40, 10, dtype=dtype, cyclic=True)
501
- b = k.H
502
- k.add_tag("KET")
503
- b.add_tag("BRA")
504
- kb = b | k
505
-
506
- assert not np.allclose(k[block].H @ k[block], 1.0)
507
- assert not np.allclose(b[block].H @ b[block], 1.0)
508
- k.canonize_cyclic(block, bra=b)
509
- assert_allclose(k[block].H @ k[block], 1.0, rtol=2e-4)
510
- assert_allclose(b[block].H @ b[block], 1.0, rtol=2e-4)
511
-
512
- ii = kb.select(block, which="!any") ^ all
513
-
514
- if isinstance(block, slice):
515
- start, stop = block.start, block.stop
516
- else:
517
- start, stop = block, block + 1
518
-
519
- assert len(kb.select_tensors(block, "any")) == 2 * (stop - start)
520
-
521
- (ul,) = qtn.bonds(
522
- kb[k.site_tag(start - 1), "BRA"], kb[k.site_tag(start), "BRA"]
523
- )
524
- (ur,) = qtn.bonds(
525
- kb[k.site_tag(stop - 1), "BRA"], kb[k.site_tag(stop), "BRA"]
526
- )
527
- (ll,) = qtn.bonds(
528
- kb[k.site_tag(start - 1), "KET"], kb[k.site_tag(start), "KET"]
529
- )
530
- (lr,) = qtn.bonds(
531
- kb[k.site_tag(stop - 1), "KET"], kb[k.site_tag(stop), "KET"]
532
- )
533
-
534
- ii = ii.to_qarray((ul, ur), (ll, lr))
535
- assert_allclose(ii, np.eye(ii.shape[0]), rtol=0.001, atol=0.001)
536
-
537
- @pytest.mark.parametrize("bsz", [1, 2])
538
- @pytest.mark.parametrize("propagate_tags", [False, True])
539
- @pytest.mark.parametrize("contract", [False, True])
540
- def test_gate_no_contract(self, bsz, propagate_tags, contract):
541
- p = qtn.MPS_rand_state(5, 7, tags={"PSI0"})
542
- q = p.copy()
543
- G = qu.rand_uni(2**bsz)
544
- p = p.gate_(
545
- G,
546
- where=[i for i in range(2, 2 + bsz)],
547
- tags="G",
548
- contract=contract,
549
- propagate_tags=propagate_tags,
550
- )
551
- TG = p["G"]
552
- if propagate_tags or contract:
553
- assert p.site_tag(2) in TG.tags
554
- assert ("PSI0" in TG.tags) == (propagate_tags is True) or contract
555
- assert (p.H & p) ^ all == pytest.approx(1.0)
556
- assert abs((q.H & p) ^ all) < 1.0
557
- assert len(p.tensors) == 6 - int(contract) * bsz
558
- assert set(p.outer_inds()) == {f"k{i}" for i in range(5)}
559
-
560
- @pytest.mark.parametrize(
561
- "propagate_tags", [False, "sites", "register", True]
562
- )
563
- def test_gate_split_gate(self, propagate_tags):
564
- p = qtn.MPS_rand_state(5, 7, tags={"PSI0"})
565
- q = p.copy()
566
- G = qu.CNOT()
567
- p = p.gate_(
568
- G,
569
- where=[i for i in range(2, 4)],
570
- tags="G",
571
- contract="split-gate",
572
- propagate_tags=propagate_tags,
573
- )
574
-
575
- TG = sorted(p["G"], key=lambda t: sorted(t.tags))
576
-
577
- if propagate_tags is False:
578
- assert TG[0].tags == qtn.oset(("G",))
579
- assert TG[1].tags == qtn.oset(("G",))
580
-
581
- elif propagate_tags == "register":
582
- assert TG[0].tags == qtn.oset(["G", "I2"])
583
- assert TG[1].tags == qtn.oset(["G", "I3"])
584
-
585
- elif propagate_tags == "sites":
586
- assert TG[0].tags == qtn.oset(["G", "I2", "I3"])
587
- assert TG[1].tags == qtn.oset(["G", "I2", "I3"])
588
-
589
- elif propagate_tags is True:
590
- assert TG[0].tags == qtn.oset(["PSI0", "G", "I2", "I3"])
591
- assert TG[1].tags == qtn.oset(["PSI0", "G", "I2", "I3"])
592
-
593
- assert (p.H & p) ^ all == pytest.approx(1.0)
594
- assert abs((q.H & p) ^ all) < 1.0
595
- assert len(p.tensors) == 7
596
- assert set(p.outer_inds()) == {f"k{i}" for i in range(5)}
597
-
598
- def test_gate_swap_and_split_bond_sizes(self):
599
- n = 10
600
- p = qtn.MPS_computational_state("0" * n)
601
- assert p.bond_sizes() == [1] * (n - 1)
602
- G = qu.rand_uni(4)
603
- p.gate_(G, (1, n - 2), contract="swap+split")
604
- assert p.bond_sizes() == [1] + [2] * (n - 3) + [1]
605
-
606
- def test_gate_swap_and_split_matches(self):
607
- k = qtn.MPS_rand_state(6, 7)
608
- kr = k.copy()
609
-
610
- gates = [qu.rand_uni(4) for _ in range(3)]
611
- wheres = [(0, 5), (3, 2), (4, 1)]
612
-
613
- for G, (i, j) in zip(gates, wheres):
614
- k.gate_(G, (i, j), contract="swap+split")
615
- kr.gate_inds_(G, (k.site_ind(i), k.site_ind(j)))
616
-
617
- assert_allclose(k.to_dense(), kr.to_dense())
618
-
619
- def test_flip(self):
620
- p = qtn.MPS_rand_state(5, 3)
621
- pf = p.flip()
622
- # we want a single index per dimension, not all combined into one
623
- inds = [[ix] for ix in p.site_inds]
624
- assert_allclose(p.to_qarray(*inds), pf.to_qarray(*inds).transpose())
625
-
626
- def test_correlation(self):
627
- ghz = (
628
- qtn.MPS_computational_state("0000")
629
- + qtn.MPS_computational_state("1111")
630
- ) / 2**0.5
631
-
632
- assert ghz.correlation(qu.pauli("Z"), 0, 1) == pytest.approx(1.0)
633
- assert ghz.correlation(qu.pauli("Z"), 1, 2) == pytest.approx(1.0)
634
- assert ghz.correlation(qu.pauli("Z"), 3, 1) == pytest.approx(1.0)
635
- assert ghz.correlation(
636
- qu.pauli("Z"), 3, 1, B=qu.pauli("Y")
637
- ) == pytest.approx(0.0)
638
-
639
- assert ghz.H @ ghz == pytest.approx(1.0)
640
-
641
- def test_gate_split(self):
642
- psi = qtn.MPS_rand_state(10, 3)
643
- psi2 = psi.copy()
644
- G = qu.eye(2) & qu.eye(2)
645
- psi.gate_split_(G, (2, 3), cutoff=0)
646
- assert psi.bond_size(2, 3) == 6
647
- assert psi.H @ psi2 == pytest.approx(1.0)
648
-
649
- # check a unitary application
650
- G = qu.rand_uni(2**2)
651
- psi.gate_split_(G, (7, 8))
652
- psi.compress()
653
- assert psi.bond_size(2, 3) == 3
654
- assert psi.bond_size(7, 8) > 3
655
- assert psi.H @ psi == pytest.approx(1.0)
656
- assert abs(psi2.H @ psi) < 1.0
657
-
658
- # check matches dense application of gate
659
- psid = psi2.to_qarray()
660
- Gd = qu.ikron(G, [2] * 10, (7, 8))
661
- assert psi.to_qarray().H @ (Gd @ psid) == pytest.approx(1.0)
662
-
663
- def test_swap_far_sites(self):
664
- psi = qtn.MPS_rand_state(7, 2)
665
- for i, j in [(0, 6), (6, 1), (5, 2)]:
666
- k1 = psi.to_qarray(
667
- [
668
- psi.site_ind(j if site == i else i if site == j else site)
669
- for site in psi.sites
670
- ]
671
- )
672
- k2 = psi.swap_sites_with_compress(i, j).to_qarray()
673
- assert qu.fidelity(k1, k2) == pytest.approx(1.0)
674
-
675
- def test_swap_gating(self):
676
- psi0 = qtn.MPS_rand_state(20, 5)
677
- CNOT = qu.controlled("not")
678
- psi0XX = psi0.gate(CNOT, (4, 13))
679
- psi0XX_s = psi0.gate_with_auto_swap(CNOT, (4, 13))
680
- assert psi0XX.H @ psi0XX_s == pytest.approx(1.0)
681
-
682
- def test_auto_split_detection(self):
683
- psi0 = qtn.MPS_computational_state("00")
684
- CNOT = qu.controlled("not")
685
- ISWAP = qu.iswap()
686
- G = qu.rand_uni(4)
687
-
688
- opts = {"contract": "auto-split-gate", "where": (0, 1)}
689
-
690
- psi_cnot = psi0.gate(CNOT, **opts)
691
- psi_iswap = psi0.gate(ISWAP, **opts)
692
- psi_G = psi0.gate(G, **opts)
693
-
694
- assert (
695
- psi_cnot.max_bond()
696
- == psi_iswap.max_bond()
697
- == psi_G.max_bond()
698
- == 2
699
- )
700
-
701
- assert len(psi_cnot.tensors) == len(psi_iswap.tensors) == 4
702
- assert len(psi_G.tensors) == 3
703
-
704
- @pytest.mark.parametrize("cur_orthog", (None, 3))
705
- @pytest.mark.parametrize("site", (0, 5, 9))
706
- @pytest.mark.parametrize("outcome", (None, 2))
707
- @pytest.mark.parametrize("renorm", (True, False))
708
- @pytest.mark.parametrize("remove", (True, False))
709
- def test_mps_measure(self, cur_orthog, site, outcome, renorm, remove):
710
- psi = qtn.MPS_rand_state(10, 7, phys_dim=3, dtype=complex)
711
- if cur_orthog:
712
- psi.canonicalize_(cur_orthog)
713
- outcome, psim = psi.measure(
714
- site,
715
- outcome=outcome,
716
- cur_orthog=cur_orthog,
717
- renorm=renorm,
718
- remove=remove,
719
- )
720
- newL = 10 - int(remove)
721
- assert psim.L == newL
722
- assert psim.num_tensors == newL
723
- assert set(psim.site_tags) == {f"I{i}" for i in range(newL)}
724
- assert set(psim.site_inds) == {f"k{i}" for i in range(newL)}
725
- if renorm:
726
- assert psim.H @ psim == pytest.approx(1.0)
727
- else:
728
- assert 0.0 < psim.H @ psim < 1.0
729
- new_can_cen = min(site, newL - 1)
730
- t = psim[new_can_cen]
731
- if renorm:
732
- assert t.H @ t == pytest.approx(1.0)
733
- else:
734
- 0.0 < t.H @ t < 1.0
735
-
736
- def test_measure_known_outcome(self):
737
- mps = qtn.MPS_computational_state("010101")
738
- assert mps.measure_(3, get="outcome") == 1
739
-
740
- def test_permute_arrays(self):
741
- mps = qtn.MPS_rand_state(7, 5)
742
- k0 = mps.to_qarray()
743
- mps.canonicalize_(3)
744
- mps.permute_arrays("prl")
745
- assert mps[0].shape == (2, 2)
746
- assert mps[1].shape == (2, 4, 2)
747
- assert mps[2].shape == (2, 5, 4)
748
- kf = mps.to_qarray()
749
- assert qu.fidelity(k0, kf) == pytest.approx(1.0)
750
-
751
- @pytest.mark.parametrize("where", [(7, 2, 4), (0, 1), (6, 7), (0, 3, 7)])
752
- @pytest.mark.parametrize("phys_dim", [2, 3])
753
- def test_gate_non_local(self, where, phys_dim):
754
- psi = qtn.MPS_rand_state(8, 3, phys_dim=phys_dim, dtype="complex128")
755
- G = qu.rand_uni(phys_dim ** len(where))
756
- Gpsi = psi.gate_nonlocal(G, where=where)
757
- assert Gpsi.H @ Gpsi == pytest.approx(1.0)
758
- assert Gpsi.distance_normalized(
759
- psi.gate(G, where, contract=False)
760
- ) == pytest.approx(0.0, abs=1e-6)
761
-
762
- def test_sample_configuration(self):
763
- psi = qtn.MPS_rand_state(10, 7)
764
- config, omega = psi.sample_configuration()
765
- assert len(config) == 10
766
- assert abs(
767
- psi.isel(
768
- {psi.site_ind(i): xi for i, xi in enumerate(config)}
769
- ).contract()
770
- ) ** 2 == pytest.approx(omega)
771
-
772
- def test_sample_seed(self):
773
- psi = qtn.MPS_rand_state(10, 7)
774
- configs = [
775
- "".join(map(str, config))
776
- for config, _ in psi.sample(10, seed=1234)
777
- ]
778
- assert len(set(configs)) > 1
779
-
780
- def test_compute_local_expectation(self):
781
- psi = qtn.MPS_rand_state(10, 7, dtype="complex128")
782
- terms = {(i, i + 1): qu.rand_herm(4) for i in range(9)}
783
-
784
- ex = psi.compute_local_expectation_exact(terms)
785
- xa = psi.compute_local_expectation(terms, method="canonical")
786
- assert xa == pytest.approx(ex)
787
- xb = psi.compute_local_expectation(terms, method="envs")
788
- assert xb == pytest.approx(ex)
789
-
790
-
791
- class TestMatrixProductOperator:
792
- @pytest.mark.parametrize("cyclic", [False, True])
793
- def test_matrix_product_operator(self, cyclic):
794
- end_shape = (5, 5, 2, 2) if cyclic else (5, 2, 2)
795
-
796
- tensors = (
797
- [np.random.rand(*end_shape)]
798
- + [np.random.rand(5, 5, 2, 2) for _ in range(3)]
799
- + [np.random.rand(*end_shape)]
800
- )
801
- mpo = qtn.MatrixProductOperator(tensors)
802
-
803
- mpo.show()
804
- assert len(mpo.tensors) == 5
805
- assert mpo.upper_inds == ("k0", "k1", "k2", "k3", "k4")
806
- assert mpo.lower_inds == ("b0", "b1", "b2", "b3", "b4")
807
- op = mpo ^ ...
808
- # this would rely on left to right contraction if not in set form
809
- assert set(op.inds) == {
810
- "k0",
811
- "b0",
812
- "k1",
813
- "b1",
814
- "k2",
815
- "b2",
816
- "k3",
817
- "b3",
818
- "k4",
819
- "b4",
820
- }
821
-
822
- assert set(mpo.site_tags) == {f"I{i}" for i in range(5)}
823
- assert all(f"I{i}" in mpo.tags for i in range(5))
824
- mpo.site_tag_id = "TEST1,{}"
825
- assert set(mpo.site_tags) == {f"TEST1,{i}" for i in range(5)}
826
- assert not any(f"I{i}" in mpo.tags for i in range(5))
827
- assert all(f"TEST1,{i}" in mpo.tags for i in range(5))
828
-
829
- @pytest.mark.parametrize("cyclic", [False, True])
830
- def test_compress_mpo(self, cyclic):
831
- A = qtn.MPO_rand(12, 5, cyclic=cyclic)
832
- assert all(b == 5 for b in A.bond_sizes())
833
- A.expand_bond_dimension(10)
834
- assert all(b == 10 for b in A.bond_sizes())
835
- A.compress()
836
- assert all(b in (4, 5) for b in A.bond_sizes())
837
-
838
- def test_add_mpo(self):
839
- h = qtn.MPO_rand_herm(12, 5)
840
- h2 = h + h
841
- assert max(h2[6].shape) == 10
842
- t = h.trace()
843
- t2 = h2.trace()
844
- assert_allclose(2 * t, t2)
845
-
846
- def test_adding_mpo(self):
847
- h = qtn.MPO_ham_heis(6)
848
- hd = h.to_qarray()
849
- assert_allclose(h @ h.H, (hd @ hd.H).tr())
850
- h2 = h + h
851
- assert_allclose(h2 @ h2.H, (hd @ hd.H).tr() * 4)
852
- h2.right_compress()
853
- assert_allclose(h2 @ h2.H, (hd @ hd.H).tr() * 4)
854
- assert max(h2["I3"].shape) == 5
855
-
856
- @pytest.mark.parametrize("cyclic", (False, True))
857
- def test_subtract_mpo(self, cyclic):
858
- a, b = (
859
- qtn.MPO_rand(13, 7, cyclic=cyclic),
860
- qtn.MPO_rand(13, 7, cyclic=cyclic),
861
- )
862
- x1 = a.trace() - b.trace()
863
- assert_allclose(x1, (a - b).trace())
864
- a -= b
865
- assert_allclose(x1, a.trace())
866
-
867
- @pytest.mark.parametrize("cyclic", (False, True))
868
- @pytest.mark.parametrize("rand_strength", (0, 1e-9))
869
- def test_expand_mpo(self, cyclic, rand_strength):
870
- h = qtn.MPO_ham_heis(12, cyclic=cyclic)
871
- assert h[0].dtype == float
872
- he = h.expand_bond_dimension(13, rand_strength=rand_strength)
873
- assert h[0].dtype == float
874
- assert max(he[6].shape) == 13
875
-
876
- if cyclic:
877
- assert he.bond_size(0, -1) == 13
878
-
879
- t = h.trace()
880
- te = he.trace()
881
- assert_allclose(t, te)
882
-
883
- @pytest.mark.parametrize("cyclic", (False, True))
884
- @pytest.mark.parametrize("rand_strength", (0, 1e-9))
885
- def test_expand_mpo_limited(self, cyclic, rand_strength):
886
- h = qtn.MPO_ham_heis(12, cyclic=cyclic)
887
- he = h.expand_bond_dimension(3, rand_strength=rand_strength)
888
- # should do nothing
889
- assert max(he[6].shape) == 5
890
-
891
- def test_mpo_identity(self):
892
- k = qtn.MPS_rand_state(13, 7)
893
- b = qtn.MPS_rand_state(13, 7)
894
- o1 = k @ b
895
- i = qtn.MPO_identity(13)
896
- k, i, b = qtn.tensor_network_align(k, i, b)
897
- o2 = (k & i & b) ^ ...
898
- assert_allclose(o1, o2)
899
-
900
- @pytest.mark.parametrize("cyclic", [False, True])
901
- @pytest.mark.parametrize("dtype", (complex, float))
902
- def test_mpo_rand_herm_and_trace(self, dtype, cyclic):
903
- op = qtn.MPO_rand_herm(
904
- 20, bond_dim=5, phys_dim=3, dtype=dtype, cyclic=cyclic
905
- )
906
- assert_allclose(op.H @ op, 1.0)
907
- tr_val = op.trace()
908
- assert tr_val != 0.0
909
- assert_allclose(tr_val.imag, 0.0, atol=1e-14)
910
-
911
- @pytest.mark.parametrize("cyclic", [False, True])
912
- def test_mpo_rand_herm_trace_and_identity_like(self, cyclic):
913
- op = qtn.MPO_rand_herm(
914
- 20, bond_dim=5, phys_dim=3, upper_ind_id="foo{}", cyclic=cyclic
915
- )
916
- t = op.trace()
917
- assert t != 0.0
918
- Id = qtn.MPO_identity_like(op)
919
- assert_allclose(Id.trace(), 3**20)
920
- Id[0] *= 3 / 3**20
921
- op += Id
922
- assert_allclose(op.trace(), t + 3)
923
-
924
- def test_partial_transpose(self):
925
- p = qtn.MPS_rand_state(8, 10)
926
- r = p.partial_trace_to_mpo([2, 3, 4, 5, 6, 7])
927
- rd = r.to_qarray()
928
-
929
- assert qu.isherm(rd)
930
- assert qu.ispos(rd)
931
-
932
- rpt = r.partial_transpose([0, 1, 2])
933
- rptd = rpt.to_qarray()
934
-
935
- upper_inds = tuple(f"b{i}" for i in range(6))
936
- lower_inds = tuple(f"k{i}" for i in range(6))
937
- outer_inds = rpt.outer_inds()
938
- assert all(i in outer_inds for i in upper_inds + lower_inds)
939
-
940
- assert qu.isherm(rptd)
941
- assert not qu.ispos(rptd)
942
-
943
- def test_upper_lower_ind_id_guard(self):
944
- A = qtn.MPO_rand(8, 5)
945
- with pytest.raises(ValueError):
946
- A.upper_ind_id = "b{}"
947
- with pytest.raises(ValueError):
948
- A.lower_ind_id = "k{}"
949
-
950
- @pytest.mark.parametrize("cyclic", (False, True))
951
- def test_apply_mpo(self, cyclic):
952
- A = qtn.MPO_rand(8, 5, cyclic=cyclic)
953
- B = qtn.MPO_rand(
954
- 8, 5, upper_ind_id="q{}", lower_ind_id="w{}", cyclic=cyclic
955
- )
956
- C = A.apply(B)
957
- assert C.max_bond() == 25
958
- assert C.upper_ind_id == "q{}"
959
- assert C.lower_ind_id == "w{}"
960
- Ad, Bd, Cd = A.to_qarray(), B.to_qarray(), C.to_qarray()
961
- assert_allclose(Ad @ Bd, Cd)
962
-
963
- @pytest.mark.parametrize("cyclic", (False, True))
964
- @pytest.mark.parametrize("site_ind_id", ("k{}", "test{}"))
965
- def test_apply_mps(self, cyclic, site_ind_id):
966
- A = qtn.MPO_rand(8, 5, cyclic=cyclic)
967
- x = qtn.MPS_rand_state(8, 4, site_ind_id=site_ind_id, cyclic=cyclic)
968
- y = A.apply(x)
969
- assert y.max_bond() == 20
970
- assert isinstance(y, qtn.MatrixProductState)
971
- assert len(y.tensors) == 8
972
- assert y.site_ind_id == site_ind_id
973
- Ad, xd, yd = A.to_qarray(), x.to_qarray(), y.to_qarray()
974
- assert_allclose(Ad @ xd, yd)
975
-
976
- def test_permute_arrays(self):
977
- mpo = qtn.MPO_rand(4, 3)
978
- A0 = mpo.to_qarray()
979
- mpo.permute_arrays("drul")
980
- assert mpo[0].shape == (2, 3, 2)
981
- assert mpo[1].shape == (2, 3, 2, 3)
982
- Af = mpo.to_qarray()
983
- assert_allclose(A0, Af)
984
-
985
- def test_from_dense(self):
986
- A = qu.rand_uni(2**4)
987
- mpo = qtn.MatrixProductOperator.from_dense(A)
988
- assert mpo.L == 4
989
- assert_allclose(A, mpo.to_dense())
990
-
991
- def test_from_dense_sites(self):
992
- dims = [2, 3, 4, 5]
993
- A = qu.rand_uni(2 * 3 * 4 * 5)
994
- sites = [3, 1, 0, 2]
995
- mpo = qtn.MatrixProductOperator.from_dense(A, dims, sites=sites)
996
- assert mpo.L == 4
997
- perm = [sites.index(i) for i in range(4)]
998
- assert_allclose(qu.permute(A, dims, perm), mpo.to_dense())
999
-
1000
- def test_fill_empty_sites(self):
1001
- mps = qtn.MPS_rand_state(7, 3)
1002
- k = mps.to_dense()
1003
- A, B, C = (qu.rand_uni(2) for _ in range(3))
1004
- Ak = qu.ikron((A, B, C), [2] * 7, [5, 2, 3]) @ k
1005
-
1006
- ABC = A & B & C
1007
- mpo = qtn.MatrixProductOperator.from_dense(ABC, sites=[5, 2, 3], L=7)
1008
- assert mpo.bond_size(2, 3) == 1
1009
- assert mpo.num_tensors == 3
1010
- assert mpo[3].bonds(mpo[5])
1011
- mpo.fill_empty_sites_("minimal")
1012
- assert not mpo[3].bonds(mpo[5])
1013
- assert mpo.num_tensors == 4
1014
- assert_allclose(
1015
- mps.gate_with_op_lazy(mpo).to_dense(),
1016
- Ak,
1017
- )
1018
- mpo.fill_empty_sites_("full")
1019
- assert mpo.num_tensors == 7
1020
- assert_allclose(
1021
- mps.gate_with_op_lazy(mpo).to_dense(),
1022
- Ak,
1023
- )
1024
-
1025
-
1026
- # --------------------------------------------------------------------------- #
1027
- # Test specific 1D instances #
1028
- # --------------------------------------------------------------------------- #
1029
-
1030
-
1031
- class TestSpecificStatesOperators:
1032
- @pytest.mark.parametrize("cyclic", [False, True])
1033
- def test_rand_ket_mps(self, cyclic):
1034
- n = 10
1035
- rmps = qtn.MPS_rand_state(
1036
- n, 10, site_tag_id="foo{}", tags="bar", cyclic=cyclic
1037
- )
1038
- assert rmps[0].tags == qtn.oset(["foo0", "bar"])
1039
- assert rmps[3].tags == qtn.oset(["foo3", "bar"])
1040
- assert rmps[-1].tags == qtn.oset(["foo9", "bar"])
1041
-
1042
- rmpsH_rmps = rmps.H & rmps
1043
- assert len(rmpsH_rmps.tag_map["foo0"]) == 2
1044
- assert len(rmpsH_rmps.tag_map["bar"]) == n * 2
1045
-
1046
- assert_allclose(rmps.H @ rmps, 1)
1047
- c = (rmps.H & rmps) ^ slice(0, 5) ^ slice(9, 4, -1) ^ slice(4, 6)
1048
- assert_allclose(c, 1)
1049
-
1050
- assert rmps[0].data.ndim == (3 if cyclic else 2)
1051
- assert rmps[-1].data.ndim == (3 if cyclic else 2)
1052
-
1053
- def test_mps_computation_state(self):
1054
- p = qtn.MPS_neel_state(10)
1055
- pd = qu.neel_state(10)
1056
- assert_allclose(p.to_qarray(), pd)
1057
-
1058
- def test_zero_state(self):
1059
- z = qtn.MPS_zero_state(21, 7)
1060
- p = qtn.MPS_rand_state(21, 13)
1061
- assert_allclose(p.H @ z, 0.0)
1062
- assert_allclose(p.H @ p, 1.0)
1063
- zp = z + p
1064
- assert max(zp[13].shape) == 20
1065
- assert_allclose(zp.H @ p, 1.0)
1066
-
1067
- @pytest.mark.parametrize("cyclic", [False, True])
1068
- @pytest.mark.parametrize("j", [7 / 11, 1, (0.2, 0.3, 0.4)])
1069
- @pytest.mark.parametrize("bz", [0, 7 / 11, 1])
1070
- @pytest.mark.parametrize("n", [2, 3, 4])
1071
- def test_mpo_site_ham_heis(self, cyclic, j, bz, n):
1072
- hh_mpo = qtn.MPO_ham_heis(n, tags=["foo"], cyclic=cyclic, j=j, bz=bz)
1073
- assert hh_mpo[0].tags == qtn.oset(["I0", "foo"])
1074
- assert hh_mpo[1].tags == qtn.oset(["I1", "foo"])
1075
- assert hh_mpo[-1].tags == qtn.oset([f"I{n - 1}", "foo"])
1076
- assert hh_mpo.shape == (2,) * 2 * n
1077
- hh_ex = qu.ham_heis(n, cyclic=cyclic, j=j, b=bz)
1078
- assert_allclose(
1079
- qu.eigvalsh(hh_ex), qu.eigvalsh(hh_mpo.to_qarray()), atol=1e-13
1080
- )
1081
-
1082
- def test_mpo_zeros(self):
1083
- mpo0 = qtn.MPO_zeros(10)
1084
- assert mpo0.trace() == 0.0
1085
- assert mpo0.H @ mpo0 == 0.0
1086
-
1087
- @pytest.mark.parametrize("cyclic", (False, True))
1088
- def test_mpo_zeros_like(self, cyclic):
1089
- A = qtn.MPO_rand(10, 7, phys_dim=3, normalize=False, cyclic=cyclic)
1090
- Z = qtn.MPO_zeros_like(A)
1091
- assert A @ Z == 0.0
1092
- assert Z.cyclic == cyclic
1093
- x1 = A.trace()
1094
- x2 = (A + Z).trace()
1095
- assert_allclose(x1, x2)
1096
-
1097
-
1098
- class TestDense1D:
1099
- def test_simple(self):
1100
- n = 10
1101
- d_psi = qu.computational_state("0" * n)
1102
-
1103
- t_psi = qtn.Dense1D(d_psi)
1104
- assert set(t_psi.outer_inds()) == {f"k{i}" for i in range(n)}
1105
- assert t_psi.tags == qtn.oset(f"I{i}" for i in range(n))
1106
-
1107
- for i in range(n):
1108
- assert t_psi.H @ t_psi.gate(qu.pauli("Z"), i) == pytest.approx(1)
1109
-
1110
- for i in range(n):
1111
- t_psi.gate_(qu.hadamard(), i)
1112
-
1113
- assert len(t_psi.tensors) == n + 1
1114
-
1115
- # should have '++++++++++'
1116
- assert t_psi.H @ t_psi == pytest.approx(1)
1117
- for i in range(n):
1118
- assert t_psi.H @ t_psi.gate(qu.pauli("X"), i) == pytest.approx(1)
1119
-
1120
- def test_rand(self):
1121
- t_psi = qtn.Dense1D.rand(7, dtype="complex64")
1122
- assert t_psi.shape == (2,) * 7
1123
- assert t_psi.dtype == "complex64"
1124
- assert (t_psi.H @ t_psi) == pytest.approx(1.0)
1125
-
1126
-
1127
- class TestTensor1DCompress:
1128
- @pytest.mark.parametrize(
1129
- "method", ["direct", "dm", "fit", "zipup", "zipup-first"]
1130
- )
1131
- @pytest.mark.parametrize("dtype", dtypes)
1132
- def test_mps_partial_mpo_apply(self, method, dtype):
1133
- mps = qtn.MPS_rand_state(10, 7, dtype=dtype)
1134
- A = qu.rand_uni(2**3, dtype=dtype)
1135
- where = [8, 4, 5]
1136
- mpo = qtn.MatrixProductOperator.from_dense(A, sites=where)
1137
- new = mps.gate_with_op_lazy(mpo)
1138
- assert (
1139
- qtn.tensor_network_1d_compress(new, method=method, inplace=True)
1140
- is new
1141
- )
1142
- assert new.num_tensors == 10
1143
- assert new.distance_normalized(mps.gate(A, where)) == pytest.approx(
1144
- 0.0, abs=1e-3 if dtype in ("float32", "complex64") else 1e-6
1145
- )
1146
-
1147
- @pytest.mark.parametrize(
1148
- "method", ["direct", "dm", "fit", "zipup", "zipup-first"]
1149
- )
1150
- @pytest.mark.parametrize("sweep_reverse", [False, True])
1151
- def test_mpo_compress_opts(self, method, sweep_reverse):
1152
- L = 6
1153
- A = qtn.MPO_rand(L, 2, phys_dim=3)
1154
- B = qtn.MPO_rand(L, 3, phys_dim=3)
1155
- AB = A.gate_upper_with_op_lazy(B)
1156
- assert AB.num_tensors == 2 * L
1157
- ABc = qtn.tensor_network_1d_compress(
1158
- AB,
1159
- method=method,
1160
- max_bond=5,
1161
- cutoff=1e-6,
1162
- sweep_reverse=sweep_reverse,
1163
- inplace=False,
1164
- )
1165
- assert ABc.num_tensors == L
1166
- assert ABc.num_indices == 2 * L + L - 1
1167
- assert ABc.max_bond() == 5
1168
- if sweep_reverse:
1169
- assert ABc.calc_current_orthog_center() == (L - 1, L - 1)
1170
- else:
1171
- assert ABc.calc_current_orthog_center() == (0, 0)