From 8ef8aef49f511c060c7e401ba5a0fb1ec0c4b99e Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Tue, 12 Jul 2022 18:06:49 -0700 Subject: [PATCH] Remove deprecated class SerializableDevice (#5743) Remove deprecated property GridDevice.qubits. Clean up documentation references to the SerializableDevice and update the circuit validation example in the specification.md doc. Part of #5050 --- cirq-google/cirq_google/__init__.py | 1 - cirq-google/cirq_google/devices/__init__.py | 2 - .../cirq_google/devices/grid_device.py | 9 - .../cirq_google/devices/grid_device_test.py | 8 - .../devices/serializable_device.py | 347 ------------------ .../devices/serializable_device_test.py | 261 ------------- .../engine/simulated_local_processor.py | 4 +- .../cirq_google/json_test_data/spec.py | 1 - .../cirq_google/workflow/processor_record.py | 2 +- docs/google/best_practices.ipynb | 2 +- docs/google/engine.md | 2 +- docs/google/specification.md | 17 +- 12 files changed, 11 insertions(+), 645 deletions(-) delete mode 100644 cirq-google/cirq_google/devices/serializable_device.py delete mode 100644 cirq-google/cirq_google/devices/serializable_device_test.py diff --git a/cirq-google/cirq_google/__init__.py b/cirq-google/cirq_google/__init__.py index 16640aaa0a9..4e753c6ab53 100644 --- a/cirq-google/cirq_google/__init__.py +++ b/cirq-google/cirq_google/__init__.py @@ -59,7 +59,6 @@ GoogleNoiseProperties, GridDevice, NoiseModelFromGoogleNoiseProperties, - SerializableDevice, Sycamore, Sycamore23, ) diff --git a/cirq-google/cirq_google/devices/__init__.py b/cirq-google/cirq_google/devices/__init__.py index c7a43cb2033..fcc7a3a1be3 100644 --- a/cirq-google/cirq_google/devices/__init__.py +++ b/cirq-google/cirq_google/devices/__init__.py @@ -20,5 +20,3 @@ from cirq_google.devices.known_devices import Sycamore, Sycamore23 from cirq_google.devices.grid_device import GridDevice - -from cirq_google.devices.serializable_device import SerializableDevice diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index cf0c1f2d6be..271e80a4cba 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -308,15 +308,6 @@ def metadata(self) -> cirq.GridDeviceMetadata: """Get metadata information for the device.""" return self._metadata - # Some user code using SerializableDevices gets the qubit list via `device.qubits`. - # This is a stopgap solution to prevent user breakage with the change to GridDevice. - @property # type: ignore - @cirq._compat.deprecated( - deadline='v0.16', fix='Change `device.qubits` to `device.metadata.qubit_set`.' - ) - def qubits(self) -> List[cirq.Qid]: - return sorted(self._metadata.qubit_set) - def validate_operation(self, operation: cirq.Operation) -> None: """Raises an exception if an operation is not valid. diff --git a/cirq-google/cirq_google/devices/grid_device_test.py b/cirq-google/cirq_google/devices/grid_device_test.py index 4f1c88d8db2..7fb76d38b5f 100644 --- a/cirq-google/cirq_google/devices/grid_device_test.py +++ b/cirq-google/cirq_google/devices/grid_device_test.py @@ -490,11 +490,3 @@ def test_to_proto_empty(): assert len(device.metadata.qubit_pairs) == 0 assert device.metadata.gateset == cirq.Gateset() assert device.metadata.gate_durations is None - - -def test_grid_device_qubits(): - device_info, spec = _create_device_spec_with_horizontal_couplings() - device = cirq_google.GridDevice.from_proto(spec) - - with cirq.testing.assert_deprecated('device.qubits', deadline='v0.16'): - assert device.qubits == device_info.grid_qubits diff --git a/cirq-google/cirq_google/devices/serializable_device.py b/cirq-google/cirq_google/devices/serializable_device.py deleted file mode 100644 index e30ef162dc7..00000000000 --- a/cirq-google/cirq_google/devices/serializable_device.py +++ /dev/null @@ -1,347 +0,0 @@ -# Copyright 2019 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. -"""Device object for converting from device specification protos""" - -from typing import Any, Callable, cast, Dict, Iterable, List, Optional, Set, Tuple, Type, Union -import cirq -from cirq import _compat -from cirq_google.serialization import serializable_gate_set -from cirq_google.api import v2 - - -class _GateDefinition: - """Class for keeping track of gate definitions within SerializableDevice""" - - def __init__( - self, - duration: cirq.DURATION_LIKE, - target_set: Set[Tuple[cirq.Qid, ...]], - number_of_qubits: int, - is_permutation: bool, - can_serialize_predicate: Callable[[cirq.Operation], bool] = lambda x: True, - ): - self.duration = cirq.Duration(duration) - self.target_set = target_set - self.is_permutation = is_permutation - self.number_of_qubits = number_of_qubits - self.can_serialize_predicate = can_serialize_predicate - - # Compute the set of all qubits in all target sets. - self.flattened_qubits = {q for qubit_tuple in target_set for q in qubit_tuple} - - def with_can_serialize_predicate( - self, can_serialize_predicate: Callable[[cirq.Operation], bool] - ) -> '_GateDefinition': - """Creates a new _GateDefinition as a copy of the existing definition - but with a new with_can_serialize_predicate. This is useful if multiple - definitions exist for the same gate, but with different conditions. - - An example is if gates at certain angles of a gate take longer or are - not allowed. - """ - return _GateDefinition( - self.duration, - self.target_set, - self.number_of_qubits, - self.is_permutation, - can_serialize_predicate, - ) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.__dict__ == other.__dict__ - - -_GateOrFrozenCircuitTypes = Union[Type[cirq.Gate], Type[cirq.FrozenCircuit]] - - -@_compat.deprecated_class(deadline='v0.16', fix='Use cirq_google.GridDevice instead.') -class SerializableDevice(cirq.Device): - """Device object generated from a device specification proto. - - Given a device specification proto and a gate_set to translate the - serialized gate_ids to cirq Gates, this will generate a Device that can - verify operations and circuits for the hardware specified by the device. - - Expected usage is through constructing this class through a proto using - the static function call from_proto(). - - This class only supports GridQubits and NamedQubits. NamedQubits with names - that conflict (such as "4_3") may be converted to GridQubits on - deserialization. - """ - - def __init__( - self, - qubits: List[cirq.Qid], - gate_definitions: Dict[_GateOrFrozenCircuitTypes, List[_GateDefinition]], - ): - """Constructor for SerializableDevice using python objects. - - Note that the preferred method of constructing this object is through - the static from_proto() call. - - Args: - qubits: A list of valid Qid for the device. - gate_definitions: Maps cirq gates to device properties for that - gate. - """ - self.qubits = qubits - self.gate_definitions = gate_definitions - has_subcircuit_support: bool = cirq.FrozenCircuit in gate_definitions - - self._metadata = cirq.GridDeviceMetadata( - qubit_pairs=cast( - List[Tuple[cirq.GridQubit, cirq.GridQubit]], - [ - (pair[0], pair[1]) - for gate_defs in gate_definitions.values() - for gate_def in gate_defs - if gate_def.number_of_qubits == 2 - for pair in gate_def.target_set - if len(pair) == 2 - and pair[0] < pair[1] - and isinstance(pair[0], cirq.GridQubit) - and isinstance(pair[1], cirq.GridQubit) - ], - ), - gateset=cirq.Gateset( - *(g for g in gate_definitions.keys() if issubclass(g, cirq.Gate)), - cirq.GlobalPhaseGate, - unroll_circuit_op=has_subcircuit_support, - ), - gate_durations=None, - ) - - @property - def metadata(self) -> cirq.GridDeviceMetadata: - """Get metadata information for device.""" - return self._metadata - - @classmethod - @_compat.deprecated( - deadline='v0.16', - fix='cirq_google.SerializableDevice is replaced cirq_google.GridDevice.' - ' Use cirq_google.GridDevice.from_proto() instead.', - ) - def from_proto( - cls, - proto: v2.device_pb2.DeviceSpecification, - gate_sets: Iterable[serializable_gate_set.SerializableGateSet], - ) -> 'SerializableDevice': - """Create a `SerializableDevice` from a proto. - - Args: - proto: A proto describing the qubits on the device, as well as the - supported gates and timing information. - gate_sets: SerializableGateSets that can translate the gate_ids - into cirq Gates. - - Raises: - NotImplementedError: If the target ordering mixes `SUBSET_PERMUTATION` - and other types of ordering. - ValueError: If the serializable gate set does not have a serialized id - that matches that in the device specification. - """ - - # Store target sets, since they are referred to by name later - allowed_targets: Dict[str, Set[Tuple[cirq.Qid, ...]]] = {} - permutation_ids: Set[str] = set() - for ts in proto.valid_targets: - allowed_targets[ts.name] = cls._create_target_set(ts) - if ts.target_ordering == v2.device_pb2.TargetSet.SUBSET_PERMUTATION: - permutation_ids.add(ts.name) - - # Store gate definitions from proto - gate_definitions: Dict[str, _GateDefinition] = {} - for gs in proto.valid_gate_sets: - for gate_def in gs.valid_gates: - # Combine all valid targets in the gate's listed target sets - gate_target_set = { - target - for ts_name in gate_def.valid_targets - for target in allowed_targets[ts_name] - } - which_are_permutations = [t in permutation_ids for t in gate_def.valid_targets] - is_permutation = any(which_are_permutations) - if is_permutation: - if not all(which_are_permutations): - raise NotImplementedError( - f'Id {gate_def.id} in {gs.name} mixes ' - 'SUBSET_PERMUTATION with other types which is not ' - 'currently allowed.' - ) - gate_definitions[gate_def.id] = _GateDefinition( - duration=cirq.Duration(picos=gate_def.gate_duration_picos), - target_set=gate_target_set, - is_permutation=is_permutation, - number_of_qubits=gate_def.number_of_qubits, - ) - - # Loop through serializers and map gate_definitions to type - gates_by_type: Dict[_GateOrFrozenCircuitTypes, List[_GateDefinition]] = {} - for gate_set in gate_sets: - for internal_type in gate_set.supported_internal_types(): - for serializer in gate_set.serializers[internal_type]: - serialized_id = serializer.serialized_id - if serialized_id not in gate_definitions: - raise ValueError( - f'Serializer has {serialized_id} which is not supported ' - 'by the device specification' - ) - if internal_type not in gates_by_type: - gates_by_type[internal_type] = [] - gate_def = gate_definitions[serialized_id].with_can_serialize_predicate( - serializer.can_serialize_predicate - ) - gates_by_type[internal_type].append(gate_def) - - return SerializableDevice( - qubits=[_qid_from_str(q) for q in proto.valid_qubits], gate_definitions=gates_by_type - ) - - @classmethod - def _create_target_set(cls, ts: v2.device_pb2.TargetSet) -> Set[Tuple[cirq.Qid, ...]]: - """Transform a TargetSet proto into a set of qubit tuples""" - target_set = set() - for target in ts.targets: - qid_tuple = tuple(_qid_from_str(q) for q in target.ids) - target_set.add(qid_tuple) - if ts.target_ordering == v2.device_pb2.TargetSet.SYMMETRIC: - target_set.add(qid_tuple[::-1]) - return target_set - - def __str__(self) -> str: - # If all qubits are grid qubits, render an appropriate text diagram. - if all(isinstance(q, cirq.GridQubit) for q in self.qubits): - diagram = cirq.TextDiagramDrawer() - - qubits = cast(List[cirq.GridQubit], self.qubits) - - # Don't print out extras newlines if the row/col doesn't start at 0 - min_col = min(q.col for q in qubits) - min_row = min(q.row for q in qubits) - - for q in qubits: - diagram.write(q.col - min_col, q.row - min_row, str(q)) - - # Find pairs that are connected by two-qubit gates. - Pair = Tuple[cirq.GridQubit, cirq.GridQubit] - pairs = { - cast(Pair, pair) - for gate_defs in self.gate_definitions.values() - for gate_def in gate_defs - if gate_def.number_of_qubits == 2 - for pair in gate_def.target_set - if len(pair) == 2 - } - - # Draw lines between connected pairs. Limit to horizontal/vertical - # lines since that is all the diagram drawer can handle. - for q1, q2 in sorted(pairs): - if q1.row == q2.row or q1.col == q2.col: - diagram.grid_line( - q1.col - min_col, q1.row - min_row, q2.col - min_col, q2.row - min_row - ) - - return diagram.render( - horizontal_spacing=3, vertical_spacing=2, use_unicode_characters=True - ) - - return super().__str__() - - def _repr_pretty_(self, p: Any, cycle: bool) -> None: - """Creates ASCII diagram for Jupyter, IPython, etc.""" - # There should never be a cycle, but just in case use the default repr. - p.text(repr(self) if cycle else str(self)) - - def _find_operation_type(self, op: cirq.Operation) -> Optional[_GateDefinition]: - """Finds the type (or a compatible type) of an operation from within - a dictionary with keys of Gate type. - - Returns: - the value corresponding to that key or None if no type matches - """ - for type_key, gate_defs in self.gate_definitions.items(): - if type_key == cirq.FrozenCircuit and isinstance(op.untagged, cirq.CircuitOperation): - for gate_def in gate_defs: - if gate_def.can_serialize_predicate(op): - return gate_def - if isinstance(op.gate, type_key): - for gate_def in gate_defs: - if gate_def.can_serialize_predicate(op): - return gate_def - return None - - def duration_of(self, operation: cirq.Operation) -> cirq.Duration: - gate_def = self._find_operation_type(operation) - if gate_def is None: - raise ValueError(f'Operation {operation} does not have a known duration') - return gate_def.duration - - def validate_operation(self, operation: cirq.Operation) -> None: - for q in operation.qubits: - if q not in self.qubits: - raise ValueError(f'Qubit not on device: {q!r}') - - gate_def = self._find_operation_type(operation) - if gate_def is None: - raise ValueError(f'{operation} is not a supported gate') - - req_num_qubits = gate_def.number_of_qubits - if req_num_qubits > 0: - if len(operation.qubits) != req_num_qubits: - raise ValueError( - f'{operation} has {len(operation.qubits)} ' - f'qubits but expected {req_num_qubits}' - ) - - if gate_def.is_permutation: - # A permutation gate can have any combination of qubits - - if not gate_def.target_set: - # All qubits are valid - return - - if not all(q in gate_def.flattened_qubits for q in operation.qubits): - raise ValueError('Operation does not use valid qubits: {operation}.') - - return - - if len(operation.qubits) > 1: - # TODO: verify args. - # Github issue: https://github.com/quantumlib/Cirq/issues/2964 - - if not gate_def.target_set: - # All qubit combinations are valid - return - - qubit_tuple = tuple(operation.qubits) - - if qubit_tuple not in gate_def.target_set: - # Target is not within the target sets specified by the gate. - raise ValueError(f'Operation does not use valid qubit target: {operation}.') - - -def _qid_from_str(id_str: str) -> cirq.Qid: - """Translates a qubit id string info cirq.Qid objects. - - Tries to translate to GridQubit if possible (e.g. '4_3'), otherwise - falls back to using NamedQubit. - """ - try: - return v2.grid_qubit_from_proto_id(id_str) - except ValueError: - return v2.named_qubit_from_proto_id(id_str) diff --git a/cirq-google/cirq_google/devices/serializable_device_test.py b/cirq-google/cirq_google/devices/serializable_device_test.py deleted file mode 100644 index 26ddc1f0581..00000000000 --- a/cirq-google/cirq_google/devices/serializable_device_test.py +++ /dev/null @@ -1,261 +0,0 @@ -# Copyright 2019 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 unittest.mock as mock - -import pytest - -import cirq -import cirq_google as cg -import cirq_google.api.v2 as v2 -import cirq_google.api.v2.device_pb2 as device_pb2 - - -def _just_cz(): - # Deprecations: cirq_google.SerializableGateSet, cirq_google.GateOpSerializer, and - # cirq_google.GateOpDeserializer - with cirq.testing.assert_deprecated( - 'SerializableGateSet', 'CircuitSerializer', deadline='v0.16', count=None - ): - return cg.SerializableGateSet( - gate_set_name='cz_gate_set', - serializers=[ - cg.GateOpSerializer(gate_type=cirq.CZPowGate, serialized_gate_id='cz', args=[]) - ], - deserializers=[ - cg.GateOpDeserializer( - serialized_gate_id='cz', gate_constructor=cirq.CZPowGate, args=[] - ) - ], - ) - - -def _just_meas(): - # Deprecations: cirq_google.SerializableGateSet, cirq_google.GateOpSerializer, and - # cirq_google.GateOpDeserializer - with cirq.testing.assert_deprecated( - 'SerializableGateSet', 'CircuitSerializer', deadline='v0.16', count=None - ): - return cg.SerializableGateSet( - gate_set_name='meas_gate_set', - serializers=[ - cg.GateOpSerializer( - gate_type=cirq.MeasurementGate, serialized_gate_id='meas', args=[] - ) - ], - deserializers=[ - cg.GateOpDeserializer( - serialized_gate_id='meas', gate_constructor=cirq.MeasurementGate, args=[] - ) - ], - ) - - -@pytest.mark.parametrize('cycle,func', [(False, str), (True, repr)]) -def test_repr_pretty(cycle, func): - device = cg.Sycamore - printer = mock.Mock() - device._repr_pretty_(printer, cycle) - printer.text.assert_called_once_with(func(device)) - - -def test_gate_definition_equality(): - def1 = cg.devices.serializable_device._GateDefinition( - duration=cirq.Duration(picos=4), - target_set={(cirq.GridQubit(1, 1),)}, - number_of_qubits=1, - is_permutation=False, - ) - def1c = cg.devices.serializable_device._GateDefinition( - duration=cirq.Duration(picos=4), - target_set={(cirq.GridQubit(1, 1),)}, - number_of_qubits=1, - is_permutation=False, - ) - def2 = cg.devices.serializable_device._GateDefinition( - duration=cirq.Duration(picos=5), - target_set={(cirq.GridQubit(1, 1),)}, - number_of_qubits=1, - is_permutation=False, - ) - eq = cirq.testing.EqualsTester() - eq.add_equality_group(def1, def1c) - eq.add_equality_group(def2) - - # Wrong type, tests NotImplemented functionality - eq.add_equality_group(cirq.X) - - -def test_asymmetric_gate(): - spec = device_pb2.DeviceSpecification() - for row in range(5): - for col in range(2): - spec.valid_qubits.extend([v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) - grid_targets = spec.valid_targets.add() - grid_targets.name = 'left_to_right' - grid_targets.target_ordering = device_pb2.TargetSet.ASYMMETRIC - for row in range(5): - new_target = grid_targets.targets.add() - new_target.ids.extend( - [ - v2.qubit_to_proto_id(cirq.GridQubit(row, 0)), - v2.qubit_to_proto_id(cirq.GridQubit(row, 1)), - ] - ) - - gs_proto = spec.valid_gate_sets.add() - gs_proto.name = 'cz_left_to_right_only' - - gate = gs_proto.valid_gates.add() - gate.id = 'cz' - gate.valid_targets.extend(['left_to_right']) - - cz_gateset = _just_cz() - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=2): - dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[cz_gateset]) - - for row in range(5): - dev.validate_operation(cirq.CZ(cirq.GridQubit(row, 0), cirq.GridQubit(row, 1))) - with pytest.raises(ValueError): - dev.validate_operation(cirq.CZ(cirq.GridQubit(row, 1), cirq.GridQubit(row, 0))) - - -def test_unconstrained_gate(): - spec = device_pb2.DeviceSpecification() - for row in range(5): - for col in range(5): - spec.valid_qubits.extend([v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) - grid_targets = spec.valid_targets.add() - grid_targets.name = '2_qubit_anywhere' - grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC - gs_proto = spec.valid_gate_sets.add() - gs_proto.name = 'cz_free_for_all' - - gate = gs_proto.valid_gates.add() - gate.id = 'cz' - gate.valid_targets.extend(['2_qubit_anywhere']) - - cz_gateset = _just_cz() - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=2): - dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[cz_gateset]) - - valid_qubit1 = cirq.GridQubit(4, 4) - for row in range(4): - for col in range(4): - valid_qubit2 = cirq.GridQubit(row, col) - dev.validate_operation(cirq.CZ(valid_qubit1, valid_qubit2)) - - -def test_number_of_qubits_cz(): - spec = device_pb2.DeviceSpecification() - spec.valid_qubits.extend( - [v2.qubit_to_proto_id(cirq.GridQubit(0, 0)), v2.qubit_to_proto_id(cirq.GridQubit(0, 1))] - ) - grid_targets = spec.valid_targets.add() - grid_targets.name = '2_qubit_anywhere' - grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC - gs_proto = spec.valid_gate_sets.add() - - gs_proto.name = 'cz_requires_three_qubits' - - gate = gs_proto.valid_gates.add() - gate.id = 'cz' - gate.valid_targets.extend(['2_qubit_anywhere']) - gate.number_of_qubits = 3 - - cz_gateset = _just_cz() - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=2): - dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[cz_gateset]) - - with pytest.raises(ValueError): - dev.validate_operation(cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))) - - -def test_constrained_permutations(): - spec = device_pb2.DeviceSpecification() - for row in range(5): - for col in range(2): - spec.valid_qubits.extend([v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) - - grid_targets = spec.valid_targets.add() - grid_targets.name = 'meas_on_first_line' - grid_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION - new_target = grid_targets.targets.add() - new_target.ids.extend([v2.qubit_to_proto_id(cirq.GridQubit(i, 0)) for i in range(5)]) - - gs_proto = spec.valid_gate_sets.add() - gs_proto.name = 'meas_set' - - gate = gs_proto.valid_gates.add() - gate.id = 'meas' - gate.valid_targets.extend(['meas_on_first_line']) - - meas_gateset = _just_meas() - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=2): - dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[meas_gateset]) - - dev.validate_operation(cirq.measure(cirq.GridQubit(0, 0))) - dev.validate_operation(cirq.measure(cirq.GridQubit(1, 0))) - dev.validate_operation(cirq.measure(cirq.GridQubit(2, 0))) - dev.validate_operation(cirq.measure(*[cirq.GridQubit(i, 0) for i in range(5)])) - - with pytest.raises(ValueError): - dev.validate_operation(cirq.measure(cirq.GridQubit(1, 1))) - with pytest.raises(ValueError): - dev.validate_operation(cirq.measure(cirq.GridQubit(0, 0), cirq.GridQubit(1, 1))) - - -def test_mixing_types(): - """Mixing SUBSET_PERMUTATION with SYMMETRIC targets is confusing, - and not yet supported""" - spec = device_pb2.DeviceSpecification() - - grid_targets = spec.valid_targets.add() - grid_targets.name = 'subset' - grid_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION - - grid_targets = spec.valid_targets.add() - grid_targets.name = 'sym' - grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC - - gs_proto = spec.valid_gate_sets.add() - gs_proto.name = 'set_with_mismatched_targets' - - gate = gs_proto.valid_gates.add() - gate.id = 'meas' - gate.valid_targets.extend(['subset', 'sym']) - - meas_gateset = _just_meas() - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=1): - with pytest.raises(NotImplementedError): - _ = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[meas_gateset]) - - -def test_serializable_device_str_named_qubits(): - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=1): - device = cg.SerializableDevice( - qubits=[cirq.NamedQubit('a'), cirq.NamedQubit('b')], gate_definitions={} - ) - assert device.__class__.__name__ in str(device) - - -def test_serializable_device_gate_definitions_filter(): - """Ignore items in gate_definitions dictionary with invalid keys.""" - with cirq.testing.assert_deprecated('Use cirq_google.GridDevice', deadline='v0.16', count=1): - device = cg.SerializableDevice( - qubits=[cirq.NamedQubit('a'), cirq.NamedQubit('b')], - gate_definitions={cirq.FSimGate: [], cirq.NoiseModel: []}, - ) - # Two gates for cirq.FSimGate and the cirq.GlobalPhaseGate default - assert len(device.metadata.gateset.gates) == 2 diff --git a/cirq-google/cirq_google/engine/simulated_local_processor.py b/cirq-google/cirq_google/engine/simulated_local_processor.py index 27198f0616f..8d8b4ad2e3a 100644 --- a/cirq-google/cirq_google/engine/simulated_local_processor.py +++ b/cirq-google/cirq_google/engine/simulated_local_processor.py @@ -127,10 +127,10 @@ def get_current_calibration(self) -> Optional[calibration.Calibration]: return self.get_latest_calibration(int(datetime.datetime.now().timestamp())) def get_device(self) -> cirq.Device: - """Returns a `Device` created from the processor's device specification. + """Returns a `cirq.Device` created from the processor's device specification. This method queries the processor to retrieve the device specification, - which is then use to create a `SerializableDevice` that will validate + which is then use to create a `cirq.Device` that will validate that operations are supported and use the correct qubits. """ return self._device diff --git a/cirq-google/cirq_google/json_test_data/spec.py b/cirq-google/cirq_google/json_test_data/spec.py index f69537c1b53..913e8b98dfc 100644 --- a/cirq-google/cirq_google/json_test_data/spec.py +++ b/cirq-google/cirq_google/json_test_data/spec.py @@ -14,7 +14,6 @@ 'SYC_GATESET', 'Sycamore', 'Sycamore23', - 'SerializableDevice', 'SerializableGateSet', 'SQRT_ISWAP_GATESET', 'SQRT_ISWAP_INV_PARAMETERS', diff --git a/cirq-google/cirq_google/workflow/processor_record.py b/cirq-google/cirq_google/workflow/processor_record.py index 801f44b1ca2..d2db0d897a9 100644 --- a/cirq-google/cirq_google/workflow/processor_record.py +++ b/cirq-google/cirq_google/workflow/processor_record.py @@ -106,7 +106,7 @@ def get_processor(self) -> 'cg.engine.SimulatedLocalProcessor': ) def _get_input_device(self) -> 'cirq.Device': - """Return a `cg.SerializableDevice` for the specified processor_id. + """Return a `cirq.Device` for the specified processor_id. This method presumes the GOOGLE_CLOUD_PROJECT environment variable is set to establish a connection to the cloud service. diff --git a/docs/google/best_practices.ipynb b/docs/google/best_practices.ipynb index 7ccedac0e99..0e28d99e41f 100644 --- a/docs/google/best_practices.ipynb +++ b/docs/google/best_practices.ipynb @@ -114,7 +114,7 @@ "`cg.Sycamore.validate_circuit(circuit)` will test a lot of these\n", "conditions. Calling the `validate_circuit` function will work with any\n", "device, including those retrieved directly from the API using the\n", - "[engine object](/cirq/google/specification.md#serializable-devices), which can help\n", + "[engine object](/cirq/google/specification.md#conversion-to-cirq.device), which can help\n", "identify any qubits used in the circuit that have been disabled on the actual\n", "device." ] diff --git a/docs/google/engine.md b/docs/google/engine.md index f23d9ea711c..2f9edd18853 100644 --- a/docs/google/engine.md +++ b/docs/google/engine.md @@ -105,7 +105,7 @@ message that contains information about the qubits on the device, the connectivity, and the supported gates. This proto can be queried directly to get information about the device or can be transformed -into a `cirq.Device` by using `cirq_google.SerializableDevice.from_proto()` that will +into a `cirq.Device` by using `cirq_google.GridDevice.from_proto()` that will enforce constraints imposed by the hardware. See the [Device Specification](specification.md) page for more information on diff --git a/docs/google/specification.md b/docs/google/specification.md index f51509443c4..937f9c2d577 100644 --- a/docs/google/specification.md +++ b/docs/google/specification.md @@ -90,17 +90,12 @@ are not captured by the hard requirements above. For instance, "Do not apply two CZ gates in a row." -## Serializable Devices +## Conversion to cirq.Device -The `cirq_google.SerializableDevice` class allows someone to take this +The `cirq_google.GridDevice` class allows someone to take this device specification and turn it into a `cirq.Device` that can be used to verify a circuit. -The `cirq_google.SerializableDevice` combines a `DeviceSpecification` protocol -buffer (defining the device) with a `SerializableGateSet` (that defines the -translation from serialized id to cirq) to produce a `cirq.Device` that can -be used to validate a circuit. - The following example illustrates retrieving the device specification live from the engine and then using it to validate a circuit. @@ -113,13 +108,13 @@ engine = cg.Engine(project_id='your_project_id', proto_version=cirq_google.ProtoVersion.V2) # Replace the processor id to get the device with that id. -device = engine.get_processor('processor_id').get_device( - gate_sets=[cg.gate_sets.SQRT_ISWAP_GATESET]) +device = engine.get_processor('processor_id').get_device() q0, q1 = cirq.LineQubit.range(2) +circuit = cirq.Circuit(cirq.CZ(q0, q1)) -# Raises a ValueError, since this is not a supported gate. -cirq.Circuit(cirq.CZ(q0,q1), device=device) +# Raises a ValueError, since CZ is not a supported gate. +device.validate_circuit(circuit) ``` Note that, if network traffic is undesired, the `DeviceSpecification` can