tensorcircuit-nightly 1.3.0.dev20250729__py3-none-any.whl → 1.3.0.dev20250731__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.

@@ -1,4 +1,4 @@
1
- tensorcircuit/__init__.py,sha256=GNg45VO8J-m5ApDmmQbFvTPIzXvBpREXDg5MiVgCqqI,2055
1
+ tensorcircuit/__init__.py,sha256=3yUehn2Xo7YNGDZZMC3I-Pz8sbvVzWsuXV0XDFWkGoQ,2055
2
2
  tensorcircuit/about.py,sha256=DazTswU2nAwOmASTaDII3L04PVtaQ7oiWPty5YMI3Wk,5267
3
3
  tensorcircuit/abstractcircuit.py,sha256=0osacPqq7B1EJki-cI1aLYoVRmjFaG9q3XevWMs7SsA,44125
4
4
  tensorcircuit/asciiart.py,sha256=neY1OWFwtoW5cHPNwkQHgRPktDniQvdlP9QKHkk52fM,8236
@@ -8,17 +8,17 @@ tensorcircuit/circuit.py,sha256=mE4b_9xRu3ydoB8iDffdx35V9GZLhAQD_tkjZDLnLjg,3910
8
8
  tensorcircuit/cons.py,sha256=uYKBeYKkDoJEqJTNrOZPRM31tBtkqe5aAg8GtVidJ1Y,33014
9
9
  tensorcircuit/densitymatrix.py,sha256=VqMBnWCxO5-OsOp6LOdc5RS2AzmB3U4-w40Vn_lqygo,14865
10
10
  tensorcircuit/experimental.py,sha256=TGK4FaS6TS_ZhtjcIZgYVuAkGdRW50LN0DdXp-h4bos,29906
11
- tensorcircuit/fgs.py,sha256=pzaZuzPIFPpfr5Z-UsBQ_Yp0x7mbSM2sUc4dO2SUmVs,49543
11
+ tensorcircuit/fgs.py,sha256=J1TjAiiqZk9KO1xYX_V0xsgKlYZaUQ7Enm4s5zkRM50,49514
12
12
  tensorcircuit/gates.py,sha256=x-wA7adVpP7o0AQLt_xYUScFKj8tU_wUOV2mR1GyrPc,29322
13
13
  tensorcircuit/keras.py,sha256=5OF4dfhEeS8sRYglpqYtQsWPeqp7uK0i7-P-6RRJ7zQ,10126
14
14
  tensorcircuit/mps_base.py,sha256=UZ-v8vsr_rAsKrfun8prVgbXJ-qsdqKy2DZIHpq3sxo,15400
15
15
  tensorcircuit/mpscircuit.py,sha256=COO9xzvA2Whe7Ncp6OqrgtXKmahHgTHxXTELAVHzFSY,36777
16
16
  tensorcircuit/noisemodel.py,sha256=vzxpoYEZbHVC4a6g7_Jk4dxsHi4wvhpRFwud8b616Qo,11878
17
- tensorcircuit/quantum.py,sha256=LNkIv5cJ2KG6puC18zTuXi-5cojW1Tnz-N-WjZ0Qu5Q,90217
17
+ tensorcircuit/quantum.py,sha256=1fZJJJ_o3NF7LaPPPU5Abd82NmMSnNQ8uUp_ClZdp3c,90244
18
18
  tensorcircuit/shadows.py,sha256=6XmWNubbuaxFNvZVWu-RXd0lN9Jkk-xwong_K8o8_KE,17014
19
19
  tensorcircuit/simplify.py,sha256=O11G3UYiVAc30GOfwXXmhLXwGZrQ8OVwLTMQMZp_XBc,9414
20
- tensorcircuit/stabilizercircuit.py,sha256=yNqcEKtYzRYrgqGil8QEyKN4OEMp9g6uOG2zuRaU8uc,15465
21
- tensorcircuit/timeevol.py,sha256=LWKOw4Y4CUtUO4a_72BVzYPH26PbubGYOaJlXkmA350,11439
20
+ tensorcircuit/stabilizercircuit.py,sha256=KbrBVSo2pXnf5JHIrxwRPSPTm7bJVMIcyE4d7-dIfCM,15545
21
+ tensorcircuit/timeevol.py,sha256=GDD6IgzkRhZIyvLkSKJ7ZihnkHQBqoWOBsmBwRAC1UI,28574
22
22
  tensorcircuit/torchnn.py,sha256=z_QpM0QC3mydGyWpyp877j-tSFCPyzynCwqrTWaw-IA,4637
23
23
  tensorcircuit/translation.py,sha256=VnU7DnYmbk1cWjqa7N68WNLNDn3DwENrMzmbG4_CQco,28611
24
24
  tensorcircuit/utils.py,sha256=nEDR1wTh1WF_yV6UyZYlifqOPWdKk_Krr4HjhrWHnGQ,7228
@@ -40,15 +40,15 @@ tensorcircuit/applications/physics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
40
40
  tensorcircuit/applications/physics/baseline.py,sha256=RWrzMGnC0PtmpYSFkvCE7r1llR88gncXuCakAAhFE-w,1775
