tensorcircuit-nightly 1.3.0.dev20250728__py3-none-any.whl → 1.4.0.dev20251103__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.

Potentially problematic release.


This version of tensorcircuit-nightly might be problematic. Click here for more details.

Files changed (72) hide show
  1. tensorcircuit/__init__.py +5 -1
  2. tensorcircuit/abstractcircuit.py +4 -0
  3. tensorcircuit/analogcircuit.py +413 -0
  4. tensorcircuit/applications/layers.py +1 -1
  5. tensorcircuit/applications/van.py +1 -1
  6. tensorcircuit/backends/abstract_backend.py +312 -5
  7. tensorcircuit/backends/cupy_backend.py +3 -1
  8. tensorcircuit/backends/jax_backend.py +92 -3
  9. tensorcircuit/backends/jax_ops.py +108 -0
  10. tensorcircuit/backends/numpy_backend.py +49 -3
  11. tensorcircuit/backends/pytorch_backend.py +92 -3
  12. tensorcircuit/backends/tensorflow_backend.py +102 -3
  13. tensorcircuit/basecircuit.py +123 -82
  14. tensorcircuit/circuit.py +67 -57
  15. tensorcircuit/cloud/local.py +1 -1
  16. tensorcircuit/cloud/quafu_provider.py +1 -1
  17. tensorcircuit/cloud/tencent.py +1 -1
  18. tensorcircuit/compiler/simple_compiler.py +2 -2
  19. tensorcircuit/cons.py +1 -0
  20. tensorcircuit/densitymatrix.py +16 -11
  21. tensorcircuit/experimental.py +7 -152
  22. tensorcircuit/fgs.py +5 -6
  23. tensorcircuit/gates.py +66 -22
  24. tensorcircuit/keras.py +3 -3
  25. tensorcircuit/mpscircuit.py +109 -61
  26. tensorcircuit/quantum.py +697 -133
  27. tensorcircuit/quditcircuit.py +733 -0
  28. tensorcircuit/quditgates.py +618 -0
  29. tensorcircuit/results/counts.py +45 -31
  30. tensorcircuit/shadows.py +1 -1
  31. tensorcircuit/simplify.py +3 -1
  32. tensorcircuit/stabilizercircuit.py +4 -2
  33. tensorcircuit/templates/blocks.py +2 -2
  34. tensorcircuit/templates/hamiltonians.py +29 -8
  35. tensorcircuit/templates/lattice.py +676 -335
  36. tensorcircuit/timeevol.py +896 -0
  37. {tensorcircuit_nightly-1.3.0.dev20250728.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/METADATA +50 -25
  38. tensorcircuit_nightly-1.4.0.dev20251103.dist-info/RECORD +96 -0
  39. {tensorcircuit_nightly-1.3.0.dev20250728.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/top_level.txt +0 -1
  40. tensorcircuit_nightly-1.3.0.dev20250728.dist-info/RECORD +0 -122
  41. tests/__init__.py +0 -0
  42. tests/conftest.py +0 -67
  43. tests/test_backends.py +0 -1035
  44. tests/test_calibrating.py +0 -149
  45. tests/test_channels.py +0 -409
  46. tests/test_circuit.py +0 -1713
  47. tests/test_cloud.py +0 -219
  48. tests/test_compiler.py +0 -147
  49. tests/test_dmcircuit.py +0 -555
  50. tests/test_ensemble.py +0 -72
  51. tests/test_fgs.py +0 -318
  52. tests/test_gates.py +0 -156
  53. tests/test_hamiltonians.py +0 -159
  54. tests/test_interfaces.py +0 -557
  55. tests/test_keras.py +0 -160
  56. tests/test_lattice.py +0 -1666
  57. tests/test_miscs.py +0 -334
  58. tests/test_mpscircuit.py +0 -341
  59. tests/test_noisemodel.py +0 -156
  60. tests/test_qaoa.py +0 -86
  61. tests/test_qem.py +0 -152
  62. tests/test_quantum.py +0 -549
  63. tests/test_quantum_attr.py +0 -42
  64. tests/test_results.py +0 -379
  65. tests/test_shadows.py +0 -160
  66. tests/test_simplify.py +0 -46
  67. tests/test_stabilizer.py +0 -226
  68. tests/test_templates.py +0 -218
  69. tests/test_torchnn.py +0 -99
  70. tests/test_van.py +0 -102
  71. {tensorcircuit_nightly-1.3.0.dev20250728.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/WHEEL +0 -0
  72. {tensorcircuit_nightly-1.3.0.dev20250728.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/licenses/LICENSE +0 -0
tests/test_miscs.py DELETED
@@ -1,334 +0,0 @@
1
- # pylint: disable=invalid-name
2
-
3
- import sys
4
- import os
5
- from functools import partial
6
- import numpy as np
7
- import tensorflow as tf
8
- import pytest
9
- from pytest_lazyfixture import lazy_fixture as lf
10
-
11
- thisfile = os.path.abspath(__file__)
12
- modulepath = os.path.dirname(os.path.dirname(thisfile))
13
-
14
- sys.path.insert(0, modulepath)
15
- import tensorcircuit as tc
16
- from tensorcircuit import experimental
17
- from tensorcircuit.quantum import PauliString2COO, PauliStringSum2COO
18
- from tensorcircuit.applications.vqes import construct_matrix_v2
19
- from tensorcircuit.applications.physics.baseline import TFIM1Denergy, Heisenberg1Denergy
20
-
21
- i, x, y, z = [t.tensor for t in tc.gates.pauli_gates]
22
-
23
- # note i is in use!
24
-
25
- check_pairs = [
26
- ([0, 0], np.eye(4)),
27
- ([0, 1], np.kron(i, x)),
28
- ([2, 1], np.kron(y, x)),
29
- ([3, 1], np.kron(z, x)),
30
- ([3, 2, 2, 0], np.kron(np.kron(np.kron(z, y), y), i)),
31
- ([0, 1, 1, 1], np.kron(np.kron(np.kron(i, x), x), x)),
32
- ]
33
-
34
-
35
- def test_about():
36
- print(tc.about())
37
-
38
-
39
- def test_cite():
40
- print(tc.cite())
41
- print(tc.cite("aps"))
42
-
43
-
44
- def test_ps2coo(tfb):
45
- for l, a in check_pairs:
46
- r1 = PauliString2COO(tf.constant(l, dtype=tf.int64))
47
- np.testing.assert_allclose(tc.backend.to_dense(r1), a, atol=1e-5)
48
-
49
-
50
- def test_pss2coo(tfb):
51
- l = [t[0] for t in check_pairs[:4]]
52
- a = sum([t[1] for t in check_pairs[:4]])
53
- r1 = PauliStringSum2COO(tf.constant(l, dtype=tf.int64))
54
- np.testing.assert_allclose(tc.backend.to_dense(r1), a, atol=1e-5)
55
- l = [t[0] for t in check_pairs[4:]]
56
- a = sum([t[1] for t in check_pairs[4:]])
57
- r1 = PauliStringSum2COO(tf.constant(l, dtype=tf.int64), weight=[0.5, 1])
58
- a = check_pairs[4][1] * 0.5 + check_pairs[5][1] * 1.0
59
- np.testing.assert_allclose(tc.backend.to_dense(r1), a, atol=1e-5)
60
-
61
-
62
- def test_sparse(benchmark, tfb):
63
- def sparse(h):
64
- return PauliStringSum2COO(h)
65
-
66
- h = [[1 for _ in range(12)], [2 for _ in range(12)]]
67
- h = tf.constant(h, dtype=tf.int64)
68
- sparse(h)
69
- benchmark(sparse, h)
70
-
71
-
72
- def test_dense(benchmark, tfb):
73
- def dense(h):
74
- return construct_matrix_v2(h, dtype=tf.complex64)
75
-
76
- h = [[1 for _ in range(12)], [2 for _ in range(12)]]
77
- h = [[1.0] + hi for hi in h]
78
- dense(h)
79
- benchmark(dense, h)
80
-
81
-
82
- @pytest.mark.parametrize("backend", [lf("tfb"), lf("jaxb")])
83
- def test_adaptive_vmap(backend):
84
- def f(x):
85
- return x**2
86
-
87
- x = tc.backend.ones([30, 2])
88
-
89
- vf = experimental.adaptive_vmap(f, chunk_size=6)
90
- np.testing.assert_allclose(vf(x), tc.backend.ones([30, 2]), atol=1e-5)
91
-
92
- vf2 = experimental.adaptive_vmap(f, chunk_size=7)
93
- np.testing.assert_allclose(vf2(x), tc.backend.ones([30, 2]), atol=1e-5)
94
-
95
- def f2(x):
96
- return tc.backend.sum(x)
97
-
98
- vf3 = experimental.adaptive_vmap(f2, chunk_size=7)
99
- np.testing.assert_allclose(vf3(x), 2 * tc.backend.ones([30]), atol=1e-5)
100
-
101
- vf3_jit = tc.backend.jit(vf3)
102
- np.testing.assert_allclose(vf3_jit(x), 2 * tc.backend.ones([30]), atol=1e-5)
103
-
104
-
105
- @pytest.mark.parametrize("backend", [lf("tfb"), lf("jaxb")])
106
- def test_adaptive_vmap_mul_io(backend):
107
- def f(x, y, a):
108
- return x + y + a
109
-
110
- vf = experimental.adaptive_vmap(f, chunk_size=6, vectorized_argnums=(0, 1))
111
- x = tc.backend.ones([30, 2])
112
- a = tc.backend.ones([2])
113
- # jax vmap has some weird behavior in terms of keyword arguments...
114
- # TODO(@refraction-ray): further investigate jax vmap behavior with kwargs
115
- np.testing.assert_allclose(vf(x, x, a), 3 * tc.backend.ones([30, 2]), atol=1e-5)
116
-
117
-
118
- @pytest.mark.parametrize("backend", [lf("tfb"), lf("jaxb")])
119
- def test_qng(backend):
120
- n = 6
121
-
122
- def f(params):
123
- params = tc.backend.reshape(params, [4, n])
124
- c = tc.Circuit(n)
125
- c = tc.templates.blocks.example_block(c, params)
126
- return c.state()
127
-
128
- params = tc.backend.ones([4 * n])
129
- fim = experimental.qng(f)(params)
130
- assert tc.backend.shape_tuple(fim) == (4 * n, 4 * n)
131
- print(experimental.dynamics_matrix(f)(params))
132
-
133
-
134
- @pytest.mark.parametrize("backend", [lf("tfb"), lf("jaxb")])
135
- def test_dynamic_rhs(backend):
136
- h1 = tc.array_to_tensor(tc.gates._z_matrix)
137
-
138
- def f(param):
139
- c = tc.Circuit(1)
140
- c.rx(0, theta=param)
141
- return c.state()
142
-
143
- rhsf = experimental.dynamics_rhs(f, h1)
144
- np.testing.assert_allclose(rhsf(tc.backend.ones([])), -np.sin(1.0) / 2, atol=1e-5)
145
-
146
- h2 = tc.backend.coo_sparse_matrix(
147
- indices=tc.array_to_tensor(np.array([[0, 0], [1, 1]]), dtype="int64"),
148
- values=tc.array_to_tensor(np.array([1, -1])),
149
- shape=[2, 2],
150
- )
151
-
152
- rhsf = experimental.dynamics_rhs(f, h2)
153
- np.testing.assert_allclose(rhsf(tc.backend.ones([])), -np.sin(1.0) / 2, atol=1e-5)
154
-
155
-
156
- @pytest.mark.parametrize("backend", ["tensorflow", "jax"])
157
- def test_two_qng_approaches(backend):
158
- n = 6
159
- nlayers = 2
160
- with tc.runtime_backend(backend) as K:
161
- with tc.runtime_dtype("complex128"):
162
-
163
- def state(params):
164
- params = K.reshape(params, [2 * nlayers, n])
165
- c = tc.Circuit(n)
166
- c = tc.templates.blocks.example_block(c, params, nlayers=nlayers)
167
- return c.state()
168
-
169
- params = K.ones([2 * nlayers * n])
170
- params = K.cast(params, "float32")
171
- n1 = experimental.qng(state)(params)
172
- n2 = experimental.qng2(state)(params)
173
- np.testing.assert_allclose(n1, n2, atol=1e-7)
174
-
175
-
176
- def test_arg_alias():
177
- @partial(tc.utils.arg_alias, alias_dict={"theta": ["alpha", "gamma"]})
178
- def f(theta: float, beta: float) -> float:
179
- """
180
- f doc
181
-
182
- :param theta: theta angle
183
- :type theta: float
184
- :param beta: beta angle
185
- :type beta: float
186
- :return: sum angle
187
- :rtype: float
188
- """
189
- return theta + beta
190
-
191
- np.testing.assert_allclose(f(beta=0.2, alpha=0.1), 0.3, atol=1e-5)
192
- print(f.__doc__)
193
- assert len(f.__doc__.strip().split("\n")) == 12
194
-
195
-
196
- def test_finite_difference_tf(tfb):
197
- def f(param1, param2):
198
- n = 4
199
- c = tc.Circuit(n)
200
- for i in range(n):
201
- c.rx(i, theta=param1[i])
202
- for i in range(n - 1):
203
- c.cx(i, i + 1)
204
- for i in range(n - 1):
205
- c.rzz(i, i + 1, theta=param2[i])
206
- r = [c.expectation_ps(z=[i]) for i in range(n)]
207
- return tc.backend.stack(r)
208
-
209
- def fsum(param1, param2):
210
- return tc.backend.mean(f(param1, param2))
211
-
212
- p1 = tf.ones([4])
213
- p2 = tf.ones([3])
214
- g1, g2 = tc.backend.value_and_grad(fsum)(p1, p2)
215
-
216
- f1 = experimental.finite_difference_differentiator(
217
- f, argnums=(0, 1), shifts=(np.pi / 2, 2)
218
- )
219
-
220
- def fsum1(param1, param2):
221
- return tc.backend.mean(f1(param1, param2))
222
-
223
- g3, g4 = tc.backend.value_and_grad(fsum1)(p1, p2)
224
-
225
- np.testing.assert_allclose(g1, g3, atol=1e-5)
226
- np.testing.assert_allclose(g2, g4, atol=1e-5)
227
-
228
-
229
- def test_evol(jaxb):
230
- def h_square(t, b):
231
- return (tc.backend.sign(t - 1.0) + 1) / 2 * b * tc.gates.x().tensor
232
-
233
- c = tc.Circuit(3)
234
- c.x(0)
235
- c.cx(0, 1)
236
- c.h(2)
237
- c = experimental.evol_local(
238
- c, [1], h_square, 2.0, tc.backend.convert_to_tensor(0.2)
239
- )
240
- c.rx(1, theta=np.pi - 0.4)
241
- np.testing.assert_allclose(c.expectation_ps(z=[1]), 1.0, atol=1e-5)
242
-
243
- ixi = tc.quantum.PauliStringSum2COO([[0, 1, 0]])
244
-
245
- def h_square_sparse(t, b):
246
- return (tc.backend.sign(t - 1.0) + 1) / 2 * b * ixi
247
-
248
- c = tc.Circuit(3)
249
- c.x(0)
250
- c.cx(0, 1)
251
- c.h(2)
252
- c = experimental.evol_global(
253
- c, h_square_sparse, 2.0, tc.backend.convert_to_tensor(0.2)
254
- )
255
- c.rx(1, theta=np.pi - 0.4)
256
- np.testing.assert_allclose(c.expectation_ps(z=[1]), 1.0, atol=1e-5)
257
-
258
-
259
- def test_energy_baseline():
260
- print(TFIM1Denergy(10))
261
- print(Heisenberg1Denergy(10))
262
-
263
-
264
- def test_jax_function_load(jaxb, tmp_path):
265
- K = tc.backend
266
-
267
- @K.jit
268
- def f(weights):
269
- c = tc.Circuit(3)
270
- c.rx(range(3), theta=weights)
271
- return K.real(c.expectation_ps(z=[0]))
272
-
273
- print(f(K.ones([3])))
274
-
275
- experimental.jax_jitted_function_save(
276
- os.path.join(tmp_path, "temp.bin"), f, K.ones([3])
277
- )
278
-
279
- f_load = tc.experimental.jax_jitted_function_load(
280
- os.path.join(tmp_path, "temp.bin")
281
- )
282
- np.testing.assert_allclose(f_load(K.ones([3])), 0.5403, atol=1e-4)
283
-
284
-
285
- def test_distrubuted_contractor(jaxb):
286
- def nodes_fn(params):
287
- c = tc.Circuit(4)
288
- c.rx(range(4), theta=params["x"])
289
- c.cnot([0, 1, 2], [1, 2, 3])
290
- c.ry(range(4), theta=params["y"])
291
- return c.expectation_before([tc.gates.z(), [-1]], reuse=False)
292
-
293
- params = {"x": np.ones([4]), "y": 0.3 * np.ones([4])}
294
- dc = experimental.DistributedContractor(
295
- nodes_fn,
296
- params,
297
- {
298
- "slicing_reconf_opts": {"target_size": 2**3},
299
- "max_repeats": 8,
300
- "minimize": "write",
301
- "parallel": False,
302
- },
303
- )
304
- value, grad = dc.value_and_grad(params)
305
- assert grad["y"].shape == (4,)
306
-
307
- def baseline(params):
308
- c = tc.Circuit(4)
309
- c.rx(range(4), theta=params["x"])
310
- c.cnot([0, 1, 2], [1, 2, 3])
311
- c.ry(range(4), theta=params["y"])
312
- return c.expectation_ps(z=[-1])
313
-
314
- np.testing.assert_allclose(value, baseline(params), atol=1e-6)
315
-
316
-
317
- @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
318
- def test_runtime_nodes_capture(backend):
319
- with tc.cons.runtime_nodes_capture() as captured:
320
- c = tc.Circuit(3)
321
- c.h(0)
322
- c.amplitude("010")
323
- len(captured["nodes"]) == 7
324
-
325
-
326
- @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
327
- def test_function_nodes_capture(backend):
328
- @tc.cons.function_nodes_capture
329
- def exp(theta):
330
- c = tc.Circuit(3)
331
- c.h(0)
332
- return c.expectation_ps(z=[-3], reuse=False)
333
-
334
- assert len(exp(0.3)) == 9
tests/test_mpscircuit.py DELETED
@@ -1,341 +0,0 @@
1
- # pylint: disable=unused-variable
2
- # pylint: disable=invalid-name
3
-
4
- from typing import Tuple, Any
5
- import sys
6
- import os
7
- import numpy as np
8
- import pytest
9
- from pytest_lazyfixture import lazy_fixture as lf
10
-
11
- Tensor = Any
12
-
13
- thisfile = os.path.abspath(__file__)
14
- modulepath = os.path.dirname(os.path.dirname(thisfile))
15
-
16
- sys.path.insert(0, modulepath)
17
- import tensorcircuit as tc
18
-
19
-
20
- N = 8
21
- D = 6
22
- split = tc.cons.split_rules(max_singular_values=D)
23
- type_test_circuits = Tuple[
24
- tc.Circuit, Tensor, tc.MPSCircuit, Tensor, tc.MPSCircuit, Tensor
25
- ]
26
-
27
-
28
- def reproducible_unitary(n, param):
29
- exp2n = 2**n
30
- A = tc.backend.cast(
31
- tc.backend.reshape(tc.backend.arange(exp2n**2), (exp2n, exp2n)), tc.dtypestr
32
- )
33
- A = A + tc.backend.sin(A) * param * 1j
34
- A = A - tc.backend.conj(tc.backend.transpose(A))
35
- return tc.backend.reshape(tc.backend.expm(A), (2,) * n * 2)
36
-
37
-
38
- def simulate(c, check=True, params=None):
39
- if params is None:
40
- params = tc.backend.ones((3,), dtype=tc.dtypestr)
41
- O1 = tc.gates.any(reproducible_unitary(1, params[0]))
42
- O2 = tc.gates.any(reproducible_unitary(2, params[1]))
43
- O3 = tc.gates.any(reproducible_unitary(3, params[2]))
44
-
45
- # Construct a complicated circuit by Circuit and MPSCircuit and compare
46
-
47
- c.H(0)
48
- # create as much correlation as possible
49
- for i in range(0, N - 1, 2):
50
- c.apply(O2.copy(), i, i + 1)
51
- c.apply(O1.copy(), i)
52
- c.apply(O3.copy(), int(N * 0.1), int(N * 0.5), int(N * 0.9))
53
- c.apply(O2.copy(), 1, N - 2)
54
- if check and isinstance(c, tc.MPSCircuit):
55
- np.testing.assert_allclose(np.abs(c._mps.check_canonical()), 0, atol=1e-12)
56
- c.cz(2, 3)
57
-
58
-
59
- def get_test_circuits() -> type_test_circuits:
60
- c = tc.Circuit(N)
61
- simulate(c)
62
- w_c = c.wavefunction()
63
-
64
- mps = tc.MPSCircuit(N, split=split)
65
- simulate(mps)
66
- do_test_norm(mps)
67
- mps.normalize()
68
- w_mps = mps.wavefunction()
69
-
70
- mps_exact = tc.MPSCircuit(N)
71
- simulate(mps_exact)
72
- w_mps_exact = mps_exact.wavefunction()
73
-
74
- return [c, w_c, mps, w_mps, mps_exact, w_mps_exact]
75
-
76
-
77
- def do_test_norm(mps: tc.MPSCircuit):
78
- norm1 = mps.get_norm()
79
- norm2 = tc.backend.norm(mps.wavefunction())
80
- np.testing.assert_allclose(norm1, norm2, atol=1e-12)
81
-
82
-
83
- def do_test_canonical(test_circuits: type_test_circuits):
84
- (
85
- c,
86
- w_c,
87
- mps,
88
- w_mps,
89
- mps_exact,
90
- w_mps_exact,
91
- ) = test_circuits
92
- np.testing.assert_allclose(np.abs(mps._mps.check_canonical()), 0, atol=1e-12)
93
- np.testing.assert_allclose(np.abs(mps_exact._mps.check_canonical()), 0, atol=1e-12)
94
-
95
-
96
- def do_test_wavefunction(test_circuits: type_test_circuits):
97
- (
98
- c,
99
- w_c,
100
- mps,
101
- w_mps,
102
- mps_exact,
103
- w_mps_exact,
104
- ) = test_circuits
105
- # the wavefuntion is exact if there's no truncation
106
- np.testing.assert_allclose(tc.backend.numpy(w_mps_exact), tc.backend.numpy(w_c))
107
-
108
-
109
- def do_test_truncation(
110
- test_circuits: type_test_circuits, real_fedility_ref, estimated_fedility_ref
111
- ):
112
- (
113
- c,
114
- w_c,
115
- mps,
116
- w_mps,
117
- mps_exact,
118
- w_mps_exact,
119
- ) = test_circuits
120
- # compare with a precalculated value
121
- real_fedility = (
122
- np.abs(tc.backend.numpy(w_mps).conj().dot(tc.backend.numpy(w_c))) ** 2
123
- )
124
- estimated_fedility = tc.backend.numpy(mps._fidelity)
125
- print(real_fedility, estimated_fedility)
126
- if real_fedility_ref is not None:
127
- np.testing.assert_allclose(real_fedility, real_fedility_ref, atol=1e-5)
128
- if estimated_fedility_ref is not None:
129
- np.testing.assert_allclose(
130
- estimated_fedility, estimated_fedility_ref, atol=1e-5
131
- )
132
-
133
-
134
- def do_test_amplitude(test_circuits: type_test_circuits):
135
- (
136
- c,
137
- w_c,
138
- mps,
139
- w_mps,
140
- mps_exact,
141
- w_mps_exact,
142
- ) = test_circuits
143
- # compare with wavefunction
144
- s = "01" * (N // 2)
145
- sint = int(s, 2) # binary to decimal
146
- err_amplitude = tc.backend.abs(mps.amplitude(s) - w_mps[sint])
147
- np.testing.assert_allclose(err_amplitude, 0, atol=1e-12)
148
-
149
-
150
- def do_test_expectation(test_circuits: type_test_circuits):
151
- (
152
- c,
153
- w_c,
154
- mps,
155
- w_mps,
156
- mps_exact,
157
- w_mps_exact,
158
- ) = test_circuits
159
-
160
- single_gate = (tc.gates.z(), [3])
161
- tensor = (np.sin(np.arange(16)) + np.cos(np.arange(16)) * 1j).reshape((2, 2, 2, 2))
162
- double_gate_nonunitary = (
163
- tc.gates.Gate(tc.backend.convert_to_tensor(tensor)),
164
- [2, 6],
165
- )
166
- double_gate = (tc.gates.cnot(), [2, 6])
167
- triple_gate = (tc.gates.toffoli(), [7, 1, 5])
168
- gates = [single_gate, double_gate_nonunitary, triple_gate]
169
-
170
- exp_mps = mps_exact.expectation(*gates)
171
- exp_c = c.expectation(*gates, reuse=False)
172
- np.testing.assert_allclose(exp_mps, exp_c, atol=1e-7)
173
-
174
- # ps
175
- x = [0, 2]
176
- y = [5, 3, 1]
177
- z = [6, 4]
178
- exp_mps = mps_exact.expectation_ps(x=x, y=y, z=z)
179
- exp_c = c.expectation_ps(x=x, y=y, z=z)
180
- np.testing.assert_allclose(exp_mps, exp_c, atol=1e-7)
181
-
182
-
183
- def external_wavefunction():
184
- # create a fixed wavefunction and create the corresponding MPS
185
- w_external = np.abs(np.sin(np.arange(2**N) % np.exp(1))).astype(
186
- tc.dtypestr
187
- ) # Just want to find a function that is so strange that the correlation is strong enough
188
- w_external /= np.linalg.norm(w_external)
189
- w_external = tc.backend.convert_to_tensor(w_external)
190
- mps_external = tc.MPSCircuit(N, wavefunction=w_external, split=split)
191
- mps_external_exact = tc.MPSCircuit(N, wavefunction=w_external)
192
- return w_external, mps_external, mps_external_exact
193
-
194
-
195
- def do_test_fromwavefunction(external_wavefunction, relative_err_ref):
196
- (
197
- w_external,
198
- mps_external,
199
- mps_external_exact,
200
- ) = external_wavefunction
201
- np.testing.assert_allclose(mps_external_exact.wavefunction(), w_external, atol=1e-7)
202
- # compare fidelity of truncation with theoretical limit obtained by SVD
203
- w_external = tc.backend.numpy(w_external)
204
- real_fedility = (
205
- np.abs(tc.backend.numpy(mps_external.wavefunction()).conj().dot(w_external))
206
- ** 2
207
- )
208
- s = np.linalg.svd(w_external.reshape((2 ** (N // 2), 2 ** (N // 2))))[1]
209
- theoretical_upper_limit = np.sum(s[0:D] ** 2)
210
- relative_err = np.log((1 - real_fedility) / (1 - theoretical_upper_limit))
211
- if relative_err_ref is not None:
212
- np.testing.assert_allclose(relative_err, relative_err_ref, atol=1e-4)
213
-
214
-
215
- def do_test_proj(test_circuits: type_test_circuits, external_wavefunction):
216
- (
217
- c,
218
- w_c,
219
- mps,
220
- w_mps,
221
- mps_exact,
222
- w_mps_exact,
223
- ) = test_circuits
224
- (
225
- w_external,
226
- mps_external,
227
- mps_external_exact,
228
- ) = external_wavefunction
229
- # compare projection value with wavefunction calculated results
230
- proj = mps.proj_with_mps(mps_external)
231
- proj_ref = (
232
- tc.backend.numpy(mps_external.wavefunction())
233
- .conj()
234
- .dot(tc.backend.numpy(w_mps))
235
- )
236
- np.testing.assert_allclose(proj, proj_ref, atol=1e-12)
237
-
238
-
239
- def do_test_tensor_input(test_circuits: type_test_circuits):
240
- (
241
- c,
242
- w_c,
243
- mps,
244
- w_mps,
245
- mps_exact,
246
- w_mps_exact,
247
- ) = test_circuits
248
- newmps = tc.MPSCircuit(
249
- mps._nqubits,
250
- tensors=mps.get_tensors(),
251
- center_position=mps.get_center_position(),
252
- )
253
- for t1, t2 in zip(newmps.get_tensors(), mps.get_tensors()):
254
- np.testing.assert_allclose(
255
- tc.backend.numpy(t1), tc.backend.numpy(t2), atol=1e-12
256
- )
257
-
258
-
259
- def do_test_measure(test_circuits: type_test_circuits):
260
- (
261
- c,
262
- w_c,
263
- mps,
264
- w_mps,
265
- mps_exact,
266
- w_mps_exact,
267
- ) = test_circuits
268
- index = [6, 5, 2, 1]
269
- status = tc.backend.convert_to_tensor([0.1, 0.3, 0.7, 0.9])
270
- result_c = c.measure(*index, with_prob=True, status=status)
271
- result_mps_exact = mps_exact.measure(*index, with_prob=True, status=status)
272
- np.testing.assert_allclose(result_mps_exact[0], result_c[0], atol=1e-8)
273
- np.testing.assert_allclose(result_mps_exact[1], result_c[1], atol=1e-8)
274
-
275
-
276
- def test_MPO_conversion(highp, tfb):
277
- O3 = reproducible_unitary(3, 1.0)
278
- I = tc.backend.eye(2, dtype=tc.dtypestr)
279
- gate = tc.gates.Gate(O3)
280
-
281
- MPO3, _ = tc.MPSCircuit.gate_to_MPO(gate, 2, 3, 4)
282
- tensor3 = tc.MPSCircuit.MPO_to_gate(MPO3).tensor
283
- tensor3 = tc.backend.numpy(tensor3)
284
- tensor3_ref = tc.backend.numpy(O3)
285
- np.testing.assert_allclose(tensor3, tensor3_ref, atol=1e-12)
286
-
287
- MPO4, _ = tc.MPSCircuit.gate_to_MPO(gate, 1, 3, 4)
288
- tensor4 = tc.MPSCircuit.MPO_to_gate(MPO4).tensor
289
- tensor4_ref = tc.backend.einsum("ijkabc,pq->ipjkaqbc", O3, I)
290
- tensor4 = tc.backend.numpy(tensor4)
291
- tensor4_ref = tc.backend.numpy(tensor4_ref)
292
- np.testing.assert_allclose(tensor4, tensor4_ref, atol=1e-12)
293
-
294
-
295
- @pytest.mark.parametrize(
296
- "backend, dtype", [(lf("tfb"), lf("highp")), (lf("jaxb"), lf("highp"))]
297
- )
298
- def test_circuits(backend, dtype):
299
- circuits = get_test_circuits()
300
- do_test_canonical(circuits)
301
- do_test_wavefunction(circuits)
302
- do_test_truncation(circuits, 0.902663090851, 0.910305380327)
303
- do_test_amplitude(circuits)
304
- do_test_expectation(circuits)
305
- external = external_wavefunction()
306
- do_test_fromwavefunction(external, 0.276089)
307
- do_test_proj(circuits, external)
308
- do_test_tensor_input(circuits)
309
- do_test_measure(circuits)
310
-
311
-
312
- @pytest.mark.parametrize("backend, dtype", [(lf("tfb"), lf("highp"))])
313
- def test_circuits_jit(backend, dtype):
314
- def expec(params):
315
- mps = tc.MPSCircuit(N, split=split)
316
- simulate(mps, check=False, params=params)
317
- x = [0, 2]
318
- y = [5, 3, 1]
319
- z = [6, 4]
320
- exp = mps.expectation_ps(x=x, y=y, z=z)
321
- return tc.backend.real(exp)
322
-
323
- params = tc.backend.ones((3,), dtype=tc.dtypestr)
324
- expec_vg = tc.backend.value_and_grad(expec)
325
- expec_vg_jit = tc.backend.jit(expec_vg)
326
- exp = expec(params)
327
- exp_jit, exp_grad_jit = expec_vg_jit(params)
328
- dir = tc.backend.convert_to_tensor(np.array([1.0, 2.0, 3.0], dtype=tc.dtypestr))
329
- epsilon = 1e-6
330
- exp_p = expec(params + dir * epsilon)
331
- exp_m = expec(params - dir * epsilon)
332
- exp_grad_dir_numerical = (exp_p - exp_m) / (epsilon * 2)
333
- exp_grad_dir_jit = tc.backend.real(tc.backend.sum(exp_grad_jit * dir))
334
- np.testing.assert_allclose(
335
- tc.backend.numpy(exp), tc.backend.numpy(exp_jit), atol=1e-10
336
- )
337
- np.testing.assert_allclose(
338
- tc.backend.numpy(exp_grad_dir_numerical),
339
- tc.backend.numpy(exp_grad_dir_jit),
340
- atol=1e-6,
341
- )