Skip to content

Fix PauliString.pass_operations_over not supporting common gates #2351

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

Merged
merged 10 commits into from
Oct 29, 2019
4 changes: 2 additions & 2 deletions cirq/contrib/routing/device_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@

import pytest

import networkx as nx

import cirq
import cirq.contrib.routing as ccr

import networkx as nx


def test_xmon_device_to_graph():
foxtail_graph = ccr.xmon_device_to_graph(cirq.google.Foxtail)
Expand Down
3 changes: 2 additions & 1 deletion cirq/contrib/routing/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
# limitations under the License.
import pytest

import networkx as nx

import cirq
import cirq.contrib.routing as ccr
import networkx as nx


def test_ops_are_consistent_with_device_graph():
Expand Down
60 changes: 60 additions & 0 deletions cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ def _eigen_components(self):
(1, np.array([[0.5, -0.5], [-0.5, 0.5]])),
]

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
if self.exponent % 2 == 0:
return []
if self.exponent % 2 == 0.5:
return SingleQubitCliffordGate.X_sqrt.on(*qubits)
if self.exponent % 2 == 1:
return SingleQubitCliffordGate.X.on(*qubits)
if self.exponent % 2 == 1.5:
return SingleQubitCliffordGate.X_nsqrt.on(*qubits)
return NotImplemented

def _trace_distance_bound_(self) -> Optional[float]:
if self._is_parameterized_():
return None
Expand Down Expand Up @@ -218,6 +230,18 @@ def with_canonical_global_phase(self) -> 'YPowGate':
"""Returns an equal-up-global-phase standardized form of the gate."""
return YPowGate(exponent=self._exponent)

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
if self.exponent % 2 == 0:
return []
if self.exponent % 2 == 0.5:
return SingleQubitCliffordGate.Y_sqrt.on(*qubits)
if self.exponent % 2 == 1:
return SingleQubitCliffordGate.Y.on(*qubits)
if self.exponent % 2 == 1.5:
return SingleQubitCliffordGate.Y_nsqrt.on(*qubits)
return NotImplemented

def _eigen_components(self):
return [
(0, np.array([[0.5, -0.5j], [0.5j, 0.5]])),
Expand Down Expand Up @@ -335,6 +359,18 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
args.target_tensor *= p
return args.target_tensor

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
if self.exponent % 2 == 0:
return []
if self.exponent % 2 == 0.5:
return SingleQubitCliffordGate.Z_sqrt.on(*qubits)
if self.exponent % 2 == 1:
return SingleQubitCliffordGate.Z.on(*qubits)
if self.exponent % 2 == 1.5:
return SingleQubitCliffordGate.Z_nsqrt.on(*qubits)
return NotImplemented

def in_su2(self) -> 'ZPowGate':
"""Returns an equal-up-global-phase gate from the group SU2."""
return ZPowGate(exponent=self._exponent, global_shift=-0.5)
Expand Down Expand Up @@ -494,6 +530,14 @@ def _pauli_expansion_(self) -> value.LinearDict[str]:
'Z': -1j * phase * np.sin(angle) / np.sqrt(2),
})

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
if self.exponent % 2 == 1:
return SingleQubitCliffordGate.H.on(*qubits)
if self.exponent % 2 == 0:
return []
return NotImplemented