41
41
  tensorcircuit/applications/physics/fss.py,sha256=ny3U9ZDmT459PXjA1oUGfarBOlSKSy6fs04vD9s1XH4,3633
42
42
  tensorcircuit/backends/__init__.py,sha256=WiUmbUFzM29w3hKfhuKxVUk3PpqDFiXf4za9g0ctpZA,80
43
- tensorcircuit/backends/abstract_backend.py,sha256=tzhOFZSOkZ_iraMvY7g84VbWBpYcELX1O0bhUipZ7YQ,59131
43
+ tensorcircuit/backends/abstract_backend.py,sha256=fAzyKvZ-1Mw2wvbyuR5IScVGhwZjY7AxBVtRo6viVY0,61743
44
44
  tensorcircuit/backends/backend_factory.py,sha256=Z0aQ-RnxOnQzp-SRw8sefAH8XyBSlj2NXZwOlHinbfY,1713
45
45
  tensorcircuit/backends/cupy_backend.py,sha256=4vgO3lnQnsvWL5hukhskjJp37EAHqio6z6TVXTQcdjs,15077
46
- tensorcircuit/backends/jax_backend.py,sha256=dkDQ380CJHIdlt1fZvlN_g8DIowWPEcTTV_XBcs0YB0,26088
47
- tensorcircuit/backends/jax_ops.py,sha256=o7tLlQMRnaKWcr5rVnOMqwG6KZVpR8M8ryNQ-ceXVxs,4789
48
- tensorcircuit/backends/numpy_backend.py,sha256=sd1migp_E2FWjchvOeYRuyM47yexegT2_SW_ukSYSF8,14171
46
+ tensorcircuit/backends/jax_backend.py,sha256=GIWsJwhlz0PD_KcypRkNWcjkegdNdoFMsmo0u0RQqrk,26704
47
+ tensorcircuit/backends/jax_ops.py,sha256=WyUGavch2R9uEFsI1Ap7eP1UcU4s2TItBgGsrVS3Hzs,9320
48
+ tensorcircuit/backends/numpy_backend.py,sha256=hhjrm0GK0d05TBYHNCZrBBBIJQ7V6qN99m1KLl0WKro,14408
49
49
  tensorcircuit/backends/pytorch_backend.py,sha256=yhfZSrm99yNW-dmijk8t6zAkbVgLRd4b_aIWKrpT7bY,24230
50
50
  tensorcircuit/backends/pytorch_ops.py,sha256=lLxpK6OqfpVwifyFlgsqhpnt-oIn4R5paPMVg51WaW0,3826
51
- tensorcircuit/backends/tensorflow_backend.py,sha256=N8iL2P76ZRp3USJSyFdZ2LWG8muXYe1kOuengv1ijXo,36444
51
+ tensorcircuit/backends/tensorflow_backend.py,sha256=CQhdWjUoqCNHxmJgfYOhUVpwDqjSo0RYrmsiaVWmxCU,37842
52
52
  tensorcircuit/backends/tf_ops.py,sha256=FJwDU7LhZrt0VUIx12DJU0gZnWhMv7B7r9sAKG710As,3378
53
53
  tensorcircuit/cloud/__init__.py,sha256=n0Lx07GYF6YbdIa6AJCLJk4zlAm5CqaeHszvkxxuoI4,139
54
54
  tensorcircuit/cloud/abstraction.py,sha256=6aSxbz0MP21jBVdFbSMrvJPLQH117vGz9sSHbMFoodE,14582
@@ -86,10 +86,10 @@ tensorcircuit/templates/graphs.py,sha256=cPYrxjoem0xZ-Is9dZKAvEzWZL_FejfIRiCEOTA
86
86
  tensorcircuit/templates/hamiltonians.py,sha256=Ag8djD6lckTeU7I99gCbXiQAb2VYqzm_p7-hpXo-5u4,5554
87
87
  tensorcircuit/templates/lattice.py,sha256=F35ebANk0DSmSHLR0-Q_hUbcznyCmZjb4fKmvCMywmA,58575
88
88
  tensorcircuit/templates/measurements.py,sha256=pzc5Aa9S416Ilg4aOY77Z6ZhUlYcXnAkQNQFTuHjFFs,10943
89
- tensorcircuit_nightly-1.3.0.dev20250729.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
89
+ tensorcircuit_nightly-1.3.0.dev20250731.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
90
90
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  tests/conftest.py,sha256=J9nHlLE3Zspz1rMyzadEuBWhaS5I4Q9sq0lnWybcdIA,1457
92
- tests/test_backends.py,sha256=rClxb2gyAoGeXd_ZYVSAJ0zEvJ7z_2btAeFM_Iy_wwY,33925
92
+ tests/test_backends.py,sha256=MLxpRWavWF0qWcjVI61lIa3CYGbztvTO8ITFOYX47ao,38312
93
93
  tests/test_calibrating.py,sha256=D1Tlv8mucUhg3ULvB5QlYyaDfw7aEERwq69-aGSb1A4,3805
94
94
  tests/test_channels.py,sha256=BL4CirU8ku9-_NrI6PZAS5xZ0wrL1UEC1S3wPI9dYQM,12628
