"""Pauli gates ± {1,j} × {I, X, Y, Z}."""# noqa: RUF002from__future__importannotationsimportdataclassesfromtypingimportTYPE_CHECKING,ClassVarimporttyping_extensionsfromgraphix.fundamentalsimportIXYZ,Axis,ComplexUnit,SupportsComplexCtorfromgraphix.opsimportOpsfromgraphix.statesimportBasicStatesifTYPE_CHECKING:fromcollections.abcimportIteratorimportnumpyasnpimportnumpy.typingasnptfromgraphix.statesimportPlanarStateclass_PauliMeta(type):def__iter__(cls)->Iterator[Pauli]:"""Iterate over all Pauli gates, including the unit."""returnPauli.iterate()
[docs]@dataclasses.dataclass(frozen=True)classPauli(metaclass=_PauliMeta):r"""Pauli gate: ``u * {I, X, Y, Z}`` where u is a complex unit. Pauli gates can be multiplied with other Pauli gates (with ``@``), with complex units and unit constants (with ``*``), and can be negated. """symbol:IXYZ=IXYZ.Iunit:ComplexUnit=ComplexUnit.ONEI:ClassVar[Pauli]X:ClassVar[Pauli]Y:ClassVar[Pauli]Z:ClassVar[Pauli]@staticmethoddeffrom_axis(axis:Axis)->Pauli:"""Return the Pauli associated to the given axis."""returnPauli(IXYZ[axis.name])@propertydefaxis(self)->Axis:"""Return the axis associated to the Pauli. Fails if the Pauli is identity. """ifself.symbol==IXYZ.I:raiseValueError("I is not an axis.")returnAxis[self.symbol.name]@propertydefmatrix(self)->npt.NDArray[np.complex128]:"""Return the matrix of the Pauli gate."""co=complex(self.unit)ifself.symbol==IXYZ.I:returnco*Ops.Iifself.symbol==IXYZ.X:returnco*Ops.Xifself.symbol==IXYZ.Y:returnco*Ops.Yifself.symbol==IXYZ.Z:returnco*Ops.Ztyping_extensions.assert_never(self.symbol)defeigenstate(self,binary:int=0)->PlanarState:"""Return the eigenstate of the Pauli."""ifbinarynotin{0,1}:raiseValueError("b must be 0 or 1.")ifself.symbol==IXYZ.X:returnBasicStates.PLUSifbinary==0elseBasicStates.MINUSifself.symbol==IXYZ.Y:returnBasicStates.PLUS_Iifbinary==0elseBasicStates.MINUS_Iifself.symbol==IXYZ.Z:returnBasicStates.ZEROifbinary==0elseBasicStates.ONE# Any state is eigenstate of the identityifself.symbol==IXYZ.I:returnBasicStates.PLUStyping_extensions.assert_never(self.symbol)def_repr_impl(self,prefix:str|None)->str:"""Return ``repr`` string with an optional prefix."""sym=self.symbol.nameifprefixisnotNone:sym=f"{prefix}.{sym}"ifself.unit==ComplexUnit.ONE:returnsymifself.unit==ComplexUnit.MINUS_ONE:returnf"-{sym}"ifself.unit==ComplexUnit.J:returnf"1j * {sym}"ifself.unit==ComplexUnit.MINUS_J:returnf"-1j * {sym}"typing_extensions.assert_never(self.unit)def__repr__(self)->str:"""Return a string representation of the Pauli."""returnself._repr_impl(self.__class__.__name__)def__str__(self)->str:"""Return a simplified string representation of the Pauli."""returnself._repr_impl(None)@staticmethoddef_matmul_impl(lhs:IXYZ,rhs:IXYZ)->Pauli:"""Return the product of ``lhs`` and ``rhs`` ignoring units."""iflhs==IXYZ.I:returnPauli(rhs)ifrhs==IXYZ.I:returnPauli(lhs)iflhs==rhs:returnPauli()lr=(lhs,rhs)iflr==(IXYZ.X,IXYZ.Y):returnPauli(IXYZ.Z,ComplexUnit.J)iflr==(IXYZ.Y,IXYZ.X):returnPauli(IXYZ.Z,ComplexUnit.MINUS_J)iflr==(IXYZ.Y,IXYZ.Z):returnPauli(IXYZ.X,ComplexUnit.J)iflr==(IXYZ.Z,IXYZ.Y):returnPauli(IXYZ.X,ComplexUnit.MINUS_J)iflr==(IXYZ.Z,IXYZ.X):returnPauli(IXYZ.Y,ComplexUnit.J)iflr==(IXYZ.X,IXYZ.Z):returnPauli(IXYZ.Y,ComplexUnit.MINUS_J)raiseRuntimeError("Unreachable.")# pragma: no coverdef__matmul__(self,other:Pauli)->Pauli:"""Return the product of two Paulis."""ifisinstance(other,Pauli):returnself._matmul_impl(self.symbol,other.symbol)*(self.unit*other.unit)returnNotImplementeddef__mul__(self,other:ComplexUnit|SupportsComplexCtor)->Pauli:"""Return the product of two Paulis."""ifu:=ComplexUnit.try_from(other):returndataclasses.replace(self,unit=self.unit*u)returnNotImplementeddef__rmul__(self,other:ComplexUnit|SupportsComplexCtor)->Pauli:"""Return the product of two Paulis."""returnself.__mul__(other)def__neg__(self)->Pauli:"""Return the opposite."""returndataclasses.replace(self,unit=-self.unit)@staticmethoddefiterate(symbol_only:bool=False)->Iterator[Pauli]:"""Iterate over all Pauli gates. Parameters ---------- symbol_only (bool, optional): Exclude the unit in the iteration. Defaults to False. """us=(ComplexUnit.ONE,)ifsymbol_onlyelsetuple(ComplexUnit)forsymbolinIXYZ:forunitinus:yieldPauli(symbol,unit)