tensorcircuit-nightly 1.2.1.dev20250725__py3-none-any.whl → 1.3.0.dev20250727__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.
- tensorcircuit/__init__.py +1 -1
- tensorcircuit/backends/jax_backend.py +8 -1
- tensorcircuit/circuit.py +48 -0
- tensorcircuit/cons.py +60 -2
- tensorcircuit/fgs.py +254 -72
- tensorcircuit/mpscircuit.py +45 -4
- tensorcircuit/results/counts.py +99 -0
- tensorcircuit/stabilizercircuit.py +25 -15
- tensorcircuit/templates/__init__.py +1 -0
- tensorcircuit/templates/hamiltonians.py +153 -0
- tensorcircuit/utils.py +7 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/METADATA +2 -2
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/RECORD +22 -20
- tests/test_circuit.py +13 -0
- tests/test_dmcircuit.py +1 -1
- tests/test_fgs.py +8 -0
- tests/test_hamiltonians.py +159 -0
- tests/test_miscs.py +20 -0
- tests/test_stabilizer.py +9 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/WHEEL +0 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/licenses/LICENSE +0 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import numpy as np
|
|
3
|
+
from pytest_lazyfixture import lazy_fixture as lf
|
|
4
|
+
|
|
5
|
+
import tensorcircuit as tc
|
|
6
|
+
|
|
7
|
+
from tensorcircuit.templates.lattice import (
|
|
8
|
+
ChainLattice,
|
|
9
|
+
SquareLattice,
|
|
10
|
+
CustomizeLattice,
|
|
11
|
+
)
|
|
12
|
+
from tensorcircuit.templates.hamiltonians import (
|
|
13
|
+
heisenberg_hamiltonian,
|
|
14
|
+
rydberg_hamiltonian,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
PAULI_X = np.array([[0, 1], [1, 0]], dtype=complex)
|
|
18
|
+
PAULI_Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
|
|
19
|
+
PAULI_Z = np.array([[1, 0], [0, -1]], dtype=complex)
|
|
20
|
+
PAULI_I = np.eye(2, dtype=complex)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TestHeisenbergHamiltonian:
|
|
24
|
+
"""
|
|
25
|
+
Test suite for the heisenberg_hamiltonian function.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def test_empty_lattice(self):
|
|
29
|
+
"""
|
|
30
|
+
Test that an empty lattice produces a 0x0 matrix.
|
|
31
|
+
"""
|
|
32
|
+
empty_lattice = CustomizeLattice(
|
|
33
|
+
dimensionality=2, identifiers=[], coordinates=[]
|
|
34
|
+
)
|
|
35
|
+
h = heisenberg_hamiltonian(empty_lattice)
|
|
36
|
+
assert h.shape == (1, 1)
|
|
37
|
+
assert h.nnz == 0
|
|
38
|
+
|
|
39
|
+
def test_single_site(self):
|
|
40
|
+
"""
|
|
41
|
+
Test that a single-site lattice (no bonds) produces a 2x2 zero matrix.
|
|
42
|
+
"""
|
|
43
|
+
single_site_lattice = ChainLattice(size=(1,), pbc=False)
|
|
44
|
+
h = heisenberg_hamiltonian(single_site_lattice)
|
|
45
|
+
assert h.shape == (2, 2)
|
|
46
|
+
assert h.nnz == 0
|
|
47
|
+
|
|
48
|
+
@pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
|
|
49
|
+
def test_two_sites_chain(self, backend):
|
|
50
|
+
"""
|
|
51
|
+
Test a two-site chain against a manually calculated Hamiltonian.
|
|
52
|
+
This is the most critical test for scientific correctness.
|
|
53
|
+
"""
|
|
54
|
+
lattice = ChainLattice(size=(2,), pbc=False)
|
|
55
|
+
j_coupling = -1.5 # Test with a non-trivial coupling constant
|
|
56
|
+
h_generated = heisenberg_hamiltonian(lattice, j_coupling=j_coupling)
|
|
57
|
+
|
|
58
|
+
# Manually construct the expected Hamiltonian: H = J * (X_0X_1 + Y_0Y_1 + Z_0Z_1)
|
|
59
|
+
xx = np.kron(PAULI_X, PAULI_X)
|
|
60
|
+
yy = np.kron(PAULI_Y, PAULI_Y)
|
|
61
|
+
zz = np.kron(PAULI_Z, PAULI_Z)
|
|
62
|
+
h_expected = j_coupling * (xx + yy + zz)
|
|
63
|
+
|
|
64
|
+
assert h_generated.shape == (4, 4)
|
|
65
|
+
print(tc.backend.to_dense(h_generated))
|
|
66
|
+
assert np.allclose(tc.backend.to_dense(h_generated), h_expected, atol=1e-5)
|
|
67
|
+
|
|
68
|
+
def test_square_lattice_properties(self):
|
|
69
|
+
"""
|
|
70
|
+
Test properties of a larger lattice (2x2 square) without full matrix comparison.
|
|
71
|
+
"""
|
|
72
|
+
lattice = SquareLattice(size=(2, 2), pbc=True) # 4 sites, 8 bonds with PBC
|
|
73
|
+
h = heisenberg_hamiltonian(lattice, j_coupling=1.0)
|
|
74
|
+
|
|
75
|
+
assert h.shape == (16, 16)
|
|
76
|
+
assert h.nnz > 0
|
|
77
|
+
h_dense = tc.backend.to_dense(h)
|
|
78
|
+
assert np.allclose(h_dense, h_dense.conj().T)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TestRydbergHamiltonian:
|
|
82
|
+
"""
|
|
83
|
+
Test suite for the rydberg_hamiltonian function.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def test_single_site_rydberg(self):
|
|
87
|
+
"""
|
|
88
|
+
Test a single atom, which should only have driving and detuning terms.
|
|
89
|
+
"""
|
|
90
|
+
lattice = ChainLattice(size=(1,), pbc=False)
|
|
91
|
+
omega, delta, c6 = 2.0, 0.5, 100.0
|
|
92
|
+
h_generated = rydberg_hamiltonian(lattice, omega, delta, c6)
|
|
93
|
+
|
|
94
|
+
h_expected = (omega / 2.0) * PAULI_X + (delta / 2.0) * PAULI_Z
|
|
95
|
+
|
|
96
|
+
assert h_generated.shape == (2, 2)
|
|
97
|
+
assert np.allclose(tc.backend.to_dense(h_generated), h_expected)
|
|
98
|
+
|
|
99
|
+
def test_two_sites_rydberg(self):
|
|
100
|
+
"""
|
|
101
|
+
Test a two-site chain for Rydberg Hamiltonian, including interaction.
|
|
102
|
+
"""
|
|
103
|
+
lattice = ChainLattice(size=(2,), pbc=False, lattice_constant=1.5)
|
|
104
|
+
omega, delta, c6 = 1.0, -0.5, 10.0
|
|
105
|
+
h_generated = rydberg_hamiltonian(lattice, omega, delta, c6)
|
|
106
|
+
|
|
107
|
+
v_ij = c6 / (1.5**6)
|
|
108
|
+
|
|
109
|
+
h1 = (omega / 2.0) * (np.kron(PAULI_X, PAULI_I) + np.kron(PAULI_I, PAULI_X))
|
|
110
|
+
z0_coeff = delta / 2.0 - v_ij / 4.0
|
|
111
|
+
z1_coeff = delta / 2.0 - v_ij / 4.0
|
|
112
|
+
h2 = z0_coeff * np.kron(PAULI_Z, PAULI_I) + z1_coeff * np.kron(PAULI_I, PAULI_Z)
|
|
113
|
+
h3 = (v_ij / 4.0) * np.kron(PAULI_Z, PAULI_Z)
|
|
114
|
+
|
|
115
|
+
h_expected = h1 + h2 + h3
|
|
116
|
+
|
|
117
|
+
assert h_generated.shape == (4, 4)
|
|
118
|
+
h_generated_dense = tc.backend.to_dense(h_generated)
|
|
119
|
+
|
|
120
|
+
assert np.allclose(h_generated_dense, h_expected)
|
|
121
|
+
|
|
122
|
+
def test_zero_distance_robustness(self):
|
|
123
|
+
"""
|
|
124
|
+
Test that the function does not crash when two atoms have zero distance.
|
|
125
|
+
"""
|
|
126
|
+
lattice = CustomizeLattice(
|
|
127
|
+
dimensionality=2,
|
|
128
|
+
identifiers=[0, 1],
|
|
129
|
+
coordinates=[[0.0, 0.0], [0.0, 0.0]],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
h = rydberg_hamiltonian(lattice, omega=1.0, delta=1.0, c6=1.0)
|
|
134
|
+
# The X terms contribute 8 non-zero elements.
|
|
135
|
+
# The Z terms (Z0+Z1) have diagonal elements that cancel out,
|
|
136
|
+
# resulting in only 2 non-zero elements. Total nnz = 8 + 2 = 10.
|
|
137
|
+
assert h.nnz == 10
|
|
138
|
+
except ZeroDivisionError:
|
|
139
|
+
pytest.fail("The function failed to handle zero distance between sites.")
|
|
140
|
+
|
|
141
|
+
@pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
|
|
142
|
+
def test_anisotropic_heisenberg(self, backend):
|
|
143
|
+
"""
|
|
144
|
+
Test the anisotropic Heisenberg model with different Jx, Jy, Jz.
|
|
145
|
+
"""
|
|
146
|
+
lattice = ChainLattice(size=(2,), pbc=False)
|
|
147
|
+
j_coupling = [-1.0, 0.5, 2.0] # Jx, Jy, Jz
|
|
148
|
+
h_generated = heisenberg_hamiltonian(lattice, j_coupling=j_coupling)
|
|
149
|
+
|
|
150
|
+
# Manually construct the expected Hamiltonian
|
|
151
|
+
jx, jy, jz = j_coupling
|
|
152
|
+
xx = np.kron(PAULI_X, PAULI_X)
|
|
153
|
+
yy = np.kron(PAULI_Y, PAULI_Y)
|
|
154
|
+
zz = np.kron(PAULI_Z, PAULI_Z)
|
|
155
|
+
h_expected = jx * xx + jy * yy + jz * zz
|
|
156
|
+
|
|
157
|
+
h_generated_dense = tc.backend.to_dense(h_generated)
|
|
158
|
+
assert h_generated_dense.shape == (4, 4)
|
|
159
|
+
assert np.allclose(h_generated_dense, h_expected)
|
tests/test_miscs.py
CHANGED
|
@@ -312,3 +312,23 @@ def test_distrubuted_contractor(jaxb):
|
|
|
312
312
|
return c.expectation_ps(z=[-1])
|
|
313
313
|
|
|
314
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_stabilizer.py
CHANGED
|
@@ -215,3 +215,12 @@ def test_mipt():
|
|
|
215
215
|
return c.entanglement_entropy(list(range(n // 2)))
|
|
216
216
|
|
|
217
217
|
print(ruc(50, 10, 0.1))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def test_measure_with_prob():
|
|
221
|
+
c = tc.StabilizerCircuit(3)
|
|
222
|
+
c.h(0)
|
|
223
|
+
c.cnot(0, 1)
|
|
224
|
+
m, p = c.measure(0, 2, with_prob=True)
|
|
225
|
+
np.testing.assert_allclose(p, 0.5, atol=1e-6)
|
|
226
|
+
print(m)
|
|
File without changes
|
|
File without changes
|