95
95
  tests/test_circuit.py,sha256=IsSIFEs7hUCSYexMb-ESt1ZUpztHtLA0qz0CZolGdc4,52240
@@ -115,10 +115,10 @@ tests/test_shadows.py,sha256=1T3kJesVJ5XfZrSncL80xdq-taGCSnTDF3eL15UlavY,5160
115
115
  tests/test_simplify.py,sha256=35tbOu1QANsPvY1buLwNhqPnMkBOsnBtHn82qaukmgI,1175
116
116
  tests/test_stabilizer.py,sha256=MivuZ5pY7GOcEPTanhtrflXostyLBToHyjfPqCU0tG0,5450
117
117
  tests/test_templates.py,sha256=Xm9otFFaaBWG9TZpgJ-nNh9MBfRipTzFWL8fBOnie2k,7192
118
- tests/test_timeevol.py,sha256=b5fsUzW3kfLZV909jnJpH9vCBz5fefONOUSrm2N6Nxg,7886
118
+ tests/test_timeevol.py,sha256=zz17x21C-5f8ZvcgkXm30JzLgZMhsKaOCzyHCyS43h0,20333
119
119
  tests/test_torchnn.py,sha256=CHLTfWkF7Ses5_XnGFN_uv_JddfgenFEFzaDtSH8XYU,2848
120
120
  tests/test_van.py,sha256=kAWz860ivlb5zAJuYpzuBe27qccT-Yf0jatf5uXtTo4,3163
121
- tensorcircuit_nightly-1.3.0.dev20250729.dist-info/METADATA,sha256=MijyspDQzOzMCKoGxFN50a89pOhICnhrpUeXdPASpQg,34922
122
- tensorcircuit_nightly-1.3.0.dev20250729.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
123
- tensorcircuit_nightly-1.3.0.dev20250729.dist-info/top_level.txt,sha256=O_Iqeh2x02lasEYMI9iyPNNNtMzcpg5qvwMOkZQ7n4A,20
124
- tensorcircuit_nightly-1.3.0.dev20250729.dist-info/RECORD,,
121
+ tensorcircuit_nightly-1.3.0.dev20250731.dist-info/METADATA,sha256=QqZGkP34B7fJ3L38AiVOyyAgoYx_pZlrkWyWx8DcWEs,34922
122
+ tensorcircuit_nightly-1.3.0.dev20250731.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
123
+ tensorcircuit_nightly-1.3.0.dev20250731.dist-info/top_level.txt,sha256=O_Iqeh2x02lasEYMI9iyPNNNtMzcpg5qvwMOkZQ7n4A,20
124
+ tensorcircuit_nightly-1.3.0.dev20250731.dist-info/RECORD,,
tests/test_backends.py CHANGED
@@ -9,6 +9,7 @@ os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
9
9
  import numpy as np
10
10
  import pytest
11
11
  from pytest_lazyfixture import lazy_fixture as lf
12
+ import scipy
12
13
  import tensorflow as tf
13
14
 
14
15
  thisfile = os.path.abspath(__file__)
@@ -60,6 +61,126 @@ def test_grad_torch(torchb):
60
61
  np.testing.assert_allclose(f(a), np.ones([2]), atol=1e-5)
61
62
 
62
63
 
