Skip to content

Commit 089a5a3

Browse files
elenbaascrturrado
andauthored
[CQT-297] Check that composing bloch sphere rotations is done correctly (#425)
Co-authored-by: Roberto Turrado Camblor <rturrado@gmail.com>
1 parent ae7a712 commit 089a5a3

File tree

4 files changed

+33
-9
lines changed

4 files changed

+33
-9
lines changed

opensquirrel/passes/decomposer/cnot_decomposer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def decompose(self, g: Gate) -> list[Gate]:
3838
# See https://threeplusone.com/pubs/on_gates.pdf
3939

4040
# Try special case first, see https://arxiv.org/pdf/quant-ph/9503016.pdf lemma 5.5
41-
controlled_rotation_times_x = general_merger.compose_bloch_sphere_rotations(X(target_qubit), g.target_gate)
41+
controlled_rotation_times_x = general_merger.compose_bloch_sphere_rotations(g.target_gate, X(target_qubit))
4242
theta0_with_x, theta1_with_x, theta2_with_x = ZYZDecomposer().get_decomposition_angles(
4343
controlled_rotation_times_x.axis,
4444
controlled_rotation_times_x.angle,

opensquirrel/passes/merger/general_merger.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,16 @@
1515

1616
def compose_bloch_sphere_rotations(bsr_a: BlochSphereRotation, bsr_b: BlochSphereRotation) -> BlochSphereRotation:
1717
"""Computes the Bloch sphere rotation resulting from the composition of two Bloch sphere rotations.
18-
The first rotation is applied and then the second.
19-
If the final Bloch sphere rotation is anonymous, we will try to match it to a default gate.
18+
The first rotation (A) is applied and then the second (B):
19+
20+
As separate gates:
21+
A q
22+
B q
23+
24+
A linear operations:
25+
(B * A) q
26+
27+
If the final Bloch sphere rotation is anonymous, we try to match it to a default gate.
2028
2129
Uses Rodrigues' rotation formula (see https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula).
2230
"""
@@ -40,7 +48,7 @@ def compose_bloch_sphere_rotations(bsr_a: BlochSphereRotation, bsr_b: BlochSpher
4048
* (
4149
sin(bsr_a.angle / 2) * cos(bsr_b.angle / 2) * bsr_a.axis.value
4250
+ cos(bsr_a.angle / 2) * sin(bsr_b.angle / 2) * bsr_b.axis.value
43-
+ sin(bsr_a.angle / 2) * sin(bsr_b.angle / 2) * np.cross(bsr_a.axis, bsr_b.axis)
51+
+ sin(bsr_a.angle / 2) * sin(bsr_b.angle / 2) * np.cross(bsr_b.axis, bsr_a.axis)
4452
)
4553
),
4654
order_of_magnitude,

opensquirrel/passes/merger/single_qubit_gates_merger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def merge(self, ir: IR, qubit_register_size: int) -> None:
2525
instruction: Instruction = cast(Instruction, statement)
2626
if isinstance(instruction, BlochSphereRotation):
2727
already_accumulated = accumulators_per_qubit[instruction.qubit]
28-
composed = compose_bloch_sphere_rotations(instruction, already_accumulated)
28+
composed = compose_bloch_sphere_rotations(already_accumulated, instruction)
2929
accumulators_per_qubit[instruction.qubit] = composed
3030
del ir.statements[statement_index]
3131
continue

test/merger/test_general_merger.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from opensquirrel import Circuit, CircuitBuilder, H, I, Rx, Ry, X
5+
from opensquirrel import Circuit, CircuitBuilder, H, I, Rx, Ry, X, Y, Z
66
from opensquirrel.ir import BlochSphereRotation, Float
77
from opensquirrel.passes.merger.general_merger import compose_bloch_sphere_rotations, rearrange_barriers
88

@@ -19,29 +19,45 @@ def test_compose_bloch_sphere_rotations_different_axis() -> None:
1919
a = BlochSphereRotation(qubit=123, axis=(1, 0, 0), angle=math.pi / 2)
2020
b = BlochSphereRotation(qubit=123, axis=(0, 0, 1), angle=-math.pi / 2)
2121
c = BlochSphereRotation(qubit=123, axis=(0, 1, 0), angle=math.pi / 2)
22-
composed = compose_bloch_sphere_rotations(a, compose_bloch_sphere_rotations(b, c))
22+
composed = compose_bloch_sphere_rotations(compose_bloch_sphere_rotations(c, b), a)
2323
assert composed == BlochSphereRotation(qubit=123, axis=(1, 1, 0), angle=math.pi)
2424

2525

2626
@pytest.mark.parametrize(
2727
("bsr_a", "bsr_b", "expected_result"),
2828
[
29+
(Y(0), X(0), BlochSphereRotation(0, axis=(0, 0, 1), angle=math.pi, phase=math.pi)),
30+
(X(0), Y(0), BlochSphereRotation(0, axis=(0, 0, -1), angle=math.pi, phase=math.pi)),
31+
(Z(0), Y(0), BlochSphereRotation(0, axis=(1, 0, 0), angle=math.pi, phase=math.pi)),
32+
(Y(0), Z(0), BlochSphereRotation(0, axis=(-1, 0, 0), angle=math.pi, phase=math.pi)),
33+
(Z(0), X(0), BlochSphereRotation(0, axis=(0, -1, 0), angle=math.pi, phase=math.pi)),
34+
(X(0), Z(0), BlochSphereRotation(0, axis=(0, 1, 0), angle=math.pi, phase=math.pi)),
35+
(
36+
Rx(0, theta=math.pi),
37+
Ry(0, theta=-math.pi / 2),
38+
BlochSphereRotation(0, axis=(0.70711, 0.0, 0.70711), angle=math.pi, phase=0.0),
39+
),
2940
(I(0), Rx(0, theta=math.pi), Rx(0, theta=math.pi)),
3041
(Rx(0, theta=math.pi), I(0), Rx(0, theta=math.pi)),
3142
(X(0), X(0), I(0)),
3243
(H(0), H(0), I(0)),
3344
(Rx(0, theta=math.pi), Rx(0, theta=math.pi), I(0)),
3445
(Rx(0, theta=math.pi / 2), Rx(0, theta=math.pi / 2), Rx(0, theta=math.pi)),
35-
(Rx(0, theta=math.pi), Ry(0, theta=math.pi / 2), BlochSphereRotation(0, axis=(1, 0, 1), angle=math.pi)),
3646
],
3747
ids=[
48+
"[bsr_a = Y, bsr_b = X] X * Y = iZ",
49+
"[bsr_a = X, bsr_b = Y] Y * X = -iZ",
50+
"[bsr_a = Z, bsr_b = Y] Y * Z = iX",
51+
"[bsr_a = Y, bsr_b = Z] Z * Y = -iX",
52+
"[bsr_a = Z, bsr_b = X] X * Z = -iY",
53+
"[bsr_a = X, bsr_b = Z] Z * X = iY",
54+
"[bsr_a = Rx(pi), bsr_b = Ry(-pi/2)] Ry(-pi/2) * Rx(pi) ~ H",
3855
"[bsr_a == I]",
3956
"[bsr_b == I]",
4057
"[bsr_a.generator == bsr_b.generator] X * X == I",
4158
"[bsr_a.generator == bsr_b.generator] H * H == I",
4259
"[bsr_a.generator == bsr_b.generator] Rx(pi) * Rx(pi) == I",
4360
"[bsr_a.generator == bsr_b.generator] Rx(pi/2) * Rx(pi/2) = Rx(pi) ~ X",
44-
"[bsr_a.generator != bsr_b.generator] Rx(pi) * Ry(pi/2) ~ H",
4561
],
4662
)
4763
def test_compose_bloch_sphere_rotations(

0 commit comments

Comments
 (0)