From 9596c7067e35e700febabd77624c19f9775b2172 Mon Sep 17 00:00:00 2001 From: vtomole Date: Tue, 19 Apr 2022 17:44:13 -0500 Subject: [PATCH 01/10] Gate features --- cirq-core/cirq/ops/gate_features.py | 15 ++++++++++++++- cirq-core/cirq/ops/gate_features_test.py | 21 ++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/ops/gate_features.py b/cirq-core/cirq/ops/gate_features.py index 70c3150bf6d..130329322de 100644 --- a/cirq-core/cirq/ops/gate_features.py +++ b/cirq-core/cirq/ops/gate_features.py @@ -18,7 +18,10 @@ """ import abc +import warnings +from cirq import value +from cirq._compat import deprecated_class from cirq.ops import raw_types @@ -30,7 +33,17 @@ def qubit_index_to_equivalence_group_key(self, index: int) -> int: return 0 -class SingleQubitGate(raw_types.Gate, metaclass=abc.ABCMeta): +class _SingleQubitGateMeta(value.ABCMetaImplementAnyOneOf): + def __instancecheck__(cls, instance): + warnings.warn( + 'isinstance(gate, SingleQubitGate) is deprecated. Use cirq.num_qubits(gate) == 1 instead', + DeprecationWarning, + ) + return isinstance(instance, raw_types.Gate) and instance._num_qubits_() == 1 + + +@deprecated_class(deadline='v1.0', fix='Define _num_qubits_ manually.') +class SingleQubitGate(raw_types.Gate, metaclass=_SingleQubitGateMeta): """A gate that must be applied to exactly one qubit.""" def _num_qubits_(self) -> int: diff --git a/cirq-core/cirq/ops/gate_features_test.py b/cirq-core/cirq/ops/gate_features_test.py index cdc0c5aa250..acc2e7e5a27 100644 --- a/cirq-core/cirq/ops/gate_features_test.py +++ b/cirq-core/cirq/ops/gate_features_test.py @@ -15,14 +15,19 @@ import pytest import cirq +from cirq.testing import assert_deprecated def test_single_qubit_gate_validate_args(): - class Dummy(cirq.SingleQubitGate): + class Dummy(cirq.Gate): def matrix(self): pass - g = Dummy() + with assert_deprecated(deadline="v1.0"): + g = Dummy() + + with assert_deprecated(deadline="isinstance(gate, SingleQubitGate) is deprecated"): + assert isinstance(g, cirq.Gate) q1 = cirq.NamedQubit('q1') q2 = cirq.NamedQubit('q2') @@ -36,10 +41,13 @@ def matrix(self): def test_single_qubit_gate_validates_on_each(): - class Dummy(cirq.SingleQubitGate): + class Dummy(cirq.Gate): def matrix(self): pass + def _num_qubits_(self) -> int: + return 1 + g = Dummy() assert g.num_qubits() == 1 @@ -56,10 +64,13 @@ def matrix(self): def test_single_qubit_validates_on(): - class Dummy(cirq.SingleQubitGate): + class Dummy(cirq.Gate): def matrix(self): pass + def _num_qubits_(self) -> int: + return 1 + g = Dummy() assert g.num_qubits() == 1 @@ -108,7 +119,7 @@ def test_qasm_output_args_format(): def test_multi_qubit_gate_validate(): class Dummy(cirq.Gate): - def num_qubits(self) -> int: + def _num_qubits_(self) -> int: return self._num_qubits def __init__(self, num_qubits): From e1ef5b53f6a78f17b7d35f79f095edf25494965a Mon Sep 17 00:00:00 2001 From: vtomole Date: Tue, 19 Apr 2022 18:32:23 -0500 Subject: [PATCH 02/10] Pass parser test --- cirq-core/cirq/circuits/qasm_output.py | 5 +++-- .../cirq/contrib/qasm_import/_parser_test.py | 4 ++-- .../contrib/quirk/export_to_quirk_test.py | 10 ++++++---- cirq-core/cirq/devices/noise_model.py | 2 +- .../cirq/interop/quirk/cells/control_cells.py | 6 +++--- .../cirq/ion/convert_to_ion_gates_test.py | 9 ++++++--- cirq-core/cirq/ion/ion_device_test.py | 2 +- .../convert_to_neutral_atom_gates_test.py | 8 ++++++-- cirq-core/cirq/ops/clifford_gate.py | 4 +++- cirq-core/cirq/ops/common_gates.py | 20 +++++++++++++++---- cirq-core/cirq/ops/common_gates_test.py | 10 ++++++---- cirq-core/cirq/ops/phased_x_gate.py | 7 +++++-- cirq-core/cirq/ops/phased_x_z_gate.py | 6 ++++-- .../optimizers/convert_to_xmon_gates_test.py | 13 ++++++++---- 14 files changed, 71 insertions(+), 35 deletions(-) diff --git a/cirq-core/cirq/circuits/qasm_output.py b/cirq-core/cirq/circuits/qasm_output.py index 25540ad167a..3b5a2426f97 100644 --- a/cirq-core/cirq/circuits/qasm_output.py +++ b/cirq-core/cirq/circuits/qasm_output.py @@ -26,7 +26,7 @@ @value.value_equality(approximate=True) -class QasmUGate(ops.SingleQubitGate): +class QasmUGate(ops.Gate): def __init__(self, theta, phi, lmda) -> None: """A QASM gate representing any single qubit unitary with a series of three rotations, Z, Y, and Z. @@ -41,7 +41,8 @@ def __init__(self, theta, phi, lmda) -> None: self.lmda = lmda % 2 self.theta = theta % 2 self.phi = phi % 2 - + def _num_qubits_(self) -> int: + return 1 @staticmethod def from_matrix(mat: np.ndarray) -> 'QasmUGate': pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 451e30da4c0..ddd71ce9220 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -429,7 +429,7 @@ def test_unknown_function(): @pytest.mark.parametrize('qasm_gate,cirq_gate', rotation_gates) -def test_rotation_gates(qasm_gate: str, cirq_gate: cirq.SingleQubitGate): +def test_rotation_gates(qasm_gate: str, cirq_gate: cirq.Gate): qasm = """OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; @@ -989,7 +989,7 @@ def test_three_qubit_gates_with_too_much_parameters(qasm_gate: str): @pytest.mark.parametrize('qasm_gate,cirq_gate', single_qubit_gates) -def test_single_qubit_gates(qasm_gate: str, cirq_gate: cirq.SingleQubitGate): +def test_single_qubit_gates(qasm_gate: str, cirq_gate: cirq.Gate): qasm = """OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; diff --git a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py index 49d18f75297..a2961088530 100644 --- a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py +++ b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py @@ -177,8 +177,9 @@ def with_qubits(self, *new_qubits): return MysteryOperation(*new_qubits) -class MysteryGate(cirq.SingleQubitGate): - pass +class MysteryGate(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 def test_various_unknown_gate_types(): @@ -279,8 +280,9 @@ def test_unrecognized_single_qubit_gate_with_matrix(): def test_unknown_gate(): - class UnknownGate(cirq.SingleQubitGate): - pass + class UnknownGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 a = cirq.NamedQubit('a') circuit = cirq.Circuit(UnknownGate()(a)) diff --git a/cirq-core/cirq/devices/noise_model.py b/cirq-core/cirq/devices/noise_model.py index b30ded1ab5d..8300cde7003 100644 --- a/cirq-core/cirq/devices/noise_model.py +++ b/cirq-core/cirq/devices/noise_model.py @@ -264,7 +264,7 @@ def noisy_moment( """, ) -NOISE_MODEL_LIKE = Union[None, 'cirq.NoiseModel', 'cirq.SingleQubitGate'] +NOISE_MODEL_LIKE = Union[None, 'cirq.NoiseModel', 'cirq.Gate'] document( NOISE_MODEL_LIKE, # type: ignore """A `cirq.NoiseModel` or a value that can be trivially converted into one. diff --git a/cirq-core/cirq/interop/quirk/cells/control_cells.py b/cirq-core/cirq/interop/quirk/cells/control_cells.py index dc0d8b85198..3bc23e210c3 100644 --- a/cirq-core/cirq/interop/quirk/cells/control_cells.py +++ b/cirq-core/cirq/interop/quirk/cells/control_cells.py @@ -132,7 +132,7 @@ def generate_all_control_cell_makers() -> Iterator[CellMaker]: yield _reg_parity_control("zpar", basis_change=None) -def _reg_control(identifier: str, *, basis_change: Optional['cirq.SingleQubitGate']) -> CellMaker: +def _reg_control(identifier: str, *, basis_change: Optional['cirq.Gate']) -> CellMaker: return CellMaker( identifier=identifier, size=1, @@ -143,7 +143,7 @@ def _reg_control(identifier: str, *, basis_change: Optional['cirq.SingleQubitGat def _reg_parity_control( - identifier: str, *, basis_change: Optional['cirq.SingleQubitGate'] = None + identifier: str, *, basis_change: Optional['cirq.Gate'] = None ) -> CellMaker: return CellMaker( identifier=identifier, @@ -155,7 +155,7 @@ def _reg_parity_control( def _basis_else_empty( - basis_change: Optional['cirq.SingleQubitGate'], qureg: Union['cirq.Qid', Iterable['cirq.Qid']] + basis_change: Optional['cirq.Gate'], qureg: Union['cirq.Qid', Iterable['cirq.Qid']] ) -> Iterable['cirq.Operation']: if basis_change is None: return () diff --git a/cirq-core/cirq/ion/convert_to_ion_gates_test.py b/cirq-core/cirq/ion/convert_to_ion_gates_test.py index 40970638e11..1968c685400 100644 --- a/cirq-core/cirq/ion/convert_to_ion_gates_test.py +++ b/cirq-core/cirq/ion/convert_to_ion_gates_test.py @@ -19,13 +19,16 @@ import cirq -class OtherX(cirq.SingleQubitGate): +class OtherX(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) -class NoUnitary(cirq.SingleQubitGate): - pass +class NoUnitary(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 class OtherCNOT(cirq.testing.TwoQubitGate): diff --git a/cirq-core/cirq/ion/ion_device_test.py b/cirq-core/cirq/ion/ion_device_test.py index eec92851b6d..2191dfc4673 100644 --- a/cirq-core/cirq/ion/ion_device_test.py +++ b/cirq-core/cirq/ion/ion_device_test.py @@ -54,7 +54,7 @@ def test_init(): assert d.duration_of(cirq.measure(q0, q1)) == 100 * ms assert d.duration_of(cirq.ops.XX(q0, q1)) == 200 * ms with pytest.raises(ValueError): - _ = d.duration_of(cirq.SingleQubitGate().on(q0)) + _ = d.duration_of(cirq.PauliX().on(q0)) with pytest.raises(TypeError, match="NamedQubit"): _ = cirq.IonDevice( diff --git a/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py b/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py index 2e132535647..d4a4cff7b28 100644 --- a/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +++ b/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py @@ -50,11 +50,15 @@ def with_qubits(self, *new_qubits): def test_avoids_decompose_fallback_when_matrix_available_single_qubit(): - class OtherX(cirq.SingleQubitGate): + class OtherX(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) - class OtherOtherX(cirq.SingleQubitGate): + class OtherOtherX(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 def _decompose_(self, qubits): return OtherX().on(*qubits) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index 5d9af227a0c..e6e01b021b9 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -133,7 +133,7 @@ def _validate_map_input( @value.value_equality -class SingleQubitCliffordGate(gate_features.SingleQubitGate): +class SingleQubitCliffordGate(raw_types.Gate): """Any single qubit Clifford rotation.""" I = _pretend_initialized() @@ -151,6 +151,8 @@ class SingleQubitCliffordGate(gate_features.SingleQubitGate): def __init__(self, *, _clifford_tableau: qis.CliffordTableau) -> None: self._clifford_tableau = _clifford_tableau + def _num_qubits_(self) -> int: + return 1 @property def clifford_tableau(self): return self._clifford_tableau diff --git a/cirq-core/cirq/ops/common_gates.py b/cirq-core/cirq/ops/common_gates.py index 0721b3d579e..d2f6d830f02 100644 --- a/cirq-core/cirq/ops/common_gates.py +++ b/cirq-core/cirq/ops/common_gates.py @@ -67,7 +67,7 @@ def _pi(rads): @value.value_equality -class XPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): +class XPowGate(eigen_gate.EigenGate): """A gate that rotates around the X axis of the Bloch sphere. The unitary matrix of ``XPowGate(exponent=t)`` is: @@ -90,6 +90,9 @@ class XPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): `cirq.X`, the Pauli X gate, is an instance of this gate at exponent=1. """ + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> Optional[np.ndarray]: if self._exponent != 1: return NotImplemented @@ -282,7 +285,7 @@ def _from_json_dict_(cls, rads, **kwargs) -> 'Rx': @value.value_equality -class YPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): +class YPowGate(eigen_gate.EigenGate): """A gate that rotates around the Y axis of the Bloch sphere. The unitary matrix of ``YPowGate(exponent=t)`` is: @@ -305,6 +308,9 @@ class YPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): `cirq.Y`, the Pauli Y gate, is an instance of this gate at exponent=1. """ + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> Optional[np.ndarray]: if self._exponent != 1: return NotImplemented @@ -450,7 +456,7 @@ def _from_json_dict_(cls, rads, **kwargs) -> 'Ry': @value.value_equality -class ZPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): +class ZPowGate(eigen_gate.EigenGate): """A gate that rotates around the Z axis of the Bloch sphere. The unitary matrix of ``ZPowGate(exponent=t)`` is: @@ -471,6 +477,9 @@ class ZPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): `cirq.Z`, the Pauli Z gate, is an instance of this gate at exponent=1. """ + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> Optional[np.ndarray]: if protocols.is_parameterized(self): return None @@ -688,7 +697,7 @@ def _from_json_dict_(cls, rads, **kwargs) -> 'Rz': return cls(rads=rads) -class HPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): +class HPowGate(eigen_gate.EigenGate): """A Gate that performs a rotation around the X+Z axis of the Bloch sphere. The unitary matrix of ``HPowGate(exponent=t)`` is: @@ -716,6 +725,9 @@ def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: return [(0, component0), (1, component1)] + def _num_qubits_(self) -> int: + return 1 + def _trace_distance_bound_(self) -> Optional[float]: if self._is_parameterized_(): return None diff --git a/cirq-core/cirq/ops/common_gates_test.py b/cirq-core/cirq/ops/common_gates_test.py index 803fa43e17d..43f44024b77 100644 --- a/cirq-core/cirq/ops/common_gates_test.py +++ b/cirq-core/cirq/ops/common_gates_test.py @@ -322,16 +322,18 @@ def test_x_act_on_tableau(): cirq.act_on(cirq.X**foo, args, [cirq.LineQubit(1)]) -class iZGate(cirq.SingleQubitGate): +class iZGate(cirq.Gate): """Equivalent to an iZ gate without _act_on_ defined on it.""" - + def _num_qubits_(self) -> int: + return 1 def _unitary_(self): return np.array([[1j, 0], [0, -1j]]) -class MinusOnePhaseGate(cirq.SingleQubitGate): +class MinusOnePhaseGate(cirq.Gate): """Equivalent to a -1 global phase without _act_on_ defined on it.""" - + def _num_qubits_(self) -> int: + return 1 def _unitary_(self): return np.array([[-1, 0], [0, -1]]) diff --git a/cirq-core/cirq/ops/phased_x_gate.py b/cirq-core/cirq/ops/phased_x_gate.py index ef17dfb583c..fa6723793a0 100644 --- a/cirq-core/cirq/ops/phased_x_gate.py +++ b/cirq-core/cirq/ops/phased_x_gate.py @@ -21,12 +21,12 @@ import cirq from cirq import value, protocols from cirq._compat import proper_repr -from cirq.ops import gate_features, common_gates +from cirq.ops import common_gates, raw_types from cirq.type_workarounds import NotImplementedType @value.value_equality(manual_cls=True, approximate=True) -class PhasedXPowGate(gate_features.SingleQubitGate): +class PhasedXPowGate(raw_types.Gate): """A gate equivalent to the circuit ───Z^-p───X^t───Z^p───.""" def __init__( @@ -124,6 +124,9 @@ def _unitary_(self) -> Union[np.ndarray, NotImplementedType]: p = np.exp(1j * np.pi * self._global_shift * self._exponent) return np.dot(np.dot(z, x), np.conj(z)) * p + def _num_qubits_(self) -> int: + return 1 + def _pauli_expansion_(self) -> value.LinearDict[str]: if self._is_parameterized_(): return NotImplemented diff --git a/cirq-core/cirq/ops/phased_x_z_gate.py b/cirq-core/cirq/ops/phased_x_z_gate.py index 053e3bffddb..7024fc7e606 100644 --- a/cirq-core/cirq/ops/phased_x_z_gate.py +++ b/cirq-core/cirq/ops/phased_x_z_gate.py @@ -6,7 +6,7 @@ import sympy from cirq import value, ops, protocols, linalg -from cirq.ops import gate_features +from cirq.ops import raw_types from cirq._compat import proper_repr if TYPE_CHECKING: @@ -14,7 +14,7 @@ @value.value_equality(approximate=True) -class PhasedXZGate(gate_features.SingleQubitGate): +class PhasedXZGate(raw_types.Gate): """A single qubit operation expressed as $Z^z Z^a X^x Z^{-a}$. The above expression is a matrix multiplication with time going to the left. @@ -138,6 +138,8 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio ) return protocols.qasm(qasm_gate, args=args, qubits=qubits) + def _num_qubits_(self) -> int: + return 1 def _has_unitary_(self) -> bool: return not self._is_parameterized_() diff --git a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py index 9a6477ed430..c3a9c271527 100644 --- a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py +++ b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py @@ -18,7 +18,9 @@ import cirq_google -class OtherX(cirq.SingleQubitGate): +class OtherX(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) @@ -28,13 +30,16 @@ def _decompose_(self, qubits): return OtherOtherX().on(*qubits) # coverage:ignore -class OtherOtherX(cirq.SingleQubitGate): +class OtherOtherX(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 def _decompose_(self, qubits): return OtherX().on(*qubits) -class NonNativeGate(cirq.SingleQubitGate): - pass +class NonNativeGate(cirq.Gate): + def _num_qubits_(self)-> int: + return 1 def test_avoids_infinite_cycle_when_matrix_available(): From d62b3bb9519985b89605a16613815291822dba94 Mon Sep 17 00:00:00 2001 From: vtomole Date: Tue, 19 Apr 2022 20:54:45 -0500 Subject: [PATCH 03/10] Two coverage left --- cirq-core/cirq/circuits/circuit_test.py | 16 ++++----- cirq-core/cirq/circuits/moment_test.py | 10 ++---- cirq-core/cirq/circuits/qasm_output.py | 2 ++ cirq-core/cirq/circuits/quil_output.py | 5 ++- .../contrib/quirk/export_to_quirk_test.py | 7 ++-- .../experiments/cross_entropy_benchmarking.py | 6 ++-- .../cirq/ion/convert_to_ion_gates_test.py | 5 +-- cirq-core/cirq/ion/ion_device_test.py | 4 +-- .../convert_to_neutral_atom_gates_test.py | 8 ++--- .../neutral_atom_devices_test.py | 6 ++-- cirq-core/cirq/ops/clifford_gate.py | 11 ++---- cirq-core/cirq/ops/common_channels.py | 34 ++++++++++++++----- cirq-core/cirq/ops/common_channels_test.py | 2 ++ .../cirq/ops/common_gate_families_test.py | 4 +-- cirq-core/cirq/ops/common_gates_test.py | 4 +++ cirq-core/cirq/ops/controlled_gate_test.py | 21 ++++++++---- .../cirq/ops/controlled_operation_test.py | 14 +++++--- cirq-core/cirq/ops/eigen_gate_test.py | 4 +-- cirq-core/cirq/ops/gate_features.py | 3 +- cirq-core/cirq/ops/gate_features_test.py | 4 +-- cirq-core/cirq/ops/gate_operation_test.py | 23 +++++++------ cirq-core/cirq/ops/gateset_test.py | 2 +- cirq-core/cirq/ops/identity_test.py | 5 +-- cirq-core/cirq/ops/op_tree_test.py | 14 +++++--- cirq-core/cirq/ops/parallel_gate_test.py | 28 ++++++++++----- cirq-core/cirq/ops/pauli_string_test.py | 5 +-- cirq-core/cirq/ops/phased_x_z_gate.py | 1 + cirq-core/cirq/ops/raw_types_test.py | 4 +-- .../convert_to_cz_and_single_gates_test.py | 5 ++- cirq-core/cirq/optimizers/eject_z_test.py | 5 +-- .../cirq/optimizers/expand_composite_test.py | 5 ++- .../merge_single_qubit_gates_test.py | 5 +-- .../protocols/apply_unitary_protocol_test.py | 4 +-- .../has_stabilizer_effect_protocol_test.py | 2 +- .../protocols/has_unitary_protocol_test.py | 4 +-- .../cirq/protocols/kraus_protocol_test.py | 8 ++--- .../act_on_clifford_tableau_args_test.py | 7 ++-- .../act_on_stabilizer_ch_form_args_test.py | 4 +-- cirq-core/cirq/sim/sparse_simulator_test.py | 8 ++--- cirq-core/cirq/testing/__init__.py | 2 +- .../cirq/testing/consistent_act_on_test.py | 10 ++++-- .../consistent_controlled_gate_op_test.py | 4 +-- .../testing/consistent_decomposition_test.py | 17 +++++++--- .../consistent_pauli_expansion_test.py | 8 ++--- .../cirq/testing/consistent_protocols_test.py | 10 ++++-- cirq-core/cirq/testing/gate_features.py | 7 ++++ .../single_qubit_decompositions.py | 4 +-- .../single_qubit_decompositions_test.py | 2 +- cirq-core/cirq/transformers/eject_z_test.py | 2 +- .../transformers/expand_composite_test.py | 2 +- .../transformers/merge_k_qubit_gates_test.py | 5 ++- .../target_gatesets/cz_gateset_test.py | 2 +- .../calibration/engine_simulator.py | 10 ++++-- .../cirq_google/calibration/workflow.py | 6 ++-- .../cirq_google/devices/known_devices.py | 11 +++--- .../cirq_google/devices/xmon_device_test.py | 2 +- .../optimizers/convert_to_xmon_gates_test.py | 8 +++-- .../serialization/op_deserializer_test.py | 2 +- .../serialization/op_serializer_test.py | 6 ++-- cirq-web/cirq_web/circuits/symbols_test.py | 10 ++++-- examples/hhl.py | 6 ++-- 61 files changed, 272 insertions(+), 173 deletions(-) diff --git a/cirq-core/cirq/circuits/circuit_test.py b/cirq-core/cirq/circuits/circuit_test.py index eb24c353bce..00f326dd02c 100644 --- a/cirq-core/cirq/circuits/circuit_test.py +++ b/cirq-core/cirq/circuits/circuit_test.py @@ -1884,7 +1884,7 @@ def test_qid_shape_qubit(circuit_cls): @pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit]) def test_qid_shape_qudit(circuit_cls): - class PlusOneMod3Gate(cirq.SingleQubitGate): + class PlusOneMod3Gate(cirq.testing.SingleQubitGate): def _qid_shape_(self): return (3,) @@ -1892,7 +1892,7 @@ class C2NotGate(cirq.Gate): def _qid_shape_(self): return (3, 2) - class IdentityGate(cirq.SingleQubitGate): + class IdentityGate(cirq.testing.SingleQubitGate): def _qid_shape_(self): return (1,) @@ -1987,13 +1987,13 @@ def test_to_text_diagram_teleportation_to_diagram(circuit_cls): @pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit]) def test_diagram_with_unknown_exponent(circuit_cls): - class WeirdGate(cirq.SingleQubitGate): + class WeirdGate(cirq.testing.SingleQubitGate): def _circuit_diagram_info_( self, args: cirq.CircuitDiagramInfoArgs ) -> cirq.CircuitDiagramInfo: return cirq.CircuitDiagramInfo(wire_symbols=('B',), exponent='fancy') - class WeirderGate(cirq.SingleQubitGate): + class WeirderGate(cirq.testing.SingleQubitGate): def _circuit_diagram_info_( self, args: cirq.CircuitDiagramInfoArgs ) -> cirq.CircuitDiagramInfo: @@ -2103,7 +2103,7 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str def test_to_text_diagram_parameterized_value(circuit_cls): q = cirq.NamedQubit('cube') - class PGate(cirq.SingleQubitGate): + class PGate(cirq.testing.SingleQubitGate): def __init__(self, val): self.val = val @@ -2266,10 +2266,10 @@ def test_diagram_global_phase(circuit_cls): @pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit]) def test_has_unitary(circuit_cls): - class NonUnitary(cirq.SingleQubitGate): + class NonUnitary(cirq.testing.SingleQubitGate): pass - class EventualUnitary(cirq.SingleQubitGate): + class EventualUnitary(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return cirq.X.on_each(*qubits) @@ -4098,7 +4098,7 @@ def test_indexing_by_numpy_integer(circuit_cls): @pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit]) def test_all_measurement_key_names(circuit_cls): - class Unknown(cirq.SingleQubitGate): + class Unknown(cirq.testing.SingleQubitGate): def _measurement_key_name_(self): return 'test' diff --git a/cirq-core/cirq/circuits/moment_test.py b/cirq-core/cirq/circuits/moment_test.py index a62a42b15f6..9ce069057bb 100644 --- a/cirq-core/cirq/circuits/moment_test.py +++ b/cirq-core/cirq/circuits/moment_test.py @@ -574,10 +574,7 @@ def test_moment_text_diagram(): xy_breakdown_func=lambda q: ('abc'[q.x], q.x), ) - class EmptyGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - + class EmptyGate(cirq.testing.SingleQubitGate): def __str__(self): return 'Empty' @@ -701,9 +698,8 @@ def test_kraus_too_big(): def test_op_has_no_kraus(): - class EmptyGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class EmptyGate(cirq.testing.SingleQubitGate): + pass m = cirq.Moment(EmptyGate().on(cirq.NamedQubit("a"))) assert not cirq.has_kraus(m) diff --git a/cirq-core/cirq/circuits/qasm_output.py b/cirq-core/cirq/circuits/qasm_output.py index 3b5a2426f97..2d19138f47e 100644 --- a/cirq-core/cirq/circuits/qasm_output.py +++ b/cirq-core/cirq/circuits/qasm_output.py @@ -41,8 +41,10 @@ def __init__(self, theta, phi, lmda) -> None: self.lmda = lmda % 2 self.theta = theta % 2 self.phi = phi % 2 + def _num_qubits_(self) -> int: return 1 + @staticmethod def from_matrix(mat: np.ndarray) -> 'QasmUGate': pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat) diff --git a/cirq-core/cirq/circuits/quil_output.py b/cirq-core/cirq/circuits/quil_output.py index d28cc15f36b..1954ce2eb8e 100644 --- a/cirq-core/cirq/circuits/quil_output.py +++ b/cirq-core/cirq/circuits/quil_output.py @@ -25,7 +25,7 @@ def to_quil_complex_format(num) -> str: @value.value_equality(approximate=True) -class QuilOneQubitGate(ops.SingleQubitGate): +class QuilOneQubitGate(ops.Gate): """A QUIL gate representing any single qubit unitary with a DEFGATE and 2x2 matrix in QUIL. """ @@ -38,6 +38,9 @@ def __init__(self, matrix: np.ndarray) -> None: """ self.matrix = matrix + def _num_qubits_(self) -> int: + return 1 + def _quil_(self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter') -> str: return ( f'DEFGATE USERGATE:\n ' diff --git a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py index a2961088530..176cc7a0665 100644 --- a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py +++ b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py @@ -178,7 +178,7 @@ def with_qubits(self, *new_qubits): class MysteryGate(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 @@ -280,9 +280,8 @@ def test_unrecognized_single_qubit_gate_with_matrix(): def test_unknown_gate(): - class UnknownGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class UnknownGate(cirq.testing.SingleQubitGate): + pass a = cirq.NamedQubit('a') circuit = cirq.Circuit(UnknownGate()(a)) diff --git a/cirq-core/cirq/experiments/cross_entropy_benchmarking.py b/cirq-core/cirq/experiments/cross_entropy_benchmarking.py index 2d6855ccc90..5c4a2060541 100644 --- a/cirq-core/cirq/experiments/cross_entropy_benchmarking.py +++ b/cirq-core/cirq/experiments/cross_entropy_benchmarking.py @@ -284,7 +284,7 @@ def cross_entropy_benchmarking( num_circuits: int = 20, repetitions: int = 1000, cycles: Union[int, Iterable[int]] = range(2, 103, 10), - scrambling_gates_per_cycle: List[List[ops.SingleQubitGate]] = None, + scrambling_gates_per_cycle: List[List[ops.Gate]] = None, simulator: sim.Simulator = None, ) -> CrossEntropyResult: r"""Cross-entropy benchmarking (XEB) of multiple qubits. @@ -482,7 +482,7 @@ def build_entangling_layers( def _build_xeb_circuits( qubits: Sequence[ops.Qid], cycles: Sequence[int], - single_qubit_gates: List[List[ops.SingleQubitGate]] = None, + single_qubit_gates: List[List[ops.Gate]] = None, benchmark_ops: Sequence[circuits.Moment] = None, ) -> List[circuits.Circuit]: if benchmark_ops is not None: @@ -570,7 +570,7 @@ def _random_half_rotations(qubits: Sequence[ops.Qid], num_layers: int) -> List[L def _random_any_gates( - qubits: Sequence[ops.Qid], op_list: List[List[ops.SingleQubitGate]], num_layers: int + qubits: Sequence[ops.Qid], op_list: List[List[ops.Gate]], num_layers: int ) -> List[List[ops.OP_TREE]]: num_ops = len(op_list) num_qubits = len(qubits) diff --git a/cirq-core/cirq/ion/convert_to_ion_gates_test.py b/cirq-core/cirq/ion/convert_to_ion_gates_test.py index 1968c685400..ac38bda68f5 100644 --- a/cirq-core/cirq/ion/convert_to_ion_gates_test.py +++ b/cirq-core/cirq/ion/convert_to_ion_gates_test.py @@ -20,14 +20,15 @@ class OtherX(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 + def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) class NoUnitary(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 diff --git a/cirq-core/cirq/ion/ion_device_test.py b/cirq-core/cirq/ion/ion_device_test.py index 2191dfc4673..6d577633e46 100644 --- a/cirq-core/cirq/ion/ion_device_test.py +++ b/cirq-core/cirq/ion/ion_device_test.py @@ -54,7 +54,7 @@ def test_init(): assert d.duration_of(cirq.measure(q0, q1)) == 100 * ms assert d.duration_of(cirq.ops.XX(q0, q1)) == 200 * ms with pytest.raises(ValueError): - _ = d.duration_of(cirq.PauliX().on(q0)) + _ = d.duration_of(cirq.ISWAP(q0)) with pytest.raises(TypeError, match="NamedQubit"): _ = cirq.IonDevice( @@ -86,7 +86,7 @@ def test_init_timedelta(): assert d.duration_of(cirq.measure(q0, q1)) == 100 * ms assert d.duration_of(cirq.ops.XX(q0, q1)) == 200 * ms with pytest.raises(ValueError): - _ = d.duration_of(cirq.SingleQubitGate().on(q0)) + _ = d.duration_of(cirq.testing.SingleQubitGate().on(q0)) def test_decomposition_deprecated(): diff --git a/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py b/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py index d4a4cff7b28..ae88e2d9656 100644 --- a/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +++ b/cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py @@ -50,15 +50,11 @@ def with_qubits(self, *new_qubits): def test_avoids_decompose_fallback_when_matrix_available_single_qubit(): - class OtherX(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class OtherX(cirq.testing.SingleQubitGate): def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) - class OtherOtherX(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class OtherOtherX(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return OtherX().on(*qubits) diff --git a/cirq-core/cirq/neutral_atoms/neutral_atom_devices_test.py b/cirq-core/cirq/neutral_atoms/neutral_atom_devices_test.py index fc8e37e427a..0561931ca16 100644 --- a/cirq-core/cirq/neutral_atoms/neutral_atom_devices_test.py +++ b/cirq-core/cirq/neutral_atoms/neutral_atom_devices_test.py @@ -53,7 +53,7 @@ def test_init(): assert d.duration_of(cirq.GateOperation(cirq.IdentityGate(1), [q00])) == 100 * us assert d.duration_of(cirq.measure(q00)) == 50 * ms with pytest.raises(ValueError): - _ = d.duration_of(cirq.SingleQubitGate().on(q00)) + _ = d.duration_of(cirq.testing.SingleQubitGate().on(q00)) def test_metadata(): @@ -83,7 +83,7 @@ def test_init_timedelta(): assert d.duration_of(cirq.GateOperation(cirq.IdentityGate(1), [q00])) == 100 * us assert d.duration_of(cirq.measure(q00)) == 50 * ms with pytest.raises(ValueError): - _ = d.duration_of(cirq.SingleQubitGate().on(q00)) + _ = d.duration_of(cirq.testing.SingleQubitGate().on(q00)) def test_init_errors(): @@ -126,7 +126,7 @@ def test_validate_gate_errors(): with pytest.raises(ValueError, match="controlled gates must have integer exponents"): d.validate_gate(cirq.CNotPowGate(exponent=0.5)) with pytest.raises(ValueError, match="Unsupported gate"): - d.validate_gate(cirq.SingleQubitGate()) + d.validate_gate(cirq.testing.SingleQubitGate()) def test_validate_operation_errors(): diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index e6e01b021b9..46f92c6a0e6 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -30,15 +30,7 @@ from cirq import protocols, value, linalg, qis from cirq._doc import document from cirq._import import LazyLoader -from cirq.ops import ( - common_gates, - gate_features, - identity, - named_qubit, - raw_types, - pauli_gates, - phased_x_z_gate, -) +from cirq.ops import common_gates, identity, named_qubit, raw_types, pauli_gates, phased_x_z_gate from cirq.ops.pauli_gates import Pauli from cirq.type_workarounds import NotImplementedType @@ -153,6 +145,7 @@ def __init__(self, *, _clifford_tableau: qis.CliffordTableau) -> None: def _num_qubits_(self) -> int: return 1 + @property def clifford_tableau(self): return self._clifford_tableau diff --git a/cirq-core/cirq/ops/common_channels.py b/cirq-core/cirq/ops/common_channels.py index 8b5ec1c5bc2..87eda95424b 100644 --- a/cirq-core/cirq/ops/common_channels.py +++ b/cirq-core/cirq/ops/common_channels.py @@ -20,7 +20,7 @@ import numpy as np from cirq import protocols, value -from cirq.ops import raw_types, common_gates, pauli_gates, gate_features, identity +from cirq.ops import raw_types, common_gates, pauli_gates, identity if TYPE_CHECKING: @@ -28,7 +28,7 @@ @value.value_equality -class AsymmetricDepolarizingChannel(gate_features.SingleQubitGate): +class AsymmetricDepolarizingChannel(raw_types.Gate): """A channel that depolarizes asymmetrically along different directions.""" def __init__( @@ -380,7 +380,7 @@ def depolarize(p: float, n_qubits: int = 1) -> DepolarizingChannel: @value.value_equality -class GeneralizedAmplitudeDampingChannel(gate_features.SingleQubitGate): +class GeneralizedAmplitudeDampingChannel(raw_types.Gate): """Dampen qubit amplitudes through non ideal dissipation. This channel models the effect of energy dissipation into the environment @@ -444,6 +444,9 @@ def __init__(self, p: float, gamma: float) -> None: self._p = value.validate_probability(p, 'p') self._gamma = value.validate_probability(gamma, 'gamma') + def _num_qubits_(self) -> int: + return 1 + def _kraus_(self) -> Iterable[np.ndarray]: p0 = np.sqrt(self._p) p1 = np.sqrt(1.0 - self._p) @@ -541,7 +544,7 @@ def generalized_amplitude_damp(p: float, gamma: float) -> GeneralizedAmplitudeDa @value.value_equality -class AmplitudeDampingChannel(gate_features.SingleQubitGate): +class AmplitudeDampingChannel(raw_types.Gate): """Dampen qubit amplitudes through dissipation. This channel models the effect of energy dissipation to the @@ -585,6 +588,9 @@ def __init__(self, gamma: float) -> None: self._gamma = value.validate_probability(gamma, 'gamma') self._delegate = GeneralizedAmplitudeDampingChannel(1.0, self._gamma) + def _num_qubits_(self) -> int: + return 1 + def _kraus_(self) -> Iterable[np.ndarray]: # just return first two kraus ops, we don't care about # the last two. @@ -655,7 +661,7 @@ def amplitude_damp(gamma: float) -> AmplitudeDampingChannel: @value.value_equality -class ResetChannel(gate_features.SingleQubitGate): +class ResetChannel(raw_types.Gate): """Reset a qubit back to its |0⟩ state. The reset channel is equivalent to performing an unobserved measurement @@ -697,6 +703,9 @@ def __init__(self, dimension: int = 2) -> None: """ self._dimension = dimension + def _num_qubits_(self) -> int: + return 1 + def _has_stabilizer_effect_(self) -> Optional[bool]: return True @@ -782,7 +791,7 @@ def reset_each(*qubits: 'cirq.Qid') -> List[raw_types.Operation]: @value.value_equality -class PhaseDampingChannel(gate_features.SingleQubitGate): +class PhaseDampingChannel(raw_types.Gate): """Dampen qubit phase. This channel models phase damping which is the loss of quantum @@ -824,6 +833,9 @@ def __init__(self, gamma: float) -> None: """ self._gamma = value.validate_probability(gamma, 'gamma') + def _num_qubits_(self) -> int: + return 1 + def _kraus_(self) -> Iterable[np.ndarray]: return ( np.array([[1.0, 0.0], [0.0, np.sqrt(1.0 - self._gamma)]]), @@ -895,7 +907,7 @@ def phase_damp(gamma: float) -> PhaseDampingChannel: @value.value_equality -class PhaseFlipChannel(gate_features.SingleQubitGate): +class PhaseFlipChannel(raw_types.Gate): """Probabilistically flip the sign of the phase of a qubit.""" def __init__(self, p: float) -> None: @@ -934,6 +946,9 @@ def __init__(self, p: float) -> None: self._p = value.validate_probability(p, 'p') self._delegate = AsymmetricDepolarizingChannel(0.0, 0.0, p) + def _num_qubits_(self) -> int: + return 1 + def _mixture_(self) -> Sequence[Tuple[float, np.ndarray]]: mixture = self._delegate._mixture_() # just return identity and z term @@ -1048,7 +1063,7 @@ def phase_flip(p: Optional[float] = None) -> Union[common_gates.ZPowGate, PhaseF @value.value_equality -class BitFlipChannel(gate_features.SingleQubitGate): +class BitFlipChannel(raw_types.Gate): r"""Probabilistically flip a qubit from 1 to 0 state or vice versa.""" def __init__(self, p: float) -> None: @@ -1087,6 +1102,9 @@ def __init__(self, p: float) -> None: self._p = value.validate_probability(p, 'p') self._delegate = AsymmetricDepolarizingChannel(p, 0.0, 0.0) + def _num_qubits_(self) -> int: + return 1 + def _mixture_(self) -> Sequence[Tuple[float, np.ndarray]]: mixture = self._delegate._mixture_() # just return identity and x term diff --git a/cirq-core/cirq/ops/common_channels_test.py b/cirq-core/cirq/ops/common_channels_test.py index e3090beb7fb..0f87a522843 100644 --- a/cirq-core/cirq/ops/common_channels_test.py +++ b/cirq-core/cirq/ops/common_channels_test.py @@ -443,6 +443,8 @@ def test_reset_channel(): np.testing.assert_almost_equal( cirq.kraus(r), (np.array([[1.0, 0.0], [0.0, 0]]), np.array([[0.0, 1.0], [0.0, 0.0]])) ) + + assert cirq.num_qubits(r) == 1 assert cirq.has_kraus(r) assert not cirq.has_mixture(r) assert cirq.qid_shape(r) == (2,) diff --git a/cirq-core/cirq/ops/common_gate_families_test.py b/cirq-core/cirq/ops/common_gate_families_test.py index 5c2a25a72c4..06585285df2 100644 --- a/cirq-core/cirq/ops/common_gate_families_test.py +++ b/cirq-core/cirq/ops/common_gate_families_test.py @@ -51,12 +51,12 @@ def test_any_unitary_gate_family(): assert 'Any-Qubit' in gate_family.name assert 'any unitary' in gate_family.description - assert cirq.SingleQubitGate() not in cirq.AnyUnitaryGateFamily() + assert cirq.testing.SingleQubitGate() not in cirq.AnyUnitaryGateFamily() def test_any_integer_power_gate_family(): with pytest.raises(ValueError, match='subclass of `cirq.EigenGate`'): - cirq.AnyIntegerPowerGateFamily(gate=cirq.SingleQubitGate) + cirq.AnyIntegerPowerGateFamily(gate=cirq.testing.SingleQubitGate) with pytest.raises(ValueError, match='subclass of `cirq.EigenGate`'): cirq.AnyIntegerPowerGateFamily(gate=CustomXPowGate()) eq = cirq.testing.EqualsTester() diff --git a/cirq-core/cirq/ops/common_gates_test.py b/cirq-core/cirq/ops/common_gates_test.py index 43f44024b77..31f7fa8eb14 100644 --- a/cirq-core/cirq/ops/common_gates_test.py +++ b/cirq-core/cirq/ops/common_gates_test.py @@ -324,16 +324,20 @@ def test_x_act_on_tableau(): class iZGate(cirq.Gate): """Equivalent to an iZ gate without _act_on_ defined on it.""" + def _num_qubits_(self) -> int: return 1 + def _unitary_(self): return np.array([[1j, 0], [0, -1j]]) class MinusOnePhaseGate(cirq.Gate): """Equivalent to a -1 global phase without _act_on_ defined on it.""" + def _num_qubits_(self) -> int: return 1 + def _unitary_(self): return np.array([[-1, 0], [0, -1]]) diff --git a/cirq-core/cirq/ops/controlled_gate_test.py b/cirq-core/cirq/ops/controlled_gate_test.py index d436c6f01a4..370242fb5ee 100644 --- a/cirq-core/cirq/ops/controlled_gate_test.py +++ b/cirq-core/cirq/ops/controlled_gate_test.py @@ -22,7 +22,10 @@ from cirq.type_workarounds import NotImplementedType -class GateUsingWorkspaceForApplyUnitary(cirq.SingleQubitGate): +class GateUsingWorkspaceForApplyUnitary(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: args.available_buffer[...] = args.target_tensor args.target_tensor[...] = 0 @@ -38,10 +41,13 @@ def __repr__(self): return 'cirq.ops.controlled_gate_test.GateUsingWorkspaceForApplyUnitary()' -class GateAllocatingNewSpaceForResult(cirq.SingleQubitGate): +class GateAllocatingNewSpaceForResult(cirq.Gate): def __init__(self): self._matrix = cirq.testing.random_unitary(2, random_state=4321) + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: assert len(args.axes) == 1 a = args.axes[0] @@ -69,7 +75,10 @@ def __repr__(self): return 'cirq.ops.controlled_gate_test.GateAllocatingNewSpaceForResult()' -class RestrictedGate(cirq.SingleQubitGate): +class RestrictedGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def __str__(self): return 'Restricted' @@ -247,7 +256,7 @@ def test_eq(): def test_control(): - g = cirq.SingleQubitGate() + g = cirq.testing.SingleQubitGate() # Ignores empty. assert g.controlled() == cirq.ControlledGate(g) @@ -423,7 +432,7 @@ def test_reversible(): ) -class UnphaseableGate(cirq.SingleQubitGate): +class UnphaseableGate(cirq.Gate): pass @@ -458,7 +467,7 @@ def test_circuit_diagram_info(): wire_symbols=('@', 'S'), exponent=1 ) - class UndiagrammableGate(cirq.SingleQubitGate): + class UndiagrammableGate(cirq.testing.SingleQubitGate): pass assert ( diff --git a/cirq-core/cirq/ops/controlled_operation_test.py b/cirq-core/cirq/ops/controlled_operation_test.py index ee9eb62adf8..547d60be479 100644 --- a/cirq-core/cirq/ops/controlled_operation_test.py +++ b/cirq-core/cirq/ops/controlled_operation_test.py @@ -23,7 +23,10 @@ from cirq.type_workarounds import NotImplementedType -class GateUsingWorkspaceForApplyUnitary(cirq.SingleQubitGate): +class GateUsingWorkspaceForApplyUnitary(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: args.available_buffer[...] = args.target_tensor args.target_tensor[...] = 0 @@ -39,10 +42,13 @@ def __repr__(self): return 'cirq.ops.controlled_operation_test.GateUsingWorkspaceForApplyUnitary()' -class GateAllocatingNewSpaceForResult(cirq.SingleQubitGate): +class GateAllocatingNewSpaceForResult(cirq.Gate): def __init__(self): self._matrix = cirq.testing.random_unitary(2, random_state=1234) + def _num_qubits_(self) -> int: + return 1 + def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: assert len(args.axes) == 1 a = args.axes[0] @@ -73,7 +79,7 @@ def __repr__(self): def test_controlled_operation_init(): cb = cirq.NamedQubit('ctr') q = cirq.NamedQubit('q') - g = cirq.SingleQubitGate() + g = cirq.testing.SingleQubitGate() v = cirq.GateOperation(g, (q,)) c = cirq.ControlledOperation([cb], v) assert c.sub_operation == v @@ -296,7 +302,7 @@ def test_uninformed_circuit_diagram_info(): def test_non_diagrammable_subop(): qbits = cirq.LineQubit.range(2) - class UndiagrammableGate(cirq.SingleQubitGate): + class UndiagrammableGate(cirq.testing.SingleQubitGate): pass undiagrammable_op = UndiagrammableGate()(qbits[1]) diff --git a/cirq-core/cirq/ops/eigen_gate_test.py b/cirq-core/cirq/ops/eigen_gate_test.py index 60a95e3de58..ecd59ee5289 100644 --- a/cirq-core/cirq/ops/eigen_gate_test.py +++ b/cirq-core/cirq/ops/eigen_gate_test.py @@ -294,7 +294,7 @@ def test_resolve_parameters(resolve_fn): def test_diagram_period(): - class ShiftyGate(cirq.EigenGate, cirq.SingleQubitGate): + class ShiftyGate(cirq.EigenGate, cirq.testing.SingleQubitGate): def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: raise NotImplementedError() @@ -327,7 +327,7 @@ def _eigen_shifts(self): assert ShiftyGate(505.2, 0, np.pi, np.e)._diagram_exponent(args) == 505.2 -class WeightedZPowGate(cirq.EigenGate, cirq.SingleQubitGate): +class WeightedZPowGate(cirq.EigenGate, cirq.testing.SingleQubitGate): def __init__(self, weight, **kwargs): self.weight = weight super().__init__(**kwargs) diff --git a/cirq-core/cirq/ops/gate_features.py b/cirq-core/cirq/ops/gate_features.py index 130329322de..77dc9faecf7 100644 --- a/cirq-core/cirq/ops/gate_features.py +++ b/cirq-core/cirq/ops/gate_features.py @@ -36,7 +36,8 @@ def qubit_index_to_equivalence_group_key(self, index: int) -> int: class _SingleQubitGateMeta(value.ABCMetaImplementAnyOneOf): def __instancecheck__(cls, instance): warnings.warn( - 'isinstance(gate, SingleQubitGate) is deprecated. Use cirq.num_qubits(gate) == 1 instead', + 'isinstance(gate, SingleQubitGate) is deprecated. ' + 'Use cirq.num_qubits(gate) == 1 instead', DeprecationWarning, ) return isinstance(instance, raw_types.Gate) and instance._num_qubits_() == 1 diff --git a/cirq-core/cirq/ops/gate_features_test.py b/cirq-core/cirq/ops/gate_features_test.py index acc2e7e5a27..7f91a16865a 100644 --- a/cirq-core/cirq/ops/gate_features_test.py +++ b/cirq-core/cirq/ops/gate_features_test.py @@ -19,7 +19,7 @@ def test_single_qubit_gate_validate_args(): - class Dummy(cirq.Gate): + class Dummy(cirq.SingleQubitGate): def matrix(self): pass @@ -27,7 +27,7 @@ def matrix(self): g = Dummy() with assert_deprecated(deadline="isinstance(gate, SingleQubitGate) is deprecated"): - assert isinstance(g, cirq.Gate) + assert isinstance(g, cirq.SingleQubitGate) q1 = cirq.NamedQubit('q1') q2 = cirq.NamedQubit('q2') diff --git a/cirq-core/cirq/ops/gate_operation_test.py b/cirq-core/cirq/ops/gate_operation_test.py index aeaceadbc29..d4ee752c886 100644 --- a/cirq-core/cirq/ops/gate_operation_test.py +++ b/cirq-core/cirq/ops/gate_operation_test.py @@ -20,7 +20,7 @@ def test_gate_operation_init(): q = cirq.NamedQubit('q') - g = cirq.SingleQubitGate() + g = cirq.testing.SingleQubitGate() v = cirq.GateOperation(g, (q,)) assert v.gate == g assert v.qubits == (q,) @@ -45,8 +45,8 @@ def test_immutable(): def test_gate_operation_eq(): - g1 = cirq.SingleQubitGate() - g2 = cirq.SingleQubitGate() + g1 = cirq.testing.SingleQubitGate() + g2 = cirq.testing.SingleQubitGate() g3 = cirq.testing.TwoQubitGate() r1 = [cirq.NamedQubit('r1')] r2 = [cirq.NamedQubit('r2')] @@ -157,7 +157,7 @@ def test_extrapolate(): q = cirq.NamedQubit('q') # If the gate isn't extrapolatable, you get a type error. - op0 = cirq.GateOperation(cirq.SingleQubitGate(), [q]) + op0 = cirq.GateOperation(cirq.testing.SingleQubitGate(), [q]) with pytest.raises(TypeError): _ = op0**0.5 @@ -170,7 +170,7 @@ def test_inverse(): q = cirq.NamedQubit('q') # If the gate isn't reversible, you get a type error. - op0 = cirq.GateOperation(cirq.SingleQubitGate(), [q]) + op0 = cirq.GateOperation(cirq.testing.SingleQubitGate(), [q]) assert cirq.inverse(op0, None) is None op1 = cirq.GateOperation(cirq.S, [q]) @@ -182,7 +182,7 @@ def test_text_diagrammable(): q = cirq.NamedQubit('q') # If the gate isn't diagrammable, you get a type error. - op0 = cirq.GateOperation(cirq.SingleQubitGate(), [q]) + op0 = cirq.GateOperation(cirq.testing.SingleQubitGate(), [q]) with pytest.raises(TypeError): _ = cirq.circuit_diagram_info(op0) @@ -196,7 +196,7 @@ def test_bounded_effect(): q = cirq.NamedQubit('q') # If the gate isn't bounded, you get a type error. - op0 = cirq.GateOperation(cirq.SingleQubitGate(), [q]) + op0 = cirq.GateOperation(cirq.testing.SingleQubitGate(), [q]) assert cirq.trace_distance_bound(op0) >= 1 op1 = cirq.GateOperation(cirq.Z**0.000001, [q]) op1_bound = cirq.trace_distance_bound(op1) @@ -253,8 +253,8 @@ def test_channel(): np.testing.assert_allclose(cirq.kraus(op), cirq.kraus(op.gate)) assert cirq.has_kraus(op) - assert cirq.kraus(cirq.SingleQubitGate()(a), None) is None - assert not cirq.has_kraus(cirq.SingleQubitGate()(a)) + assert cirq.kraus(cirq.testing.SingleQubitGate()(a), None) is None + assert not cirq.has_kraus(cirq.testing.SingleQubitGate()(a)) def test_measurement_key(): @@ -288,7 +288,10 @@ def test_repr(): repr(cirq.GateOperation(cirq.CZ, (a, b))) == 'cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1))' ) - class Inconsistent(cirq.SingleQubitGate): + class Inconsistent(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def __repr__(self): return 'Inconsistent' diff --git a/cirq-core/cirq/ops/gateset_test.py b/cirq-core/cirq/ops/gateset_test.py index c050d62e5f5..7427ed35ae5 100644 --- a/cirq-core/cirq/ops/gateset_test.py +++ b/cirq-core/cirq/ops/gateset_test.py @@ -126,7 +126,7 @@ def test_gate_family_eq(): (CustomX**0.5, True), (CustomX ** sympy.Symbol('theta'), True), (CustomXPowGate(exponent=0.25, global_shift=0.15), True), - (cirq.SingleQubitGate(), False), + (cirq.testing.SingleQubitGate(), False), (cirq.X**0.5, False), (None, False), (cirq.global_phase_operation(1j), False), diff --git a/cirq-core/cirq/ops/identity_test.py b/cirq-core/cirq/ops/identity_test.py index e9a7892d280..1603d0c8656 100644 --- a/cirq-core/cirq/ops/identity_test.py +++ b/cirq-core/cirq/ops/identity_test.py @@ -178,8 +178,9 @@ def test_identity_global(): def test_identity_mul(): - class UnknownGate(cirq.SingleQubitGate): - pass + class UnknownGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 class UnknownOperation(cirq.Operation): @property diff --git a/cirq-core/cirq/ops/op_tree_test.py b/cirq-core/cirq/ops/op_tree_test.py index 60609e356c2..f2ccc87dfde 100644 --- a/cirq-core/cirq/ops/op_tree_test.py +++ b/cirq-core/cirq/ops/op_tree_test.py @@ -20,7 +20,8 @@ def test_flatten_op_tree(): operations = [ - cirq.GateOperation(cirq.SingleQubitGate(), [cirq.NamedQubit(str(i))]) for i in range(10) + cirq.GateOperation(cirq.testing.SingleQubitGate(), [cirq.NamedQubit(str(i))]) + for i in range(10) ] # Empty tree. @@ -54,7 +55,8 @@ def test_flatten_op_tree(): def test_flatten_to_ops_or_moments(): operations = [ - cirq.GateOperation(cirq.SingleQubitGate(), [cirq.NamedQubit(str(i))]) for i in range(10) + cirq.GateOperation(cirq.testing.SingleQubitGate(), [cirq.NamedQubit(str(i))]) + for i in range(10) ] op_tree = [operations[0], cirq.Moment(operations[1:5]), operations[5:]] output = [operations[0], cirq.Moment(operations[1:5])] + operations[5:] @@ -72,7 +74,8 @@ def test_flatten_to_ops_or_moments(): def test_freeze_op_tree(): operations = [ - cirq.GateOperation(cirq.SingleQubitGate(), [cirq.NamedQubit(str(i))]) for i in range(10) + cirq.GateOperation(cirq.testing.SingleQubitGate(), [cirq.NamedQubit(str(i))]) + for i in range(10) ] # Empty tree. @@ -114,7 +117,7 @@ def test_transform_bad_tree(): def test_transform_leaves(): - gs = [cirq.SingleQubitGate() for _ in range(10)] + gs = [cirq.testing.SingleQubitGate() for _ in range(10)] operations = [cirq.GateOperation(gs[i], [cirq.NamedQubit(str(i))]) for i in range(10)] expected = [cirq.GateOperation(gs[i], [cirq.NamedQubit(str(i) + 'a')]) for i in range(10)] @@ -145,7 +148,8 @@ def move_tree_left_freeze(root): def test_transform_internal_nodes(): operations = [ - cirq.GateOperation(cirq.SingleQubitGate(), [cirq.LineQubit(2 * i)]) for i in range(10) + cirq.GateOperation(cirq.testing.SingleQubitGate(), [cirq.LineQubit(2 * i)]) + for i in range(10) ] def skip_first(op): diff --git a/cirq-core/cirq/ops/parallel_gate_test.py b/cirq-core/cirq/ops/parallel_gate_test.py index 1e8255c78e4..dc2eb70601b 100644 --- a/cirq-core/cirq/ops/parallel_gate_test.py +++ b/cirq-core/cirq/ops/parallel_gate_test.py @@ -21,7 +21,7 @@ @pytest.mark.parametrize( 'gate, num_copies, qubits', [ - (cirq.SingleQubitGate(), 2, cirq.LineQubit.range(2)), + (cirq.testing.SingleQubitGate(), 2, cirq.LineQubit.range(2)), (cirq.X**0.5, 4, cirq.LineQubit.range(4)), ], ) @@ -35,9 +35,19 @@ def test_parallel_gate_operation_init(gate, num_copies, qubits): @pytest.mark.parametrize( 'gate, num_copies, qubits, error_msg', [ - (cirq.SingleQubitGate(), 3, cirq.LineQubit.range(2), "Wrong number of qubits"), - (cirq.SingleQubitGate(), 0, cirq.LineQubit.range(4), "gate must be applied at least once"), - (cirq.SingleQubitGate(), 2, [cirq.NamedQubit("a"), cirq.NamedQubit("a")], "Duplicate"), + (cirq.testing.SingleQubitGate(), 3, cirq.LineQubit.range(2), "Wrong number of qubits"), + ( + cirq.testing.SingleQubitGate(), + 0, + cirq.LineQubit.range(4), + "gate must be applied at least once", + ), + ( + cirq.testing.SingleQubitGate(), + 2, + [cirq.NamedQubit("a"), cirq.NamedQubit("a")], + "Duplicate", + ), (cirq.testing.TwoQubitGate(), 2, cirq.LineQubit.range(4), "must be a single qubit gate"), ], ) @@ -65,14 +75,14 @@ def test_decompose_raises(): def test_with_num_copies(): - g = cirq.SingleQubitGate() + g = cirq.testing.SingleQubitGate() pg = cirq.ParallelGate(g, 3) assert pg.with_num_copies(5) == cirq.ParallelGate(g, 5) def test_extrapolate(): # If the gate isn't extrapolatable, you get a type error. - g = cirq.ParallelGate(cirq.SingleQubitGate(), 2) + g = cirq.ParallelGate(cirq.testing.SingleQubitGate(), 2) with pytest.raises(TypeError): _ = g**0.5 # If the gate is extrapolatable, the effect is applied on the underlying gate. @@ -90,7 +100,7 @@ def test_parameterizable_gates(resolve_fn): assert not cirq.is_parameterized(g2) -@pytest.mark.parametrize('gate', [cirq.X ** sympy.Symbol("a"), cirq.SingleQubitGate()]) +@pytest.mark.parametrize('gate', [cirq.X ** sympy.Symbol("a"), cirq.testing.SingleQubitGate()]) def test_no_unitary(gate): g = cirq.ParallelGate(gate, 2) assert not cirq.has_unitary(g) @@ -115,10 +125,10 @@ def test_unitary(gate, num_copies, qubits): def test_not_implemented_diagram(): q = cirq.LineQubit.range(2) - g = cirq.SingleQubitGate() + g = cirq.testing.SingleQubitGate() c = cirq.Circuit() c.append(cirq.ParallelGate(g, 2)(*q)) - assert 'cirq.ops.gate_features.SingleQubitGate' in str(c) + assert 'cirq.testing.gate_features.SingleQubitGate ' in str(c) def test_repr(): diff --git a/cirq-core/cirq/ops/pauli_string_test.py b/cirq-core/cirq/ops/pauli_string_test.py index 659aa45750c..ee810939e85 100644 --- a/cirq-core/cirq/ops/pauli_string_test.py +++ b/cirq-core/cirq/ops/pauli_string_test.py @@ -709,8 +709,9 @@ def test_pass_operations_over_cz(): def test_pass_operations_over_no_common_qubits(): - class DummyGate(cirq.SingleQubitGate): - pass + class DummyGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 q0, q1 = _make_qubits(2) op0 = DummyGate()(q1) diff --git a/cirq-core/cirq/ops/phased_x_z_gate.py b/cirq-core/cirq/ops/phased_x_z_gate.py index 7024fc7e606..300d6229d19 100644 --- a/cirq-core/cirq/ops/phased_x_z_gate.py +++ b/cirq-core/cirq/ops/phased_x_z_gate.py @@ -140,6 +140,7 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio def _num_qubits_(self) -> int: return 1 + def _has_unitary_(self) -> bool: return not self._is_parameterized_() diff --git a/cirq-core/cirq/ops/raw_types_test.py b/cirq-core/cirq/ops/raw_types_test.py index daec1f3c0d8..92e1f6ee65d 100644 --- a/cirq-core/cirq/ops/raw_types_test.py +++ b/cirq-core/cirq/ops/raw_types_test.py @@ -765,7 +765,7 @@ def qubits(self): def test_single_qubit_gate_validates_on_each(): - class Dummy(cirq.SingleQubitGate): + class Dummy(cirq.testing.SingleQubitGate): def matrix(self): pass @@ -785,7 +785,7 @@ def matrix(self): def test_on_each(): - class CustomGate(cirq.SingleQubitGate): + class CustomGate(cirq.testing.SingleQubitGate): pass a = cirq.NamedQubit('a') diff --git a/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py b/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py index 58d53be2dbd..bc2b3be9db2 100644 --- a/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py +++ b/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py @@ -63,7 +63,10 @@ def test_kak_decomposes_unknown_two_qubit_gate(): def test_composite_gates_without_matrix(): - class CompositeDummy(cirq.SingleQubitGate): + class CompositeDummy(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _decompose_(self, qubits): yield cirq.X(qubits[0]) yield cirq.Y(qubits[0]) ** 0.5 diff --git a/cirq-core/cirq/optimizers/eject_z_test.py b/cirq-core/cirq/optimizers/eject_z_test.py index 8cd7c84b920..657c02fc960 100644 --- a/cirq-core/cirq/optimizers/eject_z_test.py +++ b/cirq-core/cirq/optimizers/eject_z_test.py @@ -159,8 +159,9 @@ def test_measurement_consumes_zs(): def test_unphaseable_causes_earlier_merge_without_size_increase(): - class UnknownGate(cirq.SingleQubitGate): - pass + class UnknownGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 u = UnknownGate() diff --git a/cirq-core/cirq/optimizers/expand_composite_test.py b/cirq-core/cirq/optimizers/expand_composite_test.py index 1dae9a06ebb..748bf5261e5 100644 --- a/cirq-core/cirq/optimizers/expand_composite_test.py +++ b/cirq-core/cirq/optimizers/expand_composite_test.py @@ -105,7 +105,10 @@ def test_recursive_composite(): def test_decompose_returns_not_flat_op_tree(): - class DummyGate(cirq.SingleQubitGate): + class DummyGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _decompose_(self, qubits): (q0,) = qubits # Yield a tuple of gates instead of yielding a gate diff --git a/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py b/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py index ce1d8c86bcc..8576bc4e175 100644 --- a/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py +++ b/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py @@ -129,8 +129,9 @@ def test_ignores_2qubit_target(): def test_ignore_unsupported_gate(): - class UnsupportedDummy(cirq.SingleQubitGate): - pass + class UnsupportedDummy(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 q0 = cirq.LineQubit(0) circuit = cirq.Circuit(UnsupportedDummy()(q0)) diff --git a/cirq-core/cirq/protocols/apply_unitary_protocol_test.py b/cirq-core/cirq/protocols/apply_unitary_protocol_test.py index f3304cdc4c2..ef675180569 100644 --- a/cirq-core/cirq/protocols/apply_unitary_protocol_test.py +++ b/cirq-core/cirq/protocols/apply_unitary_protocol_test.py @@ -325,14 +325,14 @@ def test_apply_unitaries(): def test_apply_unitaries_mixed_qid_shapes(): - class PlusOneMod3Gate(cirq.SingleQubitGate): + class PlusOneMod3Gate(cirq.testing.SingleQubitGate): def _qid_shape_(self): return (3,) def _unitary_(self): return np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) # yapf: disable - class PlusOneMod4Gate(cirq.SingleQubitGate): + class PlusOneMod4Gate(cirq.testing.SingleQubitGate): def _qid_shape_(self): return (4,) diff --git a/cirq-core/cirq/protocols/has_stabilizer_effect_protocol_test.py b/cirq-core/cirq/protocols/has_stabilizer_effect_protocol_test.py index 321b73359a1..d54d00db305 100644 --- a/cirq-core/cirq/protocols/has_stabilizer_effect_protocol_test.py +++ b/cirq-core/cirq/protocols/has_stabilizer_effect_protocol_test.py @@ -98,7 +98,7 @@ def _unitary_(self): def test_inconclusive(): assert not cirq.has_stabilizer_effect(object()) assert not cirq.has_stabilizer_effect('boo') - assert not cirq.has_stabilizer_effect(cirq.SingleQubitGate()) + assert not cirq.has_stabilizer_effect(cirq.testing.SingleQubitGate()) assert not cirq.has_stabilizer_effect(No()) assert not cirq.has_stabilizer_effect(NoOp()) diff --git a/cirq-core/cirq/protocols/has_unitary_protocol_test.py b/cirq-core/cirq/protocols/has_unitary_protocol_test.py index 20530cb92b9..a91d3d971be 100644 --- a/cirq-core/cirq/protocols/has_unitary_protocol_test.py +++ b/cirq-core/cirq/protocols/has_unitary_protocol_test.py @@ -74,7 +74,7 @@ class No2(EmptyOp): def _apply_unitary_(self, args): return NotImplemented - class No3(cirq.SingleQubitGate): + class No3(cirq.testing.SingleQubitGate): def _apply_unitary_(self, args): return NotImplemented @@ -86,7 +86,7 @@ class Yes1(EmptyOp): def _apply_unitary_(self, args): return args.target_tensor - class Yes2(cirq.SingleQubitGate): + class Yes2(cirq.testing.SingleQubitGate): def _apply_unitary_(self, args): return args.target_tensor diff --git a/cirq-core/cirq/protocols/kraus_protocol_test.py b/cirq-core/cirq/protocols/kraus_protocol_test.py index 4fc9fc90ea5..a9da792fa7d 100644 --- a/cirq-core/cirq/protocols/kraus_protocol_test.py +++ b/cirq-core/cirq/protocols/kraus_protocol_test.py @@ -137,22 +137,22 @@ def _unitary_(self) -> np.ndarray: assert cirq.has_kraus(ReturnsUnitary()) -class HasKraus(cirq.SingleQubitGate): +class HasKraus(cirq.testing.SingleQubitGate): def _has_kraus_(self) -> bool: return True -class HasMixture(cirq.SingleQubitGate): +class HasMixture(cirq.testing.SingleQubitGate): def _has_mixture_(self) -> bool: return True -class HasUnitary(cirq.SingleQubitGate): +class HasUnitary(cirq.testing.SingleQubitGate): def _has_unitary_(self) -> bool: return True -class HasKrausWhenDecomposed(cirq.SingleQubitGate): +class HasKrausWhenDecomposed(cirq.testing.SingleQubitGate): def __init__(self, decomposed_cls): self.decomposed_cls = decomposed_cls diff --git a/cirq-core/cirq/sim/clifford/act_on_clifford_tableau_args_test.py b/cirq-core/cirq/sim/clifford/act_on_clifford_tableau_args_test.py index 29157766bc5..8135841841e 100644 --- a/cirq-core/cirq/sim/clifford/act_on_clifford_tableau_args_test.py +++ b/cirq-core/cirq/sim/clifford/act_on_clifford_tableau_args_test.py @@ -21,10 +21,7 @@ def test_unitary_fallback(): - class UnitaryXGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - + class UnitaryXGate(cirq.testing.SingleQubitGate): def _unitary_(self): return np.array([[0, 1], [1, 0]]) @@ -64,7 +61,7 @@ def test_cannot_act(): class NoDetails: pass - class NoDetailsSingleQubitGate(cirq.SingleQubitGate): + class NoDetailsSingleQubitGate(cirq.testing.SingleQubitGate): pass args = cirq.ActOnCliffordTableauArgs( diff --git a/cirq-core/cirq/sim/clifford/act_on_stabilizer_ch_form_args_test.py b/cirq-core/cirq/sim/clifford/act_on_stabilizer_ch_form_args_test.py index 2e655944a2a..32d6d7aa922 100644 --- a/cirq-core/cirq/sim/clifford/act_on_stabilizer_ch_form_args_test.py +++ b/cirq-core/cirq/sim/clifford/act_on_stabilizer_ch_form_args_test.py @@ -26,7 +26,7 @@ def test_init_state(): def test_cannot_act(): - class NoDetails(cirq.SingleQubitGate): + class NoDetails(cirq.testing.SingleQubitGate): pass args = cirq.ActOnStabilizerCHFormArgs(qubits=[], prng=np.random.RandomState()) @@ -36,7 +36,7 @@ class NoDetails(cirq.SingleQubitGate): def test_gate_with_act_on(): - class CustomGate(cirq.SingleQubitGate): + class CustomGate(cirq.testing.SingleQubitGate): def _act_on_(self, args, qubits): if isinstance(args, cirq.ActOnStabilizerCHFormArgs): qubit = args.qubit_map[qubits[0]] diff --git a/cirq-core/cirq/sim/sparse_simulator_test.py b/cirq-core/cirq/sim/sparse_simulator_test.py index 0a27e775f30..3fd3cb16e32 100644 --- a/cirq-core/cirq/sim/sparse_simulator_test.py +++ b/cirq-core/cirq/sim/sparse_simulator_test.py @@ -694,7 +694,7 @@ def test_simulate_expectation_values_qubit_order(dtype: Type[np.number], split: def test_invalid_run_no_unitary(): - class NoUnitary(cirq.SingleQubitGate): + class NoUnitary(cirq.testing.SingleQubitGate): pass q0 = cirq.LineQubit(0) @@ -706,7 +706,7 @@ class NoUnitary(cirq.SingleQubitGate): def test_allocates_new_state(): - class NoUnitary(cirq.SingleQubitGate): + class NoUnitary(cirq.testing.SingleQubitGate): def _has_unitary_(self): return True @@ -727,7 +727,7 @@ def test_does_not_modify_initial_state(): q0 = cirq.LineQubit(0) simulator = cirq.Simulator() - class InPlaceUnitary(cirq.SingleQubitGate): + class InPlaceUnitary(cirq.testing.SingleQubitGate): def _has_unitary_(self): return True @@ -1276,7 +1276,7 @@ def test_separated_measurements(): def test_state_vector_copy(): sim = cirq.Simulator(split_untangled_states=False) - class InplaceGate(cirq.SingleQubitGate): + class InplaceGate(cirq.testing.SingleQubitGate): """A gate that modifies the target tensor in place, multiply by -1.""" def _apply_unitary_(self, args): diff --git a/cirq-core/cirq/testing/__init__.py b/cirq-core/cirq/testing/__init__.py index 5f2a3e20d98..9788ad1b98b 100644 --- a/cirq-core/cirq/testing/__init__.py +++ b/cirq-core/cirq/testing/__init__.py @@ -62,7 +62,7 @@ from cirq.testing.equivalent_repr_eval import assert_equivalent_repr -from cirq.testing.gate_features import TwoQubitGate, ThreeQubitGate +from cirq.testing.gate_features import SingleQubitGate, TwoQubitGate, ThreeQubitGate from cirq.testing.json import assert_json_roundtrip_works diff --git a/cirq-core/cirq/testing/consistent_act_on_test.py b/cirq-core/cirq/testing/consistent_act_on_test.py index 0e5500c0e12..a8c72cfb11f 100644 --- a/cirq-core/cirq/testing/consistent_act_on_test.py +++ b/cirq-core/cirq/testing/consistent_act_on_test.py @@ -20,7 +20,10 @@ import cirq -class GoodGate(cirq.SingleQubitGate): +class GoodGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _unitary_(self): return np.array([[0, 1], [1, 0]]) @@ -33,7 +36,10 @@ def _act_on_(self, args: 'cirq.OperationTarget', qubits: Sequence['cirq.Qid']): return NotImplemented -class BadGate(cirq.SingleQubitGate): +class BadGate(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _unitary_(self): return np.array([[0, 1j], [1, 0]]) diff --git a/cirq-core/cirq/testing/consistent_controlled_gate_op_test.py b/cirq-core/cirq/testing/consistent_controlled_gate_op_test.py index 1e5b2d3c421..381a96aa22e 100644 --- a/cirq-core/cirq/testing/consistent_controlled_gate_op_test.py +++ b/cirq-core/cirq/testing/consistent_controlled_gate_op_test.py @@ -21,7 +21,7 @@ import cirq -class GoodGate(cirq.EigenGate, cirq.SingleQubitGate): +class GoodGate(cirq.EigenGate, cirq.testing.SingleQubitGate): def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: # coverage: ignore return [(0, np.diag([1, 0])), (1, np.diag([0, 1]))] @@ -36,7 +36,7 @@ def controlled_by( return cirq.ControlledOperation(control_qubits, self, control_values) -class BadGate(cirq.EigenGate, cirq.SingleQubitGate): +class BadGate(cirq.EigenGate, cirq.testing.SingleQubitGate): def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: # coverage: ignore return [(0, np.diag([1, 0])), (1, np.diag([0, 1]))] diff --git a/cirq-core/cirq/testing/consistent_decomposition_test.py b/cirq-core/cirq/testing/consistent_decomposition_test.py index 002ed0668fd..b57c158cc1f 100644 --- a/cirq-core/cirq/testing/consistent_decomposition_test.py +++ b/cirq-core/cirq/testing/consistent_decomposition_test.py @@ -20,7 +20,10 @@ import cirq -class GoodGateDecompose(cirq.SingleQubitGate): +class GoodGateDecompose(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _decompose_(self, qubits): return cirq.X(qubits[0]) @@ -28,7 +31,10 @@ def _unitary_(self): return np.array([[0, 1], [1, 0]]) -class BadGateDecompose(cirq.SingleQubitGate): +class BadGateDecompose(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _decompose_(self, qubits): return cirq.Y(qubits[0]) @@ -68,12 +74,15 @@ def _decompose_(self, qubits): yield GateDecomposeNotImplemented().on_each(*qubits) -class GateDecomposeNotImplemented(cirq.SingleQubitGate): +class GateDecomposeNotImplemented(cirq.Gate): + def _num_qubits_(self) -> int: + return 1 + def _decompose_(self, qubits): return NotImplemented -class ParameterizedGate(cirq.SingleQubitGate): +class ParameterizedGate(cirq.Gate): def _num_qubits_(self): return 2 diff --git a/cirq-core/cirq/testing/consistent_pauli_expansion_test.py b/cirq-core/cirq/testing/consistent_pauli_expansion_test.py index 1e6d25ae115..d5b490b2424 100644 --- a/cirq-core/cirq/testing/consistent_pauli_expansion_test.py +++ b/cirq-core/cirq/testing/consistent_pauli_expansion_test.py @@ -22,7 +22,7 @@ Z = np.diag([1, -1]) -class GoodGateExplicitPauliExpansion(cirq.SingleQubitGate): +class GoodGateExplicitPauliExpansion(cirq.testing.SingleQubitGate): def _unitary_(self) -> np.ndarray: return np.sqrt(1 / 2) * X + np.sqrt(1 / 3) * Y + np.sqrt(1 / 6) * Z @@ -35,16 +35,16 @@ def num_qubits(self) -> int: return 4 -class GoodGateNoUnitary(cirq.SingleQubitGate): +class GoodGateNoUnitary(cirq.testing.SingleQubitGate): def _pauli_expansion_(self) -> cirq.LinearDict[str]: return cirq.LinearDict({'X': np.sqrt(1 / 2), 'Y': np.sqrt(1 / 2)}) -class GoodGateNoPauliExpansionNoUnitary(cirq.SingleQubitGate): +class GoodGateNoPauliExpansionNoUnitary(cirq.testing.SingleQubitGate): pass -class BadGateInconsistentPauliExpansion(cirq.SingleQubitGate): +class BadGateInconsistentPauliExpansion(cirq.testing.SingleQubitGate): def _unitary_(self) -> np.ndarray: return np.sqrt(1 / 2) * X + np.sqrt(1 / 3) * Y + np.sqrt(1 / 6) * Z diff --git a/cirq-core/cirq/testing/consistent_protocols_test.py b/cirq-core/cirq/testing/consistent_protocols_test.py index 893a79e51bd..f2b47af4ca2 100644 --- a/cirq-core/cirq/testing/consistent_protocols_test.py +++ b/cirq-core/cirq/testing/consistent_protocols_test.py @@ -25,7 +25,7 @@ import cirq.testing.consistent_controlled_gate_op_test as controlled_gate_op_test -class GoodGate(cirq.SingleQubitGate): +class GoodGate(cirq.Gate): def __init__( self, *, @@ -35,6 +35,9 @@ def __init__( self.phase_exponent = cirq.canonicalize_half_turns(phase_exponent) self.exponent = exponent + def _num_qubits_(self) -> int: + return 1 + def _has_unitary_(self): return not cirq.is_parameterized(self) @@ -184,10 +187,13 @@ def __repr__(self): return f"BadGateRepr({', '.join(args)})" -class GoodEigenGate(cirq.EigenGate, cirq.SingleQubitGate): +class GoodEigenGate(cirq.EigenGate): def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: return [(0, np.diag([1, 0])), (1, np.diag([0, 1]))] + def _num_qubits_(self) -> int: + return 1 + def __repr__(self): return 'GoodEigenGate(exponent={}, global_shift={!r})'.format( proper_repr(self._exponent), self._global_shift diff --git a/cirq-core/cirq/testing/gate_features.py b/cirq-core/cirq/testing/gate_features.py index ff0561c7dec..4e95b4d342c 100644 --- a/cirq-core/cirq/testing/gate_features.py +++ b/cirq-core/cirq/testing/gate_features.py @@ -17,6 +17,13 @@ from cirq.ops import raw_types +class SingleQubitGate(raw_types.Gate): + """A gate that must be applied to exactly one qubit.""" + + def _num_qubits_(self) -> int: + return 1 + + class TwoQubitGate(raw_types.Gate): """A gate that must be applied to exactly two qubits.""" diff --git a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py index 289da0f959a..1efdbc34988 100644 --- a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +++ b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py @@ -97,9 +97,7 @@ def is_no_turn(half_turns): return [(pauli, ht) for pauli, ht in rotation_list if not is_no_turn(ht)] -def single_qubit_matrix_to_gates( - mat: np.ndarray, tolerance: float = 0 -) -> List[ops.SingleQubitGate]: +def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> List[ops.Gate]: """Implements a single-qubit operation with few gates. Args: diff --git a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py index 9f82ae8c410..8ba7490cd3d 100644 --- a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +++ b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py @@ -33,7 +33,7 @@ def test_deprecated_submodule(): def assert_gates_implement_unitary( - gates: Sequence[cirq.SingleQubitGate], intended_effect: np.ndarray, atol: float + gates: Sequence[cirq.testing.SingleQubitGate], intended_effect: np.ndarray, atol: float ): actual_effect = cirq.dot(*[cirq.unitary(g) for g in reversed(gates)]) cirq.testing.assert_allclose_up_to_global_phase(actual_effect, intended_effect, atol=atol) diff --git a/cirq-core/cirq/transformers/eject_z_test.py b/cirq-core/cirq/transformers/eject_z_test.py index 45059304b3b..623010a1e75 100644 --- a/cirq-core/cirq/transformers/eject_z_test.py +++ b/cirq-core/cirq/transformers/eject_z_test.py @@ -187,7 +187,7 @@ def test_measurement_consumes_zs(): def test_unphaseable_causes_earlier_merge_without_size_increase(): - class UnknownGate(cirq.SingleQubitGate): + class UnknownGate(cirq.testing.SingleQubitGate): pass u = UnknownGate() diff --git a/cirq-core/cirq/transformers/expand_composite_test.py b/cirq-core/cirq/transformers/expand_composite_test.py index dcbe31120d4..5eb145ecf62 100644 --- a/cirq-core/cirq/transformers/expand_composite_test.py +++ b/cirq-core/cirq/transformers/expand_composite_test.py @@ -105,7 +105,7 @@ def test_recursive_composite(): def test_decompose_returns_not_flat_op_tree(): - class DummyGate(cirq.SingleQubitGate): + class DummyGate(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): (q0,) = qubits # Yield a tuple of gates instead of yielding a gate diff --git a/cirq-core/cirq/transformers/merge_k_qubit_gates_test.py b/cirq-core/cirq/transformers/merge_k_qubit_gates_test.py index 9f475326060..0803579ce7d 100644 --- a/cirq-core/cirq/transformers/merge_k_qubit_gates_test.py +++ b/cirq-core/cirq/transformers/merge_k_qubit_gates_test.py @@ -74,9 +74,8 @@ def test_ignores_2qubit_target(): def test_ignore_unsupported_gate(): - class UnsupportedDummy(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class UnsupportedDummy(cirq.testing.SingleQubitGate): + pass c = cirq.Circuit(UnsupportedDummy()(cirq.LineQubit(0))) assert_optimizes(optimized=cirq.merge_k_qubit_unitaries(c, k=1), expected=c) diff --git a/cirq-core/cirq/transformers/target_gatesets/cz_gateset_test.py b/cirq-core/cirq/transformers/target_gatesets/cz_gateset_test.py index 3f3964d9385..40952cd895b 100644 --- a/cirq-core/cirq/transformers/target_gatesets/cz_gateset_test.py +++ b/cirq-core/cirq/transformers/target_gatesets/cz_gateset_test.py @@ -245,7 +245,7 @@ def _decompose_(self, qubits): def test_composite_gates_without_matrix(): - class CompositeDummy(cirq.SingleQubitGate): + class CompositeDummy(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): yield cirq.X(qubits[0]) yield cirq.Y(qubits[0]) ** 0.5 diff --git a/cirq-google/cirq_google/calibration/engine_simulator.py b/cirq-google/cirq_google/calibration/engine_simulator.py index bc6708df676..69eba099950 100644 --- a/cirq-google/cirq_google/calibration/engine_simulator.py +++ b/cirq-google/cirq_google/calibration/engine_simulator.py @@ -472,10 +472,16 @@ def _convert_to_circuit_with_drift( simulator: PhasedFSimEngineSimulator, circuit: cirq.AbstractCircuit ) -> cirq.Circuit: def map_func(op: cirq.Operation, _) -> cirq.Operation: - if isinstance(op.gate, (cirq.MeasurementGate, cirq.SingleQubitGate, cirq.WaitGate)): - return op + if op.gate is None: raise IncompatibleMomentError(f'Operation {op} has a missing gate') + + if ( + isinstance(op.gate, (cirq.MeasurementGate, cirq.WaitGate)) + or cirq.num_qubits(op.gate) == 1 + ): + return op + translated = simulator.gates_translator(op.gate) if translated is None: raise IncompatibleMomentError( diff --git a/cirq-google/cirq_google/calibration/workflow.py b/cirq-google/cirq_google/calibration/workflow.py index fb793fa5f9a..e0882ebe0ad 100644 --- a/cirq-google/cirq_google/calibration/workflow.py +++ b/cirq-google/cirq_google/calibration/workflow.py @@ -39,7 +39,7 @@ from cirq_google.engine import Engine, QuantumEngineSampler, util from cirq_google.serialization.serializer import Serializer -_CALIBRATION_IRRELEVANT_GATES = cirq.MeasurementGate, cirq.SingleQubitGate, cirq.WaitGate +_CALIBRATION_IRRELEVANT_GATES = cirq.MeasurementGate, cirq.WaitGate @dataclasses.dataclass(frozen=True) @@ -184,7 +184,7 @@ def _list_moment_pairs_to_characterize( if isinstance(op.gate, cirq.GlobalPhaseGate): raise IncompatibleMomentError('Moment contains global phase gate') - if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES): + if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES) or cirq.num_qubits(op.gate) == 1: other_operation = True else: translated = gates_translator(op.gate) @@ -1079,7 +1079,7 @@ def _find_moment_zeta_chi_gamma_corrections( if isinstance(op.gate, cirq.GlobalPhaseGate): raise IncompatibleMomentError('Moment contains global phase gate') - if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES): + if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES) or cirq.num_qubits(op.gate) == 1: other.append(op) continue diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index f333bd133cc..d92d15ab991 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import inspect from typing import Any, Collection, Dict, Optional, Iterable, List, Set, Tuple import cirq @@ -147,8 +147,8 @@ def create_device_proto_for_qubits( # Choose target set and number of qubits based on gate type. gate_type = internal_type - # Note: if it is not a measurement gate and doesn't inherit - # from SingleQubitGate, it's assumed to be a two qubit gate. + # Note: if it is not a measurement gate, and it's _num_qubits_ method + # doesn't return 2, it's assumed to be a two qubit gate. if gate_type == cirq.MeasurementGate: gate.valid_targets.append(_MEAS_TARGET_SET) elif gate_type == cirq.WaitGate: @@ -157,7 +157,10 @@ def create_device_proto_for_qubits( # Github issue: # https://github.com/quantumlib/Cirq/issues/2537 gate.number_of_qubits = 1 - elif issubclass(gate_type, cirq.SingleQubitGate): + elif ( + inspect.getsource(gate_type._num_qubits_) + == ' def _num_qubits_(self) -> int:\n return 1\n' + ): gate.number_of_qubits = 1 else: # This must be a two-qubit gate diff --git a/cirq-google/cirq_google/devices/xmon_device_test.py b/cirq-google/cirq_google/devices/xmon_device_test.py index b9b1413dc66..4ad483b67ae 100644 --- a/cirq-google/cirq_google/devices/xmon_device_test.py +++ b/cirq-google/cirq_google/devices/xmon_device_test.py @@ -98,7 +98,7 @@ def test_init(): assert d.duration_of(cirq.X(q00)) == 2 * ns assert d.duration_of(cirq.CZ(q00, q01)) == 3 * ns with pytest.raises(ValueError): - _ = d.duration_of(cirq.SingleQubitGate().on(q00)) + _ = d.duration_of(cirq.testing.SingleQubitGate().on(q00)) @mock.patch.dict(os.environ, clear='CIRQ_TESTING') diff --git a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py index c3a9c271527..ded6828b3b2 100644 --- a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py +++ b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py @@ -19,8 +19,9 @@ class OtherX(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 + def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) @@ -31,14 +32,15 @@ def _decompose_(self, qubits): class OtherOtherX(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 + def _decompose_(self, qubits): return OtherX().on(*qubits) class NonNativeGate(cirq.Gate): - def _num_qubits_(self)-> int: + def _num_qubits_(self) -> int: return 1 diff --git a/cirq-google/cirq_google/serialization/op_deserializer_test.py b/cirq-google/cirq_google/serialization/op_deserializer_test.py index c8f54040db1..b9ca8206c15 100644 --- a/cirq-google/cirq_google/serialization/op_deserializer_test.py +++ b/cirq-google/cirq_google/serialization/op_deserializer_test.py @@ -33,7 +33,7 @@ def op_proto(json_dict: Dict) -> v2.program_pb2.Operation: @cirq.value_equality -class GateWithAttribute(cirq.SingleQubitGate): +class GateWithAttribute(cirq.testing.SingleQubitGate): def __init__(self, val, not_req=None): self.val = val self.not_req = not_req diff --git a/cirq-google/cirq_google/serialization/op_serializer_test.py b/cirq-google/cirq_google/serialization/op_serializer_test.py index 2b32a1b76af..b96ff9a6ea6 100644 --- a/cirq-google/cirq_google/serialization/op_serializer_test.py +++ b/cirq-google/cirq_google/serialization/op_serializer_test.py @@ -35,12 +35,12 @@ def op_proto(json: Dict) -> v2.program_pb2.Operation: return op -class GateWithAttribute(cirq.SingleQubitGate): +class GateWithAttribute(cirq.testing.SingleQubitGate): def __init__(self, val): self.val = val -class GateWithProperty(cirq.SingleQubitGate): +class GateWithProperty(cirq.testing.SingleQubitGate): def __init__(self, val, not_req=None): self._val = val self._not_req = not_req @@ -50,7 +50,7 @@ def val(self): return self._val -class GateWithMethod(cirq.SingleQubitGate): +class GateWithMethod(cirq.testing.SingleQubitGate): def __init__(self, val): self._val = val diff --git a/cirq-web/cirq_web/circuits/symbols_test.py b/cirq-web/cirq_web/circuits/symbols_test.py index 72829f60bbf..963eee4139d 100644 --- a/cirq-web/cirq_web/circuits/symbols_test.py +++ b/cirq-web/cirq_web/circuits/symbols_test.py @@ -16,15 +16,21 @@ import pytest -class MockGateNoDiagramInfo(cirq.SingleQubitGate): +class MockGateNoDiagramInfo(cirq.Gate): def __init__(self): super(MockGateNoDiagramInfo, self) + def _num_qubits_(self) -> int: + return 1 -class MockGateUnimplementedDiagramInfo(cirq.SingleQubitGate): + +class MockGateUnimplementedDiagramInfo(cirq.Gate): def __init__(self): super(MockGateUnimplementedDiagramInfo, self) + def _num_qubits_(self) -> int: + return 1 + def _circuit_diagram_info_(self, args): return NotImplemented diff --git a/examples/hhl.py b/examples/hhl.py index 8c9399b747b..2e17dd452ed 100644 --- a/examples/hhl.py +++ b/examples/hhl.py @@ -95,7 +95,7 @@ def _decompose_(self, qubits): yield cirq.qft(*qubits[:-1], without_reverse=True) ** -1 -class HamiltonianSimulation(cirq.EigenGate, cirq.SingleQubitGate): +class HamiltonianSimulation(cirq.EigenGate): """A gate that represents e^iAt. This EigenGate + np.linalg.eigh() implementation is used here purely for demonstrative @@ -104,7 +104,6 @@ class HamiltonianSimulation(cirq.EigenGate, cirq.SingleQubitGate): """ def __init__(self, A, t, exponent=1.0): - cirq.SingleQubitGate.__init__(self) cirq.EigenGate.__init__(self, exponent=exponent) self.A = A self.t = t @@ -115,6 +114,9 @@ def __init__(self, A, t, exponent=1.0): P = np.outer(v, np.conj(v)) self.eigen_components.append((theta, P)) + def _num_qubits_(self) -> int: + return 1 + def _with_exponent(self, exponent): return HamiltonianSimulation(self.A, self.t, exponent) From 477f4f4aea72cf1987577ddd88c7640b1aaeb992 Mon Sep 17 00:00:00 2001 From: vtomole Date: Tue, 19 Apr 2022 21:23:59 -0500 Subject: [PATCH 04/10] Check --- cirq-core/cirq/ops/common_channels.py | 3 --- .../analytical_decompositions/single_qubit_decompositions.py | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/cirq-core/cirq/ops/common_channels.py b/cirq-core/cirq/ops/common_channels.py index 87eda95424b..dda34bfb96f 100644 --- a/cirq-core/cirq/ops/common_channels.py +++ b/cirq-core/cirq/ops/common_channels.py @@ -703,9 +703,6 @@ def __init__(self, dimension: int = 2) -> None: """ self._dimension = dimension - def _num_qubits_(self) -> int: - return 1 - def _has_stabilizer_effect_(self) -> Optional[bool]: return True diff --git a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py index 1efdbc34988..7c101555cbb 100644 --- a/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +++ b/cirq-core/cirq/transformers/analytical_decompositions/single_qubit_decompositions.py @@ -164,9 +164,7 @@ def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> Tuple[f return (_signed_mod_1(xy_turn), _signed_mod_1(xy_phase_turn), _signed_mod_1(total_z_turn)) -def single_qubit_matrix_to_phased_x_z( - mat: np.ndarray, atol: float = 0 -) -> List[ops.SingleQubitGate]: +def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> List[ops.Gate]: """Implements a single-qubit operation with a PhasedX and Z gate. If one of the gates isn't needed, it will be omitted. From 7c83e4c39ff9644983e7eccc00f1a0786a35596d Mon Sep 17 00:00:00 2001 From: Victory Omole Date: Tue, 19 Apr 2022 21:41:40 -0500 Subject: [PATCH 05/10] Update known_devices.py --- cirq-google/cirq_google/devices/known_devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index d92d15ab991..b7a4a55b30f 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -148,7 +148,7 @@ def create_device_proto_for_qubits( gate_type = internal_type # Note: if it is not a measurement gate, and it's _num_qubits_ method - # doesn't return 2, it's assumed to be a two qubit gate. + # doesn't return 1, it's assumed to be a two qubit gate. if gate_type == cirq.MeasurementGate: gate.valid_targets.append(_MEAS_TARGET_SET) elif gate_type == cirq.WaitGate: From 3adc5d3542d1ea238ee20d93f439ba414bdb7299 Mon Sep 17 00:00:00 2001 From: vtomole Date: Wed, 20 Apr 2022 12:51:40 -0500 Subject: [PATCH 06/10] Review 1 --- .../cirq/contrib/quirk/export_to_quirk_test.py | 5 ++--- cirq-core/cirq/ion/convert_to_ion_gates_test.py | 10 +++------- cirq-core/cirq/ion/ion_device_test.py | 4 ++-- cirq-core/cirq/ops/common_gates_test.py | 10 ++-------- cirq-core/cirq/ops/controlled_gate_test.py | 15 +++------------ cirq-core/cirq/ops/controlled_operation_test.py | 10 ++-------- cirq-core/cirq/ops/gate_operation_test.py | 7 ++----- cirq-core/cirq/ops/identity_test.py | 5 ++--- cirq-core/cirq/ops/pauli_string_test.py | 5 ++--- .../convert_to_cz_and_single_gates_test.py | 5 +---- cirq-core/cirq/optimizers/eject_z_test.py | 5 ++--- .../cirq/optimizers/expand_composite_test.py | 5 +---- .../optimizers/merge_single_qubit_gates_test.py | 5 ++--- cirq-core/cirq/testing/consistent_act_on_test.py | 10 ++-------- .../cirq/testing/consistent_decomposition_test.py | 15 +++------------ .../cirq/testing/consistent_protocols_test.py | 10 ++-------- .../optimizers/convert_to_xmon_gates_test.py | 15 ++++----------- cirq-web/cirq_web/circuits/symbols_test.py | 10 ++-------- 18 files changed, 39 insertions(+), 112 deletions(-) diff --git a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py index 176cc7a0665..2656cb2a969 100644 --- a/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py +++ b/cirq-core/cirq/contrib/quirk/export_to_quirk_test.py @@ -177,9 +177,8 @@ def with_qubits(self, *new_qubits): return MysteryOperation(*new_qubits) -class MysteryGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 +class MysteryGate(cirq.testing.SingleQubitGate): + pass def test_various_unknown_gate_types(): diff --git a/cirq-core/cirq/ion/convert_to_ion_gates_test.py b/cirq-core/cirq/ion/convert_to_ion_gates_test.py index ac38bda68f5..3f0979477d0 100644 --- a/cirq-core/cirq/ion/convert_to_ion_gates_test.py +++ b/cirq-core/cirq/ion/convert_to_ion_gates_test.py @@ -19,17 +19,13 @@ import cirq -class OtherX(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class OtherX(cirq.testing.SingleQubitGate): def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) -class NoUnitary(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 +class NoUnitary(cirq.testing.SingleQubitGate): + pass class OtherCNOT(cirq.testing.TwoQubitGate): diff --git a/cirq-core/cirq/ion/ion_device_test.py b/cirq-core/cirq/ion/ion_device_test.py index 6d577633e46..24f9e8a1b7e 100644 --- a/cirq-core/cirq/ion/ion_device_test.py +++ b/cirq-core/cirq/ion/ion_device_test.py @@ -53,8 +53,8 @@ def test_init(): assert d.duration_of(cirq.measure(q0)) == 100 * ms assert d.duration_of(cirq.measure(q0, q1)) == 100 * ms assert d.duration_of(cirq.ops.XX(q0, q1)) == 200 * ms - with pytest.raises(ValueError): - _ = d.duration_of(cirq.ISWAP(q0)) + with pytest.raises(ValueError, match="Unsupported gate type"): + _ = d.duration_of(cirq.I(q0)) with pytest.raises(TypeError, match="NamedQubit"): _ = cirq.IonDevice( diff --git a/cirq-core/cirq/ops/common_gates_test.py b/cirq-core/cirq/ops/common_gates_test.py index 31f7fa8eb14..d2fcb6f5de9 100644 --- a/cirq-core/cirq/ops/common_gates_test.py +++ b/cirq-core/cirq/ops/common_gates_test.py @@ -322,22 +322,16 @@ def test_x_act_on_tableau(): cirq.act_on(cirq.X**foo, args, [cirq.LineQubit(1)]) -class iZGate(cirq.Gate): +class iZGate(cirq.testing.SingleQubitGate): """Equivalent to an iZ gate without _act_on_ defined on it.""" - def _num_qubits_(self) -> int: - return 1 - def _unitary_(self): return np.array([[1j, 0], [0, -1j]]) -class MinusOnePhaseGate(cirq.Gate): +class MinusOnePhaseGate(cirq.testing.SingleQubitGate): """Equivalent to a -1 global phase without _act_on_ defined on it.""" - def _num_qubits_(self) -> int: - return 1 - def _unitary_(self): return np.array([[-1, 0], [0, -1]]) diff --git a/cirq-core/cirq/ops/controlled_gate_test.py b/cirq-core/cirq/ops/controlled_gate_test.py index 370242fb5ee..b8686ee7a9d 100644 --- a/cirq-core/cirq/ops/controlled_gate_test.py +++ b/cirq-core/cirq/ops/controlled_gate_test.py @@ -22,10 +22,7 @@ from cirq.type_workarounds import NotImplementedType -class GateUsingWorkspaceForApplyUnitary(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class GateUsingWorkspaceForApplyUnitary(cirq.testing.SingleQubitGate): def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: args.available_buffer[...] = args.target_tensor args.target_tensor[...] = 0 @@ -41,13 +38,10 @@ def __repr__(self): return 'cirq.ops.controlled_gate_test.GateUsingWorkspaceForApplyUnitary()' -class GateAllocatingNewSpaceForResult(cirq.Gate): +class GateAllocatingNewSpaceForResult(cirq.testing.SingleQubitGate): def __init__(self): self._matrix = cirq.testing.random_unitary(2, random_state=4321) - def _num_qubits_(self) -> int: - return 1 - def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: assert len(args.axes) == 1 a = args.axes[0] @@ -75,10 +69,7 @@ def __repr__(self): return 'cirq.ops.controlled_gate_test.GateAllocatingNewSpaceForResult()' -class RestrictedGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class RestrictedGate(cirq.testing.SingleQubitGate): def __str__(self): return 'Restricted' diff --git a/cirq-core/cirq/ops/controlled_operation_test.py b/cirq-core/cirq/ops/controlled_operation_test.py index 547d60be479..33849c99804 100644 --- a/cirq-core/cirq/ops/controlled_operation_test.py +++ b/cirq-core/cirq/ops/controlled_operation_test.py @@ -23,10 +23,7 @@ from cirq.type_workarounds import NotImplementedType -class GateUsingWorkspaceForApplyUnitary(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class GateUsingWorkspaceForApplyUnitary(cirq.testing.SingleQubitGate): def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: args.available_buffer[...] = args.target_tensor args.target_tensor[...] = 0 @@ -42,13 +39,10 @@ def __repr__(self): return 'cirq.ops.controlled_operation_test.GateUsingWorkspaceForApplyUnitary()' -class GateAllocatingNewSpaceForResult(cirq.Gate): +class GateAllocatingNewSpaceForResult(cirq.testing.SingleQubitGate): def __init__(self): self._matrix = cirq.testing.random_unitary(2, random_state=1234) - def _num_qubits_(self) -> int: - return 1 - def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs) -> Union[np.ndarray, NotImplementedType]: assert len(args.axes) == 1 a = args.axes[0] diff --git a/cirq-core/cirq/ops/gate_operation_test.py b/cirq-core/cirq/ops/gate_operation_test.py index d4ee752c886..a2d57f9235e 100644 --- a/cirq-core/cirq/ops/gate_operation_test.py +++ b/cirq-core/cirq/ops/gate_operation_test.py @@ -288,10 +288,7 @@ def test_repr(): repr(cirq.GateOperation(cirq.CZ, (a, b))) == 'cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1))' ) - class Inconsistent(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - + class Inconsistent(cirq.testing.SingleQubitGate): def __repr__(self): return 'Inconsistent' @@ -425,7 +422,7 @@ def test_cannot_remap_non_measurement_gate(): def test_is_parameterized(): - class No1(cirq.Gate): + class No1(cirq.testing.SingleQubitGate): def num_qubits(self) -> int: return 1 diff --git a/cirq-core/cirq/ops/identity_test.py b/cirq-core/cirq/ops/identity_test.py index 1603d0c8656..c782cd39228 100644 --- a/cirq-core/cirq/ops/identity_test.py +++ b/cirq-core/cirq/ops/identity_test.py @@ -178,9 +178,8 @@ def test_identity_global(): def test_identity_mul(): - class UnknownGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class UnknownGate(cirq.testing.SingleQubitGate): + pass class UnknownOperation(cirq.Operation): @property diff --git a/cirq-core/cirq/ops/pauli_string_test.py b/cirq-core/cirq/ops/pauli_string_test.py index ee810939e85..d372dcebe82 100644 --- a/cirq-core/cirq/ops/pauli_string_test.py +++ b/cirq-core/cirq/ops/pauli_string_test.py @@ -709,9 +709,8 @@ def test_pass_operations_over_cz(): def test_pass_operations_over_no_common_qubits(): - class DummyGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class DummyGate(cirq.testing.SingleQubitGate): + pass q0, q1 = _make_qubits(2) op0 = DummyGate()(q1) diff --git a/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py b/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py index bc2b3be9db2..2c8f9f7e6ef 100644 --- a/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py +++ b/cirq-core/cirq/optimizers/convert_to_cz_and_single_gates_test.py @@ -63,10 +63,7 @@ def test_kak_decomposes_unknown_two_qubit_gate(): def test_composite_gates_without_matrix(): - class CompositeDummy(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - + class CompositeDummy(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): yield cirq.X(qubits[0]) yield cirq.Y(qubits[0]) ** 0.5 diff --git a/cirq-core/cirq/optimizers/eject_z_test.py b/cirq-core/cirq/optimizers/eject_z_test.py index 657c02fc960..c5d1f28309f 100644 --- a/cirq-core/cirq/optimizers/eject_z_test.py +++ b/cirq-core/cirq/optimizers/eject_z_test.py @@ -159,9 +159,8 @@ def test_measurement_consumes_zs(): def test_unphaseable_causes_earlier_merge_without_size_increase(): - class UnknownGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class UnknownGate(cirq.testing.SingleQubitGate): + pass u = UnknownGate() diff --git a/cirq-core/cirq/optimizers/expand_composite_test.py b/cirq-core/cirq/optimizers/expand_composite_test.py index 748bf5261e5..d367fa19a4a 100644 --- a/cirq-core/cirq/optimizers/expand_composite_test.py +++ b/cirq-core/cirq/optimizers/expand_composite_test.py @@ -105,10 +105,7 @@ def test_recursive_composite(): def test_decompose_returns_not_flat_op_tree(): - class DummyGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - + class DummyGate(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): (q0,) = qubits # Yield a tuple of gates instead of yielding a gate diff --git a/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py b/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py index 8576bc4e175..a3a9ecf8451 100644 --- a/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py +++ b/cirq-core/cirq/optimizers/merge_single_qubit_gates_test.py @@ -129,9 +129,8 @@ def test_ignores_2qubit_target(): def test_ignore_unsupported_gate(): - class UnsupportedDummy(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 + class UnsupportedDummy(cirq.testing.SingleQubitGate): + pass q0 = cirq.LineQubit(0) circuit = cirq.Circuit(UnsupportedDummy()(q0)) diff --git a/cirq-core/cirq/testing/consistent_act_on_test.py b/cirq-core/cirq/testing/consistent_act_on_test.py index a8c72cfb11f..34be8031b95 100644 --- a/cirq-core/cirq/testing/consistent_act_on_test.py +++ b/cirq-core/cirq/testing/consistent_act_on_test.py @@ -20,10 +20,7 @@ import cirq -class GoodGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class GoodGate(cirq.testing.SingleQubitGate): def _unitary_(self): return np.array([[0, 1], [1, 0]]) @@ -36,10 +33,7 @@ def _act_on_(self, args: 'cirq.OperationTarget', qubits: Sequence['cirq.Qid']): return NotImplemented -class BadGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class BadGate(cirq.testing.SingleQubitGate): def _unitary_(self): return np.array([[0, 1j], [1, 0]]) diff --git a/cirq-core/cirq/testing/consistent_decomposition_test.py b/cirq-core/cirq/testing/consistent_decomposition_test.py index b57c158cc1f..88c98ec437b 100644 --- a/cirq-core/cirq/testing/consistent_decomposition_test.py +++ b/cirq-core/cirq/testing/consistent_decomposition_test.py @@ -20,10 +20,7 @@ import cirq -class GoodGateDecompose(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class GoodGateDecompose(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return cirq.X(qubits[0]) @@ -31,10 +28,7 @@ def _unitary_(self): return np.array([[0, 1], [1, 0]]) -class BadGateDecompose(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class BadGateDecompose(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return cirq.Y(qubits[0]) @@ -74,10 +68,7 @@ def _decompose_(self, qubits): yield GateDecomposeNotImplemented().on_each(*qubits) -class GateDecomposeNotImplemented(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class GateDecomposeNotImplemented(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return NotImplemented diff --git a/cirq-core/cirq/testing/consistent_protocols_test.py b/cirq-core/cirq/testing/consistent_protocols_test.py index f2b47af4ca2..8b9e275dfb8 100644 --- a/cirq-core/cirq/testing/consistent_protocols_test.py +++ b/cirq-core/cirq/testing/consistent_protocols_test.py @@ -25,7 +25,7 @@ import cirq.testing.consistent_controlled_gate_op_test as controlled_gate_op_test -class GoodGate(cirq.Gate): +class GoodGate(cirq.testing.SingleQubitGate): def __init__( self, *, @@ -35,9 +35,6 @@ def __init__( self.phase_exponent = cirq.canonicalize_half_turns(phase_exponent) self.exponent = exponent - def _num_qubits_(self) -> int: - return 1 - def _has_unitary_(self): return not cirq.is_parameterized(self) @@ -187,13 +184,10 @@ def __repr__(self): return f"BadGateRepr({', '.join(args)})" -class GoodEigenGate(cirq.EigenGate): +class GoodEigenGate(cirq.EigenGate, cirq.testing.SingleQubitGate): def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: return [(0, np.diag([1, 0])), (1, np.diag([0, 1]))] - def _num_qubits_(self) -> int: - return 1 - def __repr__(self): return 'GoodEigenGate(exponent={}, global_shift={!r})'.format( proper_repr(self._exponent), self._global_shift diff --git a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py index ded6828b3b2..e1d2313328a 100644 --- a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py +++ b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates_test.py @@ -18,10 +18,7 @@ import cirq_google -class OtherX(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class OtherX(cirq.testing.SingleQubitGate): def _unitary_(self) -> np.ndarray: return np.array([[0, 1], [1, 0]]) @@ -31,17 +28,13 @@ def _decompose_(self, qubits): return OtherOtherX().on(*qubits) # coverage:ignore -class OtherOtherX(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 - +class OtherOtherX(cirq.testing.SingleQubitGate): def _decompose_(self, qubits): return OtherX().on(*qubits) -class NonNativeGate(cirq.Gate): - def _num_qubits_(self) -> int: - return 1 +class NonNativeGate(cirq.testing.SingleQubitGate): + pass def test_avoids_infinite_cycle_when_matrix_available(): diff --git a/cirq-web/cirq_web/circuits/symbols_test.py b/cirq-web/cirq_web/circuits/symbols_test.py index 963eee4139d..79bb457bdda 100644 --- a/cirq-web/cirq_web/circuits/symbols_test.py +++ b/cirq-web/cirq_web/circuits/symbols_test.py @@ -16,21 +16,15 @@ import pytest -class MockGateNoDiagramInfo(cirq.Gate): +class MockGateNoDiagramInfo(cirq.testing.SingleQubitGate): def __init__(self): super(MockGateNoDiagramInfo, self) - def _num_qubits_(self) -> int: - return 1 - -class MockGateUnimplementedDiagramInfo(cirq.Gate): +class MockGateUnimplementedDiagramInfo(cirq.testing.SingleQubitGate): def __init__(self): super(MockGateUnimplementedDiagramInfo, self) - def _num_qubits_(self) -> int: - return 1 - def _circuit_diagram_info_(self, args): return NotImplemented From 54fb0c0a9c28cd5bb2930f47ee6b8d7ac6902304 Mon Sep 17 00:00:00 2001 From: vtomole Date: Wed, 20 Apr 2022 14:33:03 -0500 Subject: [PATCH 07/10] Hardcode single qubit gates --- cirq-google/cirq_google/devices/known_devices.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index b7a4a55b30f..16105578bb6 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -109,6 +109,9 @@ def create_device_proto_for_qubits( # Create valid qubit list out.valid_qubits.extend(v2.qubit_to_proto_id(q) for q in qubits) + # Single qubit gates in this gateset + single_qubit_gates = (cirq.PhasedXPowGate, cirq.PhasedXZGate, cirq.ZPowGate) + # Set up a target set for measurement (any qubit permutation) meas_targets = out.valid_targets.add() meas_targets.name = _MEAS_TARGET_SET @@ -157,10 +160,7 @@ def create_device_proto_for_qubits( # Github issue: # https://github.com/quantumlib/Cirq/issues/2537 gate.number_of_qubits = 1 - elif ( - inspect.getsource(gate_type._num_qubits_) - == ' def _num_qubits_(self) -> int:\n return 1\n' - ): + elif gate_type in single_qubit_gates: gate.number_of_qubits = 1 else: # This must be a two-qubit gate From 9fc2be2eda90a2b48c5351e11386f34cc51e66d4 Mon Sep 17 00:00:00 2001 From: vtomole Date: Thu, 21 Apr 2022 10:42:25 -0500 Subject: [PATCH 08/10] Nits --- cirq-core/cirq/ops/clifford_gate.py | 2 +- cirq-google/cirq_google/devices/known_devices.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index 48906d89437..06cfcb9afc2 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -127,7 +127,7 @@ def _validate_map_input( def _pad_tableau( clifford_tableau: qis.CliffordTableau, num_qubits_after_padding: int, axes: List[int] ) -> qis.CliffordTableau: - """Roughly, this function copies self.tabluea into the "identity" matrix.""" + """Roughly, this function copies self.tableau into the "identity" matrix.""" # Sanity check if len(set(axes)) != clifford_tableau.n: raise ValueError( diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index 16105578bb6..7ccd10a3d4d 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import inspect + from typing import Any, Collection, Dict, Optional, Iterable, List, Set, Tuple import cirq From d7e900821c4e29ae82d23cb727f4014be0ad4955 Mon Sep 17 00:00:00 2001 From: vtomole Date: Thu, 21 Apr 2022 10:58:22 -0500 Subject: [PATCH 09/10] Update comment --- cirq-google/cirq_google/devices/known_devices.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index 7ccd10a3d4d..28e396e61ce 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -150,8 +150,8 @@ def create_device_proto_for_qubits( # Choose target set and number of qubits based on gate type. gate_type = internal_type - # Note: if it is not a measurement gate, and it's _num_qubits_ method - # doesn't return 1, it's assumed to be a two qubit gate. + # Note: if it is not a measurement gate, and it's type + # is not in the single_qubit_gates tuple, it's assumed to be a two qubit gate. if gate_type == cirq.MeasurementGate: gate.valid_targets.append(_MEAS_TARGET_SET) elif gate_type == cirq.WaitGate: From d3f9372a2cacdbe87659db7059d83acec813933e Mon Sep 17 00:00:00 2001 From: Victory Omole Date: Thu, 21 Apr 2022 12:04:13 -0500 Subject: [PATCH 10/10] Update known_devices.py --- cirq-google/cirq_google/devices/known_devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/devices/known_devices.py b/cirq-google/cirq_google/devices/known_devices.py index 28e396e61ce..d6f5b800fa5 100644 --- a/cirq-google/cirq_google/devices/known_devices.py +++ b/cirq-google/cirq_google/devices/known_devices.py @@ -150,7 +150,7 @@ def create_device_proto_for_qubits( # Choose target set and number of qubits based on gate type. gate_type = internal_type - # Note: if it is not a measurement gate, and it's type + # Note: if it is not a measurement gate and it's type # is not in the single_qubit_gates tuple, it's assumed to be a two qubit gate. if gate_type == cirq.MeasurementGate: gate.valid_targets.append(_MEAS_TARGET_SET)