64
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
65
+ def test_sparse_csr_from_coo(backend):
66
+ # Create a sparse matrix in COO format
67
+ values = tc.backend.convert_to_tensor(np.array([1.0, 2.0, 3.0]))
68
+ values = tc.backend.cast(values, "complex64")
69
+ indices = tc.backend.convert_to_tensor(np.array([[0, 0], [1, 1], [2, 3]]))
70
+ indices = tc.backend.cast(indices, "int64")
71
+ coo_matrix = tc.backend.coo_sparse_matrix(indices, values, shape=[4, 4])
72
+
73
+ # Convert COO to CSR
74
+ csr_matrix = tc.backend.sparse_csr_from_coo(coo_matrix)
75
+
76
+ # Check that the result is still recognized as sparse
77
+ assert tc.backend.is_sparse(csr_matrix) is True
78
+
79
+ # Check that the conversion preserves values by comparing dense representations
80
+ coo_dense = tc.backend.to_dense(coo_matrix)
81
+ csr_dense = tc.backend.to_dense(csr_matrix)
82
+ np.testing.assert_allclose(coo_dense, csr_dense, atol=1e-5)
83
+
84
+
85
+ def test_sparse_tensor_matmul_monkey_patch(tfb):
86
+ """
87
+ Test the monkey-patched __matmul__ method for tf.SparseTensor.
88
+ This test specifically targets the line:
89
+ tf.SparseTensor.__matmul__ = sparse_tensor_matmul
90
+ """
91
+ # Create a sparse matrix in COO format
92
+ indices = tf.constant([[0, 0], [1, 1], [2, 3]], dtype=tf.int64)
93
+ values = tf.constant([1.0, 2.0, 3.0], dtype=tf.complex64)
94
+ shape = [4, 4]
95
+ sparse_matrix = tf.SparseTensor(indices=indices, values=values, dense_shape=shape)
96
+
97
+ # Test 1: Matrix-vector multiplication with 1D vector
98
+ vector_1d = tf.constant([1.0, 2.0, 3.0, 4.0], dtype=tf.complex64)
99
+ result_1d = sparse_matrix @ vector_1d # Using the monkey-patched @ operator
100
+
101
+ expected_1d = tf.constant([1.0, 4.0, 12.0, 0.0], dtype=tf.complex64)
102
+
103
+ np.testing.assert_allclose(result_1d, expected_1d, atol=1e-6)
104
+ vector_1d = tc.backend.reshape(vector_1d, [4, 1])
105
+ result_1dn = sparse_matrix @ vector_1d # Using the monkey-patched @ operator
106
+ expected_1d = tc.backend.reshape(expected_1d, [4, 1])
107
+
108
+ np.testing.assert_allclose(result_1dn, expected_1d, atol=1e-6)
109
+
110
+ # Test 2: Matrix-matrix multiplication with 2D matrix
111
+ matrix_2d = tf.constant(
112
+ [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0]], dtype=tf.complex64
113
+ )
114
+ result_2d = sparse_matrix @ matrix_2d # Using the monkey-patched @ operator
115
+
116
+ expected_2d = tf.sparse.sparse_dense_matmul(sparse_matrix, matrix_2d)
117
+
118
+ np.testing.assert_allclose(result_2d.numpy(), expected_2d.numpy(), atol=1e-6)
119
+
120
+ # Test 3: Verify that the operation is consistent with sparse_dense_matmul
121
+
122
+ reference_result = tc.backend.sparse_dense_matmul(sparse_matrix, vector_1d)
123
+ reference_result_squeezed = tc.backend.reshape(reference_result, [-1])
124
+
125
+ np.testing.assert_allclose(result_1d, reference_result_squeezed, atol=1e-6)
126
+
127
+
128
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("jaxb")])
129
+ def test_backend_jv(backend, highp):
130
+ def calculate_M(k, x_val):
131
+ safety_factor = 15
132
+ M = max(k, int(abs(x_val))) + int(safety_factor * np.sqrt(abs(x_val)))
133
+ M = max(M, k + 30)
134
+ return M
135
+
136
+ k_values = [5, 20, 50, 200, 500, 3000]
137
+ x_values = [0.0, 0.1, 1.0, 10.0, 100, 1000, 6000]
138
+ for k in k_values:
139
+ for x_val in x_values:
140
+ M = calculate_M(k, x_val)
141
+ f_vals = tc.backend.special_jv(k, x_val, M)
142
+ np.testing.assert_allclose(
143
+ f_vals, scipy.special.jv(np.arange(k), x_val), atol=1e-6
144
+ )
145
+
146
+
147
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("jaxb")])
148
+ def test_backend_jaxy_scan(backend):
149
+ def body_fun(carry, x):
150
+ counter, decrementor = carry
151
+
152
+ # 更新状态
153
+ new_counter = counter + 1
154
+ new_decrementor = decrementor - 1
155
+ new_carry = (new_counter, new_decrementor)
156
+
157
+ y = counter + decrementor
158
+
159
+ return new_carry, y
160
+
161
+ init_val = (0, 100)
162
+
163
+ final_carry, stacked_ys = tc.backend.jaxy_scan(
164
+ f=body_fun,
165
+ init=init_val,
166
+ xs=tc.backend.arange(5),
167
+ )
168
+
169
+ expected_final_carry = (5, 95)
170
+ expected_stacked_ys = np.array([100, 100, 100, 100, 100])
171
+
172
+ assert final_carry == expected_final_carry
173
+
174
+ np.testing.assert_array_equal(np.asarray(stacked_ys), expected_stacked_ys)
175
+
176
+
177
+ def test_backend_jv_grad(jaxb, highp):
178
+ def f(x):
179
+ return tc.backend.sum(tc.backend.special_jv(5, x, 100))
180
+
181
+ print(tc.backend.jit(tc.backend.value_and_grad(f))(0.2))
182
+
183
+
63
184
  @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
64
185
  def test_backend_scatter(backend):
