Skip to content

Upstream

steane7_initialize_with_noise

steane7_initialize_with_noise(
    local_px: float = 0.0,
    local_py: float = 0.0,
    local_pz: float = 0.0,
    local_loss_prob: float = 0.0,
    mover_px: float = 0.0,
    mover_py: float = 0.0,
    mover_pz: float = 0.0,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0,
    sitter_py: float = 0.0,
    sitter_pz: float = 0.0,
    sit_loss_prob: float = 0.0,
    loss: bool = True,
) -> tuple[
    ir.Method[
        [
            float,
            float,
            float,
            ilist.IList[qubit.Qubit, Literal[7]],
        ],
        None,
    ],
    ir.Method[
        [
            float,
            float,
            float,
            ilist.IList[qubit.Qubit, Literal[7]],
        ],
        None,
    ],
]

Return (clean_kernel, noisy_kernel) for Steane [[7,1,3]] initialization.

The clean kernel is the ideal initialization circuit. The noisy kernel is the same circuit with single-qubit Pauli channels after each gate layer and move/sitter noise after each CZ layer, parameterized by the provided error probabilities.

For CZ layers, one side physically moves to the other. The mover/sitter assignment alternates across layers:

  • Layer 1 (odds x evens[1:]): targets move, controls sit
  • Layer 2 (evens[:-1] x [3,5,6]): controls move, targets sit
  • Layer 3 (evens[:-1] x odds): targets move, controls sit

Parameters:

Name Type Description Default
local_px float

X-error probability for single-qubit gates.

0.0
local_py float

Y-error probability for single-qubit gates.

0.0
local_pz float

Z-error probability for single-qubit gates.

0.0
local_loss_prob float

Loss probability for single-qubit gates.

0.0
mover_px float

X-error probability for qubits that move during CZ.

0.0
mover_py float

Y-error probability for qubits that move during CZ.

0.0
mover_pz float

Z-error probability for qubits that move during CZ.

0.0
move_loss_prob float

Loss probability for moving qubits during CZ.

0.0
sitter_px float

X-error probability for stationary qubits during CZ.

0.0
sitter_py float

Y-error probability for stationary qubits during CZ.

0.0
sitter_pz float

Z-error probability for stationary qubits during CZ.

0.0
sit_loss_prob float

Loss probability for stationary qubits during CZ.

0.0
loss bool

Whether to include loss channels.

True

Returns:

Type Description
tuple[Method[[float, float, float, IList[Qubit, Literal[7]]], None], Method[[float, float, float, IList[Qubit, Literal[7]]], None]]

A tuple of (clean_kernel, noisy_kernel).

Source code in .venv/lib/python3.12/site-packages/bloqade/lanes/arch/gemini/logical/upstream.py
 61
 62
 63
 64
 65
 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
