Source code for qiskit.pulse.pulse_lib.discrete

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

# pylint: disable=missing-return-doc, invalid-name

"""Module for builtin discrete pulses.

Note the sampling strategy use for all discrete pulses is `midpoint`.
"""
import warnings
from typing import Optional

from ..exceptions import PulseError
from .sample_pulse import SamplePulse
from . import continuous
from . import samplers


_sampled_constant_pulse = samplers.midpoint(continuous.constant)


[docs]def constant(duration: int, amp: complex, name: Optional[str] = None) -> SamplePulse: r"""Generates constant-sampled :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, samples from the function: .. math:: f(x) = A Args: duration: Duration of pulse. Must be greater than zero. amp: Complex pulse amplitude. name: Name of pulse. """ return _sampled_constant_pulse(duration, amp, name=name)
_sampled_zero_pulse = samplers.midpoint(continuous.zero)
[docs]def zero(duration: int, name: Optional[str] = None) -> SamplePulse: """Generates zero-sampled :class:`~qiskit.pulse.SamplePulse`. Samples from the function: .. math:: f(x) = 0 Args: duration: Duration of pulse. Must be greater than zero. name: Name of pulse. """ return _sampled_zero_pulse(duration, name=name)
_sampled_square_pulse = samplers.midpoint(continuous.square)
[docs]def square(duration: int, amp: complex, freq: float = None, period: float = None, phase: float = 0, name: Optional[str] = None) -> SamplePulse: r"""Generates square wave :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`T=` ``period``, and :math:`\phi=` ``phase``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A \text{sign}\left[ \sin\left(\frac{2 \pi x}{T} + 2\phi\right) \right] with the convention :math:`\text{sign}(0) = 1`. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. Wave range is :math:`[-` ``amp`` :math:`,` ``amp`` :math:`]`. freq: Pulse frequency, units of 1./dt. If ``None`` defaults to 1./duration. period: Pulse period, units of dt. (Deprecated, use `freq` instead) phase: Pulse phase. name: Name of pulse. """ if (freq is None) and (period is None): freq = 1./duration elif freq is None: freq = 1./period warnings.warn("The argument `period` is being deprecated." " Use `freq` for frequency instead", DeprecationWarning) return _sampled_square_pulse(duration, amp, freq, phase=phase, name=name)
_sampled_sawtooth_pulse = samplers.midpoint(continuous.sawtooth)
[docs]def sawtooth(duration: int, amp: complex, freq: float = None, period: float = None, phase: float = 0, name: Optional[str] = None) -> SamplePulse: r"""Generates sawtooth wave :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`T=` ``period``, and :math:`\phi=` ``phase``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = 2 A \left( g(x) - \left\lfloor \frac{1}{2} + g(x) \right\rfloor\right) where :math:`g(x) = x/T + \phi/\pi`. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. Wave range is :math:`[-` ``amp`` :math:`,` ``amp`` :math:`]`. freq: Pulse frequency, units of 1./dt. If ``None`` defaults to 1./duration. period: Pulse period, units of dt. (Deprecated, use `freq` instead) phase: Pulse phase. name: Name of pulse. Example: .. jupyter-execute:: import matplotlib.pyplot as plt from qiskit.pulse.pulse_lib import sawtooth import numpy as np duration = 100 amp = 1 period = duration sawtooth_wave = np.real(sawtooth(duration, amp, period).samples) plt.plot(range(duration), sawtooth_wave) """ if (freq is None) and (period is None): freq = 1./duration elif freq is None: freq = 1./period warnings.warn("The argument `period` is being deprecated." " Use `freq` for frequency instead", DeprecationWarning) return _sampled_sawtooth_pulse(duration, amp, freq, phase=phase, name=name)
_sampled_triangle_pulse = samplers.midpoint(continuous.triangle)
[docs]def triangle(duration: int, amp: complex, freq: float = None, period: float = None, phase: float = 0, name: Optional[str] = None) -> SamplePulse: r"""Generates triangle wave :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`T=` ``period``, and :math:`\phi=` ``phase``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A \left(-2\left|\text{sawtooth}(x, A, T, \phi)\right| + 1\right) This a non-sinusoidal wave with linear ramping. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. Wave range is :math:`[-` ``amp`` :math:`,` ``amp`` :math:`]`. freq: Pulse frequency, units of 1./dt. If ``None`` defaults to 1./duration. period: Pulse period, units of dt. (Deprecated, use `freq` instead) phase: Pulse phase. name: Name of pulse. Example: .. jupyter-execute:: import matplotlib.pyplot as plt from qiskit.pulse.pulse_lib import triangle import numpy as np duration = 100 amp = 1 period = duration triangle_wave = np.real(triangle(duration, amp, period).samples) plt.plot(range(duration), triangle_wave) """ if (freq is None) and (period is None): freq = 1./duration elif freq is None: freq = 1./period warnings.warn("The argument `period` is being deprecated." " Use `freq` for frequency instead", DeprecationWarning) return _sampled_triangle_pulse(duration, amp, freq, phase=phase, name=name)
_sampled_cos_pulse = samplers.midpoint(continuous.cos)
[docs]def cos(duration: int, amp: complex, freq: float = None, phase: float = 0, name: Optional[str] = None) -> SamplePulse: r"""Generates cosine wave :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`\omega=` ``freq``, and :math:`\phi=` ``phase``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A \cos(2 \pi \omega x + \phi) Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. freq: Pulse frequency, units of 1/dt. If ``None`` defaults to single cycle. phase: Pulse phase. name: Name of pulse. """ if freq is None: freq = 1/duration return _sampled_cos_pulse(duration, amp, freq, phase=phase, name=name)
_sampled_sin_pulse = samplers.midpoint(continuous.sin)
[docs]def sin(duration: int, amp: complex, freq: float = None, phase: float = 0, name: Optional[str] = None) -> SamplePulse: r"""Generates sine wave :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`\omega=` ``freq``, and :math:`\phi=` ``phase``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A \sin(2 \pi \omega x + \phi) Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. freq: Pulse frequency, units of 1/dt. If ``None`` defaults to single cycle. phase: Pulse phase. name: Name of pulse. """ if freq is None: freq = 1/duration return _sampled_sin_pulse(duration, amp, freq, phase=phase, name=name)
_sampled_gaussian_pulse = samplers.midpoint(continuous.gaussian)
[docs]def gaussian(duration: int, amp: complex, sigma: float, name: Optional[str] = None, zero_ends: bool = True) -> SamplePulse: r"""Generates unnormalized gaussian :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp`` and :math:`\sigma=` ``sigma``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A\exp\left(\left(\frac{x - \mu}{2\sigma}\right)^2 \right), with the center :math:`\mu=` ``duration/2``. If ``zero_ends==True``, each output sample :math:`y` is modifed according to: .. math:: y \mapsto A\frac{y-y^*}{A-y^*}, where :math:`y^*` is the value of the endpoint samples. This sets the endpoints to :math:`0` while preserving the amplitude at the center. If :math:`A=y^*`, :math:`y` is set to :math:`1`. Integrated area under the full curve is ``amp * np.sqrt(2*np.pi*sigma**2)`` Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude at ``duration/2``. sigma: Width (standard deviation) of pulse. name: Name of pulse. zero_ends: If True, make the first and last sample zero, but rescale to preserve amp. """ center = duration/2 zeroed_width = duration if zero_ends else None rescale_amp = bool(zero_ends) return _sampled_gaussian_pulse(duration, amp, center, sigma, zeroed_width=zeroed_width, rescale_amp=rescale_amp, name=name)
_sampled_gaussian_deriv_pulse = samplers.midpoint(continuous.gaussian_deriv)
[docs]def gaussian_deriv(duration: int, amp: complex, sigma: float, name: Optional[str] = None) -> SamplePulse: r"""Generates unnormalized gaussian derivative :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp`` and :math:`\sigma=` ``sigma`` applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A\frac{(x - \mu)}{\sigma^2}\exp\left(\left(\frac{x - \mu}{2\sigma}\right)^2 \right) i.e. the derivative of the Gaussian function, with center :math:`\mu=` ``duration/2``. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude of corresponding Gaussian at the pulse center (``duration/2``). sigma: Width (standard deviation) of pulse. name: Name of pulse. """ center = duration/2 return _sampled_gaussian_deriv_pulse(duration, amp, center, sigma, name=name)
_sampled_sech_pulse = samplers.midpoint(continuous.sech)
[docs]def sech(duration: int, amp: complex, sigma: float, name: str = None, zero_ends: bool = True) -> SamplePulse: r"""Generates unnormalized sech :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp`` and :math:`\sigma=` ``sigma``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = A\text{sech}\left(\frac{x-\mu}{\sigma} \right) with the center :math:`\mu=` ``duration/2``. If ``zero_ends==True``, each output sample :math:`y` is modifed according to: .. math:: y \mapsto A\frac{y-y^*}{A-y^*}, where :math:`y^*` is the value of the endpoint samples. This sets the endpoints to :math:`0` while preserving the amplitude at the center. If :math:`A=y^*`, :math:`y` is set to :math:`1`. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude at `duration/2`. sigma: Width (standard deviation) of pulse. name: Name of pulse. zero_ends: If True, make the first and last sample zero, but rescale to preserve amp. """ center = duration/2 zeroed_width = duration if zero_ends else None rescale_amp = bool(zero_ends) return _sampled_sech_pulse(duration, amp, center, sigma, zeroed_width=zeroed_width, rescale_amp=rescale_amp, name=name)
_sampled_sech_deriv_pulse = samplers.midpoint(continuous.sech_deriv)
[docs]def sech_deriv(duration: int, amp: complex, sigma: float, name: str = None) -> SamplePulse: r"""Generates unnormalized sech derivative :class:`~qiskit.pulse.SamplePulse`. For :math:`A=` ``amp``, :math:`\sigma=` ``sigma``, and center :math:`\mu=` ``duration/2``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = \frac{d}{dx}\left[A\text{sech}\left(\frac{x-\mu}{\sigma} \right)\right], i.e. the derivative of :math:`\text{sech}`. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude at `center`. sigma: Width (standard deviation) of pulse. name: Name of pulse. """ center = duration/2 return _sampled_sech_deriv_pulse(duration, amp, center, sigma, name=name)
_sampled_gaussian_square_pulse = samplers.midpoint(continuous.gaussian_square)
[docs]def gaussian_square(duration: int, amp: complex, sigma: float, risefall: Optional[float] = None, width: Optional[float] = None, name: Optional[str] = None, zero_ends: bool = True) -> SamplePulse: r"""Generates gaussian square :class:`~qiskit.pulse.SamplePulse`. For :math:`d=` ``duration``, :math:`A=` ``amp``, :math:`\sigma=` ``sigma``, and :math:`r=` ``risefall``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = \begin{cases} g(x - r) ) & x\leq r \\ A & r\leq x\leq d-r \\ g(x - (d - r)) & d-r\leq x \end{cases} where :math:`g(x)` is the Gaussian function sampled from in :meth:`gaussian` with :math:`A=` ``amp``, :math:`\mu=1`, and :math:`\sigma=` ``sigma``. I.e. :math:`f(x)` represents a square pulse with smooth Gaussian edges. If ``zero_ends == True``, the samples for the Gaussian ramps are remapped as in :meth:`gaussian`. Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude. sigma: Width (standard deviation) of Gaussian rise/fall portion of the pulse. risefall: Number of samples over which pulse rise and fall happen. Width of square portion of pulse will be ``duration-2*risefall``. width: The duration of the embedded square pulse. Only one of ``width`` or ``risefall`` should be specified as the functional form requires ``width = duration - 2 * risefall``. name: Name of pulse. zero_ends: If ``True``, make the first and last sample zero, but rescale to preserve amp. Raises: PulseError: If ``risefall`` and ``width`` arguments are inconsistent or not enough info. """ if risefall is None and width is None: raise PulseError("gaussian_square missing required argument: 'width' or 'risefall'.") if risefall is not None: if width is None: width = duration - 2 * risefall elif 2 * risefall + width != duration: raise PulseError("Both width and risefall were specified, and they are " "inconsistent: 2 * risefall + width == {} != " "duration == {}.".format(2 * risefall + width, duration)) center = duration / 2 zeroed_width = duration if zero_ends else None return _sampled_gaussian_square_pulse(duration, amp, center, width, sigma, zeroed_width=zeroed_width, name=name)
_sampled_drag_pulse = samplers.midpoint(continuous.drag)
[docs]def drag(duration: int, amp: complex, sigma: float, beta: float, name: Optional[str] = None, zero_ends: bool = True) -> SamplePulse: r"""Generates Y-only correction DRAG :class:`~qiskit.pulse.SamplePulse` for standard nonlinear oscillator (SNO) [1]. For :math:`A=` ``amp``, :math:`\sigma=` ``sigma``, and :math:`\beta=` ``beta``, applies the `midpoint` sampling strategy to generate a discrete pulse sampled from the continuous function: .. math:: f(x) = g(x) + i \beta h(x), where :math:`g(x)` is the function sampled in :meth:`gaussian`, and :math:`h(x)` is the function sampled in :meth:`gaussian_deriv`. If ``zero_ends == True``, the samples from :math:`g(x)` are remapped as in :meth:`gaussian`. References: 1. |citation1|_ .. _citation1: http://dx.doi.org/10.1103/PhysRevA.83.012308 .. |citation1| replace:: *Gambetta, J. M., Motzoi, F., Merkel, S. T. & Wilhelm, F. K. "Analytic control methods for high-fidelity unitary operations in a weakly nonlinear oscillator." Phys. Rev. A 83, 012308 (2011).* Args: duration: Duration of pulse. Must be greater than zero. amp: Pulse amplitude at center ``duration/2``. sigma: Width (standard deviation) of pulse. beta: Y correction amplitude. For the SNO this is :math:`\beta=-\frac{\lambda_1^2}{4\Delta_2}`. Where :math:`\lambda_1` is the relative coupling strength between the first excited and second excited states and :math:`\Delta_2` is the detuning between the respective excited states. name: Name of pulse. zero_ends: If ``True``, make the first and last sample zero, but rescale to preserve amp. """ center = duration/2 zeroed_width = duration if zero_ends else None rescale_amp = bool(zero_ends) return _sampled_drag_pulse(duration, amp, center, sigma, beta, zeroed_width=zeroed_width, rescale_amp=rescale_amp, name=name)