65
186
  np.testing.assert_allclose(
tests/test_timeevol.py CHANGED
@@ -11,7 +11,7 @@ sys.path.insert(0, modulepath)
11
11
  import tensorcircuit as tc
12
12
 
13
13
 
14
- def test_ode_evol(jaxb):
14
+ def test_circuit_ode_evol(jaxb):
15
15
  def h_square(t, b):
16
16
  return (tc.backend.sign(t - 1.0) + 1) / 2 * b * tc.gates.x().tensor
17
17
 
@@ -19,9 +19,7 @@ def test_ode_evol(jaxb):
19
19
  c.x(0)
20
20
  c.cx(0, 1)
21
21
  c.h(2)
22
- c = tc.timeevol.ode_evol_local(
23
- c, [1], h_square, 2.0, tc.backend.convert_to_tensor(0.2)
24
- )
22
+ c = tc.timeevol.evol_local(c, [1], h_square, 2.0, tc.backend.convert_to_tensor(0.2))
25
23
  c.rx(1, theta=np.pi - 0.4)
26
24
  np.testing.assert_allclose(c.expectation_ps(z=[1]), 1.0, atol=1e-5)
27
25
 
@@ -34,13 +32,156 @@ def test_ode_evol(jaxb):
34
32
  c.x(0)
35
33
  c.cx(0, 1)
36
34
  c.h(2)
37
- c = tc.timeevol.ode_evol_global(
35
+ c = tc.timeevol.evol_global(
38
36
  c, h_square_sparse, 2.0, tc.backend.convert_to_tensor(0.2)
39
37
  )
40
38
  c.rx(1, theta=np.pi - 0.4)
41
39
  np.testing.assert_allclose(c.expectation_ps(z=[1]), 1.0, atol=1e-5)
42
40
 
43
41
 
42
+ def test_ode_evol_local(jaxb):
43
+ def local_hamiltonian(t, Omega, phi):
44
+ angle = phi * t
45
+ coeff = Omega * tc.backend.cos(2.0 * t) # Amplitude modulation
46
+
47
+ # Single-qubit Rabi Hamiltonian (2x2 matrix)
48
+ hx = coeff * tc.backend.cos(angle) * tc.gates.x().tensor
49
+ hy = coeff * tc.backend.sin(angle) * tc.gates.y().tensor
50
+ return hx + hy
51
+
52
+ # Initial state: GHZ state |0000⟩ + |1111⟩
53
+ c = tc.Circuit(4)
54
+ c.h(0)
55
+ for i in range(3):
56
+ c.cnot(i, i + 1)
57
+ psi0 = c.state()
58
+
59
+ # Time points
60
+ times = tc.backend.arange(0.0, 3.0, 0.1)
61
+
62
+ # Evolve with local Hamiltonian acting on qubit 1
63
+ states = tc.timeevol.ode_evol_local(
64
+ local_hamiltonian,
65
+ psi0,
66
+ times,
67
+ [1], # Apply to qubit 1
68
+ None,
69
+ 1.0,
70
+ 2.0, # Omega=1.0, phi=2.0
71
+ )
72
+ assert tc.backend.shape_tuple(states) == (30, 16)
73
+
74
+
75
+ def test_ode_evol_global(jaxb):
76
+ # Create a time-dependent transverse field Hamiltonian
77
+ # H(t) = -∑ᵢ Jᵢ(t) ZᵢZᵢ₊₁ - ∑ᵢ hᵢ(t) Xᵢ
78
+
79
+ # Time-dependent coefficients
80
+ def time_dep_J(t):
81
+ return 1.0 + 0.5 * tc.backend.sin(2.0 * t)
82
+
83
+ def time_dep_h(t):
84
+ return 0.5 * tc.backend.cos(1.5 * t)
85
+
86
+ zz_ham = tc.quantum.PauliStringSum2COO(
87
+ [[3, 3, 0, 0], [0, 3, 3, 0], [0, 0, 3, 3]], [1, 1, 1]
88
+ )
89
+ x_ham = tc.quantum.PauliStringSum2COO(
90
+ [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], [1, 1, 1, 1]
91
+ )
92
+
93
+ # Hamiltonian construction function
94
+ def hamiltonian_func(t):
95
+ # Create time-dependent ZZ terms
96
+ zz_coeff = time_dep_J(t)
97
+
98
+ # Create time-dependent X terms
99
+ x_coeff = time_dep_h(t)
100
+
101
+ return zz_coeff * zz_ham + x_coeff * x_ham
102
+
103
+ # Initial state: |↑↓↑↓⟩
104
+ c = tc.Circuit(4)
105
+ c.x([1, 3])
106
+ psi0 = c.state()
107
+
108
+ # Time points for evolution
109
+ times = tc.backend.arange(0, 5, 0.5)
110
+
111
+ def zobs(state):
112
+ n = int(np.log2(state.shape[-1]))
113
+ c = tc.Circuit(n, inputs=state)
114
+ return tc.backend.real(c.expectation_ps(z=[0]))
115
+
116
+ # Perform global ODE evolution
117
+ states = tc.timeevol.ode_evol_global(hamiltonian_func, psi0, times, zobs)
118
+ assert tc.backend.shape_tuple(states) == (10,)
119
+
120
+ zz_ham = tc.quantum.PauliStringSum2COO([[3, 3, 0, 0], [0, 3, 3, 0]], [1, 1])
121
+ x_ham = tc.quantum.PauliStringSum2COO([[1, 0, 0, 0], [0, 1, 0, 0]], [1, 1])
122
+
123
+ # Example with parameterized Hamiltonian and optimization
124
+ def parametrized_hamiltonian(t, params):
125
+ # params = [J0, J1, h0, h1] - parameters to optimize
126
+ J_t = params[0] + params[1] * tc.backend.sin(2.0 * t)
127
+ h_t = params[2] + params[3] * tc.backend.cos(1.5 * t)
128
+
129
+ return J_t * zz_ham + h_t * x_ham
130
+
131
+ # Observable function: measure ZZ correlation
132
+ def zz_correlation(state):
133
+ n = int(np.log2(state.shape[0]))
134
+ circuit = tc.Circuit(n, inputs=state)
135
+ return circuit.expectation_ps(z=[0, 1])
136
+
137
+ @tc.backend.jit
138
+ @tc.backend.value_and_grad
139
+ def objective_function(params):
140
+ states = tc.timeevol.ode_evol_global(
141
+ parametrized_hamiltonian,
142
+ psi0,
143
+ tc.backend.convert_to_tensor([0, 1.0]),
144
+ None,
145
+ params,
146
+ )
147
+ # Measure ZZ correlation at final time
148
+ final_state = states[-1]
149
+ return tc.backend.real(zz_correlation(final_state))
150
+
151
+ print(objective_function(tc.backend.ones([4])))
152
+
153
+
154
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
155
+ def test_ed_evol(backend):
156
+ n = 4
157
+ g = tc.templates.graphs.Line1D(n, pbc=False)
158
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=False)
159
+
160
+ # Initial Neel state: |↑↓↑↓⟩
161
+ c = tc.Circuit(n)
162
+ c.x([1, 3]) # Apply X gates to qubits 1 and 3
163
+ psi0 = c.state()
164
+
165
+ # Imaginary time evolution times
166
+ times = tc.backend.convert_to_tensor([0.0, 0.5, 1.0, 2.0])
167
+
168
+ # Evolve and get states
169
+ states = tc.timeevol.ed_evol(h, psi0, times)
170
+ print(states)
171
+
172
+ def evolve_and_measure(params):
173
+ # Parametrized Hamiltonian
174
+ h_param = tc.quantum.heisenberg_hamiltonian(
175
+ g, hzz=params[0], hxx=params[1], hyy=params[2], sparse=False
176
+ )
177
+ states = tc.timeevol.ed_evol(h_param, psi0, times)
178
+ # Measure observable on final state
179
+ circuit = tc.Circuit(n, inputs=states[-1])
180
+ return tc.backend.real(circuit.expectation_ps(z=[0]))
181
+
182
+ evolve_and_measure(tc.backend.ones([3]))
183
+
184
+
44
185
  @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
45
186
  def test_hamiltonian_evol_basic(backend):
46
187
  """Test basic functionality of hamiltonian_evol with a simple 2-qubit Hamiltonian"""
@@ -63,7 +204,7 @@ def test_hamiltonian_evol_basic(backend):
63
204
  )
