Source code for surface_sim.circuit_blocks.decorators

"""
Decorators for functions that
1. take ``model: Model`` and ``layout: Layout`` as inputs (nothing else)
2. return a generator the iterates over stim.Circuit(s)
"""

from collections.abc import Callable, Generator
from copy import deepcopy

import stim

from ..layouts import Layout
from ..models import Model

LogOpFunction = (
    Callable[[Model, Layout], Generator[stim.Circuit]]
    | Callable[[Model, Layout, Layout], Generator[stim.Circuit]]
)


[docs] class LogOpCallable:
[docs] def __init__(self, func: LogOpFunction): self.func: LogOpFunction = func self.log_op_type: list[str] = [] self.rot_basis: bool | None = None self.num_qubits: int | None = None self.noiseless: bool = False self.name: str = func.__name__ self.anc_reset: bool | None = None self.log_noise_prob: float | None = None self.pauli_observable_ind: int | None = None return
def __call__(self, *args, **kargs) -> Generator[stim.Circuit]: if self.anc_reset is not None: kargs |= {"anc_reset": self.anc_reset} if self.log_noise_prob is not None: kargs |= {"prob": self.log_noise_prob} if self.pauli_observable_ind is not None: kargs |= {"observable_ind": self.pauli_observable_ind} if not self.noiseless: yield from self.func(*args, **kargs) else: for c in self.func(*args, **kargs): yield c.without_noise() @property def __name__(self) -> str: return self.name def copy(self) -> "LogOpCallable": new_copy = LogOpCallable(deepcopy(self.func)) new_copy.log_op_type = deepcopy(self.log_op_type) new_copy.rot_basis = deepcopy(self.rot_basis) new_copy.num_qubits = deepcopy(self.num_qubits) new_copy.noiseless = deepcopy(self.noiseless) new_copy.name = deepcopy(self.name) new_copy.anc_reset = deepcopy(self.anc_reset) new_copy.log_noise_prob = deepcopy(self.log_noise_prob) new_copy.pauli_observable_ind = deepcopy(self.pauli_observable_ind) return new_copy def __str__(self) -> str: string = self.name if self.pauli_observable_ind is not None: string += f"({self.pauli_observable_ind})" if self.rot_basis is not None: string += " bX" if self.rot_basis else " bZ" if self.anc_reset is not None: string += f" anc_reset={self.anc_reset}" if self.num_qubits is not None: string += f" n={self.num_qubits}" if self.log_noise_prob is not None: string += f" log-noise-prob={self.log_noise_prob}" if self.noiseless is True: string += " noiseless" return f"'{string}'" def __repr__(self) -> str: return str(self)
LogicalOperation = tuple[LogOpCallable, Layout] | tuple[LogOpCallable, Layout, Layout]
[docs] def qec_circuit(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["qec_round"] return new_func
[docs] def to_mid_cycle_circuit(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["to_mid_cycle_circuit"] return new_func
[docs] def to_end_cycle_circuit(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["to_end_cycle_circuit"] return new_func
[docs] def sq_gate(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["sq_unitary_gate"] new_func.num_qubits = 1 return new_func
[docs] def tq_gate(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["tq_unitary_gate"] new_func.rot_basis = None new_func.num_qubits = 2 return new_func
[docs] def qubit_init_z(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["qubit_init"] new_func.rot_basis = False return new_func
[docs] def qubit_init_x(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["qubit_init"] new_func.rot_basis = True return new_func
[docs] def qubit_encoding(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["qubit_encoding"] return new_func
[docs] def logical_measurement_z(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["measurement"] new_func.rot_basis = False return new_func
[docs] def logical_measurement_x(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["measurement"] new_func.rot_basis = True return new_func
[docs] def logical_noise(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["logical_noise"] return new_func
[docs] def pauli_observable_x(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["pauli_observable"] return new_func
[docs] def pauli_observable_y(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["pauli_observable"] return new_func
[docs] def pauli_observable_z(func: LogOpCallable | LogOpFunction) -> LogOpCallable: if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.log_op_type += ["pauli_observable"] return new_func
[docs] def noiseless(func: LogOpCallable | LogOpFunction) -> LogOpCallable: """Decorator for removing all noise channels from a ``LogOpCallable``""" if not isinstance(func, LogOpCallable): func = LogOpCallable(func) new_func = func.copy() new_func.noiseless = True return new_func
[docs] def copy_from( other_func: LogOpCallable, ) -> Callable[[LogOpCallable | LogOpFunction], LogOpCallable]: """Decorator for copying all the logical operation attributes from a function.""" def decorator( func: LogOpCallable | LogOpFunction, other_func=other_func.copy() ) -> LogOpCallable: other_func.func = func return other_func return decorator