Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isolated qubit functionality for gridmetadata. #5001

Merged
merged 4 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
39 changes: 21 additions & 18 deletions cirq-core/cirq/devices/grid_device_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def __init__(
qubit_pairs: Iterable[Tuple['cirq.Qid', 'cirq.Qid']],
gateset: 'cirq.Gateset',
gate_durations: Optional[Dict['cirq.GateFamily', 'cirq.Duration']] = None,
isolated_qubits: Optional[Iterable['cirq.Qid']] = None,
all_qubits: Optional[Iterable['cirq.Qid']] = None,
):
"""Create a GridDeviceMetadata object.

Expand All @@ -57,12 +57,16 @@ def __init__(
instances mapping to `cirq.Duration` instances for
gate timing metadata information. If provided,
must match all entries in gateset.
isolated_qubits: Optional qubits to include on the grid
that have no connections found in qubit_pairs.
all_qubits: Optional iterable specifying all qubits
found on the device. If None, all_qubits will
be inferred from the entries in qubit_pairs.

Raises:
ValueError: if the union of GateFamily keys in gate_durations
MichaelBroughton marked this conversation as resolved.
Show resolved Hide resolved
is not identical to set of gate families in gateset.
ValueError: If qubit_pairs contains a self loop.
ValueError: if all_qubits is provided and is not a superset
of all the qubits found in qubit_pairs.
"""
sorted_pairs = sorted(list(qubit_pairs))
for a, b in sorted_pairs:
Expand All @@ -78,27 +82,26 @@ def __init__(
if (b, a) not in edge_set:
edge_set.add((a, b))

if isolated_qubits is None:
isolated_qubits = frozenset({})
if all_qubits is None:
all_qubits = node_set

for q in isolated_qubits:
if q in node_set:
all_qubits = frozenset(all_qubits)
for q in node_set:
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: can be in the else block of if all_qubits is None.

if q not in all_qubits:
raise ValueError(
f"Entry for {q} found in isolated_qubits and "
" qubit_pairs. An isolated qubit may have "
"no connections to other qubits."
f"Qubit {q} found in node_set and not in"
" all_qubits. all_qubits must contain at least"
" all the qubits found in all_qubits."
)

self._isolated_qubits = frozenset(isolated_qubits)

connectivity = nx.Graph()
all_qubits = node_set | self._isolated_qubits
connectivity.add_nodes_from(sorted(all_qubits))
connectivity.add_edges_from(sorted(edge_set), directed=False)
super().__init__(all_qubits, connectivity)

self._qubit_pairs = frozenset(edge_set)
self._gateset = gateset
self._isolated_qubits = all_qubits.difference(node_set)

if gate_durations is not None:
working_gatefamilies = frozenset(gate_durations.keys())
Expand Down Expand Up @@ -142,14 +145,14 @@ def _value_equality_values_(self):
tuple(sorted(self._qubit_pairs)),
self._gateset,
tuple(duration_equality),
tuple(sorted(self._isolated_qubits)),
tuple(sorted(self.qubit_set)),
)

def __repr__(self) -> str:
return (
f'cirq.GridDeviceMetadata({repr(self._qubit_pairs)},'
f' {repr(self._gateset)}, {repr(self._gate_durations)},'
f' {repr(self._isolated_qubits)})'
f' {repr(self.qubit_set)})'
)

def _json_dict_(self):
Expand All @@ -161,9 +164,9 @@ def _json_dict_(self):
'qubit_pairs': sorted(list(self._qubit_pairs)),
'gateset': self._gateset,
'gate_durations': duration_payload,
'isolated_qubits': sorted(list(self._isolated_qubits)),
'all_qubits': sorted(list(self.qubit_set)),
}

