From 8404bd45dfa382934abec662ee26e5653c746081 Mon Sep 17 00:00:00 2001 From: Tanuj Khattar Date: Fri, 25 Feb 2022 11:44:41 -0800 Subject: [PATCH 1/2] Deprecate cg.ConvertToXmonGates and replace with cirq.CZTargetGateset --- .../cirq_google/devices/xmon_device.py | 10 ++-- .../optimizers/convert_to_xmon_gates.py | 4 ++ .../optimizers/convert_to_xmon_gates_test.py | 12 +++-- .../optimizers/optimize_for_sycamore.py | 47 +++++-------------- 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/cirq-google/cirq_google/devices/xmon_device.py b/cirq-google/cirq_google/devices/xmon_device.py index 4a7df5bfb77..dc2eb9d6663 100644 --- a/cirq-google/cirq_google/devices/xmon_device.py +++ b/cirq-google/cirq_google/devices/xmon_device.py @@ -16,7 +16,6 @@ import cirq from cirq import _compat -from cirq_google.optimizers import convert_to_xmon_gates if TYPE_CHECKING: import cirq @@ -72,10 +71,15 @@ def qubit_set(self) -> FrozenSet[cirq.GridQubit]: @_compat.deprecated( deadline='v0.15', - fix='XmonDevice.decompose_operation is deperecated. Please use ConvertToXmonGates().', + fix='XmonDevice.decompose_operation is deprecated. ' + 'Please use cirq.optimize_for_target_gateset() and cirq.CZTargetGateset.', ) def decompose_operation(self, operation: cirq.Operation) -> cirq.OP_TREE: - return convert_to_xmon_gates.ConvertToXmonGates().convert(operation) + return [ + *cirq.optimize_for_target_gateset( + cirq.Circuit(operation), gateset=cirq.CZTargetGateset(allow_partial_czs=True) + ).all_operations() + ] def neighbors_of(self, qubit: cirq.GridQubit): """Returns the qubits that the given qubit can interact with.""" diff --git a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates.py b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates.py index fff04dcbd97..fff2173fc2d 100644 --- a/cirq-google/cirq_google/optimizers/convert_to_xmon_gates.py +++ b/cirq-google/cirq_google/optimizers/convert_to_xmon_gates.py @@ -16,6 +16,10 @@ import cirq +@cirq._compat.deprecated_class( + deadline='v1.0', + fix='Use cirq.optimize_for_target_gateset and cirq.CZTargetGateset instead.', +) class ConvertToXmonGates(cirq.PointOptimizer): """Attempts to convert strange gates into XmonGates. 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 93972c340cf..9a6477ed430 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 @@ -40,8 +40,10 @@ class NonNativeGate(cirq.SingleQubitGate): def test_avoids_infinite_cycle_when_matrix_available(): q = cirq.GridQubit(0, 0) c = cirq.Circuit(OtherX().on(q), OtherOtherX().on(q)) - cirq_google.ConvertToXmonGates().optimize_circuit(c) + with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'): + cirq_google.ConvertToXmonGates().optimize_circuit(c) cirq.testing.assert_has_diagram(c, '(0, 0): ───PhX(1)───PhX(1)───') + cirq.protocols.decompose(c) @@ -52,7 +54,10 @@ def test_avoids_infinite_cycle_when_matrix_available(): def test_bad_operation(): c = cirq.Circuit(NonNativeGate().on(q[0])) with pytest.raises(TypeError): - cirq_google.ConvertToXmonGates().optimize_circuit(c) + with cirq.testing.assert_deprecated( + "Use cirq.optimize_for_target_gateset", deadline='v1.0' + ): + cirq_google.ConvertToXmonGates().optimize_circuit(c) @pytest.mark.parametrize( @@ -68,4 +73,5 @@ def test_bad_operation(): ) def test_supported_operation(op, is_valid): c = cirq.Circuit(op) - assert (cirq_google.ConvertToXmonGates().optimization_at(c, 0, op) is not None) == is_valid + with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'): + assert (cirq_google.ConvertToXmonGates().optimization_at(c, 0, op) is not None) == is_valid diff --git a/cirq-google/cirq_google/optimizers/optimize_for_sycamore.py b/cirq-google/cirq_google/optimizers/optimize_for_sycamore.py index 61e4bb024c0..fa51eaae2db 100644 --- a/cirq-google/cirq_google/optimizers/optimize_for_sycamore.py +++ b/cirq-google/cirq_google/optimizers/optimize_for_sycamore.py @@ -20,7 +20,6 @@ import cirq from cirq_google import ops as cg_ops from cirq_google.optimizers import ( - convert_to_xmon_gates, ConvertToSycamoreGates, ConvertToSqrtIswapGates, ) @@ -29,29 +28,6 @@ import cirq_google -def _get_xmon_optimizers( - tolerance: float, tabulation: Optional[cirq.TwoQubitGateTabulation] -) -> List[Callable[[cirq.Circuit], None]]: - if tabulation is not None: - # coverage: ignore - raise ValueError("Gate tabulation not supported for xmon") - - return [ - convert_to_xmon_gates.ConvertToXmonGates().optimize_circuit, - ] - - -def _get_xmon_optimizers_part_cz( - tolerance: float, tabulation: Optional[cirq.TwoQubitGateTabulation] -) -> List[Callable[[cirq.Circuit], None]]: - if tabulation is not None: - # coverage: ignore - raise ValueError("Gate tabulation not supported for xmon") - return [ - convert_to_xmon_gates.ConvertToXmonGates().optimize_circuit, - ] - - def _get_sycamore_optimizers( tolerance: float, tabulation: Optional[cirq.TwoQubitGateTabulation] ) -> List[Callable[[cirq.Circuit], None]]: @@ -68,12 +44,15 @@ def _get_sqrt_iswap_optimizers( _OPTIMIZER_TYPES = { - 'xmon': _get_xmon_optimizers, - 'xmon_partial_cz': _get_xmon_optimizers_part_cz, 'sqrt_iswap': _get_sqrt_iswap_optimizers, 'sycamore': _get_sycamore_optimizers, } +_TARGET_GATESETS = { + 'xmon': lambda atol, _: cirq.CZTargetGateset(atol=atol), + 'xmon_partial_cz': lambda atol, _: cirq.CZTargetGateset(atol=atol, allow_partial_czs=True), +} + @lru_cache() def _gate_product_tabulation_cached( @@ -131,7 +110,7 @@ def optimized_for_sycamore( ValueError: If the `optimizer_type` is not a supported type. """ copy = circuit.copy() - if optimizer_type not in _OPTIMIZER_TYPES: + if optimizer_type not in _OPTIMIZER_TYPES and optimizer_type not in _TARGET_GATESETS: raise ValueError( f'{optimizer_type} is not an allowed type. Allowed ' f'types are: {_OPTIMIZER_TYPES.keys()}' @@ -141,16 +120,16 @@ def optimized_for_sycamore( if tabulation_resolution is not None: tabulation = _gate_product_tabulation_cached(optimizer_type, tabulation_resolution) - opts = _OPTIMIZER_TYPES[optimizer_type](tolerance=tolerance, tabulation=tabulation) - for optimizer in opts: - optimizer(copy) - if optimizer_type.startswith('xmon'): + if optimizer_type in _TARGET_GATESETS: copy = cirq.optimize_for_target_gateset( circuit, - gateset=cirq.CZTargetGateset( - atol=tolerance, allow_partial_czs=optimizer_type.endswith('partial_cz') - ), + gateset=_TARGET_GATESETS[optimizer_type](tolerance, tabulation), ) + if optimizer_type in _OPTIMIZER_TYPES: + opts = _OPTIMIZER_TYPES[optimizer_type](tolerance=tolerance, tabulation=tabulation) + for optimizer in opts: + optimizer(copy) + copy = cirq.merge_single_qubit_gates_to_phxz(copy, atol=tolerance) copy = cirq.eject_phased_paulis(copy, atol=tolerance) copy = cirq.eject_z(copy, atol=tolerance) From 6cdc554f5d0202e9a5707e1c6ba55085f13b38a8 Mon Sep 17 00:00:00 2001 From: Tanuj Khattar Date: Fri, 25 Feb 2022 13:43:21 -0800 Subject: [PATCH 2/2] Change CZTargetGateset to accept X/Y/Z/PhXZ/PhXPow single qubit gates --- .../target_gatesets/compilation_target_gateset.py | 4 +++- cirq-core/cirq/transformers/target_gatesets/cz_gateset.py | 6 +++++- cirq-google/cirq_google/devices/xmon_device.py | 3 +++ cirq-google/cirq_google/devices/xmon_device_test.py | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/transformers/target_gatesets/compilation_target_gateset.py b/cirq-core/cirq/transformers/target_gatesets/compilation_target_gateset.py index fd1516aec17..b7ed5738140 100644 --- a/cirq-core/cirq/transformers/target_gatesets/compilation_target_gateset.py +++ b/cirq-core/cirq/transformers/target_gatesets/compilation_target_gateset.py @@ -183,7 +183,8 @@ def _decompose_single_qubit_operation( ) -> DecomposeResult: """Decomposes (connected component of) 1-qubit operations using gates from this gateset. - By default, rewrites every operation using a single `cirq.PhasedXZGate`. + By default, rewrites every operation `op` using a single `cirq.PhasedXZGate` if `op` + is not contained in self or if `op` is a newly merged connected component of operations. Args: op: A single-qubit operation (can be a tagged `cirq.CircuitOperation` wrapping @@ -197,6 +198,7 @@ def _decompose_single_qubit_operation( return ( ops.PhasedXZGate.from_matrix(protocols.unitary(op)).on(op.qubits[0]) if protocols.has_unitary(op) + and (op not in self or self._intermediate_result_tag in op.tags) else NotImplemented ) diff --git a/cirq-core/cirq/transformers/target_gatesets/cz_gateset.py b/cirq-core/cirq/transformers/target_gatesets/cz_gateset.py index 989c7738c12..887213f6caa 100644 --- a/cirq-core/cirq/transformers/target_gatesets/cz_gateset.py +++ b/cirq-core/cirq/transformers/target_gatesets/cz_gateset.py @@ -38,7 +38,11 @@ def __init__(self, *, atol: float = 1e-8, allow_partial_czs: bool = False) -> No super().__init__( ops.CZPowGate if allow_partial_czs else ops.CZ, ops.MeasurementGate, - ops.AnyUnitaryGateFamily(1), + ops.XPowGate, + ops.YPowGate, + ops.ZPowGate, + ops.PhasedXPowGate, + ops.PhasedXZGate, name='CZPowTargetGateset' if allow_partial_czs else 'CZTargetGateset', ) self.atol = atol diff --git a/cirq-google/cirq_google/devices/xmon_device.py b/cirq-google/cirq_google/devices/xmon_device.py index dc2eb9d6663..74b27a8f0a6 100644 --- a/cirq-google/cirq_google/devices/xmon_device.py +++ b/cirq-google/cirq_google/devices/xmon_device.py @@ -51,6 +51,7 @@ def __init__( cirq.XPowGate, cirq.YPowGate, cirq.PhasedXPowGate, + cirq.PhasedXZGate, cirq.MeasurementGate, cirq.ZPowGate, ), @@ -113,6 +114,7 @@ def is_supported_gate(cls, gate: cirq.Gate): cirq.XPowGate, cirq.YPowGate, cirq.PhasedXPowGate, + cirq.PhasedXZGate, cirq.MeasurementGate, cirq.ZPowGate, ), @@ -158,6 +160,7 @@ def _check_if_exp11_operation_interacts( cirq.XPowGate, cirq.YPowGate, cirq.PhasedXPowGate, + cirq.PhasedXZGate, cirq.MeasurementGate, cirq.ZPowGate, ), diff --git a/cirq-google/cirq_google/devices/xmon_device_test.py b/cirq-google/cirq_google/devices/xmon_device_test.py index b7110519434..21a656a9152 100644 --- a/cirq-google/cirq_google/devices/xmon_device_test.py +++ b/cirq-google/cirq_google/devices/xmon_device_test.py @@ -52,6 +52,7 @@ def test_device_metadata(): cirq.XPowGate, cirq.YPowGate, cirq.PhasedXPowGate, + cirq.PhasedXZGate, cirq.MeasurementGate, cirq.ZPowGate, )