Skip to content

U3 to clifford

SquinU3ToClifford

Bases: RewriteRule

Rewrite squin U3 statements to clifford when possible.

decompose_U3_gates

decompose_U3_gates(
    node: U3,
) -> Tuple[List[ir.Statement], ...]

Rewrite U3 statements to clifford gates if possible.

Source code in .venv/lib/python3.12/site-packages/bloqade/squin/rewrite/U3_to_clifford.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def decompose_U3_gates(self, node: op.stmts.U3) -> Tuple[List[ir.Statement], ...]:
    """
    Rewrite U3 statements to clifford gates if possible.
    """
    theta = self.get_constant(node.theta)
    phi = self.get_constant(node.phi)
    lam = self.get_constant(node.lam)

    if theta is None or phi is None or lam is None:
        return ()

    # For U3(2*pi*n, phi, lam) = U3(0, 0, lam + phi) which is a Z rotation.
    if np.isclose(np.mod(theta, math.tau), 0):
        lam = lam + phi
        phi = 0.0
    elif np.isclose(np.mod(theta + np.pi, math.tau), 0):
        lam = lam - phi
        phi = 0.0

    theta_half_pi: int | None = self.resolve_angle(theta)
    phi_half_pi: int | None = self.resolve_angle(phi)
    lam_half_pi: int | None = self.resolve_angle(lam)

    if theta_half_pi is None or phi_half_pi is None or lam_half_pi is None:
        return ()

    angles_key = (theta_half_pi, phi_half_pi, lam_half_pi)
    if angles_key not in U3_HALF_PI_ANGLE_TO_GATES:
        angles_key = equivalent_u3_para(*angles_key)
        if angles_key not in U3_HALF_PI_ANGLE_TO_GATES:
            return ()

    gates_stmts = U3_HALF_PI_ANGLE_TO_GATES.get(angles_key)

    # no consistent gates, then:
    assert (
        gates_stmts is not None
    ), "internal error, U3 gates not found for angles: {}".format(angles_key)

    return gates_stmts()

resolve_angle

resolve_angle(angle: float) -> int | None

Normalize the angle to be in the range [0, 2π).

Source code in .venv/lib/python3.12/site-packages/bloqade/squin/rewrite/U3_to_clifford.py
76
77
78
79
80
81
82
83
84
85
86
87
88
def resolve_angle(self, angle: float) -> int | None:
    """
    Normalize the angle to be in the range [0, 2π).
    """
    # convert to 0.0~1.0, in unit of pi/2
    angle_half_pi = angle / math.pi * 2.0

    mod = angle_half_pi % 1.0
    if not (np.isclose(mod, 0.0) or np.isclose(mod, 1.0)):
        return None

    else:
        return round((angle / math.tau) % 1 * 4) % 4

rewrite_ApplyOrBroadcast_onU3

rewrite_ApplyOrBroadcast_onU3(
    node: Apply | Broadcast,
) -> RewriteResult

Rewrite Apply and Broadcast nodes to their clifford equivalent statements.

Source code in .venv/lib/python3.12/site-packages/bloqade/squin/rewrite/U3_to_clifford.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def rewrite_ApplyOrBroadcast_onU3(
    self, node: qubit.Apply | qubit.Broadcast
) -> RewriteResult:
    """
    Rewrite Apply and Broadcast nodes to their clifford equivalent statements.
    """
    if not isinstance(node.operator.owner, op.stmts.U3):
        return RewriteResult()

    gates = self.decompose_U3_gates(node.operator.owner)

    if len(gates) == 0:
        return RewriteResult()

    for stmt_list in gates:
        for gate_stmt in stmt_list[:-1]:
            gate_stmt.insert_before(node)

        oper = stmt_list[-1]
        oper.insert_before(node)
        new_node = node.__class__(operator=oper.result, qubits=node.qubits)
        new_node.insert_before(node)

    node.delete()

    # rewrite U3 to clifford gates
    return RewriteResult(has_done_something=True)

equivalent_u3_para

equivalent_u3_para(
    theta_half_pi: int, phi_half_pi: int, lam_half_pi: int
) -> tuple[int, int, int]
  1. Assume all three angles are in the range [0, 4].
  2. U3(theta, phi, lam) = -U3(2pi-theta, phi+pi, lam+pi).
Source code in .venv/lib/python3.12/site-packages/bloqade/squin/rewrite/U3_to_clifford.py
48
49
50
51
52
53
54
55
def equivalent_u3_para(
    theta_half_pi: int, phi_half_pi: int, lam_half_pi: int
) -> tuple[int, int, int]:
    """
    1. Assume all three angles are in the range [0, 4].
    2. U3(theta, phi, lam) = -U3(2pi-theta, phi+pi, lam+pi).
    """
    return ((4 - theta_half_pi) % 4, (phi_half_pi + 2) % 4, (lam_half_pi + 2) % 4)