diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index eaf91e2a..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/OpenSquirrel.iml b/.idea/OpenSquirrel.iml deleted file mode 100644 index 5625493c..00000000 --- a/.idea/OpenSquirrel.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da..00000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 098984c5..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 58c5eb79..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index c8397c94..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/opensquirrel/squirrel_ir.py b/opensquirrel/squirrel_ir.py index 56c6ae4d..8cfbf0c1 100644 --- a/opensquirrel/squirrel_ir.py +++ b/opensquirrel/squirrel_ir.py @@ -8,7 +8,15 @@ import numpy as np -from opensquirrel.common import ATOL, X, Y, Z, normalize_angle, normalize_axis +from opensquirrel.common import ( + ATOL, + X, + Y, + Z, + normalize_angle, + normalize_axis, + are_matrices_equivalent_up_to_global_phase, +) class SquirrelIRVisitor(ABC): @@ -90,6 +98,11 @@ def __init__(self, generator, arguments): self.generator = generator self.arguments = arguments + def __eq__(self, other): + if not isinstance(other, Gate): + return False + return _compare_gate_classes(self, other) + @property def name(self) -> Optional[str]: return self.generator.__name__ if self.generator else "" @@ -171,13 +184,6 @@ def __init__(self, matrix: np.ndarray, operands: List[Qubit], generator=None, ar self.matrix = matrix self.operands = operands - def __eq__(self, other): - if not (isinstance(other, ControlledGate) or isinstance(other, MatrixGate)): - return False - if isinstance(other, ControlledGate): - return _compare_gate_classes(self, other) - return np.allclose(self.matrix, other.matrix) - def __repr__(self): return f"MatrixGate(qubits={self.operands}, matrix={self.matrix})" @@ -200,17 +206,6 @@ def __init__(self, control_qubit: Qubit, target_gate: Gate, generator=None, argu self.control_qubit = control_qubit self.target_gate = target_gate - def __eq__(self, other): - - if not (isinstance(other, ControlledGate) or isinstance(other, MatrixGate)): - return False - if isinstance(other, MatrixGate): - return _compare_gate_classes(self, other) - if self.control_qubit != other.control_qubit: - return False - - return self.target_gate == other.target_gate - def __repr__(self): return f"ControlledGate(control_qubit={self.control_qubit}, {self.target_gate})" @@ -225,7 +220,7 @@ def is_identity(self) -> bool: return self.target_gate.is_identity() -def _compare_gate_classes(g1: Union[ControlledGate, MatrixGate], g2: Union[ControlledGate, MatrixGate]) -> bool: +def _compare_gate_classes(g1: Gate, g2: Gate) -> bool: union_mapping = list(set(g1.get_qubit_operands()) | set(g2.get_qubit_operands())) @@ -234,7 +229,7 @@ def _compare_gate_classes(g1: Union[ControlledGate, MatrixGate], g2: Union[Contr matrix_g1 = get_matrix_after_qubit_remapping([g1], union_mapping) matrix_g2 = get_matrix_after_qubit_remapping([g2], union_mapping) - return np.allclose(matrix_g1, matrix_g2) + return are_matrices_equivalent_up_to_global_phase(matrix_g1, matrix_g2) def named_gate(gate_generator: Callable[..., Gate]) -> Callable[..., Gate]: diff --git a/test/test_squirrel_ir.py b/test/test_squirrel_ir.py index 05ab217d..1ad7b64d 100644 --- a/test/test_squirrel_ir.py +++ b/test/test_squirrel_ir.py @@ -80,3 +80,22 @@ def test_inverse_gate(self): ) self.assertTrue(inverted_matrix_gate == inverted_cnot_gate) + + def test_global_phase(self): + inverted_matrix_with_phase = MatrixGate( + np.array( + [ + [1j, 0, 0, 0], + [0, 0, 0, 1j], + [0, 0, 1j, 0], + [0, 1j, 0, 0], + ] + ), + operands=[Qubit(0), Qubit(1)], + ) + + inverted_cnot_gate = ControlledGate( + Qubit(1), BlochSphereRotation(qubit=Qubit(0), axis=(1, 0, 0), angle=math.pi, phase=math.pi / 2) + ) + + self.assertTrue(inverted_matrix_with_phase == inverted_cnot_gate)