Source code for surface_sim.circuit_blocks.rot_surface_code_css

from collections.abc import Collection, Generator
from itertools import chain

from stim import Circuit

from ..detectors import Detectors
from ..layouts.layout import Layout
from ..models import Model
from .decorators import qec_circuit, qubit_encoding, tq_gate

# methods to have in this script
from .util import (
    general_grow_code_iterator,
    idle_iterator,
    init_qubits,
    init_qubits_iterator,
    init_qubits_x0_iterator,
    init_qubits_x1_iterator,
    init_qubits_z0_iterator,
    init_qubits_z1_iterator,
    log_depolarize1_error_iterator,
    log_fold_trans_s,
    log_fold_trans_s_iterator,
    log_meas,
    log_meas_iterator,
    log_meas_x_iterator,
    log_meas_z_iterator,
    log_trans_cnot,
    log_trans_cnot_iterator,
    log_x,
    log_x_error_iterator,
    log_x_iterator,
    log_y_error_iterator,
    log_z,
    log_z_error_iterator,
    log_z_iterator,
    pauli_observable_x_iterator,
    pauli_observable_y_iterator,
    pauli_observable_z_iterator,
    qec_round_iterator,
    qec_round_iterator_cnots,
    qubit_coords,
    to_end_cycle_iterator_cnots,
    to_mid_cycle_iterator_cnots,
)

__all__ = [
    "qubit_coords",
    "idle_iterator",
    "log_meas",
    "log_meas_iterator",
    "log_meas_z_iterator",
    "log_meas_x_iterator",
    "log_x",
    "log_x_iterator",
    "log_z",
    "log_z_iterator",
    "init_qubits",
    "init_qubits_iterator",
    "init_qubits_z0_iterator",
    "init_qubits_z1_iterator",
    "init_qubits_x0_iterator",
    "init_qubits_x1_iterator",
    "log_fold_trans_s",
    "log_fold_trans_s_iterator",
    "log_trans_cnot",
    "log_trans_cnot_iterator",
    "qec_round",
    "qec_round_iterator",
    "qec_round_iterator_cnots",
    "qec_round_pipelined",
    "qec_round_pipelined_iterator",
    "log_trans_cnot_mid_cycle_css_iterator",
    "encoding_qubits_iterator",
    "encoding_qubits_x0_iterator",
    "encoding_qubits_y0_iterator",
    "encoding_qubits_z0_iterator",
    "encoding_qubits_x0_iterator_single_layer_resets",
    "encoding_qubits_y0_iterator_single_layer_resets",
    "encoding_qubits_z0_iterator_single_layer_resets",
    "encoding_qubits_x0_iterator_cnots",
    "encoding_qubits_y0_iterator_cnots",
    "encoding_qubits_z0_iterator_cnots",
    "log_x_error_iterator",
    "log_y_error_iterator",
    "log_z_error_iterator",
    "log_depolarize1_error_iterator",
    "gate_to_iterator",
    "gate_to_iterator_cnots",
    "gate_to_iterator_mid_cycle_cnots",
    "tick_iterators_mid_cycle_cnots",
    "gate_to_iterator_pipelined",
    "pauli_observable_x_iterator",
    "pauli_observable_y_iterator",
    "pauli_observable_z_iterator",
]