def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
) -> Optional[np.ndarray]:
if self._exponent != 1:
Expand Down Expand Up @@ -573,6 +617,14 @@ class CZPowGate(eigen_gate.EigenGate,
`exponent=1`.
"""

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
if self.exponent % 2 == 1:
return PauliInteractionGate.CZ.on(*qubits)
if self.exponent % 2 == 0:
return []
return NotImplemented

def _eigen_components(self):
return [
(0, np.diag([1, 1, 1, 0])),
Expand Down Expand Up @@ -679,6 +731,14 @@ class CNotPowGate(eigen_gate.EigenGate, gate_features.TwoQubitGate):
`exponent=1`.
"""

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
if self.exponent % 2 == 1:
return PauliInteractionGate.CNOT.on(*qubits)
if self.exponent % 2 == 0:
return []
return NotImplemented

def _decompose_(self, qubits):
c, t = qubits
yield YPowGate(exponent=-0.5).on(t)
Expand Down
20 changes: 18 additions & 2 deletions cirq/ops/gate_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,18 @@

"""Basic types defining qubits, gates, and operations."""

from typing import (Any, Dict, FrozenSet, List, Optional, Sequence, Tuple, Type,
TypeVar, Union)
from typing import (
Any,
Dict,
FrozenSet,
List,
Optional,
Sequence,
Tuple,
Type,
TypeVar,
Union,
)

import numpy as np

Expand Down Expand Up @@ -146,6 +156,12 @@ def _circuit_diagram_info_(self, args: 'protocols.CircuitDiagramInfoArgs'
args,
NotImplemented)

def _decompose_into_clifford_(self):
sub = getattr(self.gate, '_decompose_into_clifford_with_qubits_', None)
if sub is None:
return NotImplemented
return sub(self.qubits)

def _trace_distance_bound_(self) -> float:
return protocols.trace_distance_bound(self.gate)

Expand Down
2 changes: 2 additions & 0 deletions cirq/ops/gate_operation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ def test_op_gate_isinstance():
op = cirq.X(a)
assert cirq.op_gate_isinstance(op, cirq.XPowGate)
assert not cirq.op_gate_isinstance(op, cirq.YPowGate)
assert cirq.op_gate_isinstance(op, (cirq.XPowGate, cirq.YPowGate))
assert not cirq.op_gate_isinstance(op, (cirq.YPowGate, cirq.ZPowGate))

class NonGateOperation(cirq.Operation):

Expand Down
5 changes: 4 additions & 1 deletion cirq/ops/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,11 @@ def __repr__(self):
other = ', {!r}'.format(self._qid_shape)
return 'cirq.IdentityGate({!r}{})'.format(self.num_qubits(), other)

def _decompose_(self, qubits):
return []

def __str__(self):
if (self.num_qubits() == 1):
if self.num_qubits() == 1:
return 'I'
return 'I({})'.format(self.num_qubits())

Expand Down
44 changes: 43 additions & 1 deletion cirq/ops/parity_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from cirq import protocols
from cirq._compat import proper_repr
from cirq.ops import gate_features, eigen_gate, common_gates
from cirq.ops import gate_features, eigen_gate, common_gates, pauli_gates


class XXPowGate(eigen_gate.EigenGate,
Expand Down Expand Up @@ -59,6 +59,27 @@ def _trace_distance_bound_(self) -> Optional[float]:
return None
return abs(np.sin(self._exponent * 0.5 * np.pi))

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
if self.exponent % 2 == 0:
return []
if self.exponent % 2 == 0.5:
return [
PauliInteractionGate(pauli_gates.X, False, pauli_gates.X,
False).on(*qubits),
SingleQubitCliffordGate.X_sqrt.on_each(*qubits)
]
if self.exponent % 2 == 1:
return [SingleQubitCliffordGate.X.on_each(*qubits)]
if self.exponent % 2 == 1.5:
return [
PauliInteractionGate(pauli_gates.X, False, pauli_gates.X,
False).on(*qubits),
SingleQubitCliffordGate.X_nsqrt.on_each(*qubits)
]
return NotImplemented

def _circuit_diagram_info_(self, args: 'protocols.CircuitDiagramInfoArgs'
) -> Union[str, 'protocols.CircuitDiagramInfo']:
if self._global_shift == -0.5:
Expand Down Expand Up @@ -121,6 +142,27 @@ def _trace_distance_bound_(self) -> Optional[float]:
return None
return abs(np.sin(self._exponent * 0.5 * np.pi))

def _decompose_into_clifford_with_qubits_(self, qubits):
from cirq.ops.clifford_gate import SingleQubitCliffordGate
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
if self.exponent % 2 == 0:
return []
if self.exponent % 2 == 0.5:
return [
PauliInteractionGate(pauli_gates.Y, False, pauli_gates.Y,
False).on(*qubits),
SingleQubitCliffordGate.Y_sqrt.on_each(*qubits)
]
if self.exponent % 2 == 1:
return [SingleQubitCliffordGate.Y.on_each(*qubits)]
if self.exponent % 2 == 1.5:
return [
PauliInteractionGate(pauli_gates.Y, False, pauli_gates.Y,
False).on(*qubits),
SingleQubitCliffordGate.Y_nsqrt.on_each(*qubits)
]
return NotImplemented

def _circuit_diagram_info_(self, args: 'protocols.CircuitDiagramInfoArgs'
) -> 'protocols.CircuitDiagramInfo':
return protocols.CircuitDiagramInfo(
Expand Down
Loading