Source code for sequencing.gates.onequbit

from functools import wraps

import numpy as np

from ..modes import Mode, Transmon


[docs]def single_qubit_gate(func): """A decorator used to specify that the decorated function is a single-qubit gate acting on one or more Modes. """ @wraps(func) def wrapped(*args, **kwargs): space = None for arg in args: if isinstance(arg, Mode): if space is None: space = arg.space if arg.space != space: raise ValueError("All Modes must share the same Hilbert space.") result = func(*args, **kwargs) if isinstance(result, list): if all(r is None for r in result): return None if len(result) == 1: return result[0] return result return wrapped
[docs]def pulsed_gate_exists(*types): """A decorator used to specify types of Modes for which a pulse-based version of the gate exists. If the first argument is ``None``, then the gate is required to be unitary-only for all types of Modes. """ unitary_only = False if types[0] is None: unitary_only = True def pulsed_gate_exists_decorator(func): @wraps(func) def wrapped(*args, **kwargs): kwargs = kwargs.copy() unitary = kwargs.get("unitary", True) if unitary_only: _ = kwargs.pop("unitary", None) if not unitary: if unitary_only: raise ValueError( f"No pulse-based version of " f"the {func.__name__} gate exists." ) for arg in args: if isinstance(arg, Mode) and not isinstance(arg, types): raise TypeError( f"No pulse-based version of the {func.__name__} " f"gate exists for Modes of type {type(arg)}." ) return func(*args, **kwargs) return wrapped return pulsed_gate_exists_decorator
@pulsed_gate_exists(None) @single_qubit_gate def U(theta, phi, lamda, *qubits, **kwargs): r""" .. math:: U(\theta,\phi,\lambda) = R_z(\phi)R_y(\theta)R_z(\lambda) Args: theta, phi, lamda (float): Euler angles, in radians. *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.Rz(phi) * q.Ry(theta) * q.Rz(lamda) for q in qubits]
[docs]@pulsed_gate_exists(Transmon) @single_qubit_gate def rx(theta, *qubits, **kwargs): r"""Rotates each mode about its x axis by a given angle. .. math:: R_x(\theta) = \exp(-i\theta/2 \cdot X) Args: theta (float): Rotation angle in radians. *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.rotate_x(theta, **kwargs) for q in qubits]
[docs]@pulsed_gate_exists(Transmon) @single_qubit_gate def ry(theta, *qubits, **kwargs): r"""Rotates each mode about its y axis by a given angle. .. math:: R_y(\theta) = \exp(-i\theta/2 \cdot Y) Args: theta (float): Rotation angle in radians. *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.rotate_y(theta, **kwargs) for q in qubits]
[docs]@pulsed_gate_exists(None) @single_qubit_gate def rz(phi, *qubits, **kwargs): r"""Rotates each mode about its z axis by a given angle. .. math:: R_z(\phi) = \exp(-i\phi/2 \cdot Z) Args: phi (float): Rotation angle in radians. *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.Rz(phi, **kwargs) for q in qubits]
[docs]@pulsed_gate_exists(Transmon) @single_qubit_gate def x(*qubits, **kwargs): r"""X gate. .. math:: X = R_x(\pi) Args: *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return rx(np.pi, *qubits, **kwargs)
[docs]@pulsed_gate_exists(Transmon) @single_qubit_gate def y(*qubits, **kwargs): r"""Y gate. .. math:: Y = R_y(\pi) Args: *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return ry(np.pi, *qubits, **kwargs)
[docs]@pulsed_gate_exists(None) @single_qubit_gate def z(*qubits, **kwargs): r"""Z gate. .. math:: Z = R_z(\pi) Args: *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return rz(np.pi, *qubits, **kwargs)
[docs]@pulsed_gate_exists(None) @single_qubit_gate def h(*qubits, **kwargs): r"""Hadamard gate. .. math:: H = \frac{1}{\sqrt{2}}\left(X + Z\right) Args: *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.hadamard(**kwargs) for q in qubits]
[docs]@pulsed_gate_exists(None) @single_qubit_gate def r(theta, phi, *qubits, **kwargs): r"""Rotate each mode by an angle ``theta`` about the axis given by ``phi``. .. math:: R_\text{axis}(\theta,\phi) = \exp\left(-i\theta/2 \cdot (\cos(\phi)X + \sin(\phi)Y)\right) Args: theta (float): Rotation angle in radians. phi (float): Angle between the axis of rotation and the x axis. *qubits (tuple[Mode]): Modes to which to apply the gate. Returns: list[Operation or qutip.Qobj] or None: List of length ``len(qubits)``, or None if the gates were captured. """ return [q.Raxis(theta, phi, **kwargs) for q in qubits]