Skip to content

Commit ceec634

Browse files
ehua7365cduck
andauthored
U3 to Clifford Z rotation alternatives (#386)
U3 is defined by $$U(\theta,\phi,\lambda) = R_z(\phi) R_y(\theta) R_z(\lambda)$$ When $\theta=0$, we get $$U(0,\phi,\lambda) = R_z(\phi + \lambda)$$ If we restrict to angles in $[0,2\pi)$, then the Clifford operators are $R_z(0)=I$, $R_z(\pi)=Z$, $R_z(\pi/2)=S$ $R_z(3\pi/2)=S^\dagger$. Hence as long as $\phi + \lambda$ is a multiple of $\pi/2$ then we have a Clifford, this PR ensures that this is the case by fixing the lookup table and adding tests. --------- Co-authored-by: Casey Duckering <[email protected]>
1 parent 5425cfd commit ceec634

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

src/bloqade/squin/rewrite/U3_to_clifford.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ def decompose_U3_gates(self, node: op.stmts.U3) -> Tuple[List[ir.Statement], ...
126126
if theta is None or phi is None or lam is None:
127127
return ()
128128

129+
# For U3(2*pi*n, phi, lam) = U3(0, 0, lam + phi) which is a Z rotation.
130+
if np.isclose(np.mod(theta, math.tau), 0):
131+
lam = lam + phi
132+
phi = 0.0
133+
elif np.isclose(np.mod(theta + np.pi, math.tau), 0):
134+
lam = lam - phi
135+
phi = 0.0
136+
129137
theta_half_pi: int | None = self.resolve_angle(theta)
130138
phi_half_pi: int | None = self.resolve_angle(phi)
131139
lam_half_pi: int | None = self.resolve_angle(lam)

test/squin/rewrite/test_U3_to_clifford.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ def test_equiv():
5959
assert isinstance(get_stmt_at_idx(test_equiv, 5), op.stmts.S)
6060

6161

62+
def test_s_alternative():
63+
64+
@kernel
65+
def test():
66+
q = qubit.new(4)
67+
oper = op.u(theta=0.0, phi=0.25 * math.tau, lam=0.0)
68+
qubit.apply(oper, q[0])
69+
70+
SquinToCliffordTestPass(test.dialects)(test)
71+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.S)
72+
73+
6274
def test_z():
6375

6476
@kernel
@@ -81,6 +93,18 @@ def test():
8193
assert isinstance(get_stmt_at_idx(test, 15), op.stmts.Z)
8294

8395

96+
def test_z_alternative():
97+
98+
@kernel
99+
def test():
100+
q = qubit.new(4)
101+
oper = op.u(theta=0.0, phi=0.5 * math.tau, lam=0.0)
102+
qubit.apply(oper, q[0])
103+
104+
SquinToCliffordTestPass(test.dialects)(test)
105+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.Z)
106+
107+
84108
def test_sdag():
85109

86110
@kernel
@@ -104,6 +128,58 @@ def test_equiv():
104128
assert isinstance(get_stmt_at_idx(test_equiv, 6), op.stmts.Adjoint)
105129

106130

131+
def test_sdag_alternative_negative():
132+
133+
@kernel
134+
def test():
135+
q = qubit.new(4)
136+
oper = op.u(theta=0.0, phi=-0.25 * math.tau, lam=0.0)
137+
qubit.apply(oper, q[0])
138+
139+
SquinToCliffordTestPass(test.dialects)(test)
140+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.S)
141+
assert isinstance(get_stmt_at_idx(test, 6), op.stmts.Adjoint)
142+
143+
144+
def test_sdag_alternative():
145+
146+
@kernel
147+
def test():
148+
q = qubit.new(4)
149+
oper = op.u(theta=0.0, phi=0.75 * math.tau, lam=0.0)
150+
qubit.apply(oper, q[0])
151+
152+
SquinToCliffordTestPass(test.dialects)(test)
153+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.S)
154+
assert isinstance(get_stmt_at_idx(test, 6), op.stmts.Adjoint)
155+
156+
157+
def test_sdag_weird_case():
158+
159+
@kernel
160+
def test():
161+
q = qubit.new(4)
162+
oper = op.u(theta=2 * math.tau, phi=0.7 * math.tau, lam=0.05 * math.tau)
163+
qubit.apply(oper, q[0])
164+
165+
SquinToCliffordTestPass(test.dialects)(test)
166+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.S)
167+
assert isinstance(get_stmt_at_idx(test, 6), op.stmts.Adjoint)
168+
169+
170+
def test_sdag_weirder_case():
171+
172+
@kernel
173+
def test():
174+
q = qubit.new(4)
175+
oper = op.u(theta=0.5 * math.tau, phi=0.05 * math.tau, lam=0.8 * math.tau)
176+
qubit.apply(oper, q[0])
177+
178+
SquinToCliffordTestPass(test.dialects)(test)
179+
assert isinstance(get_stmt_at_idx(test, 5), op.stmts.S)
180+
assert isinstance(get_stmt_at_idx(test, 6), op.stmts.Adjoint)
181+
182+
107183
def test_sqrt_y():
108184

109185
@kernel

0 commit comments

Comments
 (0)