Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/quantumlib/cirq into gate…
Browse files Browse the repository at this point in the history
…sets_in_optimizers
  • Loading branch information
tanujkhattar committed Sep 24, 2021
2 parents 4649591 + 2868382 commit 010e446
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 102 deletions.
27 changes: 3 additions & 24 deletions cirq-core/cirq/ion/convert_to_ion_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import numpy as np

from cirq import ops, protocols, optimizers, circuits
from cirq.ion import ms, two_qubit_matrix_to_ion_operations
from cirq.ion import ms, two_qubit_matrix_to_ion_operations, ion_device


class ConvertToIonGates:
Expand All @@ -30,6 +30,7 @@ def __init__(self, ignore_failures: bool = False) -> None:
"""
super().__init__()
self.ignore_failures = ignore_failures
self.gateset = ion_device.get_ion_gateset()

# TODO(#3388) Add documentation for Raises.
# pylint: disable=missing-raises-doc
Expand All @@ -47,7 +48,7 @@ def convert_one(self, op: ops.Operation) -> ops.OP_TREE:
if not isinstance(op, ops.GateOperation):
raise TypeError(f"{op!r} is not a gate operation.")

if is_native_ion_gate(op.gate):
if op in self.gateset:
return [op]
# one choice of known Hadamard gate decomposition
if isinstance(op.gate, ops.HPowGate) and op.gate.exponent == 1:
Expand Down Expand Up @@ -88,25 +89,3 @@ def convert_circuit(self, circuit: circuits.Circuit) -> circuits.Circuit:
optimizers.merge_single_qubit_gates_into_phased_x_z(new_circuit)

return new_circuit


def is_native_ion_gate(gate: ops.Gate) -> bool:
"""Check if a gate is a native ion gate.
Args:
gate: Input gate.
Returns:
True if the gate is native to the ion, false otherwise.
"""
return isinstance(
gate,
(
ops.XXPowGate,
ops.MeasurementGate,
ops.XPowGate,
ops.YPowGate,
ops.ZPowGate,
ops.PhasedXPowGate,
),
)
26 changes: 15 additions & 11 deletions cirq-core/cirq/ion/ion_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@
import cirq


def get_ion_gateset() -> ops.Gateset:
return ops.Gateset(
ops.XXPowGate,
ops.MeasurementGate,
ops.XPowGate,
ops.YPowGate,
ops.ZPowGate,
ops.PhasedXPowGate,
unroll_circuit_op=False,
accept_global_phase=False,
)


@value.value_equality
class IonDevice(devices.Device):
"""A device with qubits placed on a line.
Expand Down Expand Up @@ -48,6 +61,7 @@ def __init__(
self._twoq_gates_duration = value.Duration(twoq_gates_duration)
self._oneq_gates_duration = value.Duration(oneq_gates_duration)
self.qubits = frozenset(qubits)
self.gateset = get_ion_gateset()

def qubit_set(self) -> FrozenSet['cirq.LineQubit']:
return self.qubits
Expand Down Expand Up @@ -79,17 +93,7 @@ def duration_of(self, operation):
raise ValueError(f'Unsupported gate type: {operation!r}')

def validate_gate(self, gate: ops.Gate):
if not isinstance(
gate,
(
ops.XPowGate,
ops.YPowGate,
ops.ZPowGate,
ops.PhasedXPowGate,
ops.XXPowGate,
ops.MeasurementGate,
),
):
if gate not in self.gateset:
raise ValueError(f'Unsupported gate type: {gate!r}')

def validate_operation(self, operation):
Expand Down
38 changes: 17 additions & 21 deletions cirq-ionq/cirq_ionq/ionq_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# limitations under the License.
"""Devices for IonQ hardware."""

from typing import AbstractSet, Callable, Dict, Sequence, Type, Union
from typing import AbstractSet, Sequence, Union

import numpy as np

Expand Down Expand Up @@ -50,20 +50,20 @@ def __init__(self, qubits: Union[Sequence[cirq.LineQubit], int], atol=1e-8):
else:
self.qubits = frozenset(qubits)
self.atol = atol
all_gates_valid = lambda x: True
near_1_mod_2 = lambda x: abs(x.gate.exponent % 2 - 1) < self.atol
self._is_api_gate_dispatch: Dict[Type['cirq.Gate'], Callable] = {
cirq.XPowGate: all_gates_valid,
cirq.YPowGate: all_gates_valid,
cirq.ZPowGate: all_gates_valid,
cirq.XXPowGate: all_gates_valid,
cirq.YYPowGate: all_gates_valid,
cirq.ZZPowGate: all_gates_valid,
cirq.CNotPowGate: near_1_mod_2,
cirq.HPowGate: near_1_mod_2,
cirq.SwapPowGate: near_1_mod_2,
cirq.MeasurementGate: all_gates_valid,
}
self.gateset = cirq.Gateset(
cirq.H,
cirq.CNOT,
cirq.SWAP,
cirq.XPowGate,
cirq.YPowGate,
cirq.ZPowGate,
cirq.XXPowGate,
cirq.YYPowGate,
cirq.ZZPowGate,
cirq.MeasurementGate,
unroll_circuit_op=False,
accept_global_phase=False,
)

def qubit_set(self) -> AbstractSet['cirq.Qid']:
return self.qubits
Expand All @@ -79,11 +79,7 @@ def validate_operation(self, operation: cirq.Operation):
raise ValueError(f'Operation with qubits not on the device. Qubits: {operation.qubits}')

def is_api_gate(self, operation: cirq.Operation) -> bool:
gate = operation.gate
for gate_mro_type in type(gate).mro():
if gate_mro_type in self._is_api_gate_dispatch:
return self._is_api_gate_dispatch[gate_mro_type](operation)
return False
return operation in self.gateset

def decompose_operation(self, operation: cirq.Operation) -> cirq.OP_TREE:
if self.is_api_gate(operation):
Expand All @@ -97,7 +93,7 @@ def decompose_operation(self, operation: cirq.Operation) -> cirq.OP_TREE:
return self._decompose_single_qubit(operation)
if num_qubits == 2:
return self._decompose_two_qubit(operation)
raise ValueError('Operation {operation} not supported by IonQ API.')
raise ValueError(f'Operation {operation} not supported by IonQ API.')

def _decompose_single_qubit(self, operation: cirq.Operation) -> cirq.OP_TREE:
qubit = operation.qubits[0]
Expand Down
77 changes: 31 additions & 46 deletions cirq-pasqal/cirq_pasqal/pasqal_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ def __init__(self, qubits: Sequence[cirq.ops.Qid]) -> None:
'qubits.'.format(type(self), self.maximum_qubit_number)
)

