Source code for pyquil.quiltwaveforms
from typing import Optional
from typing_extensions import Self
import numpy as np
from scipy.special import erf
from pyquil.quilatom import (
TemplateWaveform,
_update_envelope,
_template_waveform_property,
)
[docs]class FlatWaveform(TemplateWaveform):
"""
A flat (constant) waveform.
"""
NAME = "flat"
def __new__(
cls,
duration: float,
iq: complex,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(cls, cls.NAME, duration=duration, iq=iq, scale=scale, phase=phase, detuning=detuning)
iq = _template_waveform_property("iq", doc="A raw IQ value.")
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
iqs = np.full(self.num_samples(rate), self.iq, dtype=np.complex128)
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)
[docs]class GaussianWaveform(TemplateWaveform):
"""A Gaussian pulse."""
NAME = "gaussian"
def __new__(
cls,
duration: float,
fwhm: float,
t0: float,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(
cls, cls.NAME, duration=duration, fwhm=fwhm, t0=t0, scale=scale, phase=phase, detuning=detuning
)
fwhm = _template_waveform_property("fwhm", doc="The Full-Width-Half-Max of the Gaussian (seconds).", dtype=float)
t0 = _template_waveform_property("t0", doc="The center time coordinate of the Gaussian (seconds).", dtype=float)
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
ts = np.arange(self.num_samples(rate), dtype=np.complex128) / rate
sigma = 0.5 * self.fwhm / np.sqrt(2.0 * np.log(2.0))
iqs = np.exp(-0.5 * (ts - self.t0) ** 2 / sigma**2)
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)
[docs]class DragGaussianWaveform(TemplateWaveform):
"""A DRAG Gaussian pulse."""
NAME = "drag_gaussian"
def __new__(
cls,
duration: float,
fwhm: float,
t0: float,
anh: float,
alpha: float,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(
cls,
cls.NAME,
duration=duration,
fwhm=fwhm,
t0=t0,
anh=anh,
alpha=alpha,
scale=scale,
phase=phase,
detuning=detuning,
)
fwhm = _template_waveform_property("fwhm", doc="The Full-Width-Half-Max of the gaussian (seconds).", dtype=float)
t0 = _template_waveform_property("t0", doc="The center time coordinate of the Gaussian (seconds).", dtype=float)
anh = _template_waveform_property("anh", doc="The anharmonicity of the qubit, f01-f12 (Hertz).", dtype=float)
alpha = _template_waveform_property("alpha", doc="Dimensionles DRAG parameter.", dtype=float)
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
ts = np.arange(self.num_samples(rate), dtype=np.complex128) / rate
sigma = 0.5 * self.fwhm / np.sqrt(2.0 * np.log(2.0))
env = np.exp(-0.5 * (ts - self.t0) ** 2 / sigma**2)
env_der = (self.alpha * (1.0 / (2 * np.pi * self.anh * sigma**2))) * (ts - self.t0) * env
iqs = env + 1.0j * env_der
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)
[docs]class HrmGaussianWaveform(TemplateWaveform):
"""A Hermite Gaussian waveform.
REFERENCE: Effects of arbitrary laser or NMR pulse shapes on population
inversion and coherence Warren S. Warren. 81, (1984); doi:
10.1063/1.447644
"""
NAME = "hrm_gaussian"
def __new__(
cls,
duration: float,
fwhm: float,
t0: float,
anh: float,
alpha: float,
second_order_hrm_coeff: float,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(
cls,
cls.NAME,
duration=duration,
fwhm=fwhm,
t0=t0,
anh=anh,
second_order_hrm_coeff=second_order_hrm_coeff,
alpha=alpha,
scale=scale,
phase=phase,
detuning=detuning,
)
fwhm = _template_waveform_property("fwhm", doc="The Full-Width-Half-Max of the Gaussian (seconds).", dtype=float)
t0 = _template_waveform_property("t0", doc="The center time coordinate of the Gaussian (seconds).", dtype=float)
anh = _template_waveform_property("anh", doc="The anharmonicity of the qubit, f01-f12 (Hertz).", dtype=float)
alpha = _template_waveform_property("alpha", doc="Dimensionles DRAG parameter.", dtype=float)
second_order_hrm_coeff = _template_waveform_property(
"second_order_hrm_coeff", doc="Second order coefficient (see Warren 1984).", dtype=float
)
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
ts = np.arange(self.num_samples(rate), dtype=np.complex128) / rate
sigma = 0.5 * self.fwhm / np.sqrt(2.0 * np.log(2.0))
exponent_of_t = 0.5 * (ts - self.t0) ** 2 / sigma**2
gauss = np.exp(-exponent_of_t)
env = (1 - self.second_order_hrm_coeff * exponent_of_t) * gauss
deriv_prefactor = -self.alpha / (2 * np.pi * self.anh)
env_der = (
deriv_prefactor
* (ts - self.t0)
/ (sigma**2)
* gauss
* (self.second_order_hrm_coeff * (exponent_of_t - 1) - 1)
)
iqs = env + 1.0j * env_der
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)
[docs]class ErfSquareWaveform(TemplateWaveform):
"""A pulse with a flat top and edges that are error functions (erf)."""
NAME = "erf_square"
def __new__(
cls,
duration: float,
risetime: float,
pad_left: float,
pad_right: float,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(
cls,
cls.NAME,
duration=duration,
risetime=risetime,
pad_left=pad_left,
pad_right=pad_right,
scale=scale,
phase=phase,
detuning=detuning,
)
risetime = _template_waveform_property(
"risetime", doc="The width of each of the rise and fall sections of the pulse (seconds).", dtype=float
)
pad_left = _template_waveform_property(
"pad_left", doc="Amount of zero-padding to add to the left of the pulse (seconds)", dtype=float
)
pad_right = _template_waveform_property(
"pad_right", doc="Amount of zero-padding to add to the right of the pulse (seconds).", dtype=float
)
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
ts = np.arange(self.num_samples(rate), dtype=np.complex128) / rate
fwhm = 0.5 * self.risetime
t1 = fwhm
t2 = self.duration - fwhm
sigma = 0.5 * fwhm / np.sqrt(2.0 * np.log(2.0))
vals = 0.5 * (erf((ts - t1) / sigma) - erf((ts - t2) / sigma))
zeros_left = np.zeros(int(np.ceil(self.pad_left * rate)), dtype=np.complex128)
zeros_right = np.zeros(int(np.ceil(self.pad_right * rate)), dtype=np.complex128)
iqs = np.concatenate((zeros_left, vals, zeros_right))
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)
[docs]class BoxcarAveragerKernel(TemplateWaveform):
NAME = "boxcar_kernel"
def __new__(
cls,
duration: float,
scale: Optional[float] = None,
phase: Optional[float] = None,
detuning: Optional[float] = None,
) -> Self:
return super().__new__(cls, cls.NAME, duration=duration, scale=scale, phase=phase, detuning=detuning)
scale = _template_waveform_property("scale", doc="An optional global scaling factor.", dtype=float)
phase = _template_waveform_property("phase", doc="An optional phase shift factor.", dtype=float)
detuning = _template_waveform_property("detuning", doc="An optional frequency detuning factor.", dtype=float)
[docs] def samples(self, rate: float) -> np.ndarray:
n = self.num_samples(rate)
iqs = np.full(n, 1.0 / n, dtype=np.complex128)
return _update_envelope(iqs, rate, scale=self.scale, phase=self.phase, detuning=self.detuning)