102
103
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def steane7_initialize_with_noise(
    local_px: float = 0.0,
    local_py: float = 0.0,
    local_pz: float = 0.0,
    local_loss_prob: float = 0.0,
    mover_px: float = 0.0,
    mover_py: float = 0.0,
    mover_pz: float = 0.0,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0,
    sitter_py: float = 0.0,
    sitter_pz: float = 0.0,
    sit_loss_prob: float = 0.0,
    loss: bool = True,
) -> tuple[
    ir.Method[[float, float, float, ilist.IList[qubit.Qubit, Literal[7]]], None],
    ir.Method[[float, float, float, ilist.IList[qubit.Qubit, Literal[7]]], None],
]:
    """Return (clean_kernel, noisy_kernel) for Steane [[7,1,3]] initialization.

    The clean kernel is the ideal initialization circuit. The noisy kernel is
    the same circuit with single-qubit Pauli channels after each gate layer
    and move/sitter noise after each CZ layer, parameterized by the provided
    error probabilities.

    For CZ layers, one side physically moves to the other. The mover/sitter
    assignment alternates across layers:

    - Layer 1 (odds x evens[1:]): targets move, controls sit
    - Layer 2 (evens[:-1] x [3,5,6]): controls move, targets sit
    - Layer 3 (evens[:-1] x odds): targets move, controls sit

    Args:
        local_px: X-error probability for single-qubit gates.
        local_py: Y-error probability for single-qubit gates.
        local_pz: Z-error probability for single-qubit gates.
        local_loss_prob: Loss probability for single-qubit gates.
        mover_px: X-error probability for qubits that move during CZ.
        mover_py: Y-error probability for qubits that move during CZ.
        mover_pz: Z-error probability for qubits that move during CZ.
        move_loss_prob: Loss probability for moving qubits during CZ.
        sitter_px: X-error probability for stationary qubits during CZ.
        sitter_py: Y-error probability for stationary qubits during CZ.
        sitter_pz: Z-error probability for stationary qubits during CZ.
        sit_loss_prob: Loss probability for stationary qubits during CZ.
        loss: Whether to include loss channels.

    Returns:
        A tuple of (clean_kernel, noisy_kernel).
    """

    @squin.kernel
    def noisy_initialize(
        theta: float,
        phi: float,
        lam: float,
        qubits: ilist.IList[qubit.Qubit, Literal[7]],
    ):
        debug.info("Begin Steane7 Noisy Initialize")

        # U3 on qubit 6
        squin.u3(theta, phi, lam, qubits[6])
        squin.single_qubit_pauli_channel(local_px, local_py, local_pz, qubits[6])
        if loss:
            squin.qubit_loss(local_loss_prob, qubits[6])

        # sqrt_y_adj on qubits 0-5
        squin.broadcast.sqrt_y_adj(qubits[:6])
        squin.broadcast.single_qubit_pauli_channel(
            local_px, local_py, local_pz, qubits[:6]
        )
        if loss:
            squin.broadcast.qubit_loss(local_loss_prob, qubits[:6])

        evens = qubits[::2]  # [0, 2, 4, 6]
        odds = qubits[1::2]  # [1, 3, 5]

        # CZ layer 1: controls=odds (sitters), targets=evens[1:] (movers)
        squin.broadcast.cz(odds, evens[1:])
        squin.broadcast.single_qubit_pauli_channel(
            sitter_px, sitter_py, sitter_pz, odds
        )
        squin.broadcast.single_qubit_pauli_channel(
            mover_px, mover_py, mover_pz, evens[1:]
        )
        if loss:
            squin.broadcast.qubit_loss(sit_loss_prob, odds)
            squin.broadcast.qubit_loss(move_loss_prob, evens[1:])

        # sqrt_y on qubit 6
        squin.sqrt_y(qubits[6])
        squin.single_qubit_pauli_channel(local_px, local_py, local_pz, qubits[6])
        if loss:
            squin.qubit_loss(local_loss_prob, qubits[6])

        # CZ layer 2: controls=evens[:-1] (movers), targets=[3,5,6] (sitters)
        cz_targets = ilist.IList([qubits[3], qubits[5], qubits[6]])
        squin.broadcast.cz(evens[:-1], cz_targets)
        squin.broadcast.single_qubit_pauli_channel(
            mover_px, mover_py, mover_pz, evens[:-1]
        )
        squin.broadcast.single_qubit_pauli_channel(
            sitter_px, sitter_py, sitter_pz, cz_targets
        )
        if loss:
            squin.broadcast.qubit_loss(move_loss_prob, evens[:-1])
            squin.broadcast.qubit_loss(sit_loss_prob, cz_targets)

        # sqrt_y on qubits 2-6
        squin.broadcast.sqrt_y(qubits[2:])
        squin.broadcast.single_qubit_pauli_channel(
            local_px, local_py, local_pz, qubits[2:]
        )
        if loss:
            squin.broadcast.qubit_loss(local_loss_prob, qubits[2:])

        # CZ layer 3: controls=evens[:-1] (sitters), targets=odds (movers)
        squin.broadcast.cz(evens[:-1], odds)
        squin.broadcast.single_qubit_pauli_channel(
            sitter_px, sitter_py, sitter_pz, evens[:-1]
        )
        squin.broadcast.single_qubit_pauli_channel(mover_px, mover_py, mover_pz, odds)
        if loss:
            squin.broadcast.qubit_loss(sit_loss_prob, evens[:-1])
            squin.broadcast.qubit_loss(move_loss_prob, odds)

        # sqrt_y on [1, 2, 4]
        correction_qubits = ilist.IList([qubits[1], qubits[2], qubits[4]])
        squin.broadcast.sqrt_y(correction_qubits)
        squin.broadcast.single_qubit_pauli_channel(
            local_px, local_py, local_pz, correction_qubits
        )
        if loss:
            squin.broadcast.qubit_loss(local_loss_prob, correction_qubits)

        # X on qubit 3
        squin.x(qubits[3])
        squin.single_qubit_pauli_channel(local_px, local_py, local_pz, qubits[3])
        if loss:
            squin.qubit_loss(local_loss_prob, qubits[3])

        # Z on [1, 5]
        z_qubits = ilist.IList([qubits[1], qubits[5]])
        squin.broadcast.z(z_qubits)
        squin.broadcast.single_qubit_pauli_channel(
            local_px, local_py, local_pz, z_qubits
        )
        if loss:
            squin.broadcast.qubit_loss(local_loss_prob, z_qubits)

        debug.info("End Steane7 Noisy Initialize")

    return steane7_initialize, noisy_initialize

steane7_transversal_map

steane7_transversal_map(
    address: AddressType,
) -> Iterator[AddressType] | None

This function is used to map logical addresses to physical addresses.

The Steane [[7,1,3]] code encodes one logical qubit into seven physical qubits. The mapping is as follows:

Logical Word ID 0 -> Physical Word IDs 0 to 6 Logical Word ID 1 -> Physical Word IDs 8 to 14

All other Word IDs remain unchanged.

Source code in .venv/lib/python3.12/site-packages/bloqade/lanes/arch/gemini/logical/upstream.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def steane7_transversal_map(address: AddressType) -> Iterator[AddressType] | None:
    """This function is used to map logical addresses to physical addresses.

    The Steane [[7,1,3]] code encodes one logical qubit into seven physical qubits.
    The mapping is as follows:

    Logical Word ID 0 -> Physical Word IDs 0 to 6
    Logical Word ID 1 -> Physical Word IDs 8 to 14

    All other Word IDs remain unchanged.

    """
    if address.word_id == 0:
        return (address.replace(word_id=word_id) for word_id in range(7))
    elif address.word_id == 1:
        return (address.replace(word_id=word_id) for word_id in range(8, 15, 1))
    else:
        return None