Skip to content

clifford

Mapping tables for converting parametric rotations with half-pi angles to Clifford gates.

expand_clifford_rotations

expand_clifford_rotations(source: Circuit) -> stim.Circuit

Return source with half-π parametric rotations expanded to Clifford gates.

REPEAT blocks are preserved structurally and expanded recursively.

Source code in src/tsim/utils/clifford.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def expand_clifford_rotations(source: stim.Circuit) -> stim.Circuit:
    """Return ``source`` with half-π parametric rotations expanded to Clifford gates.

    ``REPEAT`` blocks are preserved structurally and expanded recursively.
    """
    out = stim.Circuit()
    for instr in source:
        if isinstance(instr, stim.CircuitRepeatBlock):
            out.append(
                stim.CircuitRepeatBlock(
                    instr.repeat_count, expand_clifford_rotations(instr.body_copy())
                )
            )
            continue
        expansion = _try_clifford_expansion(instr)
        if expansion is not None:
            gates, targets = expansion
            for gate in gates:
                out.append(gate, targets, [])
        else:
            out.append(instr)
    return out

is_clifford

is_clifford(source: Circuit) -> bool

Return True iff every instruction in source is Clifford.

Recurses into REPEAT block bodies.

Source code in src/tsim/utils/clifford.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def is_clifford(source: stim.Circuit) -> bool:
    """Return True iff every instruction in ``source`` is Clifford.

    Recurses into ``REPEAT`` block bodies.
    """

    def is_half_pi_multiple(phase: Fraction) -> bool:
        return phase.denominator <= 2

    for instr in source:
        if isinstance(instr, stim.CircuitRepeatBlock):
            if not is_clifford(instr.body_copy()):
                return False
            continue

        if instr.name in ["S", "S_DAG", "SPP", "SPP_DAG"] and instr.tag == "T":
            return False

        if instr.name == "I" and instr.tag:
            result = parse_parametric_tag(instr)
            if result is None:
                continue

            gate_name, params = result
            if gate_name in ["R_X", "R_Y", "R_Z"]:
                if not is_half_pi_multiple(params["theta"]):
                    return False
            elif gate_name == "U3":
                if not all(
                    is_half_pi_multiple(params[name])
                    for name in ("theta", "phi", "lambda")
                ):
                    return False
            else:
                return False

    return True

parametric_to_clifford_gates

parametric_to_clifford_gates(
    gate_name: str, params: dict[str, Fraction]
) -> list[str] | None

Convert a parametric gate with half-π angles to stim Clifford gate names.

Parameters:

Name Type Description Default
gate_name str

One of "R_X", "R_Y", "R_Z", "U3".

required
params dict[str, Fraction]

Dict as returned by :func:~tsim.core.parse.parse_parametric_tag.

required

Returns:

Type Description
list[str] | None

Stim gate names in circuit order,

list[str] | None

or None when the angles are not half-π multiples.

Source code in src/tsim/utils/clifford.py
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def parametric_to_clifford_gates(
    gate_name: str, params: dict[str, Fraction]
) -> list[str] | None:
    """Convert a parametric gate with half-π angles to stim Clifford gate names.

    Args:
        gate_name: One of ``"R_X"``, ``"R_Y"``, ``"R_Z"``, ``"U3"``.
        params: Dict as returned by :func:`~tsim.core.parse.parse_parametric_tag`.

    Returns:
        Stim gate names in circuit order,
        or ``None`` when the angles are not half-π multiples.

    """
    if gate_name in ("R_X", "R_Y", "R_Z"):
        idx = _to_half_pi_index(params["theta"])
        if idx is None:
            return None
        table = {"R_Z": RZ_CLIFFORD, "R_X": RX_CLIFFORD, "R_Y": RY_CLIFFORD}[gate_name]
        return [table[idx]]

    if gate_name == "U3":
        theta_idx = _to_half_pi_index(params["theta"])
        phi_idx = _to_half_pi_index(params["phi"])
        lam_idx = _to_half_pi_index(params["lambda"])
        if theta_idx is None or phi_idx is None or lam_idx is None:
            return None

        key = (theta_idx, phi_idx, lam_idx)
        gates = U3_CLIFFORD.get(key)
        if gates is None:
            gates = U3_CLIFFORD.get(_equivalent_u3_key(*key))
        assert gates is not None
        return list(gates)

    return None