Source code for cirq.ops.pauli_interaction_gate

# 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 List, Sequence, Tuple, Union, cast, Dict

import numpy as np
import sympy

from cirq import value, protocols
from cirq._compat import proper_repr
from cirq.ops import raw_types, gate_features, common_gates, eigen_gate, \
        op_tree, pauli_gates
from cirq.ops.clifford_gate import SingleQubitCliffordGate


pauli_eigen_map = cast(
    Dict[pauli_gates.Pauli, np.ndarray], {
        pauli_gates.X: (np.array([[0.5, 0.5], [0.5, 0.5]
                                 ]), np.array([[0.5, -0.5], [-0.5, 0.5]])),
        pauli_gates.Y: (np.array([[0.5, -0.5j], [0.5j, 0.5]
                                 ]), np.array([[0.5, 0.5j], [-0.5j, 0.5]])),
        pauli_gates.Z: (np.diag([1, 0]), np.diag([0, 1])),
    })


[docs]@value.value_equality class PauliInteractionGate(eigen_gate.EigenGate, gate_features.InterchangeableQubitsGate, gate_features.TwoQubitGate): CZ = None # type: PauliInteractionGate CNOT = None # type: PauliInteractionGate
[docs] def __init__(self, pauli0: pauli_gates.Pauli, invert0: bool, pauli1: pauli_gates.Pauli, invert1: bool, *, exponent: Union[sympy.Basic, float] = 1.0) -> None: """ Args: pauli0: The interaction axis for the first qubit. invert0: Whether to condition on the +1 or -1 eigenvector of the first qubit's interaction axis. pauli1: The interaction axis for the second qubit. invert1: Whether to condition on the +1 or -1 eigenvector of the second qubit's interaction axis. exponent: Determines the amount of phasing to apply to the vector equal to the tensor product of the two conditions. """ super().__init__(exponent=exponent) self.pauli0 = pauli0 self.invert0 = invert0 self.pauli1 = pauli1 self.invert1 = invert1
def _value_equality_values_(self): return (self.pauli0, self.invert0, self.pauli1, self.invert1, self._canonical_exponent)
[docs] def qubit_index_to_equivalence_group_key(self, index: int) -> int: if self.pauli0 == self.pauli1 and self.invert0 == self.invert1: return 0 return index
def _with_exponent(self, exponent: Union[sympy.Basic, float] ) -> 'PauliInteractionGate': return PauliInteractionGate(self.pauli0, self.invert0, self.pauli1, self.invert1, exponent=exponent) def _eigen_shifts(self) -> List[float]: return [0.0, 1.0] def _eigen_components(self) -> List[Tuple[float, np.ndarray]]: comp1 = np.kron(pauli_eigen_map[self.pauli0][not self.invert0], pauli_eigen_map[self.pauli1][not self.invert1]) comp0 = np.eye(4) - comp1 return [(0, comp0), (1, comp1)] def _decompose_(self, qubits: Sequence[raw_types.Qid] ) -> op_tree.OP_TREE: q0, q1 = qubits right_gate0 = SingleQubitCliffordGate.from_single_map( z_to=(self.pauli0, self.invert0)) right_gate1 = SingleQubitCliffordGate.from_single_map( z_to=(self.pauli1, self.invert1)) left_gate0 = right_gate0**-1 left_gate1 = right_gate1**-1 yield left_gate0(q0) yield left_gate1(q1) yield common_gates.CZ(q0, q1)**self._exponent yield right_gate0(q0) yield right_gate1(q1) def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: labels = cast(Dict[pauli_gates.Pauli, np.ndarray], { pauli_gates.X: 'X', pauli_gates.Y: 'Y', pauli_gates.Z: '@' }) l0 = labels[self.pauli0] l1 = labels[self.pauli1] # Add brackets around letter if inverted l0, l1 = ('(-{})'.format(l) if inv else l for l, inv in ((l0, self.invert0), (l1, self.invert1))) return protocols.CircuitDiagramInfo( wire_symbols=(l0, l1), exponent=self._diagram_exponent(args)) def __repr__(self): base = 'cirq.PauliInteractionGate({!r}, {!s}, {!r}, {!s})'.format( self.pauli0, self.invert0, self.pauli1, self.invert1) if self._exponent == 1: return base return '({}**{})'.format(base, proper_repr(self._exponent))
PauliInteractionGate.CZ = PauliInteractionGate( pauli_gates.Z, False, pauli_gates.Z, False) PauliInteractionGate.CNOT = PauliInteractionGate( pauli_gates.Z, False, pauli_gates.X, False)