Source code for surface_sim.circuit_blocks.repetition_code

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

# methods to have in this script
from .util import (
    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_meas,
    log_meas_iterator,
    log_meas_x_iterator,
    log_meas_z_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,
    qubit_coords,
)
from .util import qec_round_iterator as qec_round_iterator_sc

__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",
    "qec_round",
    "qec_round_iterator",
    "log_x_error_iterator",
    "log_y_error_iterator",
    "log_z_error_iterator",
    "log_depolarize1_error_iterator",
    "gate_to_iterator",
    "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 two schedules, depending on the layout's interaction order: https://doi.org/10.1103/PhysRevApplied.8.034021 or shallowest interaction order for the rotated surface code where ancillas interact with the data qubit on the left and right in just two two-qubit-gate layers. 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
@qec_circuit def qec_round_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``. Notes ----- This implementation follows two schedules, depending on the layout's interaction order: https://doi.org/10.1103/PhysRevApplied.8.034021 or shallowest interaction order for the rotated surface code where ancillas interact with the data qubit on the left and right in just two two-qubit-gate layers. """ if layout.code not in ("repetition_code", "repetition_stability"): raise TypeError( f"The given layout is not a repetition code, but a {layout.code}" ) if "steps" not in layout.interaction_order: yield from qec_round_iterator_sc(model, layout, anc_reset=anc_reset) return # finish generator data_qubits = layout.data_qubits anc_qubits = layout.anc_qubits qubits = set(layout.qubits) int_order = layout.interaction_order.copy() mapping = { "left": ("north_west", "south_west"), "right": ("north_east", "south_east"), } int_order["steps"] = [mapping[i] for i in int_order["steps"]] stab_type = ( "z_type" if len(layout.get_qubits(role="anc", stab_type="x_type")) == 0 else "x_type" ) yield model.incoming_noise(data_qubits) yield model.tick() if anc_reset: yield model.reset(anc_qubits) + model.idle(data_qubits) yield model.tick() # a rot_qubits = set(anc_qubits) if stab_type == "x_type": rot_qubits.update(data_qubits) idle_qubits = qubits - rot_qubits yield model.hadamard(rot_qubits) + model.idle(idle_qubits) yield model.tick() # b int_pairs: list[tuple[str, str]] = [] for ord_dir in int_order["steps"][0]: int_pairs.extend( layout.get_neighbors(anc_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() # c int_pairs = [] for ord_dir in int_order["steps"][1]: int_pairs += layout.get_neighbors(anc_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() # d rot_qubits = set(anc_qubits) if stab_type == "x_type": rot_qubits.update(data_qubits) idle_qubits = qubits - rot_qubits yield model.hadamard(rot_qubits) + model.idle(idle_qubits) yield model.tick() # e yield model.measure(anc_qubits) + model.idle(data_qubits) yield model.tick() gate_to_iterator = { "TICK": qec_round_iterator, "I": idle_iterator, "X": log_x_iterator, "Z": log_z_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, }