Skip to content

Commit ab3d190

Browse files
Merge branch 'ngpr57'
2 parents 8266638 + daa78a6 commit ab3d190

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
"""
2+
Quantum Trajectory Simulation for Measurement-Induced Phase Transitions (MIPT) in Measurement-Only Models
3+
------------------------------------------------------------------------------
4+
This script simulates a quantum circuit under monitoring (weak measurements).
5+
It calculates the evolution of a quantum state under:
6+
1. Weak X measurements (single-site)
7+
2. Weak ZZ measurements (two-site link)
8+
3. Weak ZXZ measurements (three-site)
9+
10+
It utilizes TensorCircuit with a JAX backend for Just-In-Time (JIT) compilation
11+
to speed up the simulation of many trajectories. It computes Topological
12+
Entanglement Entropy (TEE) and Mutual Information (MEE).
13+
"""
14+
15+
from typing import Tuple, List, Any
16+
from functools import partial
17+
import numpy as np
18+
import numpy.typing as npt
19+
import tensorcircuit as tc
20+
21+
# Setup
22+
K = tc.set_backend("jax")
23+
tc.set_dtype("complex128")
24+
25+
# Operators with type annotations - explicitly set dtype
26+
Z: npt.NDArray[np.complex128] = np.array([[1, 0], [0, -1]], dtype=np.complex128)
27+
X: npt.NDArray[np.complex128] = np.array([[0, 1], [1, 0]], dtype=np.complex128)
28+
I8: npt.NDArray[np.complex128] = np.eye(8, dtype=np.complex128)
29+
ZXZ: npt.NDArray[np.complex128] = np.kron(np.kron(Z, X), Z)
30+
31+
32+
@partial(K.jit, static_argnums=(3, 4))
33+
def mipt_circuit(
34+
sx: npt.NDArray[np.float64],
35+
szz: npt.NDArray[np.float64],
36+
szxz: npt.NDArray[np.float64],
37+
n: int,
38+
d: int,
39+
cx_params: float,
40+
sx_params: float,
41+
czz_params: float,
42+
szz_params: float,
43+
czxz_params: float,
44+
szxz_params: float,
45+
) -> Tuple[Any, Any, Any, Any]:
46+
"""
47+
Simulates a single quantum trajectory.
48+
49+
Args:
50+
status_x, status_zz, status_zxz: Random numbers used to determine measurement outcomes.
51+
n: Number of qubits.
52+
d: Circuit depth (time steps).
53+
cx, sx: Cosine/Sine parameters for weak X measurement strength.
54+
czz, szz: Cosine/Sine parameters for weak ZZ measurement strength.
55+
czxz, szxz: Cosine/Sine parameters for weak ZXZ measurement strength.
56+
57+
Returns:
58+
x_history, zz_history, zxz_history: Record of measurement outcomes (0 or 1).
59+
state: The final normalized quantum state vector.
60+
"""
61+
sx = K.reshape(sx, [d, n])
62+
szz = K.reshape(szz, [d, n])
63+
szxz = K.reshape(szxz, [d, n])
64+
65+
# Initialize |+++...⟩ state
66+
c = tc.Circuit(n)
67+
for j in range(n):
68+
c.h(j) # type: ignore
69+
state = c.state()
70+
71+
# A. Weak X Measurement Operators (Single Qubit)
72+
M1_x = 0.5 * cx_params * K.convert_to_tensor(
73+
np.array([[1, 1], [1, 1]], dtype=np.complex128)
74+
) + 0.5 * sx_params * K.convert_to_tensor(
75+
np.array([[1, -1], [-1, 1]], dtype=np.complex128)
76+
)
77+
M2_x = 0.5 * sx_params * K.convert_to_tensor(
78+
np.array([[1, 1], [1, 1]], dtype=np.complex128)
79+
) + 0.5 * cx_params * K.convert_to_tensor(
80+
np.array([[1, -1], [-1, 1]], dtype=np.complex128)
81+
)
82+
83+
# B. Weak ZZ Measurement Operators (Two Qubits)
84+
M1_zz = czz_params * K.convert_to_tensor(
85+
np.array(
86+
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]],
87+
dtype=np.complex128,
88+
)
89+
) + szz_params * K.convert_to_tensor(
90+
np.array(
91+
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]],
92+
dtype=np.complex128,
93+
)
94+
)
95+
M2_zz = szz_params * K.convert_to_tensor(
96+
np.array(
97+
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]],
98+
dtype=np.complex128,
99+
)
100+
) + czz_params * K.convert_to_tensor(
101+
np.array(
102+
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]],
103+
dtype=np.complex128,
104+
)
105+
)
106+
M1_zz = M1_zz.reshape([2, 2, 2, 2])
107+
M2_zz = M2_zz.reshape([2, 2, 2, 2])
108+
109+
# Convert global constants to tensors
110+
I8_t = K.convert_to_tensor(I8)
111+
ZXZ_t = K.convert_to_tensor(ZXZ)
112+
113+
# C. Weak ZXZ Measurement Operators (Three Qubits)
114+
M1_zxz = 0.5 * (czxz_params * (I8_t + ZXZ_t) + szxz_params * (I8_t - ZXZ_t))
115+
M2_zxz = 0.5 * (szxz_params * (I8_t + ZXZ_t) + czxz_params * (I8_t - ZXZ_t))
116+
M1_zxz = M1_zxz.reshape([2, 2, 2, 2, 2, 2])
117+
M2_zxz = M2_zxz.reshape([2, 2, 2, 2, 2, 2])
118+
119+
x_h: List[Any] = []
120+
zz_h: List[Any] = []
121+
zxz_h: List[Any] = []
122+
123+
for t in range(d):
124+
c = tc.Circuit(n, inputs=state)
125+
126+
# ZZ measurements (alternating bonds)
127+
for i in range(t % 2, n - 1, 2):
128+
zz_h.append(
129+
c.general_kraus(
130+
[M1_zz, M2_zz], i, i + 1, status=szz[t, i], with_prob=False
131+
)
132+
)
133+
state = c.state()
134+
state = state / K.norm(state)
135+
c = tc.Circuit(n, inputs=state)
136+
137+
# ZXZ measurements (3-qubit blocks)
138+
for i in range(t % 3, n - 2, 3):
139+
zxz_h.append(
140+
c.general_kraus(
141+
[M1_zxz, M2_zxz],
142+
i,
143+
i + 1,
144+
i + 2,
145+
status=szxz[t, i],
146+
with_prob=False,
147+
)
148+
)
149+
state = c.state()
150+
state = state / K.norm(state)
151+
c = tc.Circuit(n, inputs=state)
152+
153+
# X measurements (all qubits)
154+
for i in range(n):
155+
x_h.append(
156+
c.general_kraus([M1_x, M2_x], i, status=sx[t, i], with_prob=False)
157+
)
158+
state = c.state()
159+
state = state / K.norm(state)
160+
161+
return K.stack(x_h), K.stack(zz_h), K.stack(zxz_h), state
162+
163+
164+
# --- Entanglement Metrics ---
165+
166+
167+
def TEE(state: Any, n: int) -> Any:
168+
"""Topological Entanglement Entropy: S_AB + S_BC - S_B - S_D"""
169+
p = n // 4
170+
A, B, D, C = range(0, p), range(p, 2 * p), range(2 * p, 3 * p), range(3 * p, n)
171+
172+
rho_AB = tc.quantum.reduced_density_matrix(state, cut=list(C) + list(D))
173+
rho_BC = tc.quantum.reduced_density_matrix(state, cut=list(A) + list(D))
174+
rho_B = tc.quantum.reduced_density_matrix(state, cut=list(A) + list(C) + list(D))
175+
rho_D = tc.quantum.reduced_density_matrix(state, cut=list(A) + list(B) + list(C))
176+
177+
return (
178+
tc.quantum.entropy(rho_AB)
179+
+ tc.quantum.entropy(rho_BC)
180+
- tc.quantum.entropy(rho_B)
181+
- tc.quantum.entropy(rho_D)
182+
)
183+
184+
185+
def MEE(state: Any, n: int) -> Any:
186+
"""Mutual Information between first and last qubit: S_A + S_B - S_AB"""
187+
rho_A = tc.quantum.reduced_density_matrix(state, cut=list(range(1, n)))
188+
rho_B = tc.quantum.reduced_density_matrix(state, cut=list(range(0, n - 1)))
189+
rho_AB = tc.quantum.reduced_density_matrix(state, cut=list(range(1, n - 1)))
190+
return (
191+
tc.quantum.entropy(rho_A)
192+
+ tc.quantum.entropy(rho_B)
193+
- tc.quantum.entropy(rho_AB)
194+
)
195+
196+
197+
def main() -> None:
198+
"""Main execution function."""
199+
n, d, trajectories = 6, 12, 10
200+
201+
# Measurement strengths (γ)
202+
# γ_{a} = 0: No measurement
203+
# γ_{a} = 1: Strong projective measurement with operator a
204+
γ_x, γ_zz = 0.01, 0.01
205+
206+
cx, sx = np.cos((1 - γ_x) * np.pi / 4), np.sin((1 - γ_x) * np.pi / 4)
207+
czz, szz = np.cos((1 - γ_zz) * np.pi / 4), np.sin((1 - γ_zz) * np.pi / 4)
208+
czxz, szxz = np.cos((γ_zz + γ_x) * np.pi / 4), np.sin((γ_zz + γ_x) * np.pi / 4)
209+
210+
I_ab, T_ee = 0, 0
211+
results_x, results_zz, results_zxz = [], [], []
212+
213+
for _ in range(trajectories):
214+
sx_r = np.random.uniform(size=[d * n])
215+
szz_r = np.random.uniform(size=[d * n])
216+
szxz_r = np.random.uniform(size=[d * n])
217+
218+
x, zz, zxz, state = mipt_circuit(
219+
sx_r, szz_r, szxz_r, n, d, cx, sx, czz, szz, czxz, szxz
220+
)
221+
222+
results_x.append(x)
223+
results_zz.append(zz)
224+
results_zxz.append(zxz)
225+
226+
I_ab += MEE(state, n) / trajectories
227+
T_ee += TEE(state, n) / trajectories
228+
229+
# Output
230+
print("X outcomes:", np.concatenate(results_x).tolist())
231+
print("ZZ outcomes:", np.concatenate(results_zz).tolist())
232+
print("ZXZ outcomes:", np.concatenate(results_zxz).tolist())
233+
print(f"MI (bits): {I_ab/np.log(2):.4f}")
234+
print(f"TEE (bits): {T_ee/np.log(2):.4f}")
235+
236+
237+
if __name__ == "__main__":
238+
main()

0 commit comments

Comments
 (0)