"""Instruction classes."""
from __future__ import annotations
import enum
import math
import sys
from dataclasses import dataclass, field
from enum import Enum
from typing import ClassVar, Literal, SupportsFloat, Union
from graphix import utils
from graphix.fundamentals import Plane
# Ruff suggests to move this import to a type-checking block, but dataclass requires it here
from graphix.parameter import ExpressionOrFloat # noqa: TC001
from graphix.pretty_print import OutputFormat, angle_to_str
from graphix.repr_mixins import DataclassReprMixin
def repr_angle(angle: ExpressionOrFloat) -> str:
"""
Return the representation string of an angle in radians.
This is used for pretty-printing instructions with `angle` parameters.
Delegates to :func:`pretty_print.angle_to_str`.
"""
# Non-float-supporting objects are returned as-is
if not isinstance(angle, SupportsFloat):
return str(angle)
# Convert to float, express in π units, and format in ASCII/plain mode
pi_units = float(angle) / math.pi
return angle_to_str(pi_units, OutputFormat.ASCII)
[docs]
class InstructionKind(Enum):
"""Tag for instruction kind."""
CCX = enum.auto()
RZZ = enum.auto()
CNOT = enum.auto()
SWAP = enum.auto()
H = enum.auto()
S = enum.auto()
X = enum.auto()
Y = enum.auto()
Z = enum.auto()
I = enum.auto()
M = enum.auto()
RX = enum.auto()
RY = enum.auto()
RZ = enum.auto()
# The two following instructions are used internally by the transpiler
_XC = enum.auto()
_ZC = enum.auto()
class _KindChecker:
"""Enforce tag field declaration."""
def __init_subclass__(cls) -> None:
"""Validate that subclasses define the ``kind`` attribute."""
super().__init_subclass__()
utils.check_kind(cls, {"InstructionKind": InstructionKind, "Plane": Plane})
@dataclass(repr=False)
class CCX(_KindChecker, DataclassReprMixin):
"""Toffoli circuit instruction."""
target: int
controls: tuple[int, int]
kind: ClassVar[Literal[InstructionKind.CCX]] = field(default=InstructionKind.CCX, init=False)
@dataclass(repr=False)
class RZZ(_KindChecker, DataclassReprMixin):
"""RZZ circuit instruction."""
target: int
control: int
angle: ExpressionOrFloat = field(metadata={"repr": repr_angle})
# FIXME: Remove `| None` from `meas_index`
# - `None` makes codes messy/type-unsafe
meas_index: int | None = None
kind: ClassVar[Literal[InstructionKind.RZZ]] = field(default=InstructionKind.RZZ, init=False)
[docs]
@dataclass(repr=False)
class CNOT(_KindChecker, DataclassReprMixin):
"""CNOT circuit instruction."""
target: int
control: int
kind: ClassVar[Literal[InstructionKind.CNOT]] = field(default=InstructionKind.CNOT, init=False)
[docs]
@dataclass(repr=False)
class SWAP(_KindChecker, DataclassReprMixin):
"""SWAP circuit instruction."""
targets: tuple[int, int]
kind: ClassVar[Literal[InstructionKind.SWAP]] = field(default=InstructionKind.SWAP, init=False)
[docs]
@dataclass(repr=False)
class H(_KindChecker, DataclassReprMixin):
"""H circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.H]] = field(default=InstructionKind.H, init=False)
[docs]
@dataclass(repr=False)
class S(_KindChecker, DataclassReprMixin):
"""S circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.S]] = field(default=InstructionKind.S, init=False)
[docs]
@dataclass(repr=False)
class X(_KindChecker, DataclassReprMixin):
"""X circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.X]] = field(default=InstructionKind.X, init=False)
[docs]
@dataclass(repr=False)
class Y(_KindChecker, DataclassReprMixin):
"""Y circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.Y]] = field(default=InstructionKind.Y, init=False)
[docs]
@dataclass(repr=False)
class Z(_KindChecker, DataclassReprMixin):
"""Z circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.Z]] = field(default=InstructionKind.Z, init=False)
@dataclass(repr=False)
class I(_KindChecker, DataclassReprMixin):
"""I circuit instruction."""
target: int
kind: ClassVar[Literal[InstructionKind.I]] = field(default=InstructionKind.I, init=False)
[docs]
@dataclass(repr=False)
class M(_KindChecker, DataclassReprMixin):
"""M circuit instruction."""
target: int
plane: Plane
angle: ExpressionOrFloat = field(metadata={"repr": repr_angle})
kind: ClassVar[Literal[InstructionKind.M]] = field(default=InstructionKind.M, init=False)
[docs]
@dataclass(repr=False)
class RX(_KindChecker, DataclassReprMixin):
"""X rotation circuit instruction."""
target: int
angle: ExpressionOrFloat = field(metadata={"repr": repr_angle})
meas_index: int | None = None
kind: ClassVar[Literal[InstructionKind.RX]] = field(default=InstructionKind.RX, init=False)
[docs]
@dataclass(repr=False)
class RY(_KindChecker, DataclassReprMixin):
"""Y rotation circuit instruction."""
target: int
angle: ExpressionOrFloat = field(metadata={"repr": repr_angle})
meas_index: int | None = None
kind: ClassVar[Literal[InstructionKind.RY]] = field(default=InstructionKind.RY, init=False)
[docs]
@dataclass(repr=False)
class RZ(_KindChecker, DataclassReprMixin):
"""Z rotation circuit instruction."""
target: int
angle: ExpressionOrFloat = field(metadata={"repr": repr_angle})
meas_index: int | None = None
kind: ClassVar[Literal[InstructionKind.RZ]] = field(default=InstructionKind.RZ, init=False)
@dataclass
class _XC(_KindChecker):
"""X correction circuit instruction. Used internally by the transpiler."""
target: int
domain: set[int]
kind: ClassVar[Literal[InstructionKind._XC]] = field(default=InstructionKind._XC, init=False)
@dataclass
class _ZC(_KindChecker):
"""Z correction circuit instruction. Used internally by the transpiler."""
target: int
domain: set[int]
kind: ClassVar[Literal[InstructionKind._ZC]] = field(default=InstructionKind._ZC, init=False)
if sys.version_info >= (3, 10):
Instruction = CCX | RZZ | CNOT | SWAP | H | S | X | Y | Z | I | M | RX | RY | RZ | _XC | _ZC
else:
Instruction = Union[CCX, RZZ, CNOT, SWAP, H, S, X, Y, Z, I, M, RX, RY, RZ, _XC, _ZC]