Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions cirq-core/cirq/devices/grid_device_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide typing consistent with the QubitAttributeValue proto instead of Any?
This could be done with a TypeVar, for example,

TQubitAttributeValue = TypeVar("TQubitAttributeValue", bound=bool | int | float | str)

):
"""Create a GridDeviceMetadata object.

Expand Down Expand Up @@ -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]:
Expand Down Expand Up @@ -175,25 +181,37 @@ 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:
qubit_pair_tuples = frozenset({tuple(sorted(p)) for p in self._qubit_pairs})
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)})'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we turn qubit_attributes into a keyword argument here and only add it when set?

)

def _json_dict_(self):
Expand All @@ -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()],
Comment thread
BichengYing marked this conversation as resolved.
Outdated
key=lambda x: x[0],
),
}

@classmethod
Expand All @@ -217,6 +239,7 @@ def _from_json_dict_(
gate_durations,
all_qubits,
compilation_target_gatesets=(),
qubit_attributes=None,
**kwargs,
):
return cls(
Expand All @@ -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,
Comment thread
BichengYing marked this conversation as resolved.
Outdated
)
42 changes: 42 additions & 0 deletions cirq-core/cirq/devices/grid_device_metadata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

from __future__ import annotations

from typing import Any

import networkx as nx
import pytest

Expand Down Expand Up @@ -202,3 +204,43 @@ 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: dict[cirq.GridQubit, dict[str, Any]] = {
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)
Comment on lines +223 to +225

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to test_griddevice_json_load above.


# test repr
cirq.testing.assert_equivalent_repr(metadata)
Comment on lines +227 to +228

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to test_repr above.


# test equality
qubit_attributes2: dict[cirq.GridQubit, dict[str, Any]] = {
Comment on lines +230 to +231

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move equality tests to test_griddevice_metadata_equality above.

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=qubit_attributes2
)

metadata3 = cirq.GridDeviceMetadata(
qubit_pairs=[], gateset=gateset, all_qubits=qubits, qubit_attributes=None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to leave out qubit_attributes instead of explicitly setting to None.

Suggested change
qubit_pairs=[], gateset=gateset, all_qubits=qubits, qubit_attributes=None
qubit_pairs=[], gateset=gateset, all_qubits=qubits

)

eq = cirq.testing.EqualsTester()
eq.add_equality_group(metadata)
eq.add_equality_group(metadata2)
eq.add_equality_group(metadata3)
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,6 @@
"required_sqrt_iswap_count": null,
"use_sqrt_iswap_inv": false
}
]
],
"qubit_attributes": []

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fill with some actual data.

}
Original file line number Diff line number Diff line change
@@ -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)))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please convert to a 2-item list in a similar fashion as suggested for GridDeviceMetadata.json above, ie, the first element is the original repr (without the qubit_attributes argument), and the second one a GDM with qubit_attributes set.

Also, please format with black cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.repr so this is more readable later on.

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)), {})
25 changes: 25 additions & 0 deletions cirq-google/cirq_google/api/v2/device.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a map<string, QubitAttributes> instead? That way there could be no duplicate entries for some qubit.

}

// This contains information about a single device gate.
Expand Down Expand Up @@ -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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar as above, this could just have one field of map<string, QubitAttributeValue> attributes which would prevent duplicate specification of some attribute.

}

// 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;
}
}
Loading
Loading