[docs] def qec_round( model: Model, layout: Layout, detectors: Detectors, anc_reset: bool = True, anc_detectors: Collection[str] | None = None, ) -> Circuit: """ Returns stim circuit corresponding to a QEC round of the given model. Parameters ---------- model Noise model for the gates. layout Code layout. detectors Detector object to use for their definition. anc_reset If ``True``, ancillas are reset at the beginning of the QEC round. By default ``True``. anc_detectors List of ancilla qubits for which to define the detectors. If ``None``, adds all detectors. By default ``None``. Notes ----- This implementation follows: https://doi.org/10.1103/PhysRevApplied.8.034021 It activates all the ancillas in ``detectors`` to always build the detectors. As this function should not be used when building encoded circuits with the iterating functions, it does not matter if the detectors are activated or not. """ circuit = sum( qec_round_iterator(model=model, layout=layout, anc_reset=anc_reset), start=Circuit(), ) # add detectors anc_qubits = layout.anc_qubits if anc_detectors is None: anc_detectors = anc_qubits if set(anc_detectors) > set(anc_qubits): raise ValueError("Elements in 'anc_detectors' are not ancilla qubits.") # activate detectors so that "Detectors.build_from_anc" always populates # the stim detector definitions. inactive_dets = set(anc_detectors).difference(detectors.detectors) detectors.activate_detectors(inactive_dets) circuit += detectors.build_from_anc( model.meas_target, anc_reset, anc_qubits=anc_detectors ) return circuit
[docs] def qec_round_pipelined( model: Model, layout: Layout, detectors: Detectors, anc_reset: bool = True, anc_detectors: Collection[str] | None = None, ) -> Circuit: """ Returns stim circuit corresponding to a QEC round of the given model. Parameters ---------- model Noise model for the gates. layout Code layout. detectors Detector object to use for their definition. anc_reset If ``True``, ancillas are reset at the beginning of the QEC round. By default ``True``. anc_detectors List of ancilla qubits for which to define the detectors. If ``None``, adds all detectors. By default ``None``. Notes ----- This implementation follows: https://doi.org/10.1103/PhysRevApplied.8.034021 It activates all the ancillas in ``detectors`` to always build the detectors. As this function should not be used when building encoded circuits with the iterating functions, it does not matter if the detectors are activated or not. """ circuit = sum( qec_round_pipelined_iterator(model=model, layout=layout, anc_reset=anc_reset), start=Circuit(), ) # add detectors anc_qubits = layout.anc_qubits if anc_detectors is None: anc_detectors = anc_qubits if set(anc_detectors) > set(anc_qubits): raise ValueError("Elements in 'anc_detectors' are not ancilla qubits.") # activate detectors so that "Detectors.build_from_anc" always populates # the stim detector definitions. inactive_dets = set(anc_detectors).difference(detectors.detectors) detectors.activate_detectors(inactive_dets) circuit += detectors.build_from_anc( model.meas_target, anc_reset, anc_qubits=anc_detectors ) return circuit
@qec_circuit def qec_round_pipelined_iterator( model: Model, layout: Layout, anc_reset: bool = True, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to a QEC round of the given model without the detectors. Parameters ---------- model Noise model for the gates. layout Code layout. anc_reset If ``True``, ancillas are reset at the beginning of the QEC round. By default ``True``. """ if layout.code != "rotated_surface_code": raise TypeError( f"The given layout is not a rotated surface code, but a {layout.code}" ) data_qubits = layout.data_qubits anc_qubits = layout.anc_qubits qubits = set(layout.qubits) int_order = layout.interaction_order stab_types = list(int_order.keys()) yield model.incoming_noise(data_qubits) yield model.tick() if anc_reset: yield model.reset(anc_qubits) + model.idle(data_qubits) yield model.tick() for ind, stab_type in enumerate(stab_types): stab_qubits = layout.get_qubits(role="anc", stab_type=stab_type) rot_qubits = set(stab_qubits) if stab_type == "x_type": rot_qubits.update(data_qubits) if not ind: idle_qubits = qubits - rot_qubits yield model.hadamard(rot_qubits) + model.idle(idle_qubits) yield model.tick() for ord_dir in int_order[stab_type]: int_pairs = layout.get_neighbors( stab_qubits, direction=ord_dir, as_pairs=True ) int_qubits = list(chain.from_iterable(int_pairs)) idle_qubits = qubits - set(int_qubits) yield model.cphase(int_qubits) + model.idle(idle_qubits) yield model.tick() if not ind: yield model.hadamard(qubits) else: idle_qubits = qubits - rot_qubits yield model.hadamard(rot_qubits) + model.idle(idle_qubits) yield model.tick() yield model.measure(anc_qubits) + model.idle(data_qubits) yield model.tick() @tq_gate def log_trans_cnot_mid_cycle_css_iterator( model: Model, layout_c: Layout, layout_t: Layout ) -> Generator[Circuit]: """Returns the stim circuit corresponding to a transversal logical CNOT gate. Parameters ---------- model Noise model for the gates. layout_c Code layout for the control of the logical CNOT. layout_t Code layout for the target of the logical CNOT. Notes ----- The implementation uses CNOTs and it does not add incoming noise because this logical gate is executed in the mid-cycle code. """ if layout_c.code != "rotated_surface_code": raise TypeError( f"The given layout is not a rotated surface code, but a {layout_c.code}" ) if layout_t.code != "rotated_surface_code": raise TypeError( f"The given layout is not a rotated surface code, but a {layout_t.code}" ) qubits = set(layout_c.qubits + layout_t.qubits) gate_label = f"log_trans_cnot_mid_cycle_css_{layout_c.logical_qubits[0]}_{layout_t.logical_qubits[0]}" cnot_pairs: set[tuple[str, str]] = set() for qubit in layout_c.qubits: trans_cnot = layout_c.param(gate_label, qubit) if trans_cnot is None: raise ValueError( "The layout does not have the information to run " f"{gate_label} gate on qubit {qubit}. " "Use the 'log_gates' module to set it up." ) cnot_pairs.add((qubit, trans_cnot["cnot"])) # long-range CNOT gates int_qubits = list(chain.from_iterable(cnot_pairs)) idle_qubits = qubits - set(int_qubits) yield model.cnot(int_qubits) + model.idle(idle_qubits) yield model.tick()
[docs] def encoding_qubits_iterator( model: Model, layout: Layout, physical_reset_op: str, primitive_gates: str, single_layer_resets: bool = False, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit to a rotated surface code of the given model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. physical_reset_op Reset operation to be applied to the physical qubit that will grow to a rotated surface code. primitive_gates Set of primitive gates to use. The available options are: (1) ``"cnot"``, which uses Rx, RZ, and CNOT gates, and (2) ``"cz"``, which uses RZ, H, and CZ gates. Note that the ``physical_reset_op`` will not be decomposed into primitive gates. single_layer_resets Flag to put all resets in a single operation layer at the beginning of the encoding circuit. By default ``False``. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ if layout.code != "rotated_surface_code": raise TypeError( f"The given layout is not a rotated surface code, but a {layout.code}." ) resets_x, resets_z, cnot_layers = [], [], [] if layout.distance % 2 == 1: resets_x.append([(1, 1), (1, 7), (1, 3), (1, 5)]) resets_z.append([(1, 0), (1, 2), (1, 6), (1, 4)]) cnot_layers.append( [ [(1, 1), (1, 2), (1, 3), (0, 0), (1, 5), (1, 6)], [(1, 7), (1, 0), (0, 0), (1, 1), (1, 3), (1, 4)], [(1, 0), (1, 1), (1, 7), (0, 0), (1, 3), (1, 2)], [(1, 7), (1, 6), (0, 0), (1, 5)], ] ) for d in range(3, layout.distance, 2): reset_x, reset_z, cnots = _get_grow_code_odd_d_coords(d) resets_x.append(reset_x) resets_z.append(reset_z) cnot_layers.append(cnots) else: resets_x.append([(0, 1)]) resets_z.append([(0, 2), (0, 3)]) cnot_layers.append( [ [(0, 0), (0, 3), (0, 1), (0, 2)], [(0, 1), (0, 0), (0, 2), (0, 3)], ] ) for d in range(2, layout.distance, 2): reset_x, reset_z, cnots = _get_grow_code_even_d_coords(d) resets_x.append(reset_x) resets_z.append(reset_z) cnot_layers.append(cnots) if single_layer_resets: reset_x = list(chain(*resets_x)) reset_z = list(chain(*resets_z)) yield from general_grow_code_iterator( model, layout, reset_x, reset_z, [], physical_reset_op, primitive_gates, block="resets", ) yield from general_grow_code_iterator( model, layout, resets_x[0], resets_z[0], cnot_layers[0], physical_reset_op, primitive_gates, block="unitary" if single_layer_resets else "whole", ) for reset_x, reset_z, cnots in zip(resets_x[1:], resets_z[1:], cnot_layers[1:]): yield from general_grow_code_iterator( model, layout, reset_x, reset_z, cnots, None, primitive_gates, block="unitary" if single_layer_resets else "whole", )
def _get_grow_code_even_d_coords( init_distance: int, ) -> tuple[list[tuple[int, int]], list[tuple[int, int]], list[list[tuple[int, int]]]]: """ Returns the RX, RZ and CNOT information required to run a growing circuit from an even-distance ``d`` rotated surface code to a ``d+2`` one. Note that this circuit is not fault tolerant. Notes ----- The implementation follows Figure 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ inner_ring = (init_distance - 1) // 2 outer_ring = inner_ring + 1 length = init_distance + 1 reset_x: list[tuple[int, int]] = [] reset_z = [(outer_ring, 0 + i * length) for i in range(4)] for i in [1, 3]: reset_x.append((outer_ring, 1 + i * length)) reset_x.append((outer_ring, length - 1 + i * length)) reset_z += [(outer_ring, p + 0 * length) for p in range(1, length - 1, 2)] reset_x += [(outer_ring, p + 0 * length) for p in range(2, length, 2)] reset_x += [(outer_ring, p + 2 * length) for p in range(1, length - 1, 2)] reset_z += [(outer_ring, p + 2 * length) for p in range(2, length, 2)] reset_x += [(outer_ring, p + 1 * length) for p in range(2, length - 2, 2)] reset_z += [(outer_ring, p + 1 * length) for p in range(3, length - 1, 2)] reset_z += [(outer_ring, p + 3 * length) for p in range(2, length - 2, 2)] reset_x += [(outer_ring, p + 3 * length) for p in range(3, length - 1, 2)] gate_layers_cnots: list[list[tuple[int, int]]] = [] # step 2 gate_layers_cnots.append([]) odd = [(outer_ring, p + 0 * length) for p in range(1, length - 1, 2)] even = [(outer_ring, p + 0 * length) for p in range(2, length, 2)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(even, odd))) odd = [(outer_ring, p + 2 * length) for p in range(1, length - 1, 2)] even = [(outer_ring, p + 2 * length) for p in range(2, length, 2)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(odd, even))) even = [(outer_ring, p + 1 * length) for p in range(2, length - 2, 2)] odd = [(outer_ring, p + 1 * length) for p in range(3, length - 1, 2)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(even, odd))) outer = [(outer_ring, 1 + 1 * length), (outer_ring, length - 1 + 1 * length)] inner = [(inner_ring, 0 + 1 * (length - 2)), (inner_ring, 0 + 2 * (length - 2))] gate_layers_cnots[-1] += list(chain.from_iterable(zip(outer, inner))) even = [(outer_ring, p + 3 * length) for p in range(2, length - 2, 2)] odd = [(outer_ring, p + 3 * length) for p in range(3, length - 1, 2)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(odd, even))) outer = [(outer_ring, 1 + 3 * length), (outer_ring, length - 1 + 3 * length)] inner = [(inner_ring, 0 + 3 * (length - 2)), (inner_ring, 0)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(outer, inner))) # step 3 gate_layers_cnots.append([]) for i in [0, 2]: first = (outer_ring, 0 + length * i) last = (outer_ring, (length - 1 + length * ((i - 1) % 4))) gate_layers_cnots[-1] += [last, first] outer = [(outer_ring, p + i * length) for p in range(1, length)] inner = [(inner_ring, p + i * (length - 2)) for p in range(length - 2)] inner.append((inner_ring, 0 + (i + 1) * (length - 2))) gate_layers_cnots[-1] += list(chain.from_iterable(zip(inner, outer))) for i in [1, 3]: first = (outer_ring, 0 + length * i) second = (outer_ring, 1 + length * i) gate_layers_cnots[-1] += [second, first] outer = [(outer_ring, p + i * length) for p in range(2, length - 1)] inner = [(inner_ring, p + i * (length - 2)) for p in range(1, length - 2)] gate_layers_cnots[-1] += list(chain.from_iterable(zip(outer, inner))) return reset_x, reset_z, gate_layers_cnots def _get_grow_code_odd_d_coords( init_distance: int, ) -> tuple[list[tuple[int, int]], list[tuple[int, int]], list[list[tuple[int, int]]]]: """ Returns the RX, RZ and CNOT information required to run a growing circuit from an odd-distance ``d`` rotated surface code to a ``d+2`` one. Note that this circuit is not fault tolerant. Notes ----- The implementation follows Figure 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ inner_ring = (init_distance - 1) // 2 outer_ring = inner_ring + 1 length = init_distance + 1 # step 1 reset_x: list[tuple[int, int]] = [] reset_z: list[tuple[int, int]] = [] for i in [0, 2]: reset_z.append((outer_ring, 0 + i * length)) reset_z.append((outer_ring, length - 1 + i * length)) reset_x += [(outer_ring, p + i * length) for p in range(1, length - 2, 2)] reset_z += [(outer_ring, p + i * length) for p in range(2, length - 1, 2)] for i in [1, 3]: reset_x.append((outer_ring, 0 + i * length)) reset_x.append((outer_ring, length - 1 + i * length)) reset_z += [(outer_ring, p + i * length) for p in range(1, length - 2, 2)] reset_x += [(outer_ring, p + i * length) for p in range(2, length - 1, 2)] gate_layers_cnots: list[list[tuple[int, int]]] = [] # step 2 gate_layers_cnots.append([]) for i in range(4): odd = [(outer_ring, p + i * length) for p in range(1, length - 2, 2)] even = [(outer_ring, p + i * length) for p in range(2, length - 1, 2)] if i % 2 == 1: odd, even = even, odd gate_layers_cnots[-1] += list(chain.from_iterable(zip(odd, even))) last = (outer_ring, length - 1 + i * length) inner = (inner_ring, (length - 2 + i * (length - 2)) % (4 * length - 8)) if i % 2 == 1: last, inner = inner, last gate_layers_cnots[-1] += [inner, last] # step 3 gate_layers_cnots.append([]) for i in range(4): first = (outer_ring, 0 + length * i) last = (outer_ring, (length - 1 + length * ((i - 1) % 4))) if i % 2 == 1: first, last = last, first gate_layers_cnots[-1] += [last, first] outer = [(outer_ring, p + i * length) for p in range(1, length - 1)] inner = [(inner_ring, p + i * (length - 2)) for p in range(0, length - 2)] if i % 2 == 1: outer, inner = inner, outer gate_layers_cnots[-1] += list(chain.from_iterable(zip(inner, outer))) return reset_x, reset_z, gate_layers_cnots @qubit_encoding def encoding_qubits_x0_iterator( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +X eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_x", primitive_gates="cz", ) @qubit_encoding def encoding_qubits_y0_iterator( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Y eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_y", primitive_gates="cz", ) @qubit_encoding def encoding_qubits_z0_iterator( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Z eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_z", primitive_gates="cz", ) @qubit_encoding def encoding_qubits_x0_iterator_single_layer_resets( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +X eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``, and the resets are placed as a single layer at the beginning of the circuit. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_x", primitive_gates="cz", single_layer_resets=True, ) @qubit_encoding def encoding_qubits_y0_iterator_single_layer_resets( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Y eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``, and the resets are placed as a single layer at the beginning of the circuit. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_y", primitive_gates="cz", single_layer_resets=True, ) @qubit_encoding def encoding_qubits_z0_iterator_single_layer_resets( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Z eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). but uses RZ, H, and CZ operations as primitive operations, except for the ``physical_reset_op``, and the resets are placed as a single layer at the beginning of the circuit. """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_z", primitive_gates="cz", single_layer_resets=True, ) @qubit_encoding def encoding_qubits_x0_iterator_cnots( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +X eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_x", primitive_gates="cnot", ) @qubit_encoding def encoding_qubits_y0_iterator_cnots( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Y eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_y", primitive_gates="cnot", ) @qubit_encoding def encoding_qubits_z0_iterator_cnots( model: Model, layout: Layout, ) -> Generator[Circuit]: """ Yields stim circuit blocks which as a whole correspond to an encoding circuit for the +Z eigenstate of the given rotated surface code and model without the detectors. Note that this encoding circuit is not fault tolerant. Parameters ---------- model Noise model for the gates. layout Code layout. Notes ----- The implementation follows Figures 1 and 2 from: Claes, Jahan. "Lower-depth local encoding circuits for the surface code." arXiv preprint arXiv:2509.09779 (2025). """ yield from encoding_qubits_iterator( model=model, layout=layout, physical_reset_op="reset_z", primitive_gates="cnot", ) gate_to_iterator = { "TICK": qec_round_iterator, "I": idle_iterator, "S": log_fold_trans_s_iterator, "X": log_x_iterator, "Z": log_z_iterator, "CX": log_trans_cnot_iterator, "CNOT": log_trans_cnot_iterator, "R": init_qubits_z0_iterator, "RZ": init_qubits_z0_iterator, "RX": init_qubits_x0_iterator, "M": log_meas_z_iterator, "MZ": log_meas_z_iterator, "MX": log_meas_x_iterator, "X_ERROR": log_x_error_iterator, "Y_ERROR": log_y_error_iterator, "Z_ERROR": log_z_error_iterator, "DEPOLARIZE1": log_depolarize1_error_iterator, } gate_to_iterator_cnots = { "TICK": qec_round_iterator_cnots, "I": idle_iterator, "S": log_fold_trans_s_iterator, "X": log_x_iterator, "Z": log_z_iterator, "CX": log_trans_cnot_iterator, "CNOT": log_trans_cnot_iterator, "R": init_qubits_z0_iterator, "RZ": init_qubits_z0_iterator, "RX": init_qubits_x0_iterator, "M": log_meas_z_iterator, "MZ": log_meas_z_iterator, "MX": log_meas_x_iterator, "X_ERROR": log_x_error_iterator, "Y_ERROR": log_y_error_iterator, "Z_ERROR": log_z_error_iterator, "DEPOLARIZE1": log_depolarize1_error_iterator, } gate_to_iterator_mid_cycle_cnots = { "CX": log_trans_cnot_mid_cycle_css_iterator, "CNOT": log_trans_cnot_mid_cycle_css_iterator, "R": init_qubits_z0_iterator, "RZ": init_qubits_z0_iterator, "RX": init_qubits_x0_iterator, "M": log_meas_z_iterator, "MZ": log_meas_z_iterator, "MX": log_meas_x_iterator, "X_ERROR": log_x_error_iterator, "Y_ERROR": log_y_error_iterator, "Z_ERROR": log_z_error_iterator, "DEPOLARIZE1": log_depolarize1_error_iterator, } tick_iterators_mid_cycle_cnots = [ to_mid_cycle_iterator_cnots, to_end_cycle_iterator_cnots, ] gate_to_iterator_pipelined = { "TICK": qec_round_pipelined_iterator, "I": idle_iterator, "S": log_fold_trans_s_iterator, "X": log_x_iterator, "Z": log_z_iterator, "CX": log_trans_cnot_iterator, "CNOT": log_trans_cnot_iterator, "R": init_qubits_z0_iterator, "RZ": init_qubits_z0_iterator, "RX": init_qubits_x0_iterator, "M": log_meas_z_iterator, "MZ": log_meas_z_iterator, "MX": log_meas_x_iterator, "X_ERROR": log_x_error_iterator, "Y_ERROR": log_y_error_iterator, "Z_ERROR": log_z_error_iterator, "DEPOLARIZE1": log_depolarize1_error_iterator, }