Skip to content

Commit 5c8d326

Browse files
committed
add euler angle rotation gate + test
1 parent ff31a45 commit 5c8d326

File tree

2 files changed

+98
-49
lines changed

2 files changed

+98
-49
lines changed

quantumsim/circuit.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,14 @@ def make_idling_gate(self, start_time, end_time):
7070
for s, e, t1 in self.t1s:
7171
s = max(s, start_time)
7272
e = min(e, end_time)
73-
if (s < e):
73+
if (s < e):
7474
decay_rate += (e - s)/t1/duration
7575

7676
for s, e, t2 in self.t2s:
7777
s = max(s, start_time)
7878
e = min(e, end_time)
79-
if (s < e):
79+
if (s < e):
8080
deph_rate += (e - s)/t2/duration
81-
8281

8382
return AmpPhDamp(self.name, time, duration, 1/decay_rate, 1/deph_rate)
8483

@@ -251,6 +250,26 @@ def __init__(self, bit, time, angle, dephasing=None, **kwargs):
251250
else:
252251
self.label = r"$R_z(%g)$" % angle
253252

253+
class RotateEuler(SinglePTMGate):
254+
255+
def __init__(self, bit, time, theta, phi, lamda, **kwargs):
256+
""" A single qubit rotation described by three Euler angles (theta, phi, lambda)
257+
U = R_Z(phi).R_X(theta).R_Z(lamda)
258+
"""
259+
unitary = np.array(
260+
[[np.cos(theta/2),
261+
-1j*np.exp(1j*lamda)*np.sin(theta/2)],
262+
[-1j*np.exp(1j*phi)*np.sin(theta/2),
263+
np.exp(1j*(lamda+phi))*np.cos(theta/2)]
264+
])
265+
266+
p = ptm.single_kraus_to_ptm(unitary)
267+
268+
269+
super().__init__(bit, time, p, **kwargs)
270+
271+
self.label = r"$R(\theta, \phi, \lambda)$"
272+
254273

255274
class IdlingGate:
256275
pass

quantumsim/test/test_integration.py

+76-46
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@
55
import pytest
66

77

8-
9-
108
def test_three_qbit_clean():
119
c = circuit.Circuit()
1210

1311
qubit_names = ["D1", "A1", "D2", "A2", "D3"]
1412

1513
# clean ancillas have infinite life-time
1614
for qb in qubit_names:
17-
#set lifetime to only almost inf so that waiting gates are added but ineffective
18-
c.add_qubit(qb, np.inf, 1e10)
19-
15+
# set lifetime to only almost inf so that waiting gates are added but
16+
# ineffective
17+
c.add_qubit(qb, np.inf, 1e10)
18+
2019
c.add_hadamard("A1", time=0)
2120
c.add_hadamard("A2", time=0)
2221

@@ -52,26 +51,25 @@ def test_three_qbit_clean():
5251
for i in range(100):
5352
c.apply_to(sdm)
5453

55-
5654
assert len(m1.measurements) == 100
5755
assert len(m2.measurements) == 100
5856

5957
assert sdm.classical == {}
6058

61-
#in a clean run, we expect just one possible path
59+
# in a clean run, we expect just one possible path
6260
assert np.allclose(sdm.trace(), 1)
6361

64-
assert m1.measurements == [1]*100
65-
assert m2.measurements == [0, 1]*50
62+
assert m1.measurements == [1] * 100
63+
assert m2.measurements == [0, 1] * 50
64+
6665

6766
def test_noisy_measurement_sampler():
6867
c = circuit.Circuit()
6968
c.add_qubit("A", 0, 0)
7069

71-
7270
c.add_hadamard("A", 1)
7371

74-
sampler = circuit.uniform_noisy_sampler(seed=42, readout_error = 0.1)
72+
sampler = circuit.uniform_noisy_sampler(seed=42, readout_error=0.1)
7573
m1 = c.add_measurement("A", time=2, sampler=sampler)
7674

7775
sdm = sparsedm.SparseDM("A")
@@ -82,54 +80,61 @@ def test_noisy_measurement_sampler():
8280
true_state.append(sdm.classical['A'])
8381