64
205
 
65
206
  # Evolve and get states
66
- states = tc.timeevol.hamiltonian_evol(times, h, psi0)
207
+ states = tc.timeevol.hamiltonian_evol(h, psi0, times)
67
208
 
68
209
  # Check output shape
69
210
  assert states.shape == (3, 4)
@@ -99,7 +240,7 @@ def test_hamiltonian_evol_with_callback(backend):
99
240
  return tc.backend.real(c.expectation_ps(z=[0]))
100
241
 
101
242
  # Evolve with callback
102
- results = tc.timeevol.hamiltonian_evol(times, h, psi0, callback)
243
+ results = tc.timeevol.hamiltonian_evol(h, psi0, times, callback)
103
244
 
104
245
  # Check output shape - should be scalar for each time point
105
246
  assert results.shape == (3,)
@@ -121,7 +262,7 @@ def test_hamiltonian_evol_imaginary_time(backend):
121
262
  times = tc.backend.convert_to_tensor([0.0, 10.0])
122
263
 
123
264
  # Evolve
124
- states = tc.timeevol.hamiltonian_evol(times, h, psi0)
265
+ states = tc.timeevol.hamiltonian_evol(h, psi0, times)
125
266
 
126
267
  # Ground state is |1⟩ (eigenvalue 1.0), so after long imaginary time
127
268
  # evolution, we should approach this state
@@ -138,7 +279,6 @@ def test_krylov_evol_heisenberg_6_sites(backend):
138
279
 
139
280
  # Generate Heisenberg Hamiltonian
140
281
  h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=False)
141
- print(h.dtype)
142
282
  # Initial state - all spins up except last one down
143
283
  psi0 = np.zeros((2**n,))
144
284
  psi0[62] = 1.0
@@ -236,3 +376,266 @@ def test_krylov_evol_subspace_accuracy(backend):
236
376
  # At least verify they have the correct shape
237
377
  assert state_small.shape == (1, 2**n)
238
378
  assert state_large.shape == (1, 2**n)
