Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions qiskit/pulse/library/parametric_pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,22 @@ class ParametricPulse(Pulse):
"""The abstract superclass for parametric pulses."""

@abstractmethod
def __init__(self, duration: Union[int, ParameterExpression], name: Optional[str] = None):
def __init__(
self,
duration: Union[int, ParameterExpression],
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
):
"""Create a parametric pulse and validate the input parameters.

Args:
duration: Pulse length in terms of the the sampling period `dt`.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
waveform to 1. The default is ``True`` and the
amplitude is constrained to 1.
"""
super().__init__(duration=duration, name=name)
super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
self.validate_parameters()

@abstractmethod
Expand Down Expand Up @@ -141,6 +149,7 @@ def __init__(
amp: Union[complex, ParameterExpression],
sigma: Union[float, ParameterExpression],
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
):
"""Initialize the gaussian pulse.

Expand All @@ -150,12 +159,15 @@ def __init__(
sigma: A measure of how wide or narrow the Gaussian peak is; described mathematically
in the class docstring.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
waveform to 1. The default is ``True`` and the
amplitude is constrained to 1.
"""
if not _is_parameterized(amp):
amp = complex(amp)
self._amp = amp
self._sigma = sigma
super().__init__(duration=duration, name=name)
super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)

@property
def amp(self) -> Union[complex, ParameterExpression]:
Expand Down Expand Up @@ -235,6 +247,7 @@ def __init__(
width: Union[float, ParameterExpression] = None,
risefall_sigma_ratio: Union[float, ParameterExpression] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
):
"""Initialize the gaussian square pulse.

Expand All @@ -246,14 +259,17 @@ def __init__(
width: The duration of the embedded square pulse.
risefall_sigma_ratio: The ratio of each risefall duration to sigma.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
waveform to 1. The default is ``True`` and the
amplitude is constrained to 1.
"""
if not _is_parameterized(amp):
amp = complex(amp)
self._amp = amp
self._sigma = sigma
self._risefall_sigma_ratio = risefall_sigma_ratio
self._width = width
super().__init__(duration=duration, name=name)
super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)

@property
def amp(self) -> Union[complex, ParameterExpression]:
Expand Down Expand Up @@ -382,6 +398,7 @@ def __init__(
sigma: Union[float, ParameterExpression],
beta: Union[float, ParameterExpression],
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
):
"""Initialize the drag pulse.

Expand All @@ -392,13 +409,16 @@ def __init__(
in the class docstring.
beta: The correction amplitude.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
waveform to 1. The default is ``True`` and the
amplitude is constrained to 1.
"""
if not _is_parameterized(amp):
amp = complex(amp)
self._amp = amp
self._sigma = sigma
self._beta = beta
super().__init__(duration=duration, name=name)
super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)

@property
def amp(self) -> Union[complex, ParameterExpression]:
Expand Down Expand Up @@ -435,9 +455,10 @@ def validate_parameters(self) -> None:
not _is_parameterized(self.beta)
and not _is_parameterized(self.sigma)
and self.beta > self.sigma
and self.limit_amplitude
):
# If beta <= sigma, then the maximum amplitude is at duration / 2, which is
# already constrainted by self.amp <= 1
# already constrained by self.amp <= 1

# 1. Find the first maxima associated with the beta * d/dx gaussian term
# This eq is derived from solving for the roots of the norm of the drag function.
Expand Down Expand Up @@ -491,6 +512,7 @@ def __init__(
duration: Union[int, ParameterExpression],
amp: Union[complex, ParameterExpression],
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
):
"""
Initialize the constant-valued pulse.
Expand All @@ -499,11 +521,14 @@ def __init__(
duration: Pulse length in terms of the the sampling period `dt`.
amp: The amplitude of the constant square pulse.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
waveform to 1. The default is ``True`` and the
amplitude is constrained to 1.
"""
if not _is_parameterized(amp):
amp = complex(amp)
self._amp = amp
super().__init__(duration=duration, name=name)
super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)

@property
def amp(self) -> Union[complex, ParameterExpression]:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
features:
- |
Adds an argument ``limit_amplitude`` to the constructor of ParametricPulse
class, and derived classes Gaussian, GaussianSquare, Drag and Constant, to
enable or disable the amplitude limit of 1 on the pulse. Fixes #6544. This
option gets propagated to the parent class Pulse. With this option enabled,
ParametricPulse class and its subclasses do not allow amplitudes larger
than 1. By default, the value of ``limit_amplitude`` is true, so that the
amplitude is constrained to be less than 1.
34 changes: 34 additions & 0 deletions test/python/pulse/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,40 @@ def test_parametric_pulses_parameter_assignment(self):
self.assertEqual(waveform.amp, self.amp)
self.assertEqual(waveform.sigma, 12.7)

def test_parametric_pulses_limit_amplitude(self):
"""Test that the check for amplitude less than or equal to 1 can be disabled."""
waveform = pulse.library.Gaussian(
duration=100, sigma=1.0, amp=1.1 + 0.8j, limit_amplitude=False
)
self.assertGreater(np.abs(waveform.amp), 1.0)
with self.assertRaises(PulseError):
waveform = pulse.library.Gaussian(
duration=100, sigma=1.0, amp=1.1 + 0.8j, limit_amplitude=True
)

waveform = pulse.library.GaussianSquare(
duration=100, sigma=1.0, amp=1.1 + 0.8j, width=10, limit_amplitude=False
)
self.assertGreater(np.abs(waveform.amp), 1.0)
with self.assertRaises(PulseError):
waveform = pulse.library.GaussianSquare(
duration=100, sigma=1.0, amp=1.1 + 0.8j, width=10, limit_amplitude=True
)

waveform = pulse.library.Drag(
duration=100, sigma=1.0, beta=1.0, amp=1.1 + 0.8j, limit_amplitude=False
)
self.assertGreater(np.abs(waveform.amp), 1.0)
with self.assertRaises(PulseError):
waveform = pulse.library.Drag(
duration=100, sigma=1.0, beta=1.0, amp=1.1 + 0.8j, limit_amplitude=True
)

waveform = pulse.library.Constant(duration=100, amp=1.1 + 0.8j, limit_amplitude=False)
self.assertGreater(np.abs(waveform.amp), 1.0)
with self.assertRaises(PulseError):
waveform = pulse.library.Constant(duration=100, amp=1.1 + 0.8j, limit_amplitude=True)

@unittest.skip("Not yet supported by ParameterExpression")
def test_complex_value_assignment(self):
"""Test that complex values can be assigned to Parameters."""
Expand Down