From 2ef9a926135fd8969fd524dc79a471ac262e1832 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Thu, 18 Jun 2026 18:58:10 +0000 Subject: [PATCH 1/7] Add qubit_attributes to GridDeviceMetadata and corresponding device.proto message definition This will allow use to have more room to add custom qubit corresponding information to the external users in the future. This change should be backward and forwar compatible --- .../cirq/devices/grid_device_metadata.py | 28 ++++- .../cirq/devices/grid_device_metadata_test.py | 42 +++++++ .../json_test_data/GridDeviceMetadata.json | 3 +- .../json_test_data/GridDeviceMetadata.repr | 2 +- cirq-google/cirq_google/api/v2/device.proto | 25 ++++ cirq-google/cirq_google/api/v2/device_pb2.py | 118 +++++++++--------- cirq-google/cirq_google/api/v2/device_pb2.pyi | 90 ++++++++++++- .../cirq_google/devices/grid_device.py | 49 ++++++++ .../cirq_google/devices/grid_device_test.py | 64 ++++++++++ .../cirq.google.GridDevice.json | 3 +- .../cirq.google.GridDevice.repr | 2 +- 11 files changed, 363 insertions(+), 63 deletions(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index f177523b54c..bb2f6b82aed 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -17,7 +17,7 @@ from __future__ import annotations from collections.abc import Iterable, Mapping -from typing import cast, TYPE_CHECKING +from typing import Any, cast, TYPE_CHECKING import networkx as nx @@ -39,6 +39,7 @@ def __init__( gate_durations: Mapping[cirq.GateFamily, cirq.Duration] | None = None, all_qubits: Iterable[cirq.GridQubit] | None = None, compilation_target_gatesets: Iterable[cirq.CompilationTargetGateset] = (), + qubit_attributes: Mapping[cirq.GridQubit, Mapping[str, Any]] | None = None, ): """Create a GridDeviceMetadata object. @@ -117,6 +118,11 @@ def __init__( ) self._gate_durations = gate_durations + self._qubit_attributes = ( + {q: dict(attrs) for q, attrs in qubit_attributes.items()} + if qubit_attributes is not None + else {} + ) @property def qubit_set(self) -> frozenset[cirq.GridQubit]: @@ -175,17 +181,28 @@ def gate_durations(self) -> Mapping[cirq.GateFamily, cirq.Duration] | None: return self._gate_durations + @property + def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, Any]]: + """Returns a mapping from qubit to its attributes (if applicable).""" + return self._qubit_attributes + def _value_equality_values_(self): duration_equality = '' if self._gate_durations is not None: duration_equality = sorted(self._gate_durations.items(), key=lambda x: repr(x[0])) + attributes_equality = sorted( + [(q, tuple(sorted(attrs.items()))) for q, attrs in self._qubit_attributes.items()], + key=lambda x: x[0], + ) + return ( self._qubit_pairs, self._gateset, tuple(duration_equality), tuple(sorted(self.qubit_set)), frozenset(self._compilation_target_gatesets), + tuple(attributes_equality), ) def __repr__(self) -> str: @@ -193,7 +210,8 @@ def __repr__(self) -> str: return ( f'cirq.GridDeviceMetadata({repr(qubit_pair_tuples)},' f' {repr(self._gateset)}, {repr(self._gate_durations)},' - f' {repr(self.qubit_set)}, {repr(self._compilation_target_gatesets)})' + f' {repr(self.qubit_set)}, {repr(self._compilation_target_gatesets)},' + f' {repr(self._qubit_attributes)})' ) def _json_dict_(self): @@ -207,6 +225,10 @@ def _json_dict_(self): 'gate_durations': duration_payload, 'all_qubits': sorted(self.qubit_set), 'compilation_target_gatesets': list(self._compilation_target_gatesets), + 'qubit_attributes': sorted( + [(q, sorted(attrs.items())) for q, attrs in self._qubit_attributes.items()], + key=lambda x: x[0], + ), } @classmethod @@ -217,6 +239,7 @@ def _from_json_dict_( gate_durations, all_qubits, compilation_target_gatesets=(), + qubit_attributes=None, **kwargs, ): return cls( @@ -225,4 +248,5 @@ def _from_json_dict_( dict(gate_durations) if gate_durations is not None else None, all_qubits, compilation_target_gatesets, + dict(qubit_attributes) if qubit_attributes is not None else None, ) diff --git a/cirq-core/cirq/devices/grid_device_metadata_test.py b/cirq-core/cirq/devices/grid_device_metadata_test.py index eb4c2d9bbb1..7a0d1b91ac2 100644 --- a/cirq-core/cirq/devices/grid_device_metadata_test.py +++ b/cirq-core/cirq/devices/grid_device_metadata_test.py @@ -202,3 +202,45 @@ def test_repr() -> None: compilation_target_gatesets=target_gatesets, ) cirq.testing.assert_equivalent_repr(metadata) + + +def test_griddevice_metadata_qubit_attributes() -> None: + qubits = cirq.GridQubit.rect(1, 2) + gateset = cirq.Gateset(cirq.XPowGate) + qubit_attributes = { + cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.1}, + cirq.GridQubit(0, 1): {"index": 42}, + } + + metadata = cirq.GridDeviceMetadata( + qubit_pairs=[], gateset=gateset, all_qubits=qubits, qubit_attributes=qubit_attributes + ) + + assert metadata.qubit_attributes == qubit_attributes + + # test JSON serialization + rep_str = cirq.to_json(metadata) + assert metadata == cirq.read_json(json_text=rep_str) + + # test repr + cirq.testing.assert_equivalent_repr(metadata) + + # test equality + metadata2 = cirq.GridDeviceMetadata( + qubit_pairs=[], + gateset=gateset, + all_qubits=qubits, + qubit_attributes={ + cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.1}, + cirq.GridQubit(0, 1): {"index": 43}, # different index + }, + ) + + metadata3 = cirq.GridDeviceMetadata( + qubit_pairs=[], gateset=gateset, all_qubits=qubits, qubit_attributes=None + ) + + eq = cirq.testing.EqualsTester() + eq.add_equality_group(metadata) + eq.add_equality_group(metadata2) + eq.add_equality_group(metadata3) diff --git a/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.json b/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.json index 0843b9744d1..85f8aa9f664 100644 --- a/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.json +++ b/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.json @@ -265,5 +265,6 @@ "required_sqrt_iswap_count": null, "use_sqrt_iswap_inv": false } - ] + ], + "qubit_attributes": [] } \ No newline at end of file diff --git a/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.repr b/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.repr index 8d7ce4b2225..0bf7eef5f15 100644 --- a/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.repr +++ b/cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.repr @@ -1 +1 @@ -cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 0), cirq.GridQubit(1, 0)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 1), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)), (cirq.GridQubit(0, 2), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 1), cirq.GridQubit(0, 2))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate, cirq.CZ, (cirq.ISWAP**0.5), unroll_circuit_op = True), {cirq.GateFamily(gate=cirq.ops.common_gates.XPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(nanos=1), cirq.GateFamily(gate=cirq.ops.common_gates.YPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.ops.common_gates.ZPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.CZ, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=500), cirq.GateFamily(gate=(cirq.ISWAP**0.5), ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=600)}, frozenset({cirq.GridQubit(1, 0), cirq.GridQubit(0, 2), cirq.GridQubit(9, 9), cirq.GridQubit(10, 10), cirq.GridQubit(0, 1), cirq.GridQubit(1, 1), cirq.GridQubit(0, 0), cirq.GridQubit(1, 2)}), (cirq.CZTargetGateset(atol=1e-08, allow_partial_czs=False), cirq.SqrtIswapTargetGateset(atol=1e-08, required_sqrt_iswap_count=None, use_sqrt_iswap_inv=False))) \ No newline at end of file +cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 0), cirq.GridQubit(1, 0)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 1), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)), (cirq.GridQubit(0, 2), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 1), cirq.GridQubit(0, 2))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate, cirq.CZ, (cirq.ISWAP**0.5), unroll_circuit_op = True), {cirq.GateFamily(gate=cirq.ops.common_gates.XPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(nanos=1), cirq.GateFamily(gate=cirq.ops.common_gates.YPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.ops.common_gates.ZPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.CZ, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=500), cirq.GateFamily(gate=(cirq.ISWAP**0.5), ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=600)}, frozenset({cirq.GridQubit(1, 0), cirq.GridQubit(0, 2), cirq.GridQubit(9, 9), cirq.GridQubit(10, 10), cirq.GridQubit(0, 1), cirq.GridQubit(1, 1), cirq.GridQubit(0, 0), cirq.GridQubit(1, 2)}), (cirq.CZTargetGateset(atol=1e-08, allow_partial_czs=False), cirq.SqrtIswapTargetGateset(atol=1e-08, required_sqrt_iswap_count=None, use_sqrt_iswap_inv=False)), {}) \ No newline at end of file diff --git a/cirq-google/cirq_google/api/v2/device.proto b/cirq-google/cirq_google/api/v2/device.proto index 6a1689946bd..844e5f74f0b 100644 --- a/cirq-google/cirq_google/api/v2/device.proto +++ b/cirq-google/cirq_google/api/v2/device.proto @@ -34,6 +34,9 @@ message DeviceSpecification { // are advice to users of the device, specified in English text // For instance, "All Z gates are converted to VirtualZ gates". string developer_recommendations = 4; + + // Qubit attributes for the device. + repeated QubitAttributes qubit_attributes = 6; } // This contains information about a single device gate. @@ -199,3 +202,25 @@ message Target { // A list of qubit ids that form a valid gate target. repeated string ids = 1; } + +// Qubit attributes for a specific qubit. +message QubitAttributes { + string qubit = 1; + repeated QubitAttributeEntry attributes = 2; +} + +// A key-value entry representing a single qubit attribute. +message QubitAttributeEntry { + string name = 1; + QubitAttributeValue value = 2; +} + +// A generic value for a qubit attribute. +message QubitAttributeValue { + oneof val { + string string_value = 1; + int64 int_value = 2; + double double_value = 3; + bool bool_value = 4; + } +} diff --git a/cirq-google/cirq_google/api/v2/device_pb2.py b/cirq-google/cirq_google/api/v2/device_pb2.py index 13e8b0011d9..7e6282921d4 100644 --- a/cirq-google/cirq_google/api/v2/device_pb2.py +++ b/cirq-google/cirq_google/api/v2/device_pb2.py @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63irq_google/api/v2/device.proto\x12\x12\x63irq.google.api.v2\"\xfa\x01\n\x13\x44\x65viceSpecification\x12\x38\n\x0fvalid_gate_sets\x18\x01 \x03(\x0b\x32\x1b.cirq.google.api.v2.GateSetB\x02\x18\x01\x12:\n\x0bvalid_gates\x18\x05 \x03(\x0b\x32%.cirq.google.api.v2.GateSpecification\x12\x14\n\x0cvalid_qubits\x18\x02 \x03(\t\x12\x34\n\rvalid_targets\x18\x03 \x03(\x0b\x32\x1d.cirq.google.api.v2.TargetSet\x12!\n\x19\x64\x65veloper_recommendations\x18\x04 \x01(\t\"\xfb\x0c\n\x11GateSpecification\x12\x1b\n\x13gate_duration_picos\x18\x01 \x01(\x03\x12=\n\x03syc\x18\x02 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.SycamoreH\x00\x12\x45\n\nsqrt_iswap\x18\x03 \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.SqrtISwapH\x00\x12L\n\x0esqrt_iswap_inv\x18\x04 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.SqrtISwapInvH\x00\x12\x36\n\x02\x63z\x18\x05 \x01(\x0b\x32(.cirq.google.api.v2.GateSpecification.CZH\x00\x12\x43\n\tphased_xz\x18\x06 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.PhasedXZH\x00\x12I\n\x0cvirtual_zpow\x18\x07 \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.VirtualZPowH\x00\x12K\n\rphysical_zpow\x18\x08 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.PhysicalZPowH\x00\x12K\n\rcoupler_pulse\x18\t \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.CouplerPulseH\x00\x12\x41\n\x04meas\x18\n \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.MeasurementH\x00\x12:\n\x04wait\x18\x0b \x01(\x0b\x32*.cirq.google.api.v2.GateSpecification.WaitH\x00\x12L\n\x0e\x66sim_via_model\x18\x0c \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.FSimViaModelH\x00\x12L\n\x0etwo_pulse_fsim\x18\x13 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.TwoPulseFSimH\x00\x12\x46\n\x0b\x63z_pow_gate\x18\r \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.CZPowGateH\x00\x12K\n\rinternal_gate\x18\x0e \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.InternalGateH\x00\x12<\n\x05reset\x18\x0f \x01(\x0b\x32+.cirq.google.api.v2.GateSpecification.ResetH\x00\x12V\n\x13\x61nalog_detune_qubit\x18\x10 \x01(\x0b\x32\x37.cirq.google.api.v2.GateSpecification.AnalogDetuneQubitH\x00\x12\x63\n\x1a\x61nalog_detune_coupler_only\x18\x11 \x01(\x0b\x32=.cirq.google.api.v2.GateSpecification.AnalogDetuneCouplerOnlyH\x00\x12U\n\x13wait_gate_with_unit\x18\x12 \x01(\x0b\x32\x36.cirq.google.api.v2.GateSpecification.WaitGateWithUnitH\x00\x1a\n\n\x08Sycamore\x1a\x0b\n\tSqrtISwap\x1a\x0e\n\x0cSqrtISwapInv\x1a\x04\n\x02\x43Z\x1a\n\n\x08PhasedXZ\x1a\r\n\x0bVirtualZPow\x1a\x0e\n\x0cPhysicalZPow\x1a\x0e\n\x0c\x43ouplerPulse\x1a\r\n\x0bMeasurement\x1a\x06\n\x04Wait\x1a\x0e\n\x0c\x46SimViaModel\x1a\x0e\n\x0cTwoPulseFSim\x1a\x0b\n\tCZPowGate\x1a\x0e\n\x0cInternalGate\x1a\x07\n\x05Reset\x1a\x13\n\x11\x41nalogDetuneQubit\x1a\x19\n\x17\x41nalogDetuneCouplerOnly\x1a\x12\n\x10WaitGateWithUnitB\x06\n\x04gate\"P\n\x07GateSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x0bvalid_gates\x18\x02 \x03(\x0b\x32\".cirq.google.api.v2.GateDefinition\"\xa1\x01\n\x0eGateDefinition\x12\n\n\x02id\x18\x01 \x01(\t\x12\x18\n\x10number_of_qubits\x18\x02 \x01(\x05\x12\x35\n\nvalid_args\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgDefinition\x12\x1b\n\x13gate_duration_picos\x18\x04 \x01(\x03\x12\x15\n\rvalid_targets\x18\x05 \x03(\t\"\xda\x01\n\rArgDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x04type\x18\x02 \x01(\x0e\x32).cirq.google.api.v2.ArgDefinition.ArgType\x12\x39\n\x0e\x61llowed_ranges\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgumentRange\"G\n\x07\x41rgType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\t\n\x05\x46LOAT\x10\x01\x12\x14\n\x10REPEATED_BOOLEAN\x10\x02\x12\n\n\x06STRING\x10\x03\"=\n\rArgumentRange\x12\x15\n\rminimum_value\x18\x01 \x01(\x02\x12\x15\n\rmaximum_value\x18\x02 \x01(\x02\"\xef\x01\n\tTargetSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x45\n\x0ftarget_ordering\x18\x02 \x01(\x0e\x32,.cirq.google.api.v2.TargetSet.TargetOrdering\x12+\n\x07targets\x18\x03 \x03(\x0b\x32\x1a.cirq.google.api.v2.Target\"`\n\x0eTargetOrdering\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tSYMMETRIC\x10\x01\x12\x12\n\nASYMMETRIC\x10\x02\x1a\x02\x08\x01\x12\x1a\n\x12SUBSET_PERMUTATION\x10\x03\x1a\x02\x08\x01\"\x15\n\x06Target\x12\x0b\n\x03ids\x18\x01 \x03(\tB.\n\x1d\x63om.google.cirq.google.api.v2B\x0b\x44\x65viceProtoP\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63irq_google/api/v2/device.proto\x12\x12\x63irq.google.api.v2\"\xb9\x02\n\x13\x44\x65viceSpecification\x12\x38\n\x0fvalid_gate_sets\x18\x01 \x03(\x0b\x32\x1b.cirq.google.api.v2.GateSetB\x02\x18\x01\x12:\n\x0bvalid_gates\x18\x05 \x03(\x0b\x32%.cirq.google.api.v2.GateSpecification\x12\x14\n\x0cvalid_qubits\x18\x02 \x03(\t\x12\x34\n\rvalid_targets\x18\x03 \x03(\x0b\x32\x1d.cirq.google.api.v2.TargetSet\x12!\n\x19\x64\x65veloper_recommendations\x18\x04 \x01(\t\x12=\n\x10qubit_attributes\x18\x06 \x03(\x0b\x32#.cirq.google.api.v2.QubitAttributes\"\xfb\x0c\n\x11GateSpecification\x12\x1b\n\x13gate_duration_picos\x18\x01 \x01(\x03\x12=\n\x03syc\x18\x02 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.SycamoreH\x00\x12\x45\n\nsqrt_iswap\x18\x03 \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.SqrtISwapH\x00\x12L\n\x0esqrt_iswap_inv\x18\x04 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.SqrtISwapInvH\x00\x12\x36\n\x02\x63z\x18\x05 \x01(\x0b\x32(.cirq.google.api.v2.GateSpecification.CZH\x00\x12\x43\n\tphased_xz\x18\x06 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.PhasedXZH\x00\x12I\n\x0cvirtual_zpow\x18\x07 \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.VirtualZPowH\x00\x12K\n\rphysical_zpow\x18\x08 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.PhysicalZPowH\x00\x12K\n\rcoupler_pulse\x18\t \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.CouplerPulseH\x00\x12\x41\n\x04meas\x18\n \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.MeasurementH\x00\x12:\n\x04wait\x18\x0b \x01(\x0b\x32*.cirq.google.api.v2.GateSpecification.WaitH\x00\x12L\n\x0e\x66sim_via_model\x18\x0c \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.FSimViaModelH\x00\x12L\n\x0etwo_pulse_fsim\x18\x13 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.TwoPulseFSimH\x00\x12\x46\n\x0b\x63z_pow_gate\x18\r \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.CZPowGateH\x00\x12K\n\rinternal_gate\x18\x0e \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.InternalGateH\x00\x12<\n\x05reset\x18\x0f \x01(\x0b\x32+.cirq.google.api.v2.GateSpecification.ResetH\x00\x12V\n\x13\x61nalog_detune_qubit\x18\x10 \x01(\x0b\x32\x37.cirq.google.api.v2.GateSpecification.AnalogDetuneQubitH\x00\x12\x63\n\x1a\x61nalog_detune_coupler_only\x18\x11 \x01(\x0b\x32=.cirq.google.api.v2.GateSpecification.AnalogDetuneCouplerOnlyH\x00\x12U\n\x13wait_gate_with_unit\x18\x12 \x01(\x0b\x32\x36.cirq.google.api.v2.GateSpecification.WaitGateWithUnitH\x00\x1a\n\n\x08Sycamore\x1a\x0b\n\tSqrtISwap\x1a\x0e\n\x0cSqrtISwapInv\x1a\x04\n\x02\x43Z\x1a\n\n\x08PhasedXZ\x1a\r\n\x0bVirtualZPow\x1a\x0e\n\x0cPhysicalZPow\x1a\x0e\n\x0c\x43ouplerPulse\x1a\r\n\x0bMeasurement\x1a\x06\n\x04Wait\x1a\x0e\n\x0c\x46SimViaModel\x1a\x0e\n\x0cTwoPulseFSim\x1a\x0b\n\tCZPowGate\x1a\x0e\n\x0cInternalGate\x1a\x07\n\x05Reset\x1a\x13\n\x11\x41nalogDetuneQubit\x1a\x19\n\x17\x41nalogDetuneCouplerOnly\x1a\x12\n\x10WaitGateWithUnitB\x06\n\x04gate\"P\n\x07GateSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x0bvalid_gates\x18\x02 \x03(\x0b\x32\".cirq.google.api.v2.GateDefinition\"\xa1\x01\n\x0eGateDefinition\x12\n\n\x02id\x18\x01 \x01(\t\x12\x18\n\x10number_of_qubits\x18\x02 \x01(\x05\x12\x35\n\nvalid_args\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgDefinition\x12\x1b\n\x13gate_duration_picos\x18\x04 \x01(\x03\x12\x15\n\rvalid_targets\x18\x05 \x03(\t\"\xda\x01\n\rArgDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x04type\x18\x02 \x01(\x0e\x32).cirq.google.api.v2.ArgDefinition.ArgType\x12\x39\n\x0e\x61llowed_ranges\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgumentRange\"G\n\x07\x41rgType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\t\n\x05\x46LOAT\x10\x01\x12\x14\n\x10REPEATED_BOOLEAN\x10\x02\x12\n\n\x06STRING\x10\x03\"=\n\rArgumentRange\x12\x15\n\rminimum_value\x18\x01 \x01(\x02\x12\x15\n\rmaximum_value\x18\x02 \x01(\x02\"\xef\x01\n\tTargetSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x45\n\x0ftarget_ordering\x18\x02 \x01(\x0e\x32,.cirq.google.api.v2.TargetSet.TargetOrdering\x12+\n\x07targets\x18\x03 \x03(\x0b\x32\x1a.cirq.google.api.v2.Target\"`\n\x0eTargetOrdering\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tSYMMETRIC\x10\x01\x12\x12\n\nASYMMETRIC\x10\x02\x1a\x02\x08\x01\x12\x1a\n\x12SUBSET_PERMUTATION\x10\x03\x1a\x02\x08\x01\"\x15\n\x06Target\x12\x0b\n\x03ids\x18\x01 \x03(\t\"]\n\x0fQubitAttributes\x12\r\n\x05qubit\x18\x01 \x01(\t\x12;\n\nattributes\x18\x02 \x03(\x0b\x32\'.cirq.google.api.v2.QubitAttributeEntry\"[\n\x13QubitAttributeEntry\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.cirq.google.api.v2.QubitAttributeValue\"w\n\x13QubitAttributeValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x16\n\x0c\x64ouble_value\x18\x03 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x42\x05\n\x03valB.\n\x1d\x63om.google.cirq.google.api.v2B\x0b\x44\x65viceProtoP\x01\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -39,59 +39,65 @@ _globals['_TARGETSET_TARGETORDERING'].values_by_name["SUBSET_PERMUTATION"]._loaded_options = None _globals['_TARGETSET_TARGETORDERING'].values_by_name["SUBSET_PERMUTATION"]._serialized_options = b'\010\001' _globals['_DEVICESPECIFICATION']._serialized_start=56 - _globals['_DEVICESPECIFICATION']._serialized_end=306 - _globals['_GATESPECIFICATION']._serialized_start=309 - _globals['_GATESPECIFICATION']._serialized_end=1968 - _globals['_GATESPECIFICATION_SYCAMORE']._serialized_start=1695 - _globals['_GATESPECIFICATION_SYCAMORE']._serialized_end=1705 - _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_start=1707 - _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_end=1718 - _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_start=1720 - _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_end=1734 - _globals['_GATESPECIFICATION_CZ']._serialized_start=1736 - _globals['_GATESPECIFICATION_CZ']._serialized_end=1740 - _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_start=1742 - _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_end=1752 - _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_start=1754 - _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_end=1767 - _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_start=1769 - _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_end=1783 - _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_start=1785 - _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_end=1799 - _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_start=1801 - _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_end=1814 - _globals['_GATESPECIFICATION_WAIT']._serialized_start=1816 - _globals['_GATESPECIFICATION_WAIT']._serialized_end=1822 - _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_start=1824 - _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_end=1838 - _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_start=1840 - _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_end=1854 - _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_start=1856 - _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_end=1867 - _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_start=1869 - _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_end=1883 - _globals['_GATESPECIFICATION_RESET']._serialized_start=1885 - _globals['_GATESPECIFICATION_RESET']._serialized_end=1892 - _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_start=1894 - _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_end=1913 - _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_start=1915 - _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_end=1940 - _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_start=1942 - _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_end=1960 - _globals['_GATESET']._serialized_start=1970 - _globals['_GATESET']._serialized_end=2050 - _globals['_GATEDEFINITION']._serialized_start=2053 - _globals['_GATEDEFINITION']._serialized_end=2214 - _globals['_ARGDEFINITION']._serialized_start=2217 - _globals['_ARGDEFINITION']._serialized_end=2435 - _globals['_ARGDEFINITION_ARGTYPE']._serialized_start=2364 - _globals['_ARGDEFINITION_ARGTYPE']._serialized_end=2435 - _globals['_ARGUMENTRANGE']._serialized_start=2437 - _globals['_ARGUMENTRANGE']._serialized_end=2498 - _globals['_TARGETSET']._serialized_start=2501 - _globals['_TARGETSET']._serialized_end=2740 - _globals['_TARGETSET_TARGETORDERING']._serialized_start=2644 - _globals['_TARGETSET_TARGETORDERING']._serialized_end=2740 - _globals['_TARGET']._serialized_start=2742 - _globals['_TARGET']._serialized_end=2763 + _globals['_DEVICESPECIFICATION']._serialized_end=369 + _globals['_GATESPECIFICATION']._serialized_start=372 + _globals['_GATESPECIFICATION']._serialized_end=2031 + _globals['_GATESPECIFICATION_SYCAMORE']._serialized_start=1758 + _globals['_GATESPECIFICATION_SYCAMORE']._serialized_end=1768 + _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_start=1770 + _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_end=1781 + _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_start=1783 + _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_end=1797 + _globals['_GATESPECIFICATION_CZ']._serialized_start=1799 + _globals['_GATESPECIFICATION_CZ']._serialized_end=1803 + _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_start=1805 + _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_end=1815 + _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_start=1817 + _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_end=1830 + _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_start=1832 + _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_end=1846 + _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_start=1848 + _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_end=1862 + _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_start=1864 + _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_end=1877 + _globals['_GATESPECIFICATION_WAIT']._serialized_start=1879 + _globals['_GATESPECIFICATION_WAIT']._serialized_end=1885 + _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_start=1887 + _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_end=1901 + _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_start=1903 + _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_end=1917 + _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_start=1919 + _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_end=1930 + _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_start=1932 + _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_end=1946 + _globals['_GATESPECIFICATION_RESET']._serialized_start=1948 + _globals['_GATESPECIFICATION_RESET']._serialized_end=1955 + _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_start=1957 + _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_end=1976 + _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_start=1978 + _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_end=2003 + _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_start=2005 + _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_end=2023 + _globals['_GATESET']._serialized_start=2033 + _globals['_GATESET']._serialized_end=2113 + _globals['_GATEDEFINITION']._serialized_start=2116 + _globals['_GATEDEFINITION']._serialized_end=2277 + _globals['_ARGDEFINITION']._serialized_start=2280 + _globals['_ARGDEFINITION']._serialized_end=2498 + _globals['_ARGDEFINITION_ARGTYPE']._serialized_start=2427 + _globals['_ARGDEFINITION_ARGTYPE']._serialized_end=2498 + _globals['_ARGUMENTRANGE']._serialized_start=2500 + _globals['_ARGUMENTRANGE']._serialized_end=2561 + _globals['_TARGETSET']._serialized_start=2564 + _globals['_TARGETSET']._serialized_end=2803 + _globals['_TARGETSET_TARGETORDERING']._serialized_start=2707 + _globals['_TARGETSET_TARGETORDERING']._serialized_end=2803 + _globals['_TARGET']._serialized_start=2805 + _globals['_TARGET']._serialized_end=2826 + _globals['_QUBITATTRIBUTES']._serialized_start=2828 + _globals['_QUBITATTRIBUTES']._serialized_end=2921 + _globals['_QUBITATTRIBUTEENTRY']._serialized_start=2923 + _globals['_QUBITATTRIBUTEENTRY']._serialized_end=3014 + _globals['_QUBITATTRIBUTEVALUE']._serialized_start=3016 + _globals['_QUBITATTRIBUTEVALUE']._serialized_end=3135 # @@protoc_insertion_point(module_scope) diff --git a/cirq-google/cirq_google/api/v2/device_pb2.pyi b/cirq-google/cirq_google/api/v2/device_pb2.pyi index 3cdecca125a..8c5931ffcee 100644 --- a/cirq-google/cirq_google/api/v2/device_pb2.pyi +++ b/cirq-google/cirq_google/api/v2/device_pb2.pyi @@ -39,6 +39,7 @@ class DeviceSpecification(_message.Message): VALID_QUBITS_FIELD_NUMBER: _builtins.int VALID_TARGETS_FIELD_NUMBER: _builtins.int DEVELOPER_RECOMMENDATIONS_FIELD_NUMBER: _builtins.int + QUBIT_ATTRIBUTES_FIELD_NUMBER: _builtins.int developer_recommendations: _builtins.str """Additional recommendations, caveats, and soft requirements that are advice to users of the device, specified in English text @@ -71,6 +72,10 @@ class DeviceSpecification(_message.Message): def valid_targets(self) -> _containers.RepeatedCompositeFieldContainer[Global___TargetSet]: """A list of targets that gates can use.""" + @_builtins.property + def qubit_attributes(self) -> _containers.RepeatedCompositeFieldContainer[Global___QubitAttributes]: + """Qubit attributes for the device.""" + def __init__( self, *, @@ -79,10 +84,11 @@ class DeviceSpecification(_message.Message): valid_qubits: _abc.Iterable[_builtins.str] | None = ..., valid_targets: _abc.Iterable[Global___TargetSet] | None = ..., developer_recommendations: _builtins.str = ..., + qubit_attributes: _abc.Iterable[Global___QubitAttributes] | None = ..., ) -> None: ... _HasFieldArgType: _TypeAlias = _Never # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["developer_recommendations", b"developer_recommendations", "valid_gate_sets", b"valid_gate_sets", "valid_gates", b"valid_gates", "valid_qubits", b"valid_qubits", "valid_targets", b"valid_targets"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["developer_recommendations", b"developer_recommendations", "qubit_attributes", b"qubit_attributes", "valid_gate_sets", b"valid_gate_sets", "valid_gates", b"valid_gates", "valid_qubits", b"valid_qubits", "valid_targets", b"valid_targets"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... def WhichOneof(self, oneof_group: _Never) -> None: ... @@ -709,3 +715,85 @@ class Target(_message.Message): def WhichOneof(self, oneof_group: _Never) -> None: ... Global___Target: _TypeAlias = Target # noqa: Y015 + +@_typing.final +class QubitAttributes(_message.Message): + """Qubit attributes for a specific qubit.""" + + DESCRIPTOR: _descriptor.Descriptor + + QUBIT_FIELD_NUMBER: _builtins.int + ATTRIBUTES_FIELD_NUMBER: _builtins.int + qubit: _builtins.str + @_builtins.property + def attributes(self) -> _containers.RepeatedCompositeFieldContainer[Global___QubitAttributeEntry]: ... + def __init__( + self, + *, + qubit: _builtins.str = ..., + attributes: _abc.Iterable[Global___QubitAttributeEntry] | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _Never # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["attributes", b"attributes", "qubit", b"qubit"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + def WhichOneof(self, oneof_group: _Never) -> None: ... + +Global___QubitAttributes: _TypeAlias = QubitAttributes # noqa: Y015 + +@_typing.final +class QubitAttributeEntry(_message.Message): + """A key-value entry representing a single qubit attribute.""" + + DESCRIPTOR: _descriptor.Descriptor + + NAME_FIELD_NUMBER: _builtins.int + VALUE_FIELD_NUMBER: _builtins.int + name: _builtins.str + @_builtins.property + def value(self) -> Global___QubitAttributeValue: ... + def __init__( + self, + *, + name: _builtins.str = ..., + value: Global___QubitAttributeValue | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["value", b"value"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["name", b"name", "value", b"value"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + def WhichOneof(self, oneof_group: _Never) -> None: ... + +Global___QubitAttributeEntry: _TypeAlias = QubitAttributeEntry # noqa: Y015 + +@_typing.final +class QubitAttributeValue(_message.Message): + """A generic value for a qubit attribute.""" + + DESCRIPTOR: _descriptor.Descriptor + + STRING_VALUE_FIELD_NUMBER: _builtins.int + INT_VALUE_FIELD_NUMBER: _builtins.int + DOUBLE_VALUE_FIELD_NUMBER: _builtins.int + BOOL_VALUE_FIELD_NUMBER: _builtins.int + string_value: _builtins.str + int_value: _builtins.int + double_value: _builtins.float + bool_value: _builtins.bool + def __init__( + self, + *, + string_value: _builtins.str = ..., + int_value: _builtins.int = ..., + double_value: _builtins.float = ..., + bool_value: _builtins.bool = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["bool_value", b"bool_value", "double_value", b"double_value", "int_value", b"int_value", "string_value", b"string_value", "val", b"val"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["bool_value", b"bool_value", "double_value", b"double_value", "int_value", b"int_value", "string_value", b"string_value", "val", b"val"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType_val: _TypeAlias = _typing.Literal["string_value", "int_value", "double_value", "bool_value"] # noqa: Y015 + _WhichOneofArgType_val: _TypeAlias = _typing.Literal["val", b"val"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType_val) -> _WhichOneofReturnType_val | None: ... + +Global___QubitAttributeValue: _TypeAlias = QubitAttributeValue # noqa: Y015 diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index 5c197b84069..71e09d51255 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -467,6 +467,10 @@ def __init__(self, metadata: cirq.GridDeviceMetadata): """ self._metadata = metadata + @property + def qubit_attributes(self) -> dict[cirq.GridQubit, dict[str, str | int | float | bool]]: + return self._metadata.qubit_attributes + @classmethod def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: """Deserializes the `DeviceSpecification` to a `GridDevice`. @@ -499,6 +503,28 @@ def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: gateset, gate_durations = _deserialize_gateset_and_gate_durations(proto) + # Create qubit attributes + qubit_attributes = {} + for qubit_attrs_proto in proto.qubit_attributes: + qubit = v2.grid_qubit_from_proto_id(qubit_attrs_proto.qubit) + attrs = {} + for entry in qubit_attrs_proto.attributes: + val_proto = entry.value + which_val = val_proto.WhichOneof("val") + if which_val == "bool_value": + attrs[entry.name] = val_proto.bool_value + elif which_val == "int_value": + attrs[entry.name] = val_proto.int_value + elif which_val == "double_value": + attrs[entry.name] = val_proto.double_value + elif which_val == "string_value": + attrs[entry.name] = val_proto.string_value + elif which_val is None: + attrs[entry.name] = None + else: + raise ValueError(f"Unknown value in QubitAttributeValue: {which_val}") + qubit_attributes[qubit] = attrs + try: metadata = cirq.GridDeviceMetadata( qubit_pairs=qubit_pairs, @@ -506,6 +532,7 @@ def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: gate_durations=gate_durations if len(gate_durations) > 0 else None, all_qubits=all_qubits, compilation_target_gatesets=_build_compilation_target_gatesets(gateset), + qubit_attributes=qubit_attributes, ) except ValueError as ve: # pragma: no cover # Spec errors should have been caught in validation above. @@ -547,6 +574,28 @@ def to_proto( _serialize_gateset_and_gate_durations( out, gateset, {} if gate_durations is None else gate_durations ) + for qubit, attrs in self.qubit_attributes.items(): + qubit_str = v2.qubit_to_proto_id(qubit) + qubit_attrs_proto = out.qubit_attributes.add() + qubit_attrs_proto.qubit = qubit_str + for attr_name, attr_val in attrs.items(): + entry = qubit_attrs_proto.attributes.add() + entry.name = attr_name + val_proto = entry.value + if isinstance(attr_val, bool): + val_proto.bool_value = attr_val + elif isinstance(attr_val, int): + val_proto.int_value = attr_val + elif isinstance(attr_val, float): + val_proto.double_value = attr_val + elif isinstance(attr_val, str): + val_proto.string_value = attr_val + elif attr_val is None: + # leave unset + pass + else: + raise ValueError(f"Unsupported attribute value type: {type(attr_val)}") + _validate_device_specification(out) return out diff --git a/cirq-google/cirq_google/devices/grid_device_test.py b/cirq-google/cirq_google/devices/grid_device_test.py index 1e46f0c2bd0..4015801bee1 100644 --- a/cirq-google/cirq_google/devices/grid_device_test.py +++ b/cirq-google/cirq_google/devices/grid_device_test.py @@ -811,3 +811,67 @@ def test_to_proto(): assert cirq_google.GridDevice.from_proto(spec) == cirq_google.GridDevice.from_proto( expected_spec ) + + +def test_qubit_attributes_serialization_deserialization(): + device_info, spec = _create_device_spec_with_horizontal_couplings() + + # Add qubit attributes to the proto + q1_str = v2.qubit_to_proto_id(cirq.GridQubit(0, 0)) + q2_str = v2.qubit_to_proto_id(cirq.GridQubit(0, 1)) + + # Add attributes to q1 + qa1 = spec.qubit_attributes.add() + qa1.qubit = q1_str + + attr1 = qa1.attributes.add() + attr1.name = "type" + attr1.value.string_value = "transmon" + + attr2 = qa1.attributes.add() + attr2.name = "frequency" + attr2.value.double_value = 5.123 + + # Add attributes to q2 + qa2 = spec.qubit_attributes.add() + qa2.qubit = q2_str + + attr3 = qa2.attributes.add() + attr3.name = "index" + attr3.value.int_value = 42 + + attr4 = qa2.attributes.add() + attr4.name = "is_active" + attr4.value.bool_value = True + + # Deserialize and verify Python object attributes + device = cirq_google.GridDevice.from_proto(spec) + + expected_attrs = { + cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.123}, + cirq.GridQubit(0, 1): {"index": 42, "is_active": True}, + } + assert device.qubit_attributes == expected_attrs + + # Serialize back and verify it matches the spec with attributes + reserialized_spec = device.to_proto() + + # Check that they serialize to identical structures + # We can parse it back again to verify + device_parsed_again = cirq_google.GridDevice.from_proto(reserialized_spec) + assert device_parsed_again.qubit_attributes == expected_attrs + + +def test_qubit_attributes_unlisted_qubit(): + device_info, spec = _create_device_spec_with_horizontal_couplings() + + # Add attributes for an unlisted qubit + qa = spec.qubit_attributes.add() + qa.qubit = "10_10" # Not in valid_qubits + + attr = qa.attributes.add() + attr.name = "foo" + attr.value.string_value = "bar" + + device = cirq_google.GridDevice.from_proto(spec) + assert device.qubit_attributes[cirq.GridQubit(10, 10)] == {"foo": "bar"} diff --git a/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.json b/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.json index b4497a67584..1b76b8b684c 100644 --- a/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.json +++ b/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.json @@ -267,6 +267,7 @@ "required_sqrt_iswap_count": null, "use_sqrt_iswap_inv": false } - ] + ], + "qubit_attributes": [] } } \ No newline at end of file diff --git a/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.repr b/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.repr index a5ab82c61c1..d27ec9aa876 100644 --- a/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.repr +++ b/cirq-google/cirq_google/json_test_data/cirq.google.GridDevice.repr @@ -1 +1 @@ -cirq_google.GridDevice(cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(0, 1), cirq.GridQubit(0, 2)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(1, 0)), (cirq.GridQubit(0, 1), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)), (cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 2), cirq.GridQubit(1, 2))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate, cirq.CZ, (cirq.ISWAP**0.5), unroll_circuit_op = True), {cirq.GateFamily(gate=cirq.ops.common_gates.XPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(nanos=1), cirq.GateFamily(gate=cirq.ops.common_gates.YPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.ops.common_gates.ZPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.CZ, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=500), cirq.GateFamily(gate=(cirq.ISWAP**0.5), ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=600)}, frozenset({cirq.GridQubit(9, 9), cirq.GridQubit(0, 1), cirq.GridQubit(1, 1), cirq.GridQubit(0, 0), cirq.GridQubit(1, 2), cirq.GridQubit(10, 10), cirq.GridQubit(1, 0), cirq.GridQubit(0, 2)}), (cirq.CZTargetGateset(atol=1e-08, allow_partial_czs=False), cirq.SqrtIswapTargetGateset(atol=1e-08, required_sqrt_iswap_count=None, use_sqrt_iswap_inv=False)))) \ No newline at end of file +cirq_google.GridDevice(cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(0, 1), cirq.GridQubit(0, 2)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(1, 0)), (cirq.GridQubit(0, 1), cirq.GridQubit(1, 1)), (cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)), (cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(0, 2), cirq.GridQubit(1, 2))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate, cirq.CZ, (cirq.ISWAP**0.5), unroll_circuit_op = True), {cirq.GateFamily(gate=cirq.ops.common_gates.XPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(nanos=1), cirq.GateFamily(gate=cirq.ops.common_gates.YPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.ops.common_gates.ZPowGate, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=1), cirq.GateFamily(gate=cirq.CZ, ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=500), cirq.GateFamily(gate=(cirq.ISWAP**0.5), ignore_global_phase=True, tags_to_accept=frozenset(), tags_to_ignore=frozenset()): cirq.Duration(picos=600)}, frozenset({cirq.GridQubit(9, 9), cirq.GridQubit(0, 1), cirq.GridQubit(1, 1), cirq.GridQubit(0, 0), cirq.GridQubit(1, 2), cirq.GridQubit(10, 10), cirq.GridQubit(1, 0), cirq.GridQubit(0, 2)}), (cirq.CZTargetGateset(atol=1e-08, allow_partial_czs=False), cirq.SqrtIswapTargetGateset(atol=1e-08, required_sqrt_iswap_count=None, use_sqrt_iswap_inv=False)), {})) \ No newline at end of file From a120ec72009a6e53210b217a8d5f909a0bef90b0 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Thu, 18 Jun 2026 20:10:49 +0000 Subject: [PATCH 2/7] Fix the type and coverage issue --- cirq-core/cirq/devices/grid_device_metadata_test.py | 13 ++++++++----- cirq-google/cirq_google/devices/grid_device.py | 6 +++--- cirq-google/cirq_google/devices/grid_device_test.py | 6 +++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata_test.py b/cirq-core/cirq/devices/grid_device_metadata_test.py index 7a0d1b91ac2..75130b1cbf2 100644 --- a/cirq-core/cirq/devices/grid_device_metadata_test.py +++ b/cirq-core/cirq/devices/grid_device_metadata_test.py @@ -16,6 +16,8 @@ from __future__ import annotations +from typing import Any + import networkx as nx import pytest @@ -207,7 +209,7 @@ def test_repr() -> None: def test_griddevice_metadata_qubit_attributes() -> None: qubits = cirq.GridQubit.rect(1, 2) gateset = cirq.Gateset(cirq.XPowGate) - qubit_attributes = { + qubit_attributes: dict[cirq.GridQubit, dict[str, Any]] = { cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.1}, cirq.GridQubit(0, 1): {"index": 42}, } @@ -226,14 +228,15 @@ def test_griddevice_metadata_qubit_attributes() -> None: cirq.testing.assert_equivalent_repr(metadata) # test equality + qubit_attributes2: dict[cirq.GridQubit, dict[str, Any]] = { + cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.1}, + cirq.GridQubit(0, 1): {"index": 43}, # different index + } metadata2 = cirq.GridDeviceMetadata( qubit_pairs=[], gateset=gateset, all_qubits=qubits, - qubit_attributes={ - cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.1}, - cirq.GridQubit(0, 1): {"index": 43}, # different index - }, + qubit_attributes=qubit_attributes2, ) metadata3 = cirq.GridDeviceMetadata( diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index 71e09d51255..27dd8a82df0 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -468,7 +468,7 @@ def __init__(self, metadata: cirq.GridDeviceMetadata): self._metadata = metadata @property - def qubit_attributes(self) -> dict[cirq.GridQubit, dict[str, str | int | float | bool]]: + def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, Any]]: return self._metadata.qubit_attributes @classmethod @@ -522,7 +522,7 @@ def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: elif which_val is None: attrs[entry.name] = None else: - raise ValueError(f"Unknown value in QubitAttributeValue: {which_val}") + raise ValueError(f"Unknown value in QubitAttributeValue: {which_val}") # pragma: no cover qubit_attributes[qubit] = attrs try: @@ -594,7 +594,7 @@ def to_proto( # leave unset pass else: - raise ValueError(f"Unsupported attribute value type: {type(attr_val)}") + raise ValueError(f"Unsupported attribute value type: {type(attr_val)}") # pragma: no cover _validate_device_specification(out) diff --git a/cirq-google/cirq_google/devices/grid_device_test.py b/cirq-google/cirq_google/devices/grid_device_test.py index 4015801bee1..818cce9130b 100644 --- a/cirq-google/cirq_google/devices/grid_device_test.py +++ b/cirq-google/cirq_google/devices/grid_device_test.py @@ -844,12 +844,16 @@ def test_qubit_attributes_serialization_deserialization(): attr4.name = "is_active" attr4.value.bool_value = True + # Add an unset value (representing None) + attr5 = qa2.attributes.add() + attr5.name = "calibration_status" + # Deserialize and verify Python object attributes device = cirq_google.GridDevice.from_proto(spec) expected_attrs = { cirq.GridQubit(0, 0): {"type": "transmon", "frequency": 5.123}, - cirq.GridQubit(0, 1): {"index": 42, "is_active": True}, + cirq.GridQubit(0, 1): {"index": 42, "is_active": True, "calibration_status": None}, } assert device.qubit_attributes == expected_attrs From 690dddc739f5a44f53aa9095be34c0a19a421aa8 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Thu, 18 Jun 2026 22:22:41 +0000 Subject: [PATCH 3/7] format --- cirq-core/cirq/devices/grid_device_metadata_test.py | 5 +---- cirq-google/cirq_google/devices/grid_device.py | 8 ++++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata_test.py b/cirq-core/cirq/devices/grid_device_metadata_test.py index 75130b1cbf2..6f2a329705f 100644 --- a/cirq-core/cirq/devices/grid_device_metadata_test.py +++ b/cirq-core/cirq/devices/grid_device_metadata_test.py @@ -233,10 +233,7 @@ def test_griddevice_metadata_qubit_attributes() -> None: cirq.GridQubit(0, 1): {"index": 43}, # different index } metadata2 = cirq.GridDeviceMetadata( - qubit_pairs=[], - gateset=gateset, - all_qubits=qubits, - qubit_attributes=qubit_attributes2, + qubit_pairs=[], gateset=gateset, all_qubits=qubits, qubit_attributes=qubit_attributes2 ) metadata3 = cirq.GridDeviceMetadata( diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index 27dd8a82df0..e867a2c7ee2 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -522,7 +522,9 @@ def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: elif which_val is None: attrs[entry.name] = None else: - raise ValueError(f"Unknown value in QubitAttributeValue: {which_val}") # pragma: no cover + raise ValueError( + f"Unknown value in QubitAttributeValue: {which_val}" + ) # pragma: no cover qubit_attributes[qubit] = attrs try: @@ -594,7 +596,9 @@ def to_proto( # leave unset pass else: - raise ValueError(f"Unsupported attribute value type: {type(attr_val)}") # pragma: no cover + raise ValueError( + f"Unsupported attribute value type: {type(attr_val)}" + ) # pragma: no cover _validate_device_specification(out) From c2104a06d4c489f998df62e52edd2ffaa1d57d0a Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Tue, 23 Jun 2026 23:15:00 -0700 Subject: [PATCH 4/7] Update cirq-core/cirq/devices/grid_device_metadata.py Co-authored-by: Pavol Juhas --- cirq-core/cirq/devices/grid_device_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index bb2f6b82aed..c0a90d582b0 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -248,5 +248,5 @@ def _from_json_dict_( dict(gate_durations) if gate_durations is not None else None, all_qubits, compilation_target_gatesets, - dict(qubit_attributes) if qubit_attributes is not None else None, + qubit_attributes, ) From 8a710c08416dd07bc234db2f9435257d5bf19e2e Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Tue, 23 Jun 2026 23:15:12 -0700 Subject: [PATCH 5/7] Update cirq-core/cirq/devices/grid_device_metadata.py Co-authored-by: Pavol Juhas --- cirq-core/cirq/devices/grid_device_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index c0a90d582b0..a80f5acdf73 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -226,7 +226,7 @@ def _json_dict_(self): 'all_qubits': sorted(self.qubit_set), 'compilation_target_gatesets': list(self._compilation_target_gatesets), 'qubit_attributes': sorted( - [(q, sorted(attrs.items())) for q, attrs in self._qubit_attributes.items()], + ((q, sorted(attrs.items())) for q, attrs in self._qubit_attributes.items()), key=lambda x: x[0], ), } From 1c963687116e3a6ad405fa4fcd08b5837b4323c2 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 24 Jun 2026 06:32:27 +0000 Subject: [PATCH 6/7] Update the proto --- .../cirq/devices/grid_device_metadata.py | 11 +- cirq-google/cirq_google/api/v2/device.proto | 11 +- cirq-google/cirq_google/api/v2/device_pb2.py | 130 +++++++++--------- cirq-google/cirq_google/api/v2/device_pb2.pyi | 80 ++++++----- .../cirq_google/devices/grid_device.py | 44 +++--- .../cirq_google/devices/grid_device_test.py | 37 ++--- 6 files changed, 152 insertions(+), 161 deletions(-) diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index a80f5acdf73..6e978698e7f 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -17,7 +17,7 @@ from __future__ import annotations from collections.abc import Iterable, Mapping -from typing import Any, cast, TYPE_CHECKING +from typing import Any, cast, TYPE_CHECKING, TypeVar import networkx as nx @@ -28,6 +28,9 @@ import cirq +TQubitAttributeValue = TypeVar("TQubitAttributeValue", bound=bool | int | float | str | None) + + @value.value_equality class GridDeviceMetadata(device.DeviceMetadata): """Hardware metadata for homogenous 2d symmetric grid devices.""" @@ -39,7 +42,7 @@ def __init__( gate_durations: Mapping[cirq.GateFamily, cirq.Duration] | None = None, all_qubits: Iterable[cirq.GridQubit] | None = None, compilation_target_gatesets: Iterable[cirq.CompilationTargetGateset] = (), - qubit_attributes: Mapping[cirq.GridQubit, Mapping[str, Any]] | None = None, + qubit_attributes: Mapping[cirq.GridQubit, Mapping[str, TQubitAttributeValue]] | None = None, ): """Create a GridDeviceMetadata object. @@ -182,7 +185,7 @@ def gate_durations(self) -> Mapping[cirq.GateFamily, cirq.Duration] | None: return self._gate_durations @property - def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, Any]]: + def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, TQubitAttributeValue]]: """Returns a mapping from qubit to its attributes (if applicable).""" return self._qubit_attributes @@ -242,6 +245,8 @@ def _from_json_dict_( qubit_attributes=None, **kwargs, ): + if qubit_attributes is not None: + qubit_attributes = {q: dict(attrs) for q, attrs in qubit_attributes} return cls( qubit_pairs, gateset, diff --git a/cirq-google/cirq_google/api/v2/device.proto b/cirq-google/cirq_google/api/v2/device.proto index 844e5f74f0b..8b40ae79925 100644 --- a/cirq-google/cirq_google/api/v2/device.proto +++ b/cirq-google/cirq_google/api/v2/device.proto @@ -36,7 +36,7 @@ message DeviceSpecification { string developer_recommendations = 4; // Qubit attributes for the device. - repeated QubitAttributes qubit_attributes = 6; + map qubit_attributes = 6; } // This contains information about a single device gate. @@ -205,14 +205,7 @@ message Target { // Qubit attributes for a specific qubit. message QubitAttributes { - string qubit = 1; - repeated QubitAttributeEntry attributes = 2; -} - -// A key-value entry representing a single qubit attribute. -message QubitAttributeEntry { - string name = 1; - QubitAttributeValue value = 2; + map attributes = 1; } // A generic value for a qubit attribute. diff --git a/cirq-google/cirq_google/api/v2/device_pb2.py b/cirq-google/cirq_google/api/v2/device_pb2.py index 7e6282921d4..a5e3b9fa341 100644 --- a/cirq-google/cirq_google/api/v2/device_pb2.py +++ b/cirq-google/cirq_google/api/v2/device_pb2.py @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63irq_google/api/v2/device.proto\x12\x12\x63irq.google.api.v2\"\xb9\x02\n\x13\x44\x65viceSpecification\x12\x38\n\x0fvalid_gate_sets\x18\x01 \x03(\x0b\x32\x1b.cirq.google.api.v2.GateSetB\x02\x18\x01\x12:\n\x0bvalid_gates\x18\x05 \x03(\x0b\x32%.cirq.google.api.v2.GateSpecification\x12\x14\n\x0cvalid_qubits\x18\x02 \x03(\t\x12\x34\n\rvalid_targets\x18\x03 \x03(\x0b\x32\x1d.cirq.google.api.v2.TargetSet\x12!\n\x19\x64\x65veloper_recommendations\x18\x04 \x01(\t\x12=\n\x10qubit_attributes\x18\x06 \x03(\x0b\x32#.cirq.google.api.v2.QubitAttributes\"\xfb\x0c\n\x11GateSpecification\x12\x1b\n\x13gate_duration_picos\x18\x01 \x01(\x03\x12=\n\x03syc\x18\x02 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.SycamoreH\x00\x12\x45\n\nsqrt_iswap\x18\x03 \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.SqrtISwapH\x00\x12L\n\x0esqrt_iswap_inv\x18\x04 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.SqrtISwapInvH\x00\x12\x36\n\x02\x63z\x18\x05 \x01(\x0b\x32(.cirq.google.api.v2.GateSpecification.CZH\x00\x12\x43\n\tphased_xz\x18\x06 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.PhasedXZH\x00\x12I\n\x0cvirtual_zpow\x18\x07 \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.VirtualZPowH\x00\x12K\n\rphysical_zpow\x18\x08 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.PhysicalZPowH\x00\x12K\n\rcoupler_pulse\x18\t \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.CouplerPulseH\x00\x12\x41\n\x04meas\x18\n \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.MeasurementH\x00\x12:\n\x04wait\x18\x0b \x01(\x0b\x32*.cirq.google.api.v2.GateSpecification.WaitH\x00\x12L\n\x0e\x66sim_via_model\x18\x0c \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.FSimViaModelH\x00\x12L\n\x0etwo_pulse_fsim\x18\x13 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.TwoPulseFSimH\x00\x12\x46\n\x0b\x63z_pow_gate\x18\r \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.CZPowGateH\x00\x12K\n\rinternal_gate\x18\x0e \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.InternalGateH\x00\x12<\n\x05reset\x18\x0f \x01(\x0b\x32+.cirq.google.api.v2.GateSpecification.ResetH\x00\x12V\n\x13\x61nalog_detune_qubit\x18\x10 \x01(\x0b\x32\x37.cirq.google.api.v2.GateSpecification.AnalogDetuneQubitH\x00\x12\x63\n\x1a\x61nalog_detune_coupler_only\x18\x11 \x01(\x0b\x32=.cirq.google.api.v2.GateSpecification.AnalogDetuneCouplerOnlyH\x00\x12U\n\x13wait_gate_with_unit\x18\x12 \x01(\x0b\x32\x36.cirq.google.api.v2.GateSpecification.WaitGateWithUnitH\x00\x1a\n\n\x08Sycamore\x1a\x0b\n\tSqrtISwap\x1a\x0e\n\x0cSqrtISwapInv\x1a\x04\n\x02\x43Z\x1a\n\n\x08PhasedXZ\x1a\r\n\x0bVirtualZPow\x1a\x0e\n\x0cPhysicalZPow\x1a\x0e\n\x0c\x43ouplerPulse\x1a\r\n\x0bMeasurement\x1a\x06\n\x04Wait\x1a\x0e\n\x0c\x46SimViaModel\x1a\x0e\n\x0cTwoPulseFSim\x1a\x0b\n\tCZPowGate\x1a\x0e\n\x0cInternalGate\x1a\x07\n\x05Reset\x1a\x13\n\x11\x41nalogDetuneQubit\x1a\x19\n\x17\x41nalogDetuneCouplerOnly\x1a\x12\n\x10WaitGateWithUnitB\x06\n\x04gate\"P\n\x07GateSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x0bvalid_gates\x18\x02 \x03(\x0b\x32\".cirq.google.api.v2.GateDefinition\"\xa1\x01\n\x0eGateDefinition\x12\n\n\x02id\x18\x01 \x01(\t\x12\x18\n\x10number_of_qubits\x18\x02 \x01(\x05\x12\x35\n\nvalid_args\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgDefinition\x12\x1b\n\x13gate_duration_picos\x18\x04 \x01(\x03\x12\x15\n\rvalid_targets\x18\x05 \x03(\t\"\xda\x01\n\rArgDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x04type\x18\x02 \x01(\x0e\x32).cirq.google.api.v2.ArgDefinition.ArgType\x12\x39\n\x0e\x61llowed_ranges\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgumentRange\"G\n\x07\x41rgType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\t\n\x05\x46LOAT\x10\x01\x12\x14\n\x10REPEATED_BOOLEAN\x10\x02\x12\n\n\x06STRING\x10\x03\"=\n\rArgumentRange\x12\x15\n\rminimum_value\x18\x01 \x01(\x02\x12\x15\n\rmaximum_value\x18\x02 \x01(\x02\"\xef\x01\n\tTargetSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x45\n\x0ftarget_ordering\x18\x02 \x01(\x0e\x32,.cirq.google.api.v2.TargetSet.TargetOrdering\x12+\n\x07targets\x18\x03 \x03(\x0b\x32\x1a.cirq.google.api.v2.Target\"`\n\x0eTargetOrdering\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tSYMMETRIC\x10\x01\x12\x12\n\nASYMMETRIC\x10\x02\x1a\x02\x08\x01\x12\x1a\n\x12SUBSET_PERMUTATION\x10\x03\x1a\x02\x08\x01\"\x15\n\x06Target\x12\x0b\n\x03ids\x18\x01 \x03(\t\"]\n\x0fQubitAttributes\x12\r\n\x05qubit\x18\x01 \x01(\t\x12;\n\nattributes\x18\x02 \x03(\x0b\x32\'.cirq.google.api.v2.QubitAttributeEntry\"[\n\x13QubitAttributeEntry\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.cirq.google.api.v2.QubitAttributeValue\"w\n\x13QubitAttributeValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x16\n\x0c\x64ouble_value\x18\x03 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x42\x05\n\x03valB.\n\x1d\x63om.google.cirq.google.api.v2B\x0b\x44\x65viceProtoP\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63irq_google/api/v2/device.proto\x12\x12\x63irq.google.api.v2\"\xaf\x03\n\x13\x44\x65viceSpecification\x12\x38\n\x0fvalid_gate_sets\x18\x01 \x03(\x0b\x32\x1b.cirq.google.api.v2.GateSetB\x02\x18\x01\x12:\n\x0bvalid_gates\x18\x05 \x03(\x0b\x32%.cirq.google.api.v2.GateSpecification\x12\x14\n\x0cvalid_qubits\x18\x02 \x03(\t\x12\x34\n\rvalid_targets\x18\x03 \x03(\x0b\x32\x1d.cirq.google.api.v2.TargetSet\x12!\n\x19\x64\x65veloper_recommendations\x18\x04 \x01(\t\x12V\n\x10qubit_attributes\x18\x06 \x03(\x0b\x32<.cirq.google.api.v2.DeviceSpecification.QubitAttributesEntry\x1a[\n\x14QubitAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.cirq.google.api.v2.QubitAttributes:\x02\x38\x01\"\xfb\x0c\n\x11GateSpecification\x12\x1b\n\x13gate_duration_picos\x18\x01 \x01(\x03\x12=\n\x03syc\x18\x02 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.SycamoreH\x00\x12\x45\n\nsqrt_iswap\x18\x03 \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.SqrtISwapH\x00\x12L\n\x0esqrt_iswap_inv\x18\x04 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.SqrtISwapInvH\x00\x12\x36\n\x02\x63z\x18\x05 \x01(\x0b\x32(.cirq.google.api.v2.GateSpecification.CZH\x00\x12\x43\n\tphased_xz\x18\x06 \x01(\x0b\x32..cirq.google.api.v2.GateSpecification.PhasedXZH\x00\x12I\n\x0cvirtual_zpow\x18\x07 \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.VirtualZPowH\x00\x12K\n\rphysical_zpow\x18\x08 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.PhysicalZPowH\x00\x12K\n\rcoupler_pulse\x18\t \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.CouplerPulseH\x00\x12\x41\n\x04meas\x18\n \x01(\x0b\x32\x31.cirq.google.api.v2.GateSpecification.MeasurementH\x00\x12:\n\x04wait\x18\x0b \x01(\x0b\x32*.cirq.google.api.v2.GateSpecification.WaitH\x00\x12L\n\x0e\x66sim_via_model\x18\x0c \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.FSimViaModelH\x00\x12L\n\x0etwo_pulse_fsim\x18\x13 \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.TwoPulseFSimH\x00\x12\x46\n\x0b\x63z_pow_gate\x18\r \x01(\x0b\x32/.cirq.google.api.v2.GateSpecification.CZPowGateH\x00\x12K\n\rinternal_gate\x18\x0e \x01(\x0b\x32\x32.cirq.google.api.v2.GateSpecification.InternalGateH\x00\x12<\n\x05reset\x18\x0f \x01(\x0b\x32+.cirq.google.api.v2.GateSpecification.ResetH\x00\x12V\n\x13\x61nalog_detune_qubit\x18\x10 \x01(\x0b\x32\x37.cirq.google.api.v2.GateSpecification.AnalogDetuneQubitH\x00\x12\x63\n\x1a\x61nalog_detune_coupler_only\x18\x11 \x01(\x0b\x32=.cirq.google.api.v2.GateSpecification.AnalogDetuneCouplerOnlyH\x00\x12U\n\x13wait_gate_with_unit\x18\x12 \x01(\x0b\x32\x36.cirq.google.api.v2.GateSpecification.WaitGateWithUnitH\x00\x1a\n\n\x08Sycamore\x1a\x0b\n\tSqrtISwap\x1a\x0e\n\x0cSqrtISwapInv\x1a\x04\n\x02\x43Z\x1a\n\n\x08PhasedXZ\x1a\r\n\x0bVirtualZPow\x1a\x0e\n\x0cPhysicalZPow\x1a\x0e\n\x0c\x43ouplerPulse\x1a\r\n\x0bMeasurement\x1a\x06\n\x04Wait\x1a\x0e\n\x0c\x46SimViaModel\x1a\x0e\n\x0cTwoPulseFSim\x1a\x0b\n\tCZPowGate\x1a\x0e\n\x0cInternalGate\x1a\x07\n\x05Reset\x1a\x13\n\x11\x41nalogDetuneQubit\x1a\x19\n\x17\x41nalogDetuneCouplerOnly\x1a\x12\n\x10WaitGateWithUnitB\x06\n\x04gate\"P\n\x07GateSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x0bvalid_gates\x18\x02 \x03(\x0b\x32\".cirq.google.api.v2.GateDefinition\"\xa1\x01\n\x0eGateDefinition\x12\n\n\x02id\x18\x01 \x01(\t\x12\x18\n\x10number_of_qubits\x18\x02 \x01(\x05\x12\x35\n\nvalid_args\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgDefinition\x12\x1b\n\x13gate_duration_picos\x18\x04 \x01(\x03\x12\x15\n\rvalid_targets\x18\x05 \x03(\t\"\xda\x01\n\rArgDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x04type\x18\x02 \x01(\x0e\x32).cirq.google.api.v2.ArgDefinition.ArgType\x12\x39\n\x0e\x61llowed_ranges\x18\x03 \x03(\x0b\x32!.cirq.google.api.v2.ArgumentRange\"G\n\x07\x41rgType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\t\n\x05\x46LOAT\x10\x01\x12\x14\n\x10REPEATED_BOOLEAN\x10\x02\x12\n\n\x06STRING\x10\x03\"=\n\rArgumentRange\x12\x15\n\rminimum_value\x18\x01 \x01(\x02\x12\x15\n\rmaximum_value\x18\x02 \x01(\x02\"\xef\x01\n\tTargetSet\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x45\n\x0ftarget_ordering\x18\x02 \x01(\x0e\x32,.cirq.google.api.v2.TargetSet.TargetOrdering\x12+\n\x07targets\x18\x03 \x03(\x0b\x32\x1a.cirq.google.api.v2.Target\"`\n\x0eTargetOrdering\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tSYMMETRIC\x10\x01\x12\x12\n\nASYMMETRIC\x10\x02\x1a\x02\x08\x01\x12\x1a\n\x12SUBSET_PERMUTATION\x10\x03\x1a\x02\x08\x01\"\x15\n\x06Target\x12\x0b\n\x03ids\x18\x01 \x03(\t\"\xb6\x01\n\x0fQubitAttributes\x12G\n\nattributes\x18\x01 \x03(\x0b\x32\x33.cirq.google.api.v2.QubitAttributes.AttributesEntry\x1aZ\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.cirq.google.api.v2.QubitAttributeValue:\x02\x38\x01\"w\n\x13QubitAttributeValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x16\n\x0c\x64ouble_value\x18\x03 \x01(\x01H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x42\x05\n\x03valB.\n\x1d\x63om.google.cirq.google.api.v2B\x0b\x44\x65viceProtoP\x01\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -32,72 +32,78 @@ if not _descriptor._USE_C_DESCRIPTORS: _globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._serialized_options = b'\n\035com.google.cirq.google.api.v2B\013DeviceProtoP\001' + _globals['_DEVICESPECIFICATION_QUBITATTRIBUTESENTRY']._loaded_options = None + _globals['_DEVICESPECIFICATION_QUBITATTRIBUTESENTRY']._serialized_options = b'8\001' _globals['_DEVICESPECIFICATION'].fields_by_name['valid_gate_sets']._loaded_options = None _globals['_DEVICESPECIFICATION'].fields_by_name['valid_gate_sets']._serialized_options = b'\030\001' _globals['_TARGETSET_TARGETORDERING'].values_by_name["ASYMMETRIC"]._loaded_options = None _globals['_TARGETSET_TARGETORDERING'].values_by_name["ASYMMETRIC"]._serialized_options = b'\010\001' _globals['_TARGETSET_TARGETORDERING'].values_by_name["SUBSET_PERMUTATION"]._loaded_options = None _globals['_TARGETSET_TARGETORDERING'].values_by_name["SUBSET_PERMUTATION"]._serialized_options = b'\010\001' + _globals['_QUBITATTRIBUTES_ATTRIBUTESENTRY']._loaded_options = None + _globals['_QUBITATTRIBUTES_ATTRIBUTESENTRY']._serialized_options = b'8\001' _globals['_DEVICESPECIFICATION']._serialized_start=56 - _globals['_DEVICESPECIFICATION']._serialized_end=369 - _globals['_GATESPECIFICATION']._serialized_start=372 - _globals['_GATESPECIFICATION']._serialized_end=2031 - _globals['_GATESPECIFICATION_SYCAMORE']._serialized_start=1758 - _globals['_GATESPECIFICATION_SYCAMORE']._serialized_end=1768 - _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_start=1770 - _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_end=1781 - _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_start=1783 - _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_end=1797 - _globals['_GATESPECIFICATION_CZ']._serialized_start=1799 - _globals['_GATESPECIFICATION_CZ']._serialized_end=1803 - _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_start=1805 - _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_end=1815 - _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_start=1817 - _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_end=1830 - _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_start=1832 - _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_end=1846 - _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_start=1848 - _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_end=1862 - _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_start=1864 - _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_end=1877 - _globals['_GATESPECIFICATION_WAIT']._serialized_start=1879 - _globals['_GATESPECIFICATION_WAIT']._serialized_end=1885 - _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_start=1887 - _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_end=1901 - _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_start=1903 - _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_end=1917 - _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_start=1919 - _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_end=1930 - _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_start=1932 - _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_end=1946 - _globals['_GATESPECIFICATION_RESET']._serialized_start=1948 - _globals['_GATESPECIFICATION_RESET']._serialized_end=1955 - _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_start=1957 - _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_end=1976 - _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_start=1978 - _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_end=2003 - _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_start=2005 - _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_end=2023 - _globals['_GATESET']._serialized_start=2033 - _globals['_GATESET']._serialized_end=2113 - _globals['_GATEDEFINITION']._serialized_start=2116 - _globals['_GATEDEFINITION']._serialized_end=2277 - _globals['_ARGDEFINITION']._serialized_start=2280 - _globals['_ARGDEFINITION']._serialized_end=2498 - _globals['_ARGDEFINITION_ARGTYPE']._serialized_start=2427 - _globals['_ARGDEFINITION_ARGTYPE']._serialized_end=2498 - _globals['_ARGUMENTRANGE']._serialized_start=2500 - _globals['_ARGUMENTRANGE']._serialized_end=2561 - _globals['_TARGETSET']._serialized_start=2564 - _globals['_TARGETSET']._serialized_end=2803 - _globals['_TARGETSET_TARGETORDERING']._serialized_start=2707 - _globals['_TARGETSET_TARGETORDERING']._serialized_end=2803 - _globals['_TARGET']._serialized_start=2805 - _globals['_TARGET']._serialized_end=2826 - _globals['_QUBITATTRIBUTES']._serialized_start=2828 - _globals['_QUBITATTRIBUTES']._serialized_end=2921 - _globals['_QUBITATTRIBUTEENTRY']._serialized_start=2923 - _globals['_QUBITATTRIBUTEENTRY']._serialized_end=3014 - _globals['_QUBITATTRIBUTEVALUE']._serialized_start=3016 - _globals['_QUBITATTRIBUTEVALUE']._serialized_end=3135 + _globals['_DEVICESPECIFICATION']._serialized_end=487 + _globals['_DEVICESPECIFICATION_QUBITATTRIBUTESENTRY']._serialized_start=396 + _globals['_DEVICESPECIFICATION_QUBITATTRIBUTESENTRY']._serialized_end=487 + _globals['_GATESPECIFICATION']._serialized_start=490 + _globals['_GATESPECIFICATION']._serialized_end=2149 + _globals['_GATESPECIFICATION_SYCAMORE']._serialized_start=1876 + _globals['_GATESPECIFICATION_SYCAMORE']._serialized_end=1886 + _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_start=1888 + _globals['_GATESPECIFICATION_SQRTISWAP']._serialized_end=1899 + _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_start=1901 + _globals['_GATESPECIFICATION_SQRTISWAPINV']._serialized_end=1915 + _globals['_GATESPECIFICATION_CZ']._serialized_start=1917 + _globals['_GATESPECIFICATION_CZ']._serialized_end=1921 + _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_start=1923 + _globals['_GATESPECIFICATION_PHASEDXZ']._serialized_end=1933 + _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_start=1935 + _globals['_GATESPECIFICATION_VIRTUALZPOW']._serialized_end=1948 + _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_start=1950 + _globals['_GATESPECIFICATION_PHYSICALZPOW']._serialized_end=1964 + _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_start=1966 + _globals['_GATESPECIFICATION_COUPLERPULSE']._serialized_end=1980 + _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_start=1982 + _globals['_GATESPECIFICATION_MEASUREMENT']._serialized_end=1995 + _globals['_GATESPECIFICATION_WAIT']._serialized_start=1997 + _globals['_GATESPECIFICATION_WAIT']._serialized_end=2003 + _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_start=2005 + _globals['_GATESPECIFICATION_FSIMVIAMODEL']._serialized_end=2019 + _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_start=2021 + _globals['_GATESPECIFICATION_TWOPULSEFSIM']._serialized_end=2035 + _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_start=2037 + _globals['_GATESPECIFICATION_CZPOWGATE']._serialized_end=2048 + _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_start=2050 + _globals['_GATESPECIFICATION_INTERNALGATE']._serialized_end=2064 + _globals['_GATESPECIFICATION_RESET']._serialized_start=2066 + _globals['_GATESPECIFICATION_RESET']._serialized_end=2073 + _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_start=2075 + _globals['_GATESPECIFICATION_ANALOGDETUNEQUBIT']._serialized_end=2094 + _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_start=2096 + _globals['_GATESPECIFICATION_ANALOGDETUNECOUPLERONLY']._serialized_end=2121 + _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_start=2123 + _globals['_GATESPECIFICATION_WAITGATEWITHUNIT']._serialized_end=2141 + _globals['_GATESET']._serialized_start=2151 + _globals['_GATESET']._serialized_end=2231 + _globals['_GATEDEFINITION']._serialized_start=2234 + _globals['_GATEDEFINITION']._serialized_end=2395 + _globals['_ARGDEFINITION']._serialized_start=2398 + _globals['_ARGDEFINITION']._serialized_end=2616 + _globals['_ARGDEFINITION_ARGTYPE']._serialized_start=2545 + _globals['_ARGDEFINITION_ARGTYPE']._serialized_end=2616 + _globals['_ARGUMENTRANGE']._serialized_start=2618 + _globals['_ARGUMENTRANGE']._serialized_end=2679 + _globals['_TARGETSET']._serialized_start=2682 + _globals['_TARGETSET']._serialized_end=2921 + _globals['_TARGETSET_TARGETORDERING']._serialized_start=2825 + _globals['_TARGETSET_TARGETORDERING']._serialized_end=2921 + _globals['_TARGET']._serialized_start=2923 + _globals['_TARGET']._serialized_end=2944 + _globals['_QUBITATTRIBUTES']._serialized_start=2947 + _globals['_QUBITATTRIBUTES']._serialized_end=3129 + _globals['_QUBITATTRIBUTES_ATTRIBUTESENTRY']._serialized_start=3039 + _globals['_QUBITATTRIBUTES_ATTRIBUTESENTRY']._serialized_end=3129 + _globals['_QUBITATTRIBUTEVALUE']._serialized_start=3131 + _globals['_QUBITATTRIBUTEVALUE']._serialized_end=3250 # @@protoc_insertion_point(module_scope) diff --git a/cirq-google/cirq_google/api/v2/device_pb2.pyi b/cirq-google/cirq_google/api/v2/device_pb2.pyi index 8c5931ffcee..53aadab072f 100644 --- a/cirq-google/cirq_google/api/v2/device_pb2.pyi +++ b/cirq-google/cirq_google/api/v2/device_pb2.pyi @@ -34,6 +34,27 @@ class DeviceSpecification(_message.Message): DESCRIPTOR: _descriptor.Descriptor + @_typing.final + class QubitAttributesEntry(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + KEY_FIELD_NUMBER: _builtins.int + VALUE_FIELD_NUMBER: _builtins.int + key: _builtins.str + @_builtins.property + def value(self) -> Global___QubitAttributes: ... + def __init__( + self, + *, + key: _builtins.str = ..., + value: Global___QubitAttributes | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["value", b"value"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "value", b"value"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + def WhichOneof(self, oneof_group: _Never) -> None: ... + VALID_GATE_SETS_FIELD_NUMBER: _builtins.int VALID_GATES_FIELD_NUMBER: _builtins.int VALID_QUBITS_FIELD_NUMBER: _builtins.int @@ -73,7 +94,7 @@ class DeviceSpecification(_message.Message): """A list of targets that gates can use.""" @_builtins.property - def qubit_attributes(self) -> _containers.RepeatedCompositeFieldContainer[Global___QubitAttributes]: + def qubit_attributes(self) -> _containers.MessageMap[_builtins.str, Global___QubitAttributes]: """Qubit attributes for the device.""" def __init__( @@ -84,7 +105,7 @@ class DeviceSpecification(_message.Message): valid_qubits: _abc.Iterable[_builtins.str] | None = ..., valid_targets: _abc.Iterable[Global___TargetSet] | None = ..., developer_recommendations: _builtins.str = ..., - qubit_attributes: _abc.Iterable[Global___QubitAttributes] | None = ..., + qubit_attributes: _abc.Mapping[_builtins.str, Global___QubitAttributes] | None = ..., ) -> None: ... _HasFieldArgType: _TypeAlias = _Never # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... @@ -722,50 +743,43 @@ class QubitAttributes(_message.Message): DESCRIPTOR: _descriptor.Descriptor - QUBIT_FIELD_NUMBER: _builtins.int + @_typing.final + class AttributesEntry(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + KEY_FIELD_NUMBER: _builtins.int + VALUE_FIELD_NUMBER: _builtins.int + key: _builtins.str + @_builtins.property + def value(self) -> Global___QubitAttributeValue: ... + def __init__( + self, + *, + key: _builtins.str = ..., + value: Global___QubitAttributeValue | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["value", b"value"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "value", b"value"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + def WhichOneof(self, oneof_group: _Never) -> None: ... + ATTRIBUTES_FIELD_NUMBER: _builtins.int - qubit: _builtins.str @_builtins.property - def attributes(self) -> _containers.RepeatedCompositeFieldContainer[Global___QubitAttributeEntry]: ... + def attributes(self) -> _containers.MessageMap[_builtins.str, Global___QubitAttributeValue]: ... def __init__( self, *, - qubit: _builtins.str = ..., - attributes: _abc.Iterable[Global___QubitAttributeEntry] | None = ..., + attributes: _abc.Mapping[_builtins.str, Global___QubitAttributeValue] | None = ..., ) -> None: ... _HasFieldArgType: _TypeAlias = _Never # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["attributes", b"attributes", "qubit", b"qubit"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["attributes", b"attributes"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... def WhichOneof(self, oneof_group: _Never) -> None: ... Global___QubitAttributes: _TypeAlias = QubitAttributes # noqa: Y015 -@_typing.final -class QubitAttributeEntry(_message.Message): - """A key-value entry representing a single qubit attribute.""" - - DESCRIPTOR: _descriptor.Descriptor - - NAME_FIELD_NUMBER: _builtins.int - VALUE_FIELD_NUMBER: _builtins.int - name: _builtins.str - @_builtins.property - def value(self) -> Global___QubitAttributeValue: ... - def __init__( - self, - *, - name: _builtins.str = ..., - value: Global___QubitAttributeValue | None = ..., - ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["value", b"value"] # noqa: Y015 - def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["name", b"name", "value", b"value"] # noqa: Y015 - def ClearField(self, field_name: _ClearFieldArgType) -> None: ... - def WhichOneof(self, oneof_group: _Never) -> None: ... - -Global___QubitAttributeEntry: _TypeAlias = QubitAttributeEntry # noqa: Y015 - @_typing.final class QubitAttributeValue(_message.Message): """A generic value for a qubit attribute.""" diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index e867a2c7ee2..5842710c68a 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -192,6 +192,13 @@ class _GateRepresentations: ] +def _qubit_attribute_value_from_proto( + val_proto: v2.device_pb2.QubitAttributeValue, +) -> cirq.devices.TQubitAttributeValue: + which_val = val_proto.WhichOneof("val") + return getattr(val_proto, which_val) if which_val is not None else None + + def _validate_device_specification(proto: v2.device_pb2.DeviceSpecification) -> None: """Raises a ValueError if the `DeviceSpecification` proto is invalid.""" @@ -468,7 +475,9 @@ def __init__(self, metadata: cirq.GridDeviceMetadata): self._metadata = metadata @property - def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, Any]]: + def qubit_attributes( + self, + ) -> Mapping[cirq.GridQubit, Mapping[str, cirq.devices.TQubitAttributeValue]]: return self._metadata.qubit_attributes @classmethod @@ -505,26 +514,12 @@ def from_proto(cls, proto: v2.device_pb2.DeviceSpecification) -> GridDevice: # Create qubit attributes qubit_attributes = {} - for qubit_attrs_proto in proto.qubit_attributes: - qubit = v2.grid_qubit_from_proto_id(qubit_attrs_proto.qubit) - attrs = {} - for entry in qubit_attrs_proto.attributes: - val_proto = entry.value - which_val = val_proto.WhichOneof("val") - if which_val == "bool_value": - attrs[entry.name] = val_proto.bool_value - elif which_val == "int_value": - attrs[entry.name] = val_proto.int_value - elif which_val == "double_value": - attrs[entry.name] = val_proto.double_value - elif which_val == "string_value": - attrs[entry.name] = val_proto.string_value - elif which_val is None: - attrs[entry.name] = None - else: - raise ValueError( - f"Unknown value in QubitAttributeValue: {which_val}" - ) # pragma: no cover + for qubit_str, qubit_attrs_proto in proto.qubit_attributes.items(): + qubit = v2.grid_qubit_from_proto_id(qubit_str) + attrs = { + name: _qubit_attribute_value_from_proto(val_proto) + for name, val_proto in qubit_attrs_proto.attributes.items() + } qubit_attributes[qubit] = attrs try: @@ -578,12 +573,9 @@ def to_proto( ) for qubit, attrs in self.qubit_attributes.items(): qubit_str = v2.qubit_to_proto_id(qubit) - qubit_attrs_proto = out.qubit_attributes.add() - qubit_attrs_proto.qubit = qubit_str + qubit_attrs_proto = out.qubit_attributes[qubit_str] for attr_name, attr_val in attrs.items(): - entry = qubit_attrs_proto.attributes.add() - entry.name = attr_name - val_proto = entry.value + val_proto = qubit_attrs_proto.attributes[attr_name] if isinstance(attr_val, bool): val_proto.bool_value = attr_val elif isinstance(attr_val, int): diff --git a/cirq-google/cirq_google/devices/grid_device_test.py b/cirq-google/cirq_google/devices/grid_device_test.py index 818cce9130b..b0020ba70ce 100644 --- a/cirq-google/cirq_google/devices/grid_device_test.py +++ b/cirq-google/cirq_google/devices/grid_device_test.py @@ -821,32 +821,17 @@ def test_qubit_attributes_serialization_deserialization(): q2_str = v2.qubit_to_proto_id(cirq.GridQubit(0, 1)) # Add attributes to q1 - qa1 = spec.qubit_attributes.add() - qa1.qubit = q1_str - - attr1 = qa1.attributes.add() - attr1.name = "type" - attr1.value.string_value = "transmon" - - attr2 = qa1.attributes.add() - attr2.name = "frequency" - attr2.value.double_value = 5.123 + qa1 = spec.qubit_attributes[q1_str] + qa1.attributes["type"].string_value = "transmon" + qa1.attributes["frequency"].double_value = 5.123 # Add attributes to q2 - qa2 = spec.qubit_attributes.add() - qa2.qubit = q2_str - - attr3 = qa2.attributes.add() - attr3.name = "index" - attr3.value.int_value = 42 - - attr4 = qa2.attributes.add() - attr4.name = "is_active" - attr4.value.bool_value = True + qa2 = spec.qubit_attributes[q2_str] + qa2.attributes["index"].int_value = 42 + qa2.attributes["is_active"].bool_value = True # Add an unset value (representing None) - attr5 = qa2.attributes.add() - attr5.name = "calibration_status" + _ = qa2.attributes["calibration_status"] # Deserialize and verify Python object attributes device = cirq_google.GridDevice.from_proto(spec) @@ -870,12 +855,8 @@ def test_qubit_attributes_unlisted_qubit(): device_info, spec = _create_device_spec_with_horizontal_couplings() # Add attributes for an unlisted qubit - qa = spec.qubit_attributes.add() - qa.qubit = "10_10" # Not in valid_qubits - - attr = qa.attributes.add() - attr.name = "foo" - attr.value.string_value = "bar" + qa = spec.qubit_attributes["10_10"] # Not in valid_qubits + qa.attributes["foo"].string_value = "bar" device = cirq_google.GridDevice.from_proto(spec) assert device.qubit_attributes[cirq.GridQubit(10, 10)] == {"foo": "bar"} From 001dad94448fd4d1b26e5f3653ac47f0a44d7160 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 24 Jun 2026 17:40:44 +0000 Subject: [PATCH 7/7] Fix the type error --- cirq-core/cirq/__init__.py | 1 + cirq-core/cirq/devices/__init__.py | 5 ++++- cirq-core/cirq/devices/grid_device_metadata.py | 8 ++++---- cirq-google/cirq_google/devices/grid_device.py | 6 ++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cirq-core/cirq/__init__.py b/cirq-core/cirq/__init__.py index 9753de507be..1ce4cc6e1b1 100644 --- a/cirq-core/cirq/__init__.py +++ b/cirq-core/cirq/__init__.py @@ -93,6 +93,7 @@ NoiseModelFromNoiseProperties as NoiseModelFromNoiseProperties, NoiseProperties as NoiseProperties, OpIdentifier as OpIdentifier, + QubitAttributeValue as QubitAttributeValue, SuperconductingQubitsNoiseProperties as SuperconductingQubitsNoiseProperties, UNCONSTRAINED_DEVICE as UNCONSTRAINED_DEVICE, NamedTopology as NamedTopology, diff --git a/cirq-core/cirq/devices/__init__.py b/cirq-core/cirq/devices/__init__.py index f30fa4d99a5..c87792df774 100644 --- a/cirq-core/cirq/devices/__init__.py +++ b/cirq-core/cirq/devices/__init__.py @@ -16,7 +16,10 @@ from cirq.devices.device import Device as Device, DeviceMetadata as DeviceMetadata -from cirq.devices.grid_device_metadata import GridDeviceMetadata as GridDeviceMetadata +from cirq.devices.grid_device_metadata import ( + GridDeviceMetadata as GridDeviceMetadata, + QubitAttributeValue as QubitAttributeValue, +) from cirq.devices.grid_qubit import GridQid as GridQid, GridQubit as GridQubit diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index 6e978698e7f..6845226e5c7 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -17,7 +17,7 @@ from __future__ import annotations from collections.abc import Iterable, Mapping -from typing import Any, cast, TYPE_CHECKING, TypeVar +from typing import Any, cast, TYPE_CHECKING, Union import networkx as nx @@ -28,7 +28,7 @@ import cirq -TQubitAttributeValue = TypeVar("TQubitAttributeValue", bound=bool | int | float | str | None) +QubitAttributeValue = bool | int | float | str | None @value.value_equality @@ -42,7 +42,7 @@ def __init__( gate_durations: Mapping[cirq.GateFamily, cirq.Duration] | None = None, all_qubits: Iterable[cirq.GridQubit] | None = None, compilation_target_gatesets: Iterable[cirq.CompilationTargetGateset] = (), - qubit_attributes: Mapping[cirq.GridQubit, Mapping[str, TQubitAttributeValue]] | None = None, + qubit_attributes: Mapping[cirq.GridQubit, Mapping[str, QubitAttributeValue]] | None = None, ): """Create a GridDeviceMetadata object. @@ -185,7 +185,7 @@ def gate_durations(self) -> Mapping[cirq.GateFamily, cirq.Duration] | None: return self._gate_durations @property - def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, TQubitAttributeValue]]: + def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, QubitAttributeValue]]: """Returns a mapping from qubit to its attributes (if applicable).""" return self._qubit_attributes diff --git a/cirq-google/cirq_google/devices/grid_device.py b/cirq-google/cirq_google/devices/grid_device.py index 5842710c68a..89fda1bc770 100644 --- a/cirq-google/cirq_google/devices/grid_device.py +++ b/cirq-google/cirq_google/devices/grid_device.py @@ -194,7 +194,7 @@ class _GateRepresentations: def _qubit_attribute_value_from_proto( val_proto: v2.device_pb2.QubitAttributeValue, -) -> cirq.devices.TQubitAttributeValue: +) -> cirq.QubitAttributeValue: which_val = val_proto.WhichOneof("val") return getattr(val_proto, which_val) if which_val is not None else None @@ -475,9 +475,7 @@ def __init__(self, metadata: cirq.GridDeviceMetadata): self._metadata = metadata @property - def qubit_attributes( - self, - ) -> Mapping[cirq.GridQubit, Mapping[str, cirq.devices.TQubitAttributeValue]]: + def qubit_attributes(self) -> Mapping[cirq.GridQubit, Mapping[str, cirq.QubitAttributeValue]]: return self._metadata.qubit_attributes @classmethod