8482
# these samples assume a certain seed (=42)
85-
assert m1.measurements == [0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
83+
assert m1.measurements == [0, 1, 0, 0, 1, 0,
84+
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
8685
assert true_state != m1.measurements
87-
assert true_state == [0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1]
86+
assert true_state == [0, 1, 0, 0, 1, 0, 1,
87+
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1]
8888

8989
# we have two measurement errors
9090
mprob = 0.9**18 * 0.1**2
9191
assert np.allclose(sdm.classical_probability, mprob)
92-
9392
# and each measurement has outcome 1/2
9493
totprob = mprob * 0.5**20
9594
assert np.allclose(sdm.trace(), totprob)
9695

96+
9797
def test_measurement_with_output_bit():
9898
c = circuit.Circuit()
9999
c.add_qubit("A")
100100

101101
c.add_qubit("O")
102102
c.add_qubit("O2")
103103

104-
c.add_rotate_y("A", time=0, angle=np.pi/2)
104+
c.add_rotate_y("A", time=0, angle=np.pi / 2)
105105

106106
sampler = circuit.selection_sampler(1)
107107
c.add_measurement("A", time=1, sampler=sampler, output_bit="O")
108108

109-
c.add_rotate_y("A", time=3.5, angle=np.pi/2)
109+
c.add_rotate_y("A", time=3.5, angle=np.pi / 2)
110110

111111
sampler = circuit.selection_sampler(1)
112112
c.add_measurement("A", time=4, sampler=sampler, output_bit="O2")
113113

114-
c.add_rotate_y("A", time=5, angle=np.pi/2)
114+
c.add_rotate_y("A", time=5, angle=np.pi / 2)
115115
c.order()
116116

117117
sdm = sparsedm.SparseDM(c.get_qubit_names())
118118

119119
assert sdm.classical['O'] == 0
120120
assert sdm.classical['O2'] == 0
121121

122-
123122
c.apply_to(sdm)
124123

125-
126124
assert np.allclose(sdm.trace(), 0.25)
127125

128-
assert sdm.classical == {'O': 1, 'O2':1}
126+
assert sdm.classical == {'O': 1, 'O2': 1}
127+
129128

130129
@pytest.mark.skip()
131130
def test_integration_surface17():
132-
def make_circuit(t1=np.inf, t2=np.inf, seed=42, readout_error=0.015, t_gate=40, t_rest=1000):
131+
def make_circuit(
132+
t1=np.inf,
133+
t2=np.inf,
134+
seed=42,
135+
readout_error=0.015,
136+
t_gate=40,
137+
t_rest=1000):
133138
surf17 = circuit.Circuit("Surface 17")
134139

135140
t_rest += t_gate # nominal rest time is between two gates
@@ -173,7 +178,8 @@ def add_x(c, x_anc, d_bits, t=0, t_gate=t_gate):
173178
surf17.add_hadamard(b, time=4 * t_gate + t_rest + 5 * t_gate)
174179

175180
for b in z_bits:
176-
surf17.add_measurement(b, time=10 * t_gate + t_rest, sampler=sampler)
181+
surf17.add_measurement(
182+
b, time=10 * t_gate + t_rest, sampler=sampler)
177183

178184
for b in x_bits:
179185
surf17.add_measurement(b, time=6 * t_gate, sampler=sampler)
@@ -190,13 +196,12 @@ def syndrome_to_byte(syndrome):
190196
byte = 0
191197

192198
for i in range(4):
193-
byte += syndrome["X%d"%i] << (i+4)
199+
byte += syndrome["X%d" % i] << (i + 4)
194200
for i in range(4):
195-
byte += syndrome["Z%d"%i] << i
201+
byte += syndrome["Z%d" % i] << i
196202

197203
return byte
198204

199-
200205
seed = 890793515
201206

202207
t1 = 25000.0
@@ -210,12 +215,10 @@ def syndrome_to_byte(syndrome):
210215
c = make_circuit(t1=t1, t2=t2, seed=seed,
211216
readout_error=ro_error, t_gate=t_gate, t_rest=t_rest)
212217

213-
214218
sdm = sparsedm.SparseDM(c.get_qubit_names())
215-
for b in ["D%d"%i for i in range(9)]:
219+
for b in ["D%d" % i for i in range(9)]:
216220
sdm.ensure_dense(b)
217221

218-
219222
syndromes = []
220223
for _ in range(rounds):
221224
c.apply_to(sdm)
@@ -228,9 +231,11 @@ def syndrome_to_byte(syndrome):
228231

229232
assert syndrome == b'jHhJhL\x08L\tK)K\x08K\x08K\x08K\x08I'
230233

234+
231235
def test_free_decay():
232236

233-
for t1, t2 in [(np.inf, np.inf), (1000, 2000), (np.inf, 1000), (1000, 1000)]:
237+
for t1, t2 in [(np.inf, np.inf), (1000, 2000),
238+
(np.inf, 1000), (1000, 1000)]:
234239
c = circuit.Circuit("Free decay")
235240
c.add_qubit("Q", t1=t1, t2=t2)
236241
c.add_rotate_y("Q", time=0, angle=np.pi)
@@ -242,24 +247,25 @@ def test_free_decay():
242247
c.apply_to(sdm)
243248
sdm.project_measurement("Q", 0)
244249

245-
assert np.allclose(sdm.trace(), np.exp(-1000/t1))
250+
assert np.allclose(sdm.trace(), np.exp(-1000 / t1))
251+
246252

247253
def test_ramsey():
248254

249-
for t1, t2 in [(np.inf, np.inf), (1000, 2000), (np.inf, 1000), (1000, 1000)]:
255+
for t1, t2 in [(np.inf, np.inf), (1000, 2000),
256+
(np.inf, 1000), (1000, 1000)]:
250257
c = circuit.Circuit("Ramsey")
251258
c.add_qubit("Q", t1=t1, t2=t2)
252-
c.add_rotate_y("Q", time=0, angle=np.pi/2)
253-
c.add_rotate_y("Q", time=1000, angle=-np.pi/2)
259+
c.add_rotate_y("Q", time=0, angle=np.pi / 2)
260+
c.add_rotate_y("Q", time=1000, angle=-np.pi / 2)
254261
c.add_waiting_gates()
255262
c.order()
256263

257264
sdm = sparsedm.SparseDM(c.get_qubit_names())
258265
c.apply_to(sdm)
259266
sdm.project_measurement("Q", 0)
260267

261-
assert np.allclose(sdm.trace(), 0.5*(1+np.exp(-1000/t2)))
262-
268+
assert np.allclose(sdm.trace(), 0.5 * (1 + np.exp(-1000 / t2)))
263269

264270

265271
def test_two_qubit_tpcp():
@@ -271,17 +277,19 @@ def test_two_qubit_tpcp():
271277
c.add_gate("rotate_y", "B", angle=0.2, time=0)
272278
c.add_gate("rotate_z", "A", angle=0.1, time=1)
273279
c.add_gate("rotate_x", "B", angle=0.3, time=1)
274-
c.add_gate("cphase","A", "B", time=2)
280+
c.add_gate("cphase", "A", "B", time=2)
275281

276282
sdm = sparsedm.SparseDM(c.get_qubit_names())
277283
for i in range(100):
278284
c.apply_to(sdm)
279285
x = sdm.full_dm.get_diag()
280-
assert np.allclose(x.sum(), 1) # trace preserved
281-
assert np.all(x > 0) # probabilities greater than zero
282-
283-
assert np.allclose(np.linalg.eigvalsh(sdm.full_dm.to_array()), [0, 0, 0, 1])
286+
assert np.allclose(x.sum(), 1) # trace preserved
287+
assert np.all(x > 0) # probabilities greater than zero
284288

289+
assert np.allclose(
290+
np.linalg.eigvalsh(
291+
sdm.full_dm.to_array()), [
292+
0, 0, 0, 1])
285293

286294

287295
def test_cphase_rotation():
@@ -293,9 +301,8 @@ def test_cphase_rotation():
293301
c.add_gate("rotate_y", "A", angle=1.2, time=0)
294302
c.add_gate("rotate_y", "B", angle=1.2, time=0)
295303

296-
297-
for t in [1,2,3,4,5]:
298-
g = circuit.CPhaseRotation("A", "B", 2*np.pi/5, t)
304+
for t in [1, 2, 3, 4, 5]:
305+
g = circuit.CPhaseRotation("A", "B", 2 * np.pi / 5, t)
299306
c.add_gate(g)
300307

301308
c.add_gate("rotate_y", "A", angle=-1.2, time=6)
@@ -305,15 +312,38 @@ def test_cphase_rotation():
305312

306313
sdm = sparsedm.SparseDM(c.get_qubit_names())
307314

315+
c.apply_to(sdm)
308316

317+
d = sdm.full_dm.get_diag()
309318

310-
c.apply_to(sdm)
319+
assert np.allclose(d, [1, 0, 0, 0])
311320

312321

322+
def test_euler_rotation():
323+
c = circuit.Circuit("test")
324+
c.add_qubit("A")
313325

314-
d = sdm.full_dm.get_diag()
326+
theta = 0.3
327+
lamda = 0.7
328+
phi = 4.2
315329

316-
assert np.allclose(d, [1, 0, 0, 0])
330+
g = circuit.RotateEuler(bit="A", time=0, theta=theta, lamda=lamda, phi=phi)
331+
gconj = circuit.RotateEuler(
332+
bit="A",
333+
time=10,
334+
theta=-theta,
335+
lamda=-phi,
336+
phi=-lamda)
337+
338+
c.add_gate(g)
339+
c.add_gate(gconj)
340+
341+
c.order()
317342

343+
sdm = sparsedm.SparseDM(c.get_qubit_names())
344+
345+
c.apply_to(sdm)
318346

347+
d = sdm.full_dm.get_diag()
319348

349+
assert np.allclose(d, [1, 0])

0 commit comments

Comments
 (0)