self.gateset = cirq.Gateset(
cirq.ParallelGateFamily(cirq.H),
cirq.ParallelGateFamily(cirq.PhasedXPowGate),
cirq.ParallelGateFamily(cirq.XPowGate),
cirq.ParallelGateFamily(cirq.YPowGate),
cirq.ParallelGateFamily(cirq.ZPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate),
cirq.IdentityGate,
cirq.MeasurementGate,
unroll_circuit_op=False,
accept_global_phase=False,
)
self.qubits = qubits

# pylint: enable=missing-raises-doc
Expand Down Expand Up @@ -96,43 +111,9 @@ def decompose_operation(self, operation: cirq.ops.Operation) -> 'cirq.OP_TREE':
return decomposition

def is_pasqal_device_op(self, op: cirq.ops.Operation) -> bool:

if not isinstance(op, cirq.ops.Operation):
raise ValueError('Got unknown operation:', op)

if isinstance(op.gate, cirq.ops.MeasurementGate):
return True

op_gate = op.gate.sub_gate if isinstance(op.gate, cirq.ops.ParallelGate) else op.gate

if isinstance(
op_gate,
(
cirq.ops.IdentityGate,
cirq.ops.PhasedXPowGate,
cirq.ops.XPowGate,
cirq.ops.YPowGate,
cirq.ops.ZPowGate,
),
):
return True

if (
isinstance(
op_gate,
(
cirq.ops.HPowGate,
cirq.ops.CNotPowGate,
cirq.ops.CZPowGate,
cirq.ops.CCZPowGate,
cirq.ops.CCXPowGate,
),
)
and not cirq.is_parameterized(op)
):
expo = op_gate.exponent
return np.isclose(expo, np.around(expo, decimals=0))
return False
return op in self.gateset

# TODO(#3388) Add documentation for Raises.
# pylint: disable=missing-raises-doc
Expand Down Expand Up @@ -267,6 +248,15 @@ def __init__(
)

self.control_radius = control_radius
self.exclude_gateset = cirq.Gateset(
cirq.AnyIntegerPowerGateFamily(cirq.CNotPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CCNotPowGate),
cirq.AnyIntegerPowerGateFamily(cirq.CCZPowGate),
)
self.controlled_gateset = cirq.Gateset(
*self.exclude_gateset.gates,
cirq.AnyIntegerPowerGateFamily(cirq.CZPowGate),
)

@property
def supported_qubit_type(self):
Expand All @@ -278,9 +268,7 @@ def supported_qubit_type(self):
)

def is_pasqal_device_op(self, op: cirq.ops.Operation) -> bool:
return super().is_pasqal_device_op(op) and not isinstance(
op.gate, (cirq.ops.CNotPowGate, cirq.ops.CCZPowGate, cirq.ops.CCXPowGate)
)
return super().is_pasqal_device_op(op) and op not in self.exclude_gateset

def validate_operation(self, operation: cirq.ops.Operation):
"""Raises an error if the given operation is invalid on this device.
Expand All @@ -293,14 +281,11 @@ def validate_operation(self, operation: cirq.ops.Operation):
super().validate_operation(operation)

# Verify that a controlled gate operation is valid
if isinstance(operation, cirq.ops.GateOperation):
if len(operation.qubits) > 1 and not isinstance(
operation.gate, (cirq.ops.MeasurementGate, cirq.ops.ParallelGate)
):
for p in operation.qubits:
for q in operation.qubits:
if self.distance(p, q) > self.control_radius:
raise ValueError(f"Qubits {p!r}, {q!r} are too far away")
if operation in self.controlled_gateset:
for p in operation.qubits:
for q in operation.qubits:
if self.distance(p, q) > self.control_radius:
raise ValueError(f"Qubits {p!r}, {q!r} are too far away")

def validate_moment(self, moment: cirq.ops.Moment):
"""Raises an error if the given moment is invalid on this device.
Expand Down

0 comments on commit 010e446

Please sign in to comment.