Skip to content
131 changes: 127 additions & 4 deletions src/qce_circuit/connectivity/generic_gate_sequence.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# -------------------------------------------
# Module containing interface and implementation of generic (Surface17) gate sequences.
# -------------------------------------------
from abc import ABCMeta, abstractmethod
from typing import List, Union
from qce_circuit.utilities.custom_exceptions import ElementNotIncludedException, InterfaceMethodException
import warnings
from abc import ABC, ABCMeta, abstractmethod
from typing import List, Union, Optional, Dict
from qce_circuit.utilities.custom_exceptions import (
ElementNotIncludedException,
InterfaceMethodException,
)
from qce_circuit.utilities.array_manipulation import unique_in_order
from qce_circuit.connectivity.intrf_channel_identifier import (
IQubitID,
Expand All @@ -14,6 +18,7 @@
ISurfaceCodeLayer,
IParityGroup,
FrequencyGroupIdentifier,
StabilizerType,
)
from qce_circuit.connectivity.intrf_connectivity_gate_sequence import (
IGateSequenceLayer,
Expand All @@ -22,6 +27,46 @@
from qce_circuit.connectivity.connectivity_surface_code import Surface17Layer


class ILogicalObservable(ABC):
"""
Interface class, describing logical observable.
"""

# region Interface Properties
@property
@abstractmethod
def observable_basis(self) -> StabilizerType:
""":return: (StabilizerType) basis of logical observable."""
raise InterfaceMethodException

@property
@abstractmethod
def involved_data_qubit_ids(self) -> List[IQubitID]:
""":return: Array-like of data-qubit ID's involved in observable."""
raise InterfaceMethodException

@property
@abstractmethod
def concordant_stabilizer_qubit_ids(self) -> List[IQubitID]:
"""
:return: Array-like of ancilla-qubit ID's that describe the stabilizers which are concordant with the observable.
"""
raise InterfaceMethodException
# endregion

# region Interface Methods
@abstractmethod
def contains(self, element: IQubitID) -> bool:
""":return: True if element is contained in logical observable, else False."""
raise InterfaceMethodException

@abstractmethod
def get_projection_basis(self, qubit_id: IQubitID) -> StabilizerType:
""":return: Projection basis per qubit in observable."""
raise InterfaceMethodException
# endregion


class IGenericSurfaceCodeLayer(ISurfaceCodeLayer, IGateSequenceLayer, metaclass=ABCMeta):
"""
Interface class, combining ISurfaceCodeLayer and IGateSequenceLayer.
Expand All @@ -35,6 +80,63 @@ def get_gate_sequence_indices(self, parity_group: IParityGroup) -> List[int]:
Returns an empty list if parity-group is not present.
"""
raise InterfaceMethodException

@abstractmethod
def get_logical_observable(self, basis: StabilizerType) -> ILogicalObservable:
""":return: Logical observable corresponding to basis."""
raise InterfaceMethodException
# endregion


class LogicalObservable(ILogicalObservable):
"""
Data class, implementing ILogicalObservable interface.
"""

# region Interface Properties
@property
def observable_basis(self) -> StabilizerType:
""":return: (StabilizerType) basis of logical observable."""
return self._observable_basis

@property
def involved_data_qubit_ids(self) -> List[IQubitID]:
""":return: Array-like of data-qubit ID's involved in observable."""
return unique_in_order(self._data_qubit_projections.keys())

@property
def concordant_stabilizer_qubit_ids(self) -> List[IQubitID]:
"""
:return: Array-like of ancilla-qubit ID's that describe the stabilizers which are concordant with the observable.
"""
return self._supporting_stabilizers
# endregion

# region Class Constructor
def __init__(
self,
observable_basis: StabilizerType,
data_qubit_projections: Dict[IQubitID, StabilizerType],
supporting_stabilizers: List[IQubitID],
default_projections: StabilizerType = StabilizerType.STABILIZER_Z,
):
self._observable_basis: StabilizerType = observable_basis
self._data_qubit_projections: Dict[IQubitID, StabilizerType] = data_qubit_projections
self._supporting_stabilizers: List[IQubitID] = supporting_stabilizers
self._default_projections: StabilizerType = default_projections
# endregion

# region Interface Methods
def contains(self, element: IQubitID) -> bool:
""":return: True if element is contained in logical observable, else False."""
return element in self._data_qubit_projections

def get_projection_basis(self, qubit_id: IQubitID) -> StabilizerType:
""":return: Projection basis per qubit in observable."""
if qubit_id not in self._data_qubit_projections:
# raise ObservableElementNotIncludedException(f"{qubit_id} is not in logical observable. Use one of self.involved_data_qubit_ids.")
return self._default_projections
return self._data_qubit_projections[qubit_id]
# endregion


Expand Down Expand Up @@ -100,10 +202,16 @@ def edge_ids(self) -> List[IEdgeID]:
# endregion

# region Class Constructor
def __init__(self, gate_sequences: List[GateSequenceLayer], parity_group_z: List[IParityGroup], parity_group_x: List[IParityGroup], surface_code_layer: ISurfaceCodeLayer = Surface17Layer()):
def __init__(self, gate_sequences: List[GateSequenceLayer], parity_group_z: List[IParityGroup], parity_group_x: List[IParityGroup], logical_observables: Optional[List[ILogicalObservable]] = None, surface_code_layer: ISurfaceCodeLayer = Surface17Layer()):
self._gate_sequences: List[GateSequenceLayer] = gate_sequences
self._parity_group_z: List[IParityGroup] = parity_group_z
self._parity_group_x: List[IParityGroup] = parity_group_x
if logical_observables is None:
logical_observables = []
self._logical_observables: Dict[StabilizerType, ILogicalObservable] = {
logical_observable.observable_basis: logical_observable
for logical_observable in logical_observables
}
self._surface_code_layer: ISurfaceCodeLayer = surface_code_layer
# endregion

Expand All @@ -125,6 +233,21 @@ def get_gate_sequence_indices(self, parity_group: IParityGroup) -> List[int]:
continue

return result

def get_logical_observable(self, basis: StabilizerType) -> ILogicalObservable:
""":return: Logical observable corresponding to basis."""
default_fallback: bool = basis not in self._logical_observables
if default_fallback:
warnings.warn(f"Logical observable for basis {basis.name} is not defined in GenericSurfaceCode. Defaulting to {StabilizerType.STABILIZER_Z.name} for all data qubit ID's.")
return LogicalObservable(
observable_basis=StabilizerType.STABILIZER_Z,
data_qubit_projections={
data_qubit_id: StabilizerType.STABILIZER_Z
for data_qubit_id in self.data_qubit_ids
},
supporting_stabilizers=StabilizerType.STABILIZER_Z,
)
return self._logical_observables[basis]
# endregion

# region IGateSequenceLayer Interface Methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
class StabilizerType(Enum):
STABILIZER_X = 0
STABILIZER_Z = 1
STABILIZER_Y = 2


class IParityGroup(ABC):
Expand Down
14 changes: 13 additions & 1 deletion src/qce_circuit/language/intrf_declarative_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from multipledispatch import dispatch
from typing import List, Union, Dict, Optional, TypeVar, Generic
from enum import Enum, unique
import math
import numpy as np
from numpy.typing import NDArray
from qce_circuit.utilities.custom_exceptions import InterfaceMethodException
Expand Down Expand Up @@ -49,6 +50,13 @@ class InitialStateEnum(Enum):
MINUS_I = '-i'


@unique
class CodeDimension(Enum):
"""Enum class, describing code dimensions."""
REPETITION_CODE = "1D"
SURFACE_CODE = "2D"


@dataclass(frozen=True)
class InitialStateContainer(Generic[T]):
"""
Expand All @@ -58,10 +66,13 @@ class InitialStateContainer(Generic[T]):
"""Index pointers to data qubits only."""
ancilla_initial_states: Dict[T, InitialStateEnum] = field(default_factory=dict)
"""Index pointers to ancilla qubits only."""
code_dimension: CodeDimension = field(default=CodeDimension.REPETITION_CODE)

# region Class Properties
@property
def distance(self) -> int:
if self.code_dimension == CodeDimension.SURFACE_CODE:
return int(math.sqrt(len(self.initial_states)))
return len(self.initial_states)

@property
Expand Down Expand Up @@ -149,7 +160,7 @@ def get_operation(self, qubit_index: T, initial_state: InitialStateEnum, **kwarg
raise NotImplementedError(f"Initial state {initial_state} is not supported.")

@classmethod
def from_ordered_list(cls, initial_states: List[InitialStateEnum], ancilla_initial_states: Optional[List[InitialStateEnum]] = None) -> 'InitialStateContainer':
def from_ordered_list(cls, initial_states: List[InitialStateEnum], ancilla_initial_states: Optional[List[InitialStateEnum]] = None, code_dimension: CodeDimension = CodeDimension.REPETITION_CODE) -> 'InitialStateContainer':
"""
:return: Class method constructor based on ordered array of initial state.
Where each element index corresponds to qubit index.
Expand All @@ -160,6 +171,7 @@ def from_ordered_list(cls, initial_states: List[InitialStateEnum], ancilla_initi
return InitialStateContainer[int](
initial_states={i: state for i, state in enumerate(initial_states)},
ancilla_initial_states={i: state for i, state in enumerate(ancilla_initial_states)},
code_dimension=code_dimension,
)

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
from qce_circuit.connectivity.connectivity_surface_code import (
ParityGroup,
StabilizerType,
SurfaceTuna17Layer,
)
from qce_circuit.connectivity.generic_gate_sequence import (
IGenericSurfaceCodeLayer,
GenericSurfaceCode,
LogicalObservable,
)
from qce_circuit.connectivity.intrf_connectivity_gate_sequence import (
GateSequenceLayer,
Expand Down Expand Up @@ -262,6 +264,117 @@ def __init__(self):
# endregion


class Repetition9Round2Code(GenericSurfaceCode, IGenericSurfaceCodeLayer, metaclass=SingletonABCMeta):

# region Class Constructor
def __init__(self):
super().__init__(
gate_sequences=[
GateSequenceLayer(
_park_operations=[
],
_gate_operations=[
Operation.type_gate(EdgeIDObj(QubitIDObj('X4'), QubitIDObj('D8'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X3'), QubitIDObj('D7'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z3'), QubitIDObj('D4'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z1'), QubitIDObj('D5'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z4'), QubitIDObj('D6'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z2'), QubitIDObj('D3'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X2'), QubitIDObj('D2'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X1'), QubitIDObj('D1'))),
],
),
GateSequenceLayer(
_park_operations=[
],
_gate_operations=[
Operation.type_gate(EdgeIDObj(QubitIDObj('X4'), QubitIDObj('D9'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X3'), QubitIDObj('D8'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z3'), QubitIDObj('D7'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z1'), QubitIDObj('D4'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z4'), QubitIDObj('D5'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('Z2'), QubitIDObj('D6'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X2'), QubitIDObj('D3'))),
Operation.type_gate(EdgeIDObj(QubitIDObj('X1'), QubitIDObj('D2'))),
],
),
],
parity_group_z=[
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('Z1'),
_data_qubits=[ QubitIDObj('D4'), QubitIDObj('D5')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('Z2'),
_data_qubits=[QubitIDObj('D3'), QubitIDObj('D6')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('Z3'),
_data_qubits=[QubitIDObj('D4'), QubitIDObj('D7')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('Z4'),
_data_qubits=[QubitIDObj('D5'), QubitIDObj('D6')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('X1'),
_data_qubits=[ QubitIDObj('D1'), QubitIDObj('D2')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('X2'),
_data_qubits=[QubitIDObj('D2'), QubitIDObj('D3')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('X3'),
_data_qubits=[QubitIDObj('D7'), QubitIDObj('D8')]
),
ParityGroup(
_parity_type=StabilizerType.STABILIZER_Z,
_ancilla_qubit=QubitIDObj('X4'),
_data_qubits=[QubitIDObj('D8'), QubitIDObj('D9')]
),
],
parity_group_x=[
],
logical_observables=[
LogicalObservable(
observable_basis=StabilizerType.STABILIZER_Z,
data_qubit_projections={
QubitIDObj("D1"): StabilizerType.STABILIZER_Z,
QubitIDObj("D2"): StabilizerType.STABILIZER_Z,
QubitIDObj("D3"): StabilizerType.STABILIZER_Z,
QubitIDObj("D4"): StabilizerType.STABILIZER_Z,
QubitIDObj("D5"): StabilizerType.STABILIZER_Z,
QubitIDObj("D6"): StabilizerType.STABILIZER_Z,
QubitIDObj("D7"): StabilizerType.STABILIZER_Z,
QubitIDObj("D8"): StabilizerType.STABILIZER_Z,
QubitIDObj("D9"): StabilizerType.STABILIZER_Z,
},
supporting_stabilizers=[
QubitIDObj("Z1"),
QubitIDObj("Z2"),
QubitIDObj("Z3"),
QubitIDObj("Z4"),
QubitIDObj("X1"),
QubitIDObj("X2"),
QubitIDObj("X3"),
QubitIDObj("X4"),
],
default_projections=StabilizerType.STABILIZER_Z
)
],
surface_code_layer=SurfaceTuna17Layer(),
)
# endregion


class Repetition5Round4Code(GenericSurfaceCode, IGenericSurfaceCodeLayer, metaclass=SingletonABCMeta):
"""
Data class, containing repetition code for distance-5 as ran for the error injection measurements (XX-11-2024)
Expand Down
Loading
Loading