Source code for graphix.measurements

"""Data structure for single-qubit measurements in MBQC."""

from __future__ import annotations

import math
from dataclasses import dataclass
from typing import (
    Literal,
    NamedTuple,
    SupportsInt,
    TypeAlias,
)

# override introduced in Python 3.12
from typing_extensions import override

from graphix import utils
from graphix.fundamentals import AbstractMeasurement, AbstractPlanarMeasurement, Axis, ParameterizedAngle, Plane, Sign

# Ruff suggests to move this import to a type-checking block, but dataclass requires it here
from graphix.parameter import ExpressionOrFloat  # noqa: TC001

Outcome: TypeAlias = Literal[0, 1]


def outcome(b: bool) -> Outcome:
    """Return 1 if True, 0 if False."""
    return 1 if b else 0


def toggle_outcome(outcome: Outcome) -> Outcome:
    """Toggle outcome."""
    return 1 if outcome == 0 else 0


@dataclass
class Domains:
    """Represent `X^sZ^t` where s and t are XOR of results from given sets of indices."""

    s_domain: set[int]
    t_domain: set[int]


[docs] @dataclass class Measurement(AbstractPlanarMeasurement): r"""An MBQC measurement. Attributes ---------- angle : ExpressionOrFloat The angle of the measurement in units of :math:`\pi`. Should be between [0, 2). plane : graphix.fundamentals.Plane The measurement plane. """ angle: ParameterizedAngle plane: Plane
[docs] @override def isclose(self, other: AbstractMeasurement, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> bool: """Determine whether two measurements are close in angle and share the same plane. This method compares the angle of the current measurement with that of another measurement, using :func:`math.isclose` when both angles are floats. The planes must match exactly for the measurements to be considered close. Parameters ---------- other : AbstractMeasurement The measurement to compare against. rel_tol : float, optional Relative tolerance for comparing angles, passed to :func:`math.isclose`. Default is ``1e-9``. abs_tol : float, optional Absolute tolerance for comparing angles, passed to :func:`math.isclose`. Default is ``0.0``. Returns ------- bool ``True`` if both measurements lie in the same plane and their angles are equal or close within the given tolerances; ``False`` otherwise. Examples -------- >>> from graphix.measurements import Measurement >>> from graphix.fundamentals import Plane >>> Measurement(0.0, Plane.XY).isclose(Measurement(0.0, Plane.XY)) True >>> Measurement(0.0, Plane.XY).isclose(Measurement(0.0, Plane.YZ)) False >>> Measurement(0.1, Plane.XY).isclose(Measurement(0.0, Plane.XY)) False """ return ( isinstance(other, Measurement) and ( math.isclose(self.angle, other.angle, rel_tol=rel_tol, abs_tol=abs_tol) if isinstance(self.angle, float) and isinstance(other.angle, float) else self.angle == other.angle ) and self.plane == other.plane )
[docs] def to_plane_or_axis(self) -> Plane | Axis: """Return the measurements's plane or axis. Returns ------- Plane | Axis Notes ----- Measurements with Pauli angles (i.e., ``self.angle == n/2`` with ``n`` an integer) are interpreted as `Axis` instances. """ if pm := PauliMeasurement.try_from(self.plane, self.angle): return pm.axis return self.plane
[docs] def to_plane(self) -> Plane: """Return the measurement's plane. Returns ------- Plane """ return self.plane
class PauliMeasurement(NamedTuple): """Pauli measurement.""" axis: Axis sign: Sign @staticmethod def try_from(plane: Plane, angle: ExpressionOrFloat) -> PauliMeasurement | None: """Return the Pauli measurement description if a given measure is Pauli.""" angle_double = 2 * angle if not isinstance(angle_double, SupportsInt) or not utils.is_integer(angle_double): return None angle_double_mod_4 = int(angle_double) % 4 axis = plane.cos if angle_double_mod_4 % 2 == 0 else plane.sin sign = Sign.minus_if(angle_double_mod_4 >= 2) return PauliMeasurement(axis, sign)