Source code for cirq.google.xmon_device

# Copyright 2018 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Iterable, cast, Optional, List, TYPE_CHECKING

from cirq import ops, circuits, value, devices
from cirq.google import convert_to_xmon_gates
from cirq.devices.grid_qubit import GridQubit


if TYPE_CHECKING:
    # pylint: disable=unused-import
    from typing import Set


[docs]@value.value_equality class XmonDevice(devices.Device): """A device with qubits placed in a grid. Neighboring qubits can interact. """
[docs] def __init__(self, measurement_duration: value.Duration, exp_w_duration: value.Duration, exp_11_duration: value.Duration, qubits: Iterable[GridQubit]) -> None: """Initializes the description of an xmon device. Args: measurement_duration: The maximum duration of a measurement. exp_w_duration: The maximum duration of an ExpW operation. exp_11_duration: The maximum duration of an ExpZ operation. qubits: Qubits on the device, identified by their x, y location. """ self._measurement_duration = measurement_duration self._exp_w_duration = exp_w_duration self._exp_z_duration = exp_11_duration self.qubits = frozenset(qubits)
[docs] def decompose_operation(self, operation: ops.Operation) -> ops.OP_TREE: return convert_to_xmon_gates.ConvertToXmonGates().convert(operation)
[docs] def neighbors_of(self, qubit: GridQubit): """Returns the qubits that the given qubit can interact with.""" possibles = [ GridQubit(qubit.row + 1, qubit.col), GridQubit(qubit.row - 1, qubit.col), GridQubit(qubit.row, qubit.col + 1), GridQubit(qubit.row, qubit.col - 1), ] return [e for e in possibles if e in self.qubits]
[docs] def duration_of(self, operation): if isinstance(operation, ops.GateOperation): if isinstance(operation.gate, ops.CZPowGate): return self._exp_z_duration if isinstance(operation.gate, ops.MeasurementGate): return self._measurement_duration if isinstance(operation.gate, (ops.XPowGate, ops.YPowGate, ops.PhasedXPowGate)): return self._exp_w_duration if isinstance(operation.gate, ops.ZPowGate): # Z gates are performed in the control software. return value.Duration() raise ValueError('Unsupported gate type: {!r}'.format(operation))
[docs] def validate_gate(self, gate: ops.Gate): """Raises an error if the given gate isn't allowed. Raises: ValueError: Unsupported gate. """ if not isinstance(gate, (ops.CZPowGate, ops.XPowGate, ops.YPowGate, ops.PhasedXPowGate, ops.MeasurementGate, ops.ZPowGate)): raise ValueError('Unsupported gate type: {!r}'.format(gate))
[docs] def validate_operation(self, operation: ops.Operation): if not isinstance(operation, ops.GateOperation): raise ValueError('Unsupported operation: {!r}'.format(operation)) self.validate_gate(operation.gate) for q in operation.qubits: if not isinstance(q, GridQubit): raise ValueError('Unsupported qubit type: {!r}'.format(q)) if q not in self.qubits: raise ValueError('Qubit not on device: {!r}'.format(q)) if (len(operation.qubits) == 2 and not isinstance(operation.gate, ops.MeasurementGate)): p, q = operation.qubits if not cast(GridQubit, p).is_adjacent(q): raise ValueError( 'Non-local interaction: {!r}.'.format(operation))
def _check_if_exp11_operation_interacts_with_any( self, exp11_op: ops.GateOperation, others: Iterable[ops.GateOperation]) -> bool: return any(self._check_if_exp11_operation_interacts(exp11_op, op) for op in others) def _check_if_exp11_operation_interacts( self, exp11_op: ops.GateOperation, other_op: ops.GateOperation) -> bool: if isinstance(other_op.gate, (ops.XPowGate, ops.YPowGate, ops.PhasedXPowGate, ops.MeasurementGate, ops.ZPowGate)): return False return any(cast(GridQubit, q).is_adjacent(cast(GridQubit, p)) for q in exp11_op.qubits for p in other_op.qubits)
[docs] def validate_scheduled_operation(self, schedule, scheduled_operation): self.validate_operation(scheduled_operation.operation) if isinstance(scheduled_operation.operation.gate, ops.CZPowGate): for other in schedule.operations_happening_at_same_time_as( scheduled_operation): if self._check_if_exp11_operation_interacts( cast(ops.GateOperation, scheduled_operation.operation), cast(ops.GateOperation, other.operation)): raise ValueError( 'Adjacent Exp11 operations: {} vs {}.'.format( scheduled_operation, other))
[docs] def validate_circuit(self, circuit: circuits.Circuit): super().validate_circuit(circuit) _verify_unique_measurement_keys(circuit.all_operations())
[docs] def validate_moment(self, moment: circuits.Moment): super().validate_moment(moment) for op in moment.operations: if (isinstance(op, ops.GateOperation) and isinstance(op.gate, ops.CZPowGate)): for other in moment.operations: if (other is not op and self._check_if_exp11_operation_interacts( cast(ops.GateOperation, op), cast(ops.GateOperation, other))): raise ValueError( 'Adjacent Exp11 operations: {}.'.format(moment))
[docs] def can_add_operation_into_moment(self, operation: ops.Operation, moment: circuits.Moment) -> bool: self.validate_moment(moment) if not super().can_add_operation_into_moment(operation, moment): return False if (isinstance(operation, ops.GateOperation) and isinstance(operation.gate, ops.CZPowGate)): return not self._check_if_exp11_operation_interacts_with_any( cast(ops.GateOperation, operation), cast(Iterable[ops.GateOperation], moment.operations)) return True
[docs] def validate_schedule(self, schedule): _verify_unique_measurement_keys( s.operation for s in schedule.scheduled_operations) for scheduled_operation in schedule.scheduled_operations: self.validate_scheduled_operation(schedule, scheduled_operation)
[docs] def at(self, row: int, col: int) -> Optional[GridQubit]: """Returns the qubit at the given position, if there is one, else None. """ q = GridQubit(row, col) return q if q in self.qubits else None
[docs] def row(self, row: int) -> List[GridQubit]: """Returns the qubits in the given row, in ascending order.""" return sorted(q for q in self.qubits if q.row == row)
[docs] def col(self, col: int) -> List[GridQubit]: """Returns the qubits in the given column, in ascending order.""" return sorted(q for q in self.qubits if q.col == col)
def __repr__(self): return ('XmonDevice(measurement_duration={!r}, ' 'exp_w_duration={!r}, ' 'exp_11_duration={!r} ' 'qubits={!r})').format(self._measurement_duration, self._exp_w_duration, self._exp_z_duration, sorted(self.qubits)) def __str__(self): diagram = circuits.TextDiagramDrawer() for q in self.qubits: diagram.write(q.col, q.row, str(q)) for q2 in self.neighbors_of(q): diagram.grid_line(q.col, q.row, q2.col, q2.row) return diagram.render( horizontal_spacing=3, vertical_spacing=2, use_unicode_characters=True) def _value_equality_values_(self): return (self._measurement_duration, self._exp_w_duration, self._exp_z_duration, self.qubits)
def _verify_unique_measurement_keys(operations: Iterable[ops.Operation]): seen = set() # type: Set[str] for op in operations: if ops.MeasurementGate.is_measurement(op): key = cast(ops.MeasurementGate, cast(ops.GateOperation, op).gate).key if key in seen: raise ValueError('Measurement key {} repeated'.format(key)) seen.add(key)