Source code for cirq.ops.common_gates

# 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.

"""Quantum gates that are commonly used in the literature.

This module creates Gate instances for the following gates:
    X,Y,Z: Pauli gates.
    H,S: Clifford gates.
    T: A non-Clifford gate.
    CZ: Controlled phase gate.
    CNOT: Controlled not gate.
    SWAP: the swap gate.
    ISWAP: a swap gate with a phase on the swapped subspace.

Each of these are implemented as EigenGates, which means that they can be
raised to a power (i.e. cirq.H**0.5). See the definition in EigenGate.

In addition MeasurementGate is defined and convenience methods for
measurements are provided
    measure
    measure_each
"""
from typing import (
    Any, Callable, cast, Iterable, List, Optional, Tuple, Union,
)

import numpy as np

from cirq import linalg, protocols, value
from cirq.ops import gate_features, eigen_gate, raw_types, gate_operation

from cirq.type_workarounds import NotImplementedType

# Note: avoiding 'from/as' because it creates a circular dependency in python 2.
import cirq.ops.phased_x_gate


[docs]class XPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): """A gate that rotates around the X axis of the Bloch sphere. The unitary matrix of ``XPowGate(exponent=t)`` is: [[g·c, -i·g·s], [-i·g·s, g·c]] where: c = cos(π·t/2) s = sin(π·t/2) g = exp(i·π·t/2). Note in particular that this gate has a global phase factor of e^{i·π·t/2} vs the traditionally defined rotation matrices about the Pauli X axis. See `cirq.Rx` for rotations without the global phase. The global phase factor can be adjusted by using the `global_shift` parameter when initializing. `cirq.X`, the Pauli X gate, is an instance of this gate at exponent=1. """ def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if self._exponent != 1: return None zero = args.subspace_index(0) one = args.subspace_index(1) args.available_buffer[zero] = args.target_tensor[one] args.available_buffer[one] = args.target_tensor[zero] p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.available_buffer *= p return args.available_buffer def _eigen_components(self): return [ (0, np.array([[0.5, 0.5], [0.5, 0.5]])), (1, np.array([[0.5, -0.5], [-0.5, 0.5]])), ] def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> Union[str, protocols.CircuitDiagramInfo]: if self._global_shift == -0.5: return _rads_func_symbol( 'Rx', args, self._diagram_exponent(args, ignore_global_phase=False)) return protocols.CircuitDiagramInfo( wire_symbols=('X',), exponent=self._diagram_exponent(args)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: args.validate_version('2.0') if self._exponent == 1: return args.format('x {0};\n', qubits[0]) else: return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0]) @property def phase_exponent(self): return 0.0 def _phase_by_(self, phase_turns, qubit_index): """See `cirq.SupportsPhase`.""" return cirq.ops.phased_x_gate.PhasedXPowGate( exponent=self._exponent, phase_exponent=phase_turns * 2) def __str__(self) -> str: if self._exponent == 1: return 'X' return 'X**{!r}'.format(self._exponent) def __repr__(self) -> str: if self._global_shift == -0.5 and not protocols.is_parameterized(self): return 'cirq.Rx(np.pi*{!r})'.format(self._exponent) if self._global_shift == 0: if self._exponent == 1: return 'cirq.X' return '(cirq.X**{!r})'.format(self._exponent) return ( 'cirq.XPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]class YPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): """A gate that rotates around the Y axis of the Bloch sphere. The unitary matrix of ``YPowGate(exponent=t)`` is: [[g·c, g·s], [-g·s, g·c]] where: c = cos(π·t/2) s = sin(π·t/2) g = exp(i·π·t/2). Note in particular that this gate has a global phase factor of e^{i·π·t/2} vs the traditionally defined rotation matrices about the Pauli Y axis. See `cirq.Ry` for rotations without the global phase. The global phase factor can be adjusted by using the `global_shift` parameter when initializing. `cirq.Y`, the Pauli Y gate, is an instance of this gate at exponent=1. """ def _eigen_components(self): return [ (0, np.array([[0.5, -0.5j], [0.5j, 0.5]])), (1, np.array([[0.5, 0.5j], [-0.5j, 0.5]])), ] def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> Union[str, protocols.CircuitDiagramInfo]: if self._global_shift == -0.5: return _rads_func_symbol( 'Ry', args, self._diagram_exponent(args, ignore_global_phase=False)) return protocols.CircuitDiagramInfo( wire_symbols=('Y',), exponent=self._diagram_exponent(args)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: args.validate_version('2.0') if self._exponent == 1: return args.format('y {0};\n', qubits[0]) else: return args.format('ry({0:half_turns}) {1};\n', self._exponent, qubits[0]) @property def phase_exponent(self): return 0.5 def _phase_by_(self, phase_turns, qubit_index): """See `cirq.SupportsPhase`.""" return cirq.ops.phased_x_gate.PhasedXPowGate( exponent=self._exponent, phase_exponent=0.5 + phase_turns * 2) def __str__(self) -> str: if self._exponent == 1: return 'Y' return 'Y**{!r}'.format(self._exponent) def __repr__(self) -> str: if self._global_shift == -0.5 and not protocols.is_parameterized(self): return 'cirq.Ry(np.pi*{!r})'.format(self._exponent) if self._global_shift == 0: if self._exponent == 1: return 'cirq.Y' return '(cirq.Y**{!r})'.format(self._exponent) return ( 'cirq.YPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]class ZPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): """A gate that rotates around the Z axis of the Bloch sphere. The unitary matrix of ``ZPowGate(exponent=t)`` is: [[1, 0], [0, g]] where: g = exp(i·π·t). Note in particular that this gate has a global phase factor of e^{i·π·t/2} vs the traditionally defined rotation matrices about the Pauli Z axis. See `cirq.Rz` for rotations without the global phase. The global phase factor can be adjusted by using the `global_shift` parameter when initializing. `cirq.Z`, the Pauli Z gate, is an instance of this gate at exponent=1. """ def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if protocols.is_parameterized(self): return None one = args.subspace_index(1) c = 1j**(self._exponent * 2) args.target_tensor[one] *= c p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.target_tensor *= p return args.target_tensor def _eigen_components(self): return [ (0, np.diag([1, 0])), (1, np.diag([0, 1])), ] def _phase_by_(self, phase_turns: float, qubit_index: int): return self def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> Union[str, protocols.CircuitDiagramInfo]: if self._global_shift == -0.5: return _rads_func_symbol( 'Rz', args, self._diagram_exponent(args, ignore_global_phase=False)) e = self._diagram_exponent(args) if e in [-0.25, 0.25]: return protocols.CircuitDiagramInfo( wire_symbols=('T',), exponent=cast(float, e) * 4) if e in [-0.5, 0.5]: return protocols.CircuitDiagramInfo( wire_symbols=('S',), exponent=cast(float, e) * 2) return protocols.CircuitDiagramInfo( wire_symbols=('Z',), exponent=e) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: args.validate_version('2.0') if self._exponent == 1: return args.format('z {0};\n', qubits[0]) else: return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0]) def __str__(self) -> str: if self._exponent == 0.25: return 'T' if self._exponent == -0.25: return 'T**-1' if self._exponent == 0.5: return 'S' if self._exponent == -0.5: return 'S**-1' if self._exponent == 1: return 'Z' return 'Z**{}'.format(self._exponent) def __repr__(self) -> str: if self._global_shift == -0.5 and not protocols.is_parameterized(self): return 'cirq.Rz(np.pi*{!r})'.format(self._exponent) if self._global_shift == 0: if self._exponent == 0.25: return 'cirq.T' if self._exponent == -0.25: return '(cirq.T**-1)' if self._exponent == 0.5: return 'cirq.S' if self._exponent == -0.5: return '(cirq.S**-1)' if self._exponent == 1: return 'cirq.Z' return '(cirq.Z**{!r})'.format(self._exponent) return ( 'cirq.ZPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]@value.value_equality class MeasurementGate(raw_types.Gate): """A gate that measures qubits in the computational basis. The measurement gate contains a key that is used to identify results of measurements. """
[docs] def __init__(self, key: str = '', invert_mask: Tuple[bool, ...] = ()) -> None: """ Args: key: The string key of the measurement. invert_mask: A list of values indicating whether the corresponding qubits should be flipped. The list's length must not be longer than the number of qubits, but it is permitted to be shorter. Qubits with indices past the end of the mask are not flipped. """ self.key = key self.invert_mask = invert_mask or ()
[docs] @staticmethod def is_measurement(op: Union[raw_types.Gate, raw_types.Operation]) -> bool: if isinstance(op, MeasurementGate): return True if (isinstance(op, gate_operation.GateOperation) and isinstance(op.gate, MeasurementGate)): return True return False
[docs] def with_bits_flipped(self, *bit_positions: int) -> 'MeasurementGate': """Toggles whether or not the measurement inverts various outputs.""" old_mask = self.invert_mask or () n = max(len(old_mask) - 1, *bit_positions) + 1 new_mask = [k < len(old_mask) and old_mask[k] for k in range(n)] for b in bit_positions: new_mask[b] = not new_mask[b] return MeasurementGate(key=self.key, invert_mask=tuple(new_mask))
[docs] def validate_args(self, qubits): if (self.invert_mask is not None and len(self.invert_mask) > len(qubits)): raise ValueError('len(invert_mask) > len(qubits)')
def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: n = (max(1, len(self.invert_mask)) if args.known_qubit_count is None else args.known_qubit_count) symbols = ['M'] * n # Show which output bits are negated. if self.invert_mask: for i, b in enumerate(self.invert_mask): if b: symbols[i] = '!M' # Mention the measurement key. if (not args.known_qubits or self.key != _default_measurement_key(args.known_qubits)): symbols[0] += "('{}')".format(self.key) return protocols.CircuitDiagramInfo(tuple(symbols)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: args.validate_version('2.0') invert_mask = self.invert_mask if len(invert_mask) < len(qubits): invert_mask = (invert_mask + (False,) * (len(qubits) - len(invert_mask))) lines = [] for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)): if inv: lines.append(args.format( 'x {0}; // Invert the following measurement\n', qubit)) lines.append(args.format('measure {0} -> {1:meas}[{2}];\n', qubit, self.key, i)) return ''.join(lines) def __repr__(self): return 'cirq.MeasurementGate({}, {})'.format(repr(self.key), repr(self.invert_mask)) def _value_equality_values_(self): return self.key, self.invert_mask
def _default_measurement_key(qubits: Iterable[raw_types.QubitId]) -> str: return ','.join(str(q) for q in qubits)
[docs]def measure(*qubits: raw_types.QubitId, key: Optional[str] = None, invert_mask: Tuple[bool, ...] = () ) -> gate_operation.GateOperation: """Returns a single MeasurementGate applied to all the given qubits. The qubits are measured in the computational basis. Args: *qubits: The qubits that the measurement gate should measure. key: The string key of the measurement. If this is None, it defaults to a comma-separated list of the target qubits' str values. invert_mask: A list of Truthy or Falsey values indicating whether the corresponding qubits should be flipped. None indicates no inverting should be done. Returns: An operation targeting the given qubits with a measurement. Raises: ValueError if the qubits are not instances of QubitId. """ for qubit in qubits: if isinstance(qubit, np.ndarray): raise ValueError( 'measure() was called a numpy ndarray. Perhaps you meant ' 'to call measure_state_vector on numpy array?' ) elif not isinstance(qubit, raw_types.QubitId): raise ValueError( 'measure() was called with type different than QubitId.') if key is None: key = _default_measurement_key(qubits) return MeasurementGate(key, invert_mask).on(*qubits)
[docs]def measure_each(*qubits: raw_types.QubitId, key_func: Callable[[raw_types.QubitId], str] = str ) -> List[gate_operation.GateOperation]: """Returns a list of operations individually measuring the given qubits. The qubits are measured in the computational basis. Args: *qubits: The qubits to measure. key_func: Determines the key of the measurements of each qubit. Takes the qubit and returns the key for that qubit. Defaults to str. Returns: A list of operations individually measuring the given qubits. """ return [MeasurementGate(key_func(q)).on(q) for q in qubits]
[docs]class HPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate): """A Gate that performs a rotation around the X+Z axis of the Bloch sphere. The unitary matrix of ``HPowGate(exponent=t)`` is: [[g·(c-i·s/sqrt(2)), -i·g·s/sqrt(2)], [-i·g·s/sqrt(2)], g·(c+i·s/sqrt(2))]] where c = cos(π·t/2) s = sin(π·t/2) g = exp(i·π·t/2). Note in particular that for `t=1`, this gives the Hadamard matrix. `cirq.H`, the Hadamard gate, is an instance of this gate at `exponent=1`. """ def _eigen_components(self): s = np.sqrt(2) component0 = np.array([ [3 + 2 * s, 1 + s], [1 + s, 1] ]) / (4 + 2 * s) component1 = np.array([ [3 - 2 * s, 1 - s], [1 - s, 1] ]) / (4 - 2 * s) return [(0, component0), (1, component1)] def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if self._exponent != 1: return None zero = args.subspace_index(0) one = args.subspace_index(1) args.target_tensor[one] -= args.target_tensor[zero] args.target_tensor[one] *= -0.5 args.target_tensor[zero] -= args.target_tensor[one] p = 1j**(2 * self._exponent * self._global_shift) args.target_tensor *= np.sqrt(2) * p return args.target_tensor def _decompose_(self, qubits): q = qubits[0] if self._exponent == 1: yield cirq.Y(q)**0.5 yield cirq.XPowGate(global_shift=-0.25).on(q) return yield Y(q)**0.25 yield X(q)**self._exponent yield Y(q)**-0.25 def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: return protocols.CircuitDiagramInfo(('H',)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: args.validate_version('2.0') if self._exponent == 1: return args.format('h {0};\n', qubits[0]) else: return args.format('ry({0:half_turns}) {3};\n' 'rx({1:half_turns}) {3};\n' 'ry({2:half_turns}) {3};\n', 0.25, self._exponent, -0.25, qubits[0]) def __str__(self): if self._exponent == 1: return 'H' return 'H^{}'.format(self._exponent) def __repr__(self): if self._global_shift == 0: if self._exponent == 1: return 'cirq.H' return '(cirq.H**{!r})'.format(self._exponent) return ( 'cirq.HPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]class CZPowGate(eigen_gate.EigenGate, gate_features.TwoQubitGate, gate_features.InterchangeableQubitsGate): """A gate that applies a phase to the |11⟩ state of two qubits. The unitary matrix of `CZPowGate(exponent=t)` is: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, g]] where: g = exp(i·π·t/2). `cirq.CZ`, the controlled Z gate, is an instance of this gate at `exponent=1`. """ def _eigen_components(self): return [ (0, np.diag([1, 1, 1, 0])), (1, np.diag([0, 0, 0, 1])), ] def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Union[np.ndarray, NotImplementedType]: if protocols.is_parameterized(self): return NotImplemented c = 1j**(2 * self._exponent) one_one = linalg.slice_for_qubits_equal_to(args.axes, 0b11) args.target_tensor[one_one] *= c p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.target_tensor *= p return args.target_tensor def _phase_by_(self, phase_turns, qubit_index): return self def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: return protocols.CircuitDiagramInfo( wire_symbols=('@', '@'), exponent=self._diagram_exponent(args)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM args.validate_version('2.0') return args.format('cz {0},{1};\n', qubits[0], qubits[1]) def __str__(self) -> str: if self._exponent == 1: return 'CZ' return 'CZ**{!r}'.format(self._exponent) def __repr__(self) -> str: if self._global_shift == 0: if self._exponent == 1: return 'cirq.CZ' return '(cirq.CZ**{!r})'.format(self._exponent) return ( 'cirq.CZPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
def _rads_func_symbol(func_name: str, args: protocols.CircuitDiagramInfoArgs, half_turns: Any) -> str: unit = 'π' if args.use_unicode_characters else 'pi' if half_turns == 1: return '{}({})'.format(func_name, unit) if half_turns == -1: return '{}(-{})'.format(func_name, unit) return '{}({}{})'.format(func_name, half_turns, unit)
[docs]class CNotPowGate(eigen_gate.EigenGate, gate_features.TwoQubitGate): """A gate that applies a controlled power of an X gate. When applying CNOT (controlled-not) to qubits, you can either use positional arguments CNOT(q1, q2), where q2 is toggled when q1 is on, or named arguments CNOT(control=q1, target=q2). (Mixing the two is not permitted.) The unitary matrix of `CNotPowGate(exponent=t)` is: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, g·c, -i·g·s], [0, 0, -i·g·s, g·c]] where: c = cos(π·t/2) s = sin(π·t/2) g = exp(i·π·t/2). `cirq.CNOT`, the controlled NOT gate, is an instance of this gate at `exponent=1`. """ def _decompose_(self, qubits): c, t = qubits yield Y(t)**-0.5 yield CZ(c, t)**self._exponent yield Y(t)**0.5 def _eigen_components(self): return [ (0, np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0.5, 0.5], [0, 0, 0.5, 0.5]])), (1, np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0.5, -0.5], [0, 0, -0.5, 0.5]])), ] def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: return protocols.CircuitDiagramInfo( wire_symbols=('@', 'X'), exponent=self._diagram_exponent(args)) def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if self._exponent != 1: return None oo = args.subspace_index(0b11) zo = args.subspace_index(0b01) args.available_buffer[oo] = args.target_tensor[oo] args.target_tensor[oo] = args.target_tensor[zo] args.target_tensor[zo] = args.available_buffer[oo] p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.target_tensor *= p return args.target_tensor def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM args.validate_version('2.0') return args.format('cx {0},{1};\n', qubits[0], qubits[1]) def __str__(self) -> str: if self._exponent == 1: return 'CNOT' return 'CNOT**{!r}'.format(self._exponent) def __repr__(self): if self._global_shift == 0: if self._exponent == 1: return 'cirq.CNOT' return '(cirq.CNOT**{!r})'.format(self._exponent) return ( 'cirq.CNotPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs] def on(self, *args: raw_types.QubitId, **kwargs: raw_types.QubitId) -> gate_operation.GateOperation: if not kwargs: return super().on(*args) if not args and set(kwargs.keys()) == {'control', 'target'}: return super().on(kwargs['control'], kwargs['target']) raise ValueError( "Expected two positional argument or else 'target' AND 'control' " "keyword arguments. But got args={!r}, kwargs={!r}.".format( args, kwargs))
[docs]class SwapPowGate(eigen_gate.EigenGate, gate_features.TwoQubitGate, gate_features.InterchangeableQubitsGate): """The SWAP gate, possibly raised to a power. Exchanges qubits. SwapPowGate()**t = SwapPowGate(exponent=t) and acts on two qubits in the computational basis as the matrix: [[1, 0, 0, 0], [0, g·c, -i·g·s, 0], [0, -i·g·s, g·c, 0], [0, 0, 0, 1]] where: c = cos(π·t/2) s = sin(π·t/2) g = exp(i·π·t/2). `cirq.SWAP`, the swap gate, is an instance of this gate at exponent=1. """ def _decompose_(self, qubits): """See base class.""" a, b = qubits yield CNOT(a, b) yield CNOT(b, a) ** self._exponent yield CNOT(a, b) def _eigen_components(self): return [ (0, np.array([[1, 0, 0, 0], [0, 0.5, 0.5, 0], [0, 0.5, 0.5, 0], [0, 0, 0, 1]])), (1, np.array([[0, 0, 0, 0], [0, 0.5, -0.5, 0], [0, -0.5, 0.5, 0], [0, 0, 0, 0]])), ] def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if self._exponent != 1: return None zo = args.subspace_index(0b01) oz = args.subspace_index(0b10) args.available_buffer[zo] = args.target_tensor[zo] args.target_tensor[zo] = args.target_tensor[oz] args.target_tensor[oz] = args.available_buffer[zo] p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.target_tensor *= p return args.target_tensor def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: if not args.use_unicode_characters: return protocols.CircuitDiagramInfo( wire_symbols=('swap', 'swap'), exponent=self._diagram_exponent(args)) return protocols.CircuitDiagramInfo( wire_symbols=('×', '×'), exponent=self._diagram_exponent(args)) def _qasm_(self, args: protocols.QasmArgs, qubits: Tuple[raw_types.QubitId, ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM args.validate_version('2.0') return args.format('swap {0},{1};\n', qubits[0], qubits[1]) def __str__(self) -> str: if self._exponent == 1: return 'SWAP' return 'SWAP**{!r}'.format(self._exponent) def __repr__(self): if self._global_shift == 0: if self._exponent == 1: return 'cirq.SWAP' return '(cirq.SWAP**{!r})'.format(self._exponent) return ( 'cirq.SwapPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]class ISwapPowGate(eigen_gate.EigenGate, gate_features.InterchangeableQubitsGate, gate_features.TwoQubitGate): """Rotates the |01⟩-vs-|10⟩ subspace of two qubits around its Bloch X-axis. When exponent=1, swaps the two qubits and phases |01⟩ and |10⟩ by i. More generally, this gate's matrix is defined as follows: ISWAP**t ≡ exp(+i π t (X⊗X + Y⊗Y) / 4) which is given by the matrix: [[1, 0, 0, 0], [0, c, i·s, 0], [0, i·s, c, 0], [0, 0, 0, 1]] where: c = cos(π·t/2) s = sin(π·t/2) `cirq.ISWAP`, the swap gate that applies -i to the |01> and |10> states, is an instance of this gate at exponent=1. """ def _eigen_components(self): return [ (0, np.diag([1, 0, 0, 1])), (+0.5, np.array([[0, 0, 0, 0], [0, 0.5, 0.5, 0], [0, 0.5, 0.5, 0], [0, 0, 0, 0]])), (-0.5, np.array([[0, 0, 0, 0], [0, 0.5, -0.5, 0], [0, -0.5, 0.5, 0], [0, 0, 0, 0]])), ] def _decompose_(self, qubits): a, b = qubits yield CNOT(a, b) yield H(a) yield CNOT(b, a) yield S(a)**self._exponent yield CNOT(b, a) yield S(a)**-self._exponent yield H(a) yield CNOT(a, b) def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs ) -> Optional[np.ndarray]: if self._exponent != 1: return None zo = args.subspace_index(0b01) oz = args.subspace_index(0b10) args.available_buffer[zo] = args.target_tensor[zo] args.target_tensor[zo] = args.target_tensor[oz] args.target_tensor[oz] = args.available_buffer[zo] args.target_tensor[zo] *= 1j args.target_tensor[oz] *= 1j p = 1j**(2 * self._exponent * self._global_shift) if p != 1: args.target_tensor *= p return args.target_tensor def _circuit_diagram_info_(self, args: protocols.CircuitDiagramInfoArgs ) -> protocols.CircuitDiagramInfo: return protocols.CircuitDiagramInfo( wire_symbols=('iSwap', 'iSwap'), exponent=self._diagram_exponent(args)) def __str__(self) -> str: if self._exponent == 1: return 'ISWAP' return 'ISWAP**{!r}'.format(self._exponent) def __repr__(self): if self._global_shift == 0: if self._exponent == 1: return 'cirq.ISWAP' return '(cirq.ISWAP**{!r})'.format(self._exponent) return ( 'cirq.ISwapPowGate(exponent={!r}, ' 'global_shift={!r})' ).format(self._exponent, self._global_shift)
[docs]def Rx(rads: float) -> XPowGate: """Returns a gate with the matrix e^{-i X rads / 2}.""" return XPowGate(exponent=rads / np.pi, global_shift=-0.5)
[docs]def Ry(rads: float) -> YPowGate: """Returns a gate with the matrix e^{-i Y rads / 2}.""" return YPowGate(exponent=rads / np.pi, global_shift=-0.5)
[docs]def Rz(rads: float) -> ZPowGate: """Returns a gate with the matrix e^{-i Z rads / 2}.""" return ZPowGate(exponent=rads / np.pi, global_shift=-0.5)
X = XPowGate() """The Pauli X gate. Matrix: [[0, 1], [1, 0]] """ #: The Pauli Y gate. #: #: Matrix: #: #: [[0, -i], #: [i, 0]] Y = YPowGate() # The Pauli Z gate. # # Matrix: # # [[1, 0], # [0, -1]] Z = ZPowGate() # The Hadamard gate. # # Matrix: # # [[s, s], # [s, -s]] # where s = sqrt(0.5). H = HPowGate() # The Clifford S gate. # # Matrix: # # [[1, 0], # [0, i]] S = Z**0.5 # The T gate. # # Matrix: # # [[1, 0] # [0, exp(i pi / 4)]] T = Z**0.25 # The controlled Z gate. # # Matrix: # # [[1, 0, 0, 0], # [0, 1, 0, 0], # [0, 0, 1, 0], # [0, 0, 0, -1]] CZ = CZPowGate() # The controlled NOT gate. # # Matrix: # # [[1, 0, 0, 0], # [0, 1, 0, 0], # [0, 0, 0, 1], # [0, 0, 1, 0]] CNOT = CNotPowGate() # The swap gate. # # Matrix: # # [[1, 0, 0, 0], # [0, 0, 1, 0], # [0, 1, 0, 0], # [0, 0, 0, 1]] SWAP = SwapPowGate() # The iswap gate. # # Matrix: # # [[1, 0, 0, 0], # [0, 0, i, 0], # [0, i, 0, 0], # [0, 0, 0, 1]] ISWAP = ISwapPowGate()