379
+
380
+
381
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
382
+ def test_krylov_evol_scan_impl(backend):
383
+ """Test krylov_evol with scan_impl=True"""
384
+ n = 4
385
+ # Create a 1D chain graph
386
+ g = tc.templates.graphs.Line1D(n, pbc=False)
387
+
388
+ # Generate Heisenberg Hamiltonian
389
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=True)
390
+
391
+ c = tc.Circuit(n)
392
+ c.x([1, 2])
393
+ psi0 = c.state()
394
+
395
+ # Evolution times
396
+ times = tc.backend.convert_to_tensor([0.0, 0.5])
397
+
398
+ # Perform Krylov evolution with scan implementation
399
+ states_scan = tc.timeevol.krylov_evol(
400
+ h, psi0, times, subspace_dimension=8, scan_impl=True
401
+ )
402
+
403
+ states_scan_dense = tc.timeevol.krylov_evol(
404
+ tc.backend.to_dense(h), psi0, times, subspace_dimension=8, scan_impl=True
405
+ )
406
+
407
+ # Perform Krylov evolution with regular implementation
408
+ states_regular = tc.timeevol.krylov_evol(
409
+ h, psi0, times, subspace_dimension=8, scan_impl=False
410
+ )
411
+
412
+ # Check output shapes
413
+ assert states_scan.shape == (2, 2**n)
414
+ assert states_regular.shape == (2, 2**n)
415
+
416
+ # Results should be the same (up to numerical precision)
417
+ np.testing.assert_allclose(states_scan, states_regular, atol=1e-5)
418
+ np.testing.assert_allclose(states_scan_dense, states_regular, atol=1e-5)
419
+
420
+ # All states should be normalized
421
+ for state in states_scan:
422
+ norm = tc.backend.norm(state)
423
+ np.testing.assert_allclose(norm, 1.0, atol=1e-5)
424
+
425
+
426
+ @pytest.mark.parametrize("backend", [lf("jaxb")])
427
+ def test_krylov_evol_gradient(backend):
428
+ """Test gradient computation with krylov_evol"""
429
+ n = 5
430
+ # Create a 1D chain graph
431
+ g = tc.templates.graphs.Line1D(n, pbc=False)
432
+
433
+ # Generate Heisenberg Hamiltonian
434
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=False)
435
+
436
+ c = tc.Circuit(n)
437
+ c.x([1, 2])
438
+ psi0 = c.state()
439
+
440
+ # Evolution time
441
+ t = tc.backend.convert_to_tensor([1.0])
442
+
443
+ # Define a simple loss function based on the evolved state
444
+ def loss_function(t):
445
+ states = tc.timeevol.krylov_evol(
446
+ h, psi0, t, subspace_dimension=8, scan_impl=True
447
+ )
448
+ # Compute the sum of absolute values of the final state as a simple loss
449
+ return tc.backend.sum(tc.backend.abs(states[0]))
450
+
451
+ grad_fn = tc.backend.jit(tc.backend.grad(loss_function))
452
+ gradient = grad_fn(t)
453
+ print(gradient)
454
+
455
+
456
+ @pytest.mark.parametrize(
457
+ "backend, sparse",
458
+ [[lf("npb"), True], [lf("npb"), False], [lf("jaxb"), True], [lf("jaxb"), False]],
459
+ )
460
+ def test_chebyshev_evol_basic(backend, highp, sparse):
461
+ n = 6
462
+ # Create a 1D chain graph
463
+ g = tc.templates.graphs.Line1D(n, pbc=False)
464
+
465
+ # Generate Heisenberg Hamiltonian (dense for better compatibility)
466
+ h = tc.quantum.heisenberg_hamiltonian(
467
+ g, hzz=1.0, hxx=1.0, hyy=1.0, hx=0.2, sparse=sparse
468
+ )
469
+
470
+ # Initial Neel state: |↑↓↑↓⟩
471
+ c = tc.Circuit(n)
472
+ c.x([1, 3, 5]) # Apply X gates to qubits 1 and 3
473
+ psi0 = c.state()
474
+
475
+ # Evolution time
476
+ t = 2.0
477
+
478
+ # Estimate spectral bounds
479
+ e_max, e_min = tc.timeevol.estimate_spectral_bounds(h, n_iter=30)
480
+
481
+ # Estimate parameters
482
+ k = tc.timeevol.estimate_k(t, (e_max, e_min))
483
+ m = tc.timeevol.estimate_M(t, (e_max, e_min), k)
484
+
485
+ # Evolve using Chebyshev method
486
+ psi_chebyshev = tc.timeevol.chebyshev_evol(
487
+ h, psi0, t, (float(e_max) + 0.1, float(e_min) - 0.1), k, m
488
+ )
489
+
490
+ # Check that state is normalized (or close to it)
491
+ norm = tc.backend.norm(psi_chebyshev)
492
+ np.testing.assert_allclose(norm, 1.0, atol=1e-3)
493
+
494
+ # Compare with exact evolution for small system
495
+ if sparse is True:
496
+ h = tc.backend.to_dense(h)
497
+ psi_exact = tc.timeevol.ed_evol(h, psi0, 1.0j * tc.backend.convert_to_tensor([t]))[
498
+ 0
499
+ ]
500
+
501
+ # States should be close (up to global phase)
502
+ fidelity = np.abs(np.vdot(np.asarray(psi_exact), np.asarray(psi_chebyshev))) ** 2
503
+ assert fidelity > 0.95 # Should be close, but not exact due to approximations
504
+
505
+
506
+ def test_chebyshev_evol_vmap_on_t(jaxb, highp):
507
+ n = 4
508
+ # Create a 1D chain graph
509
+ g = tc.templates.graphs.Line1D(n, pbc=False)
510
+
511
+ # Generate Heisenberg Hamiltonian
512
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=False)
513
+
514
+ # Initial Neel state
515
+ c = tc.Circuit(n)
516
+ c.x([1, 3])
517
+ psi0 = c.state()
518
+
519
+ # Estimate spectral bounds
520
+ e_max, e_min = tc.timeevol.estimate_spectral_bounds(h, n_iter=20)
521
+
522
+ # Fixed parameters
523
+ k = 50
524
+ m = 150
525
+
526
+ # Define vectorized evolution function
527
+ def evolve_single_time(t):
528
+ return tc.timeevol.chebyshev_evol(
529
+ h, psi0, t, (float(e_max) + 0.1, float(e_min) - 0.1), k, m
530
+ )
531
+
532
+ # Vectorize over times
533
+ times = tc.backend.convert_to_tensor([0.5, 1.0, 1.5])
534
+ vmap_evolve = tc.backend.jit(tc.backend.vmap(evolve_single_time))
535
+ states_vmap = vmap_evolve(times)
536
+
537
+ # Check output shape
538
+ assert states_vmap.shape == (3, 2**n)
539
+
540
+ # Compare with sequential execution
541
+ states_sequential = []
542
+ for t in times:
543
+ state = tc.timeevol.chebyshev_evol(
544
+ h, psi0, float(t), (e_max + 0.1, e_min - 0.1), k, m
545
+ )
546
+ states_sequential.append(state)
547
+
548
+ states_sequential = tc.backend.stack(states_sequential)
549
+
550
+ # Results should be the same
551
+ np.testing.assert_allclose(states_vmap, states_sequential, atol=1e-5)
552
+
553
+
554
+ def test_chebyshev_evol_jit_on_psi(jaxb, highp):
555
+ """Test JIT compilation capability of chebyshev_evol on psi parameter"""
556
+ n = 4
557
+ # Create a 1D chain graph
558
+ g = tc.templates.graphs.Line1D(n, pbc=False)
559
+
560
+ # Generate Heisenberg Hamiltonian
561
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=0.6, hyy=1.0, sparse=True)
562
+
563
+ # Estimate spectral bounds
564
+ e_max, e_min = tc.timeevol.estimate_spectral_bounds(h, n_iter=20)
565
+
566
+ # Fixed parameters
567
+ t = 1.0
568
+ k = 50
569
+ m = 150
570
+
571
+ # Define JIT-compiled evolution function with psi as argument
572
+ def evolve_state(psi):
573
+ return tc.timeevol.chebyshev_evol(
574
+ h, psi, t, (float(e_max) + 0.1, float(e_min) - 0.1), k, m
575
+ )
576
+
577
+ jit_evolve = tc.backend.jit(evolve_state)
578
+
579
+ # Test with different initial states
580
+ c1 = tc.Circuit(n)
581
+ c1.x([0, 2])
582
+ psi1 = c1.state()
583
+
584
+ c2 = tc.Circuit(n)
585
+ c2.h(0)
586
+ for i in range(n - 1):
587
+ c2.cnot(i, i + 1)
588
+ psi2 = c2.state()
589
+
590
+ # Run JIT-compiled evolution
591
+ result1_jit = jit_evolve(psi1)
592
+ result2_jit = jit_evolve(psi2)
593
+
594
+ # Run regular evolution for comparison
595
+ result1_regular = tc.timeevol.chebyshev_evol(
596
+ h, psi1, t, (e_max + 0.1, e_min - 0.1), k, m
597
+ )
598
+ result2_regular = tc.timeevol.chebyshev_evol(
599
+ h, psi2, t, (e_max + 0.1, e_min - 0.1), k, m
600
+ )
601
+ print(result1_jit)
602
+ # Results should be the same
603
+ np.testing.assert_allclose(result1_jit, result1_regular, atol=1e-5)
604
+ np.testing.assert_allclose(result2_jit, result2_regular, atol=1e-5)
605
+
606
+
607
+ def test_chebyshev_evol_ad_on_t(jaxb, highp):
608
+ n = 5
609
+ # Create a 1D chain graph
610
+ g = tc.templates.graphs.Line1D(n, pbc=True)
611
+
612
+ # Generate Heisenberg Hamiltonian
613
+ h = tc.quantum.heisenberg_hamiltonian(g, hzz=1.0, hxx=1.0, hyy=1.0, sparse=True)
614
+
615
+ # Initial state
616
+ c = tc.Circuit(n)
617
+ c.x([1, 3])
618
+ psi0 = c.state()
619
+
620
+ # Estimate spectral bounds
621
+ e_max, e_min = tc.timeevol.estimate_spectral_bounds(h, n_iter=20)
622
+
623
+ # Fixed parameters
624
+ k = 50
625
+ m = 100
626
+
627
+ # Define loss function for gradient computation
628
+ def loss_function(t):
629
+ psi_t = tc.timeevol.chebyshev_evol(
630
+ h, psi0, t, (float(e_max) + 0.1, float(e_min) - 0.1), k, m
631
+ )
632
+ c = tc.Circuit(5, inputs=psi_t)
633
+ return tc.backend.real(c.expectation_ps(z=[2]))
634
+
635
+ # Compute gradient
636
+ grad_fn = tc.backend.jit(tc.backend.grad(loss_function))
637
+ t_test = tc.backend.convert_to_tensor(1.0)
638
+ gradient = grad_fn(t_test)
639
+ print(gradient)
640
+ # Gradient should be a scalar
641
+ assert gradient.shape == ()