Skip to content

Commit

Permalink
GridDevice: Exclude MeasurementGates in validation of qubit pairs (qu…
Browse files Browse the repository at this point in the history
…antumlib#5654)

I'm comfortable with special-casing MeasurementGate because it's the only gate today with the property that it can be applied to any subset of qubits.

Fixes quantumlib#5652

@maffoo
  • Loading branch information
verult authored and rht committed May 1, 2023
1 parent a6845b9 commit c8d6166
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cirq-google/cirq_google/devices/grid_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
MEASUREMENT_GATE_FAMILY = cirq.GateFamily(cirq.MeasurementGate)
WAIT_GATE_FAMILY = cirq.GateFamily(cirq.WaitGate)

# Families of gates which can be applied to any subset of valid qubits.
_VARIADIC_GATE_FAMILIES = [MEASUREMENT_GATE_FAMILY, WAIT_GATE_FAMILY]


def _validate_device_specification(proto: v2.device_pb2.DeviceSpecification) -> None:
"""Raises a ValueError if the `DeviceSpecification` proto is invalid."""
Expand Down Expand Up @@ -338,6 +341,7 @@ def validate_operation(self, operation: cirq.Operation) -> None:

if (
len(operation.qubits) == 2
and not any(operation in gf for gf in _VARIADIC_GATE_FAMILIES)
and frozenset(operation.qubits) not in self._metadata.qubit_pairs
):
raise ValueError(f'Qubit pair is not valid on device: {operation.qubits!r}.')
Expand Down
59 changes: 59 additions & 0 deletions cirq-google/cirq_google/devices/grid_device_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,74 @@ def test_grid_device_from_proto():
def test_grid_device_validate_operations_positive():
device_info, spec = _create_device_spec_with_horizontal_couplings()
device = cirq_google.GridDevice.from_proto(spec)
# Gates that can be applied to any subset of valid qubits
variadic_gates = [cirq.measure, cirq.WaitGate(cirq.Duration(nanos=1), num_qubits=2)]

for q in device_info.grid_qubits:
device.validate_operation(cirq.X(q))
device.validate_operation(cirq.measure(q))

# horizontal qubit pairs
for i in range(GRID_HEIGHT):
device.validate_operation(
cirq.CZ(device_info.grid_qubits[2 * i], device_info.grid_qubits[2 * i + 1])
)
for gate in variadic_gates:
device.validate_operation(
gate(device_info.grid_qubits[2 * i], device_info.grid_qubits[2 * i + 1])
)


@pytest.mark.parametrize(
'gate_func',
[
lambda _: cirq.measure,
lambda num_qubits: cirq.WaitGate(cirq.Duration(nanos=1), num_qubits=num_qubits),
],
)
def test_grid_device_validate_operations_variadic_gates_positive(gate_func):
device_info, spec = _create_device_spec_with_horizontal_couplings()
device = cirq_google.GridDevice.from_proto(spec)

# Single qubit operations
for q in device_info.grid_qubits:
device.validate_operation(gate_func(1)(q))

# horizontal qubit pairs (coupled)
for i in range(GRID_HEIGHT):
device.validate_operation(
gate_func(2)(device_info.grid_qubits[2 * i], device_info.grid_qubits[2 * i + 1])
)

# Variadic gates across vertical qubit pairs (uncoupled pairs) should succeed.
for i in range(GRID_HEIGHT - 1):
device.validate_operation(
gate_func(2)(device_info.grid_qubits[2 * i], device_info.grid_qubits[2 * (i + 1)])
)
device.validate_operation(
gate_func(2)(
device_info.grid_qubits[2 * i + 1], device_info.grid_qubits[2 * (i + 1) + 1]
)
)

# 3-qubit measurements
for i in range(GRID_HEIGHT - 2):
device.validate_operation(
gate_func(3)(
device_info.grid_qubits[2 * i],
device_info.grid_qubits[2 * (i + 1)],
device_info.grid_qubits[2 * (i + 2)],
)
)
device.validate_operation(
gate_func(3)(
device_info.grid_qubits[2 * i + 1],
device_info.grid_qubits[2 * (i + 1) + 1],
device_info.grid_qubits[2 * (i + 2) + 1],
)
)
# All-qubit measurement
device.validate_operation(gate_func(len(device_info.grid_qubits))(*device_info.grid_qubits))


def test_grid_device_validate_operations_negative():
Expand Down

0 comments on commit c8d6166

Please sign in to comment.