@classmethod
def _from_json_dict_(cls, qubit_pairs, gateset, gate_durations, isolated_qubits, **kwargs):
return cls(qubit_pairs, gateset, dict(gate_durations), isolated_qubits)
def _from_json_dict_(cls, qubit_pairs, gateset, gate_durations, all_qubits, **kwargs):
return cls(qubit_pairs, gateset, dict(gate_durations), all_qubits)
14 changes: 7 additions & 7 deletions cirq-core/cirq/devices/grid_device_metadata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_griddevice_metadata():
qubit_pairs = [(a, b) for a in qubits for b in qubits if a != b and a.is_adjacent(b)]
isolated_qubits = [cirq.GridQubit(9, 9), cirq.GridQubit(10, 10)]
gateset = cirq.Gateset(cirq.XPowGate, cirq.YPowGate, cirq.ZPowGate, cirq.CZ)
metadata = cirq.GridDeviceMetadata(qubit_pairs, gateset, isolated_qubits=isolated_qubits)
metadata = cirq.GridDeviceMetadata(qubit_pairs, gateset, all_qubits=qubits + isolated_qubits)
expected_pairings = frozenset(
{
(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)),
Expand Down Expand Up @@ -62,10 +62,10 @@ def test_griddevice_metadata_bad_durations():
def test_griddevice_metadata_bad_isolated():
qubits = cirq.GridQubit.rect(2, 3)
qubit_pairs = [(a, b) for a in qubits for b in qubits if a != b and a.is_adjacent(b)]
isolated_qubits = [cirq.GridQubit(0, 0)]
fewer_qubits = [cirq.GridQubit(0, 0)]
gateset = cirq.Gateset(cirq.XPowGate, cirq.YPowGate, cirq.ZPowGate, cirq.CZ)
with pytest.raises(ValueError, match='0, 0'):
_ = cirq.GridDeviceMetadata(qubit_pairs, gateset, isolated_qubits=isolated_qubits)
with pytest.raises(ValueError, match='node_set'):
_ = cirq.GridDeviceMetadata(qubit_pairs, gateset, all_qubits=fewer_qubits)


def test_griddevice_self_loop():
Expand All @@ -88,7 +88,7 @@ def test_griddevice_json_load():
}
isolated_qubits = [cirq.GridQubit(9, 9), cirq.GridQubit(10, 10)]
metadata = cirq.GridDeviceMetadata(
qubit_pairs, gateset, gate_durations=duration, isolated_qubits=isolated_qubits
qubit_pairs, gateset, gate_durations=duration, all_qubits=qubits + isolated_qubits
)
rep_str = cirq.to_json(metadata)
assert metadata == cirq.read_json(json_text=rep_str)
Expand All @@ -115,7 +115,7 @@ def test_griddevice_metadata_equality():
metadata4 = cirq.GridDeviceMetadata(qubit_pairs, gateset, gate_durations=duration2)
metadata5 = cirq.GridDeviceMetadata(reversed(qubit_pairs), gateset, gate_durations=duration)
metadata6 = cirq.GridDeviceMetadata(
qubit_pairs, gateset, gate_durations=duration, isolated_qubits=isolated_qubits
qubit_pairs, gateset, gate_durations=duration, all_qubits=qubits + isolated_qubits
)

eq = cirq.testing.EqualsTester()
Expand All @@ -139,6 +139,6 @@ def test_repr():
}
isolated_qubits = [cirq.GridQubit(9, 9)]
metadata = cirq.GridDeviceMetadata(
qubit_pairs, gateset, gate_durations=duration, isolated_qubits=isolated_qubits
qubit_pairs, gateset, gate_durations=duration, all_qubits=qubits + isolated_qubits
)
cirq.testing.assert_equivalent_repr(metadata)
32 changes: 31 additions & 1 deletion cirq-core/cirq/protocols/json_test_data/GridDeviceMetadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,37 @@
}
]
],
"isolated_qubits": [
"all_qubits": [
{
"cirq_type": "GridQubit",
"row": 0,
"col": 0
},
{
"cirq_type": "GridQubit",
"row": 0,
"col": 1
},
{
"cirq_type": "GridQubit",
"row": 0,
"col": 2
},
{
"cirq_type": "GridQubit",
"row": 1,
"col": 0
},
{
"cirq_type": "GridQubit",
"row": 1,
"col": 1
},
{
"cirq_type": "GridQubit",
"row": 1,
"col": 2
},
{
"cirq_type": "GridQubit",
"row": 9,
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(0, 2), cirq.GridQubit(1, 2)), (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(0, 1), cirq.GridQubit(0, 2)), (cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate), {cirq.GateFamily(cirq.ops.common_gates.XPowGate): cirq.Duration(nanos=1), cirq.GateFamily(cirq.ops.common_gates.YPowGate): cirq.Duration(picos=1), cirq.GateFamily(cirq.ops.common_gates.ZPowGate): cirq.Duration(picos=1)}, [cirq.GridQubit(9, 9), cirq.GridQubit(10, 10)])
cirq.GridDeviceMetadata(frozenset({(cirq.GridQubit(0, 2), cirq.GridQubit(1, 2)), (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(0, 1), cirq.GridQubit(0, 2)), (cirq.GridQubit(1, 1), cirq.GridQubit(1, 2)), (cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))}), cirq.Gateset(cirq.ops.common_gates.XPowGate, cirq.ops.common_gates.YPowGate, cirq.ops.common_gates.ZPowGate), {cirq.GateFamily(cirq.ops.common_gates.XPowGate): cirq.Duration(nanos=1), cirq.GateFamily(cirq.ops.common_gates.YPowGate): cirq.Duration(picos=1), cirq.GateFamily(cirq.ops.common_gates.ZPowGate): cirq.Duration(picos=1)}, cirq.GridQubit.rect(2, 3) + [cirq.GridQubit(9, 9), cirq.GridQubit(10, 10)])