Source code for loom.eka.operations.code_operation

"""
Copyright (c) Entropica Labs Pte Ltd 2025.

Use, distribution and reproduction of this program in its source or compiled
form is prohibited without the express written consent of Entropica Labs Pte
Ltd.

"""

from functools import partial

from pydantic.dataclasses import dataclass
from pydantic import Field, field_validator


from .base_operation import Operation
from .logical_measurement import LogicalMeasurement
from ..utilities import (
    SingleQubitPauliEigenstate,
    Direction,
    Orientation,
    ResourceState,
    dataclass_params,
    larger_than_zero_error,
)


# CodeOperation act on the code itself
[docs] @dataclass(**dataclass_params) class CodeOperation(Operation): """ Parent class for all code operations. All code operations act on blocks Properties ---------- _inputs : tuple[str, ...] Standardized way to access the input blocks names. _outputs : tuple[str, ...] Standardized way to access the output blocks names. """ @property def _inputs(self): """ Standardized way to access the input block(s) names. Returns ------- tuple[str, ...] Names of the input blocks """ if hasattr(self, "input_block_name"): return (self.input_block_name,) if hasattr(self, "input_blocks_name"): return self.input_blocks_name raise ValueError(f"No block inputs specified for {self.__class__.__name__}") @property def _outputs(self): """ Standardized way to access the output block(s) names. Returns ------- tuple[str, ...] Names of the output blocks """ if hasattr(self, "output_block_name"): return (self.output_block_name,) if hasattr(self, "output_blocks_name"): return self.output_blocks_name return self._inputs
# Readout operations
[docs] @dataclass(**dataclass_params) class MeasureBlockSyndromes(CodeOperation): """ Performs a given number of rounds of syndrome measurements on a block. Parameters ---------- input_block_name : str Name of the block to measure. n_cycles : int Number of cycles to measure. Default is 1. """ input_block_name: str n_cycles: int = 1
[docs] @dataclass(**dataclass_params) class MeasureLogicalX(CodeOperation): """ Measure the logical X operator of a block. Parameters ---------- input_block_name : str Name of the block where the logical operator to be measured is located. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be measured. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class MeasureLogicalZ(CodeOperation): """ Measure the logical Z operator of a block. Parameters ---------- input_block_name : str Name of the block where the logical operator to be measured is located. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be measured. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class MeasureLogicalY(CodeOperation): """ Measure the logical Y operator of a block. Parameters ---------- input_block_name : str Name of the block where the logical operator to be measured is located. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be measured. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class LogicalX(CodeOperation): """ Apply a logical X operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class LogicalY(CodeOperation): """ Apply a logical Y operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class LogicalZ(CodeOperation): """ Apply a logical Z operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. """ input_block_name: str logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class ResetAllDataQubits(CodeOperation): """ Reset all data qubits to a specific SingleQubitPauliEigenstate. input_block_name : str Name of the block where the logical operator should be applied. state: SingleQubitPauliEigenstate | None, optional State to which the logical qubit should be reset. Default is SingleQubitPauliEigenstate.ZERO, i.e. the zero eigenstate of the Pauli Z operator. """ input_block_name: str state: SingleQubitPauliEigenstate = Field(default=SingleQubitPauliEigenstate.ZERO)
[docs] @dataclass(**dataclass_params) class ResetAllAncillaQubits(CodeOperation): """ Reset all ancilla qubits to a specific SingleQubitPauliEigenstate. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. state: SingleQubitPauliEigenstate | None, optional State to which the ancilla qubit should be reset. Default is SingleQubitPauliEigenstate.ZERO, i.e. the zero eigenstate of the Pauli Z operator. """ input_block_name: str state: SingleQubitPauliEigenstate = Field(default=SingleQubitPauliEigenstate.ZERO)
[docs] @dataclass(**dataclass_params) class Grow(CodeOperation): """ Grow operation. Parameters ---------- input_block_name : str Name of the block to grow. direction : Direction Direction in which to grow the block. length : int Length by which to grow the block. """ input_block_name: str direction: Direction length: int _position_error = field_validator("length", mode="before")( partial(larger_than_zero_error, arg_name="length") )
[docs] @dataclass(**dataclass_params) class Shrink(CodeOperation): """ Shrink operation. Parameters ---------- input_block_name : str Name of the block to shrink. direction : Direction Direction in which to shrink the block. length : int Length by which to shrink the block. """ input_block_name: str direction: Direction length: int _position_error = field_validator("length", mode="before")( partial(larger_than_zero_error, arg_name="length") )
[docs] @dataclass(**dataclass_params) class Merge(CodeOperation): """ Merge operation. Parameters ---------- input_blocks_name : tuple[str, str] Names of the two blocks to merge. output_block_name : str Name of the resulting block. orientation : Orientation, optional Orientation along which to merge the blocks. E.g. if Orientation.HORIZONTAL, the blocks will be merged using their left and right boundaries (whichever is easiest). If None, the orientation will be derived from the blocks positions. """ input_blocks_name: tuple[str, str] output_block_name: str orientation: Orientation | None = Field(default=None, validate_default=True)
[docs] @dataclass(**dataclass_params) class Split(CodeOperation): """ Split operation. Parameters ---------- input_block_name : str Name of the block to split. output_blocks_name : tuple[str, str] Names of the resulting blocks. orientation : Orientation Orientation along which to split the block. E.g. if Orientation.HORIZONTAL, the block will be split in a horizontal cut, leaving two blocks with adjacent top and bottom boundaries. split_position : int Position at which to split the block, distance to the (0,0) corner of the block. """ input_block_name: str output_blocks_name: tuple[str, str] orientation: Orientation split_position: int _position_error = field_validator("split_position", mode="before")( partial(larger_than_zero_error, arg_name="split_position") )
[docs] @dataclass(**dataclass_params) class StateInjection(CodeOperation): """ Inject the given resource state into the specified block. This operation resets the central qubit of the block into the specified resource state and maximizes the number of stabilizers that can be initialized in a deterministic way. E.g. a T state injection in a RotatedSurfaceCode block will reset the central qubit into the T state and reset the rest of the data qubits into four quadrants, such that two quadrants are in the ``|0⟩`` state and two quadrants are in the ``|+⟩`` state. This ensures that the Z stabilizer measurements are deterministic in the ``|0⟩`` quadrants and the X stabilizer measurements are deterministic in the ``|+⟩`` quadrants. Parameters ---------- input_block_name : str Name of the block to inject the resource state into. resource_state : ResourceState The resource state to inject into the block. This can be one of the following: - ResourceState.T: T state - ResourceState.S: S state """ input_block_name: str resource_state: ResourceState
[docs] @dataclass(**dataclass_params) class ConditionalLogicalX(CodeOperation): """ Apply a conditional logical X operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. condition : LogicalMeasurement | None, optional Condition for logical pauli operation to be applied based on the value of the LogicalMeasurement provided. """ input_block_name: str condition: LogicalMeasurement logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class ConditionalLogicalY(CodeOperation): """ Apply a conditional logical Y operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. condition : LogicalMeasurement Condition for logical pauli operation to be applied based on the value of the LogicalMeasurement provided. """ input_block_name: str condition: LogicalMeasurement logical_qubit: int = Field(default=0)
[docs] @dataclass(**dataclass_params) class ConditionalLogicalZ(CodeOperation): """ Apply a conditional logical Z operator to a block. Parameters ---------- input_block_name : str Name of the block where the logical operator should be applied. logical_qubit : int | None, optional Index of the logical qubit inside the specified block which should be acted on. For blocks with a single logical qubit, this parameter does not need to be provided. Then by default the index 0 is chosen for this single logical qubit. For blocks with multiple logical qubits, this parameter is required. condition : LogicalMeasurement Condition for logical pauli operation to be applied based on the value of the LogicalMeasurement provided. """ input_block_name: str condition: LogicalMeasurement logical_qubit: int = Field(default=0)