From 7f45bfbe2bad2baa063910d94b8db6ca89b2cb44 Mon Sep 17 00:00:00 2001 From: David Yonge-Mallo Date: Thu, 31 Aug 2023 14:15:07 +0200 Subject: [PATCH] Make `quipper_name` a class var in `Gate` with a default value of `undefined`. Fixes #138. In `to_quipper`, no longer default to `name` if `quipper_name` is not defined. Behaviour changes: - calling `to_quipper` on `ParityPhase`, `InitAncilla`, and `PostSelect` will no longer cause a crash (`AttributeError: 'ParityPhase' object has no attribute 'target'. Did you mean: 'targets'?`) - calling `to_quipper` on `FSim` and `DiscardBit` will result in a `TypeError: Gate {} doesn't have a Quipper description` (previous output was, e.g., 'QGate["FSim"](db) with nocontrol') --- pyzx/circuit/gates.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/pyzx/circuit/gates.py b/pyzx/circuit/gates.py index 9593ec4d..a0f25135 100644 --- a/pyzx/circuit/gates.py +++ b/pyzx/circuit/gates.py @@ -142,9 +142,10 @@ def remove_label(self, l: int) -> None: class Gate(object): """Base class for representing quantum gates.""" name: ClassVar[str] = "BaseGate" - qc_name: ClassVar[str] = 'undefined' qasm_name: ClassVar[str] = 'undefined' qasm_name_adjoint: ClassVar[str] = 'undefined' + qc_name: ClassVar[str] = 'undefined' + quipper_name: ClassVar[str] = 'undefined' print_phase: ClassVar[bool] = False index = 0 def __str__(self) -> str: @@ -219,7 +220,7 @@ def to_basic_gates(self) -> List['Gate']: return [self] def to_quipper(self) -> str: - n = self.name if not hasattr(self, "quippername") else self.quippername # type: ignore + n = self.quipper_name if n == 'undefined': bg = self.to_basic_gates() if len(bg) == 1: @@ -299,6 +300,7 @@ def graph_add_node(self, class ZPhase(Gate): name = 'ZPhase' qasm_name = 'rz' + quipper_name = 'ZPhase' print_phase = True def __init__(self, target: int, phase: FractionLike) -> None: self.target = target @@ -353,6 +355,7 @@ class Z(ZPhase): name = 'Z' qasm_name = 'z' qc_name = 'Z' + quipper_name = 'Z' print_phase = False def __init__(self, target: int) -> None: super().__init__(target, Fraction(1,1)) @@ -362,6 +365,7 @@ class S(ZPhase): qasm_name = 's' qasm_name_adjoint = 'sdg' qc_name = 'S' + quipper_name = 'S' print_phase = False def __init__(self, target: int, adjoint:bool=False) -> None: super().__init__(target, Fraction(1,2)*(-1 if adjoint else 1)) @@ -372,6 +376,7 @@ class T(ZPhase): qasm_name = 't' qasm_name_adjoint = 'tdg' qc_name = 'T' + quipper_name = 'T' print_phase = False def __init__(self, target: int, adjoint:bool=False) -> None: super().__init__(target, Fraction(1,4)*(-1 if adjoint else 1)) @@ -380,6 +385,7 @@ def __init__(self, target: int, adjoint:bool=False) -> None: class XPhase(Gate): name = 'XPhase' qasm_name = 'rx' + quipper_name = 'XPhase' print_phase = True def __init__(self, target: int, phase: FractionLike=0) -> None: self.target = target @@ -433,6 +439,7 @@ def split_phases(self) -> List[Gate]: class YPhase(Gate): name = 'YPhase' qasm_name = 'ry' + quipper_name = 'YPhase' print_phase = True def __init__(self, target: int, phase: FractionLike=0) -> None: self.target = target @@ -460,18 +467,18 @@ def tcount(self): class NOT(XPhase): name = 'NOT' - quippername = 'not' qasm_name = 'x' qc_name = 'X' + quipper_name = 'not' print_phase = False def __init__(self, target: int) -> None: super().__init__(target, phase = Fraction(1,1)) class HAD(Gate): name = 'HAD' - quippername = 'H' qasm_name = 'h' qc_name = 'H' + quipper_name = 'H' def __init__(self, target: int) -> None: self.target = target @@ -486,9 +493,9 @@ def to_emoji(self,strings: List[List[str]]) -> None: class CNOT(Gate): name = 'CNOT' - quippername = 'not' qasm_name = 'cx' qc_name = 'Tof' + quipper_name = 'not' def __init__(self, control: int, target: int) -> None: self.target = target self.control = control @@ -518,9 +525,9 @@ def to_emoji(self,strings: List[List[str]]) -> None: class CZ(Gate): name = 'CZ' - quippername = 'Z' qasm_name = 'cz' qc_name = 'Z' + quipper_name = 'Z' def __init__(self, control: int, target: int) -> None: self.target = target self.control = control @@ -552,9 +559,9 @@ def to_emoji(self,strings: List[List[str]]) -> None: class CX(CZ): name = 'CX' - quippername = 'X' qasm_name = 'undefined' qc_name = 'undefined' + quipper_name = 'X' def to_graph(self, g, q_mapper, _c_mapper): r = max(q_mapper.next_row(self.target), q_mapper.next_row(self.control)) t = self.graph_add_node(g, q_mapper, VertexType.X, self.target, r) @@ -569,9 +576,9 @@ def to_basic_gates(self): class SWAP(CZ): name = 'SWAP' - quippername = 'undefined' qasm_name = 'swap' qc_name = 'undefined' + quipper_name = 'undefined' def to_basic_gates(self): c1 = CNOT(self.control, self.target) c2 = CNOT(self.target, self.control) @@ -584,7 +591,7 @@ def to_graph(self, g, q_mapper, c_mapper): class CRZ(Gate): name = 'CRZ' qasm_name = 'crz' - quippername = 'undefined' + quipper_name = 'undefined' print_phase = True def __init__(self, control: int, target: int, phase: FractionLike) -> None: self.target = target @@ -612,7 +619,7 @@ def to_graph(self, g, q_mapper, c_mapper): class CHAD(Gate): name = 'CHAD' qasm_name = 'ch' - quippername = 'undefined' + quipper_name = 'undefined' def __init__(self, control: int, target: int) -> None: self.target = target @@ -783,9 +790,9 @@ def tcount(self): class CCZ(Gate): name = 'CCZ' - quippername = 'Z' qasm_name = 'ccz' qc_name = 'Z' + quipper_name = 'Z' def __init__(self, ctrl1: int, ctrl2: int, target: int): self.target = target self.ctrl1 = ctrl1 @@ -838,16 +845,16 @@ def to_graph(self, g, q_mapper, _c_mapper): q_mapper.set_next_row(self.ctrl2, r+1) def to_quipper(self): - s = 'QGate["{}"]({!s})'.format(self.quippername,self.target) + s = 'QGate["{}"]({!s})'.format(self.quipper_name,self.target) s += ' with controls=[+{!s},+{!s}]'.format(self.ctrl1,self.ctrl2) s += ' with nocontrol' return s class Tofolli(CCZ): name = 'Tof' - quippername = 'not' qasm_name = 'ccx' qc_name = 'Tof' + quipper_name = 'not' def __eq__(self, other: object) -> bool: if not isinstance(other, Tofolli): return False @@ -910,7 +917,7 @@ class Measurement(Gate): target: int result_bit: Optional[int] - quippername = 'measure' + quipper_name = 'measure' # This gate has special syntax in qasm: https://qiskit.github.io/openqasm/language/insts.html def __init__(self, target: int, result_bit: Optional[int]) -> None: