From a0e60aadc60539bb40e5dff63080a76368f253f6 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Wed, 18 May 2022 15:30:57 -0700 Subject: [PATCH 1/4] Change Pasqal to use transformers - Add PasqalGateset that encapsulates gatesets used by the PasqalDevice classes. - Deprecate PasqalConverter and use cirq.convert_to_target_gateset instead. --- cirq-pasqal/cirq_pasqal/__init__.py | 2 + .../cirq_pasqal/json_resolver_cache.py | 1 + .../json_test_data/PasqalGateset.json | 4 + .../json_test_data/PasqalGateset.repr | 1 + cirq-pasqal/cirq_pasqal/pasqal_device.py | 41 ++----- cirq-pasqal/cirq_pasqal/pasqal_device_test.py | 13 ++- cirq-pasqal/cirq_pasqal/pasqal_gateset.py | 66 ++++++++++++ .../cirq_pasqal/pasqal_gateset_test.py | 102 ++++++++++++++++++ 8 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json create mode 100644 cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr create mode 100644 cirq-pasqal/cirq_pasqal/pasqal_gateset.py create mode 100644 cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py diff --git a/cirq-pasqal/cirq_pasqal/__init__.py b/cirq-pasqal/cirq_pasqal/__init__.py index e55b1229cc6..d7d35060db2 100644 --- a/cirq-pasqal/cirq_pasqal/__init__.py +++ b/cirq-pasqal/cirq_pasqal/__init__.py @@ -18,6 +18,8 @@ from cirq_pasqal.pasqal_qubits import ThreeDQubit, TwoDQubit +from cirq_pasqal.pasqal_gateset import PasqalGateset + from cirq_pasqal.pasqal_device import PasqalDevice, PasqalVirtualDevice, PasqalConverter from cirq_pasqal.pasqal_noise_model import PasqalNoiseModel diff --git a/cirq-pasqal/cirq_pasqal/json_resolver_cache.py b/cirq-pasqal/cirq_pasqal/json_resolver_cache.py index 840d84aa39d..983d14d1307 100644 --- a/cirq-pasqal/cirq_pasqal/json_resolver_cache.py +++ b/cirq-pasqal/cirq_pasqal/json_resolver_cache.py @@ -23,6 +23,7 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]: return { 'PasqalDevice': cirq_pasqal.PasqalDevice, + 'PasqalGateset': cirq_pasqal.PasqalGateset, 'PasqalVirtualDevice': cirq_pasqal.PasqalVirtualDevice, 'ThreeDQubit': cirq_pasqal.ThreeDQubit, 'TwoDQubit': cirq_pasqal.TwoDQubit, diff --git a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json new file mode 100644 index 00000000000..de9934bd559 --- /dev/null +++ b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json @@ -0,0 +1,4 @@ +{ + "cirq_type": "PasqalGateset", + "include_controlled_ops": false +} diff --git a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr new file mode 100644 index 00000000000..33125f52252 --- /dev/null +++ b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr @@ -0,0 +1 @@ +cirq_pasqal.PasqalGateset(include_controlled_ops=False) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device.py b/cirq-pasqal/cirq_pasqal/pasqal_device.py index bc80799a5b9..326d628494c 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device.py @@ -18,7 +18,7 @@ import cirq from cirq import _compat, GridQubit, LineQubit from cirq.ops import NamedQubit -from cirq_pasqal import ThreeDQubit, TwoDQubit +from cirq_pasqal import ThreeDQubit, TwoDQubit, PasqalGateset @cirq.value.value_equality @@ -63,20 +63,7 @@ def __init__(self, qubits: Sequence[cirq.Qid]) -> None: 'qubits.'.format(type(self), self.maximum_qubit_number) ) - self.gateset = cirq.Gateset( - cirq.ParallelGateFamily(cirq.H), - cirq.ParallelGateFamily(cirq.PhasedXPowGate), - cirq.ParallelGateFamily(cirq.XPowGate), - cirq.ParallelGateFamily(cirq.YPowGate), - cirq.ParallelGateFamily(cirq.ZPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate), - cirq.IdentityGate, - cirq.MeasurementGate, - unroll_circuit_op=False, - ) + self.gateset = PasqalGateset() self.qubits = qubits self._metadata = cirq.DeviceMetadata( qubits, nx.from_edgelist([(a, b) for a in qubits for b in qubits if a != b]) @@ -103,7 +90,8 @@ def qubit_list(self): return [qubit for qubit in self.qubits] @_compat.deprecated( - fix='Use PasqalConverter() to decompose operation instead.', deadline='v0.15' + fix='Use cirq.optimize_for_target_gateset(circuit, gateset=PasqalGateset()) instead.', + deadline='v0.15', ) def decompose_operation(self, operation: cirq.Operation) -> 'cirq.OP_TREE': @@ -114,9 +102,7 @@ def decompose_operation(self, operation: cirq.Operation) -> 'cirq.OP_TREE': # Try to decompose the operation into elementary device operations if not self.is_pasqal_device_op(operation): - decomposition = PasqalConverter().pasqal_convert( - operation, keep=self.is_pasqal_device_op - ) + decomposition = self.gateset.decompose_to_target_gateset(operation, 0) return decomposition @@ -253,24 +239,14 @@ def __init__( 'Control_radius cannot be larger than 3 times' ' the minimal distance between qubits.' ) - self.control_radius = control_radius - self.exclude_gateset = cirq.Gateset( - cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate), - cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate), - ) - self.controlled_gateset = cirq.Gateset( - *self.exclude_gateset.gates, cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate) - ) + self.gateset = PasqalGateset(include_controlled_ops=False) + self.controlled_gateset = cirq.Gateset(cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate)) @property def supported_qubit_type(self): return (ThreeDQubit, TwoDQubit, GridQubit, LineQubit) - def is_pasqal_device_op(self, op: cirq.Operation) -> bool: - return super().is_pasqal_device_op(op) and op not in self.exclude_gateset - def validate_operation(self, operation: cirq.Operation): """Raises an error if the given operation is invalid on this device. @@ -357,6 +333,9 @@ def _json_dict_(self) -> Dict[str, Any]: return cirq.protocols.obj_to_dict_helper(self, ['control_radius', 'qubits']) +@_compat.deprecated_class( + deadline='v0.16', fix='Use cirq.optimize_for_target_gateset(circuit, gateset=PasqalGateset()).' +) class PasqalConverter(cirq.neutral_atoms.ConvertToNeutralAtomGates): """A gate converter for compatibility with Pasqal processors. diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py index f5b70b055a7..3426223216e 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py @@ -99,16 +99,16 @@ def test_is_pasqal_device_op(): def test_decompose_operation_deprecated(): - d = generic_device(3) - with cirq.testing.assert_deprecated('decompose', deadline='v0.15', count=2): - for op in d.decompose_operation((cirq.CCZ**1.5).on(*(d.qubit_list()))): + d = generic_device(2) + with cirq.testing.assert_deprecated('decompose', deadline='v0.15'): + for op in d.decompose_operation((cirq.CZ**1.5).on(*(d.qubit_list()))): d.validate_operation(op) p_qubits = [cirq.LineQubit(3), cirq.LineQubit(4)] d = PasqalVirtualDevice(1.0, p_qubits) op = (cirq.ops.CNOT).on(*(d.qubit_list())) ** 2 - with cirq.testing.assert_deprecated('decompose', deadline='v0.15', count=2): + with cirq.testing.assert_deprecated('decompose', deadline='v0.15'): assert d.decompose_operation(op) == [] @@ -131,9 +131,8 @@ def with_qubits(self, *new_qubits): op = FakeOperation(g, q).with_qubits(*q) d = PasqalDevice(q) - with pytest.raises(TypeError, match="Don't know how to work with"): - with cirq.testing.assert_deprecated('decompose', deadline='v0.15', count=2): - d.decompose_operation(op) + with cirq.testing.assert_deprecated('decompose', deadline='v0.15', count=1): + assert d.decompose_operation(op) is NotImplemented def test_validate_operation_errors(): diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py new file mode 100644 index 00000000000..afd3a198a58 --- /dev/null +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py @@ -0,0 +1,66 @@ +# Copyright 2022 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +# +from typing import Any, Dict + + +import cirq + + +class PasqalGateset(cirq.neutral_atoms.NeutralAtomGateset): + """A Compilation target intended for Pasqal neutral atom devices. + This gateset supports single qubit gates that can be used + in a parallel fashion as well as CZ. + + This gateset can optionally include CNOT, CCNOT (TOFFOLI) gates, and + CCZ as well. + + Args: + include_controlled_ops: Whether to include CCZ, CCNOT, and CNOT + gates (defaults to True). + """ + + def __init__(self, include_controlled_ops: bool = True): + gate_families = [ + cirq.ParallelGateFamily(cirq.H), + cirq.ParallelGateFamily(cirq.PhasedXPowGate), + cirq.ParallelGateFamily(cirq.XPowGate), + cirq.ParallelGateFamily(cirq.YPowGate), + cirq.ParallelGateFamily(cirq.ZPowGate), + cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate), + cirq.IdentityGate, + cirq.MeasurementGate, + ] + self.include_controlled_ops = include_controlled_ops + if self.include_controlled_ops: + gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate)) + gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate)) + gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate)) + + # Call cirq.Gateset __init__ which is our grand-father inherited class + # pylint doesn't like this so disable checks on this. + # pylint: disable=bad-super-call + super(cirq.neutral_atoms.NeutralAtomGateset, self).__init__( + *gate_families, unroll_circuit_op=False + ) + + def __repr__(self): + return f'cirq_pasqal.PasqalGateset(include_controlled_ops={self.include_controlled_ops})' + + @classmethod + def _from_json_dict_(cls, include_controlled_ops, **kwargs) -> 'PasqalGateset': + return cls(include_controlled_ops=include_controlled_ops) + + def _json_dict_(self) -> Dict[str, Any]: + return cirq.protocols.obj_to_dict_helper(self, ['include_controlled_ops']) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py new file mode 100644 index 00000000000..af3def3b448 --- /dev/null +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py @@ -0,0 +1,102 @@ +# Copyright 2022 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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 pytest +import cirq +import cirq_pasqal + +Q, Q2, Q3 = cirq.LineQubit.range(3) + + +@pytest.mark.parametrize( + "op,expected", + [ + (cirq.H(Q), True), + (cirq.HPowGate(exponent=0.5)(Q), False), + (cirq.PhasedXPowGate(exponent=0.25, phase_exponent=0.125)(Q), True), + (cirq.XPowGate(exponent=0.5)(Q), True), + (cirq.YPowGate(exponent=0.25)(Q), True), + (cirq.ZPowGate(exponent=0.125)(Q), True), + (cirq.CZPowGate(exponent=0.5)(Q, Q2), False), + (cirq.CZ(Q, Q2), True), + (cirq.CNOT(Q, Q2), True), + (cirq.SWAP(Q, Q2), False), + (cirq.ISWAP(Q, Q2), False), + (cirq.CCNOT(Q, Q2, Q3), True), + (cirq.CCZ(Q, Q2, Q3), True), + (cirq.ParallelGate(cirq.X, num_copies=3)(Q, Q2, Q3), True), + (cirq.ParallelGate(cirq.Y, num_copies=3)(Q, Q2, Q3), True), + (cirq.ParallelGate(cirq.Z, num_copies=3)(Q, Q2, Q3), True), + (cirq.X(Q).controlled_by(Q2, Q3), True), + (cirq.Z(Q).controlled_by(Q2, Q3), True), + (cirq.ZPowGate(exponent=0.5)(Q).controlled_by(Q2, Q3), False), + ], +) +def test_gateset(op: cirq.Operation, expected: bool): + gs = cirq_pasqal.PasqalGateset() + assert gs.validate(op) == expected + assert gs.validate(cirq.Circuit(op)) == expected + + +@pytest.mark.parametrize( + "op,expected", + [ + (cirq.H(Q), True), + (cirq.HPowGate(exponent=0.5)(Q), False), + (cirq.PhasedXPowGate(exponent=0.25, phase_exponent=0.125)(Q), True), + (cirq.ParallelGate(cirq.X, num_copies=3)(Q, Q2, Q3), True), + (cirq.CZPowGate(exponent=0.5)(Q, Q2), False), + (cirq.CZ(Q, Q2), True), + (cirq.CNOT(Q, Q2), False), + (cirq.CCNOT(Q, Q2, Q3), False), + (cirq.CCZ(Q, Q2, Q3), False), + (cirq.Z(Q).controlled_by(Q2), True), + (cirq.X(Q).controlled_by(Q2, Q3), False), + (cirq.Z(Q).controlled_by(Q2, Q3), False), + (cirq.ZPowGate(exponent=0.5)(Q).controlled_by(Q2, Q3), False), + ], +) +def test_control_gates_not_included(op: cirq.Operation, expected: bool): + gs = cirq_pasqal.PasqalGateset(include_controlled_ops=False) + assert gs.validate(op) == expected + assert gs.validate(cirq.Circuit(op)) == expected + + +@pytest.mark.parametrize( + "op", + [ + cirq.X(Q), + cirq.SWAP(Q, Q2), + cirq.ISWAP(Q, Q2), + cirq.CCNOT(Q, Q2, Q3), + cirq.CCZ(Q, Q2, Q3), + cirq.ParallelGate(cirq.X, num_copies=3)(Q, Q2, Q3), + cirq.SWAP(Q, Q2).controlled_by(Q3), + ], +) +def test_decomposition(op: cirq.Operation): + circuit = cirq.Circuit(op) + gs = cirq_pasqal.PasqalGateset() + gs2 = cirq_pasqal.PasqalGateset(include_controlled_ops=False) + for gateset in [gs, gs2]: + decomposed_circuit = cirq.optimize_for_target_gateset(circuit, gateset=gateset) + for new_op in decomposed_circuit.all_operations(): + assert gs.validate(new_op) + + +def test_repr(): + gs = cirq_pasqal.PasqalGateset() + gs2 = cirq_pasqal.PasqalGateset(include_controlled_ops=False) + assert repr(gs) == 'cirq_pasqal.PasqalGateset(include_controlled_ops=True)' + assert repr(gs2) == 'cirq_pasqal.PasqalGateset(include_controlled_ops=False)' From 4b87a75808190d22a2047451ec4cf6dc0757c761 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Thu, 19 May 2022 06:05:58 -0700 Subject: [PATCH 2/4] Fix type errors and use optimize_for_gateset internally. --- cirq-pasqal/cirq_pasqal/pasqal_device.py | 12 ++++-------- cirq-pasqal/cirq_pasqal/pasqal_device_test.py | 9 +++++---- cirq-pasqal/cirq_pasqal/pasqal_gateset.py | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device.py b/cirq-pasqal/cirq_pasqal/pasqal_device.py index 326d628494c..102a6496f7e 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device.py @@ -95,16 +95,12 @@ def qubit_list(self): ) def decompose_operation(self, operation: cirq.Operation) -> 'cirq.OP_TREE': - decomposition = [operation] - if not isinstance(operation, cirq.GateOperation): - raise TypeError(f"{operation!r} is not a gate operation.") - - # Try to decompose the operation into elementary device operations - if not self.is_pasqal_device_op(operation): - decomposition = self.gateset.decompose_to_target_gateset(operation, 0) + raise TypeError(f'{operation!r} is not a gate operation.') - return decomposition + return cirq.optimize_for_target_gateset( + cirq.Circuit(operation), gateset=self.gateset + ).all_operations() def is_pasqal_device_op(self, op: cirq.Operation) -> bool: if not isinstance(op, cirq.Operation): diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py index 3426223216e..4b4be6453d5 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py @@ -109,14 +109,14 @@ def test_decompose_operation_deprecated(): op = (cirq.ops.CNOT).on(*(d.qubit_list())) ** 2 with cirq.testing.assert_deprecated('decompose', deadline='v0.15'): - assert d.decompose_operation(op) == [] + assert list(d.decompose_operation(op)) == [] -def test_pasqal_converter_deprecated(): +def test_not_gate_operation_deprecated(): q = cirq.NamedQubit.range(2, prefix='q') g = cirq.testing.TwoQubitGate() - class FakeOperation(cirq.ops.GateOperation): + class FakeOperation(cirq.ops.Operation): def __init__(self, gate, qubits): self._gate = gate self._qubits = qubits @@ -132,7 +132,8 @@ def with_qubits(self, *new_qubits): d = PasqalDevice(q) with cirq.testing.assert_deprecated('decompose', deadline='v0.15', count=1): - assert d.decompose_operation(op) is NotImplemented + with pytest.raises(TypeError, match='not a gate operation'): + d.decompose_operation(op) def test_validate_operation_errors(): diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py index afd3a198a58..c21b38e4b25 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py @@ -59,7 +59,7 @@ def __repr__(self): return f'cirq_pasqal.PasqalGateset(include_controlled_ops={self.include_controlled_ops})' @classmethod - def _from_json_dict_(cls, include_controlled_ops, **kwargs) -> 'PasqalGateset': + def _from_json_dict_(cls, include_controlled_ops, **kwargs): return cls(include_controlled_ops=include_controlled_ops) def _json_dict_(self) -> Dict[str, Any]: From 8c1a3b6b1fe136ba2924f221a0d9455069d9b76a Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Mon, 23 May 2022 11:20:17 -0700 Subject: [PATCH 3/4] Change to additional_controlled_ops and assert equivalent repr --- .../json_test_data/PasqalGateset.json | 2 +- .../json_test_data/PasqalGateset.repr | 2 +- cirq-pasqal/cirq_pasqal/pasqal_device.py | 2 +- cirq-pasqal/cirq_pasqal/pasqal_gateset.py | 17 +++++++++-------- cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py | 15 +++++++++------ 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json index de9934bd559..2a713396dd5 100644 --- a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json +++ b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.json @@ -1,4 +1,4 @@ { "cirq_type": "PasqalGateset", - "include_controlled_ops": false + "include_additional_controlled_ops": false } diff --git a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr index 33125f52252..4f050a7b6c3 100644 --- a/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr +++ b/cirq-pasqal/cirq_pasqal/json_test_data/PasqalGateset.repr @@ -1 +1 @@ -cirq_pasqal.PasqalGateset(include_controlled_ops=False) +cirq_pasqal.PasqalGateset(include_additional_controlled_ops=False) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device.py b/cirq-pasqal/cirq_pasqal/pasqal_device.py index 102a6496f7e..509a80098bf 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device.py @@ -236,7 +236,7 @@ def __init__( ' the minimal distance between qubits.' ) self.control_radius = control_radius - self.gateset = PasqalGateset(include_controlled_ops=False) + self.gateset = PasqalGateset(include_additional_controlled_ops=False) self.controlled_gateset = cirq.Gateset(cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate)) @property diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py index c21b38e4b25..2f3b24b2965 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py @@ -27,11 +27,11 @@ class PasqalGateset(cirq.neutral_atoms.NeutralAtomGateset): CCZ as well. Args: - include_controlled_ops: Whether to include CCZ, CCNOT, and CNOT + include_additional_controlled_ops: Whether to include CCZ, CCNOT, and CNOT gates (defaults to True). """ - def __init__(self, include_controlled_ops: bool = True): + def __init__(self, include_additional_controlled_ops: bool = True): gate_families = [ cirq.ParallelGateFamily(cirq.H), cirq.ParallelGateFamily(cirq.PhasedXPowGate), @@ -42,8 +42,8 @@ def __init__(self, include_controlled_ops: bool = True): cirq.IdentityGate, cirq.MeasurementGate, ] - self.include_controlled_ops = include_controlled_ops - if self.include_controlled_ops: + self.include_additional_controlled_ops = include_additional_controlled_ops + if self.include_additional_controlled_ops: gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate)) gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate)) gate_families.append(cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate)) @@ -56,11 +56,12 @@ def __init__(self, include_controlled_ops: bool = True): ) def __repr__(self): - return f'cirq_pasqal.PasqalGateset(include_controlled_ops={self.include_controlled_ops})' + return (f'cirq_pasqal.PasqalGateset(include_additional_controlled_ops=' + f'{self.include_additional_controlled_ops})') @classmethod - def _from_json_dict_(cls, include_controlled_ops, **kwargs): - return cls(include_controlled_ops=include_controlled_ops) + def _from_json_dict_(cls, include_additional_controlled_ops, **kwargs): + return cls(include_additional_controlled_ops=include_additional_controlled_ops) def _json_dict_(self) -> Dict[str, Any]: - return cirq.protocols.obj_to_dict_helper(self, ['include_controlled_ops']) + return cirq.protocols.obj_to_dict_helper(self, ['include_additional_controlled_ops']) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py index af3def3b448..189a3caa919 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset_test.py @@ -68,7 +68,7 @@ def test_gateset(op: cirq.Operation, expected: bool): ], ) def test_control_gates_not_included(op: cirq.Operation, expected: bool): - gs = cirq_pasqal.PasqalGateset(include_controlled_ops=False) + gs = cirq_pasqal.PasqalGateset(include_additional_controlled_ops=False) assert gs.validate(op) == expected assert gs.validate(cirq.Circuit(op)) == expected @@ -88,7 +88,7 @@ def test_control_gates_not_included(op: cirq.Operation, expected: bool): def test_decomposition(op: cirq.Operation): circuit = cirq.Circuit(op) gs = cirq_pasqal.PasqalGateset() - gs2 = cirq_pasqal.PasqalGateset(include_controlled_ops=False) + gs2 = cirq_pasqal.PasqalGateset(include_additional_controlled_ops=False) for gateset in [gs, gs2]: decomposed_circuit = cirq.optimize_for_target_gateset(circuit, gateset=gateset) for new_op in decomposed_circuit.all_operations(): @@ -96,7 +96,10 @@ def test_decomposition(op: cirq.Operation): def test_repr(): - gs = cirq_pasqal.PasqalGateset() - gs2 = cirq_pasqal.PasqalGateset(include_controlled_ops=False) - assert repr(gs) == 'cirq_pasqal.PasqalGateset(include_controlled_ops=True)' - assert repr(gs2) == 'cirq_pasqal.PasqalGateset(include_controlled_ops=False)' + cirq.testing.assert_equivalent_repr( + cirq_pasqal.PasqalGateset(), setup_code='import cirq_pasqal' + ) + cirq.testing.assert_equivalent_repr( + cirq_pasqal.PasqalGateset(include_additional_controlled_ops=False), + setup_code='import cirq_pasqal', + ) From 838223fa7e1c252d4ef5632400eebd95d1f27c39 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Mon, 23 May 2022 11:25:34 -0700 Subject: [PATCH 4/4] Formatting --- cirq-pasqal/cirq_pasqal/pasqal_device_test.py | 2 +- cirq-pasqal/cirq_pasqal/pasqal_gateset.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py index 7be6a378ab0..fe976fb7543 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_device_test.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_device_test.py @@ -97,7 +97,7 @@ def test_is_pasqal_device_op(): assert d.is_pasqal_device_op(cirq.ops.X(TwoDQubit(0, 0))) assert not d2.is_pasqal_device_op(op1(TwoDQubit(0, 0), TwoDQubit(0, 1))) - + def test_validate_operation_errors(): d = generic_device(3) diff --git a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py index 2f3b24b2965..3001c2e16e7 100644 --- a/cirq-pasqal/cirq_pasqal/pasqal_gateset.py +++ b/cirq-pasqal/cirq_pasqal/pasqal_gateset.py @@ -56,8 +56,10 @@ def __init__(self, include_additional_controlled_ops: bool = True): ) def __repr__(self): - return (f'cirq_pasqal.PasqalGateset(include_additional_controlled_ops=' - f'{self.include_additional_controlled_ops})') + return ( + f'cirq_pasqal.PasqalGateset(include_additional_controlled_ops=' + f'{self.include_additional_controlled_ops})' + ) @classmethod def _from_json_dict_(cls, include_additional_controlled_ops, **kwargs):