Source code for tqec.computation.cube

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import astuple, dataclass
from enum import Enum

from tqec.computation.zx_graph import ZXKind, ZXNode
from tqec.exceptions import TQECException
from tqec.position import Direction3D, Position3D


[docs] class ZXBasis(Enum): """Z or X basis.""" Z = "Z" X = "X" def with_zx_flipped(self) -> ZXBasis: """Get the basis with the Z/X flipped.""" return ZXBasis.Z if self == ZXBasis.X else ZXBasis.X def __str__(self) -> str: return self.value
[docs] class CubeKind(ABC): """Base class for the cube types.""" @abstractmethod def to_zx_kind(self) -> ZXKind: """Convert the cube kind to a ZX node kind.""" pass
[docs] @dataclass(frozen=True) class ZXCube(CubeKind): """Cube kind representing the cube surrounded by all X/Z basis walls.""" x: ZXBasis y: ZXBasis z: ZXBasis def as_tuple(self) -> tuple[ZXBasis, ZXBasis, ZXBasis]: return astuple(self) def __post_init__(self) -> None: if self.x == self.y == self.z: raise TQECException( "The cube kind with all the same basis walls is not allowed." ) def __str__(self) -> str: return f"{self.x.value}{self.y.value}{self.z.value}" @staticmethod def all_kinds() -> list[ZXCube]: """Return all the possible `ZXCube` kinds.""" return [ZXCube.from_str(s) for s in ["ZXZ", "XZZ", "ZXX", "XZX", "XXZ", "ZZX"]] @staticmethod def from_str(string: str) -> ZXCube: """Create a cube kind from the string representation.""" return ZXCube(*map(ZXBasis, string.upper())) @property def cube_basis(self) -> ZXBasis: """Return the basis of the cube. A cube has only one Z/X basis wall is a Z/X basis cube. """ if sum(basis == ZXBasis.Z for basis in astuple(self)) == 1: return ZXBasis.Z return ZXBasis.X def to_zx_kind(self) -> ZXKind: return ZXKind(self.cube_basis.value) @property def normal_direction(self) -> Direction3D: """Get the direction in which the wall basis is the same as the cube basis.""" return Direction3D(astuple(self).index(self.cube_basis)) @staticmethod def from_normal_basis(basis: ZXBasis, direction: Direction3D) -> ZXCube: """Create a cube kind with the given normal basis and direction.""" bases = [basis.with_zx_flipped() for _ in range(3)] bases[direction.value] = basis return ZXCube(*bases) @property def is_spatial_junction(self) -> bool: """Check if the cube is a spatial junction.""" return self.x == self.y def get_basis_along(self, direction: Direction3D) -> ZXBasis: """Get the basis of the wall in the given direction.""" return self.as_tuple()[direction.value]
[docs] class Port(CubeKind): """Cube kind representing the open ports in the block graph. The open ports correspond to the input/output of the computation represented by the block graph. They will have no effect on the functionality of the logical computation itself and should be invisible when visualizing the computation model. """ def __str__(self) -> str: return "PORT" def to_zx_kind(self) -> ZXKind: return ZXKind.P def __hash__(self) -> int: return hash(Port) def __eq__(self, other: object) -> bool: return isinstance(other, Port)
[docs] class YCube(CubeKind): """Cube kind representing the Y-basis initialization/measurements.""" def __str__(self) -> str: return "Y" def to_zx_kind(self) -> ZXKind: return ZXKind.Y def __hash__(self) -> int: return hash(YCube) def __eq__(self, other: object) -> bool: return isinstance(other, YCube)
[docs] @dataclass(frozen=True) class Cube: """A block representing a unit of code patch in the spacetime. Attributes: position: The position of the cube in the 3D spacetime. kind: The kind of the cube. It specifies the functionality of the cube. label: The label of the cube. If the cube is a port, the label must be non-empty. Default to an empty string. """ position: Position3D kind: CubeKind label: str = "" def __post_init__(self) -> None: if self.is_port and not self.label: raise TQECException("A port cube must have a non-empty port label.") def __str__(self) -> str: return f"{self.kind}{self.position}" @property def is_zx_cube(self) -> bool: """Check if the cube is a ZX cube.""" return isinstance(self.kind, ZXCube) @property def is_port(self) -> bool: """Check if the cube is an open port.""" return isinstance(self.kind, Port) @property def is_y_cube(self) -> bool: return isinstance(self.kind, YCube) @property def is_spatial_junction(self) -> bool: """Check if the cube is a spatial junction.""" return isinstance(self.kind, ZXCube) and self.kind.is_spatial_junction def to_zx_node(self) -> ZXNode: """Convert the cube to a ZX node.""" return ZXNode(self.position, self.kind.to_zx_kind(), self.label)