Source code for semi_cr.core.trial.shapes

from abc import ABC, abstractmethod

import numpy as np

TWO_DIMENSIONS = 2


[docs] class PulseShape(ABC): """ Abstract base class for pulse shapes. """
[docs] @abstractmethod def get_shape(self) -> np.typing.NDArray[np.floating]: """ Get the value of the pulse shape. :return: The value of the pulse shape at the given time. """ pass
[docs] def integrate(self): return self.get_shape().sum()
[docs] class YizhiPulse(PulseShape): """ A pulse shape that linearly ramps up to a specified amplitude, then "asymptotically" goes on from that amplitude's complement to the negative of that amplitude, then back to zero. Sort of like this: """ def __init__(self, amplitude: float, steps: int): if not np.isfinite(amplitude) or amplitude < 0: raise ValueError("Amplitude must be non-negative and finite.") if steps <= 0: raise ValueError("Steps must be a positive integer.") self.amplitude = amplitude self.steps = steps
[docs] def get_shape(self) -> np.typing.NDArray[np.floating]: amplitude_shape = np.linspace(-self.amplitude, self.amplitude, self.steps) return amplitude_shape
[docs] class YizhiPulse2D(PulseShape): """ A 2D pulse shape that linearly ramps up to a specified amplitude, then "asymptotically" goes on from that amplitude's complement to the negative of that amplitude, then back to zero. Sort of like this: """ def __init__(self, amplitude: float | tuple[float, float], steps: int): amplitudes = (amplitude, amplitude) if isinstance(amplitude, (int, float)) else amplitude if len(amplitudes) != TWO_DIMENSIONS or any(not np.isfinite(value) or value < 0 for value in amplitudes): raise ValueError("Each amplitude must be non-negative and finite.") if steps <= 0: raise ValueError("Steps must be a positive integer.") self.amplitude = amplitudes self.steps = steps
[docs] def get_shape(self) -> np.typing.NDArray[np.floating]: gate_1_amplitude_sequences, gate_2_amplitude_sequences = self.get_axes() return np.column_stack((gate_1_amplitude_sequences, gate_2_amplitude_sequences))
[docs] def get_axes(self) -> tuple[np.typing.NDArray[np.floating], np.typing.NDArray[np.floating]]: """ Get the axis values for the 2D pulse shape. :return: The axis values for the 2D pulse shape. """ return tuple(np.linspace(-amplitude, amplitude, self.steps) for amplitude in self.amplitude) # type: ignore[return-value]