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,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)