import numpy as np
from pydantic import BaseModel, field_validator, model_validator
from topqad_sdk.noiseprofiler.libprotocols.protocol_handler import (
ProtocolHandler,
FitSpecification,
)
[docs]
class ModelStability(BaseModel):
rounds: int
diameter: int | tuple[int, int]
[docs]
@field_validator("rounds")
@classmethod
def is_round(cls, value: int):
if type(value) is not int or value < 1:
raise ValueError("rounds must be an integer greater than or equal to 1.")
return value
[docs]
@field_validator("diameter")
@classmethod
def is_diameter(cls, value: int | tuple[int, int]):
if type(value) is int:
if value < 2 or value % 2 == 1:
raise ValueError(
"diameter must be an even integer greater than or equal to 2."
)
elif type(value) is tuple and len(value) == 2:
if value[0] < 2 or value[0] % 2 == 1 or value[1] < 2 or value[1] % 2 == 1:
raise ValueError(
"x and z diameters must be an even integers greater than or equal to 2."
)
else:
raise ValueError("Unrecognized value for diameter.")
return value
[docs]
@model_validator(mode="after")
def enforce_maximum_values(self):
if self.rounds > 16:
raise ValueError(
f"Simulations with `rounds` = {self.rounds} > 16 are not allowed."
)
if self.diameter > 16:
raise ValueError(
f"Simulations with `diameter` = {self.diameter} > 16 are not allowed."
)
return self
[docs]
class Stability(ProtocolHandler):
"""The stability protocol [1] is used to estimate how well a fault-tolerant system can move logical observables
through space or, equivalently, determine the product of a large region of stabilizers. Logical observables are, for
example, moved through space in lattice surgery operations.
### References
[1] Gidney et al, Stability Experiments: The Overlooked Dual of Memory Experiments, Quantum 6, 786 (2022)
"""
protocol_category: str = "stability"
protocol_subcategory: str = "emulated"
protocol_name: str = "stability"
protocol_parameters: BaseModel = ModelStability
includes_postselection: bool = False
fit_options: dict[tuple[str, str], FitSpecification] = dict()
def __init__(self):
"""Create handler for the Stability protocol."""
super().__init__()
self.simulation_table.fields["rounds"].full_label = "Rounds"
self.simulation_table.fields["diameter"].full_label = "Diameter"
self.simulation_table.fields["rounds"].math_symbol = "r"
self.simulation_table.fields["diameter"].math_symbol = "d"
[docs]
def add_instance(
self,
rounds: int,
diameter: int | tuple[int, int],
*,
noise_model_labels: str | list[str] | None = None,
decoder="pymatching",
):
"""Add instance of protocol parameters to be simulated.
Args:
rounds (int): Number of rounds (temporal distance).
diameter (int | tuple[int, int]): Spatial distance of code. Must be even. Can separately specify (d_x, d_z).
noise_model_label (str | list[str] | None, optional): The noise model label(s) for this instance. If None, then all added noise models are
used. Default is None.
decoder (str, optional): The decoder to use. "pymatching" is the only option.
"""
super().add_instance(
rounds=rounds,
diameter=diameter,
noise_model_labels=noise_model_labels,
decoder=decoder,
)