Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6e3d42e
make waveform amplitude limit optional
eendebakpt May 6, 2021
930e36a
change order of Waveform arguments for backwards compatibility
eendebakpt May 6, 2021
d98f165
update black once more
eendebakpt May 6, 2021
eb4760f
Update qiskit/pulse/library/waveform.py
peendebak May 16, 2021
2a9a590
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 17, 2021
68ec529
move limit_amplitude from waveform to pulse
eendebakpt May 18, 2021
fe16b2b
use limit_amplitude in pulses; add tests
eendebakpt May 18, 2021
85ddd05
format strings
eendebakpt May 18, 2021
7306f2b
fix max line length
eendebakpt May 18, 2021
f49229e
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 18, 2021
970040c
fix line length
eendebakpt May 18, 2021
0115ca4
Merge branch 'feat/waveform_amplitude_limit' of github.com:peendebak/…
eendebakpt May 18, 2021
7b545d2
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 18, 2021
a4971fa
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 20, 2021
d6e67cc
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 21, 2021
2551f7a
add release notes
eendebakpt May 21, 2021
e4dcc57
fix reno file
eendebakpt May 22, 2021
0e516ad
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 22, 2021
f0fedc7
Update releasenotes/notes/add-option-to-disable-waveform-amplitude-li…
peendebak May 24, 2021
8eb4ab6
Update releasenotes/notes/add-option-to-disable-waveform-amplitude-li…
peendebak May 24, 2021
1981f60
Update releasenotes/notes/add-option-to-disable-waveform-amplitude-li…
peendebak May 24, 2021
f176bc0
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak May 24, 2021
5d876eb
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak Jun 2, 2021
182a91b
Remove unnecessary print statement.
taalexander Jun 9, 2021
2760597
Merge branch 'main' into feat/waveform_amplitude_limit
peendebak Jun 9, 2021
27ff8e2
Merge branch 'main' into feat/waveform_amplitude_limit
mergify[bot] Jun 10, 2021
763c40f
trigger build, see #6539
eendebakpt Jun 10, 2021
0785566
Merge branch 'feat/waveform_amplitude_limit' of github.com:peendebak/…
eendebakpt Jun 10, 2021
60817f6
trigger build
eendebakpt Jun 10, 2021
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
29 changes: 20 additions & 9 deletions qiskit/pulse/library/parametric_pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ def get_waveform(self) -> Waveform:
return gaussian(duration=self.duration, amp=self.amp, sigma=self.sigma, zero_ends=True)

def validate_parameters(self) -> None:
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0:
raise PulseError("The amplitude norm must be <= 1, " "found: {}".format(abs(self.amp)))
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0 and self.limit_amplitude:
raise PulseError(
f"The amplitude norm must be <= 1, found: {abs(self.amp)}"
+ "This can be overruled by setting Pulse.limit_amplitude."
)
if not _is_parameterized(self.sigma) and self.sigma <= 0:
raise PulseError("Sigma must be greater than 0.")

Expand Down Expand Up @@ -278,9 +281,11 @@ def get_waveform(self) -> Waveform:
)

def validate_parameters(self) -> None:

if not _is_parameterized(self.amp) and abs(self.amp) > 1.0:
raise PulseError("The amplitude norm must be <= 1, " "found: {}".format(abs(self.amp)))
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0 and self.limit_amplitude:
raise PulseError(
f"The amplitude norm must be <= 1, found: {abs(self.amp)}"
+ "This can be overruled by setting Pulse.limit_amplitude."
)
if not _is_parameterized(self.sigma) and self.sigma <= 0:
raise PulseError("Sigma must be greater than 0.")
if self.width is not None and self.risefall_sigma_ratio is not None:
Expand Down Expand Up @@ -416,8 +421,11 @@ def get_waveform(self) -> Waveform:
)

def validate_parameters(self) -> None:
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0:
raise PulseError("The amplitude norm must be <= 1, " "found: {}".format(abs(self.amp)))
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0 and self.limit_amplitude:
raise PulseError(
f"The amplitude norm must be <= 1, found: {abs(self.amp)}"
+ "This can be overruled by setting Pulse.limit_amplitude."
)
if not _is_parameterized(self.sigma) and self.sigma <= 0:
raise PulseError("Sigma must be greater than 0.")
if not _is_parameterized(self.beta) and isinstance(self.beta, complex):
Expand Down Expand Up @@ -506,8 +514,11 @@ def get_waveform(self) -> Waveform:
return constant(duration=self.duration, amp=self.amp)

def validate_parameters(self) -> None:
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0:
raise PulseError("The amplitude norm must be <= 1, " "found: {}".format(abs(self.amp)))
if not _is_parameterized(self.amp) and abs(self.amp) > 1.0 and self.limit_amplitude:
raise PulseError(
f"The amplitude norm must be <= 1, found: {abs(self.amp)}"
+ "This can be overruled by setting Pulse.limit_amplitude."
)

@property
def parameters(self) -> Dict[str, Any]:
Expand Down
22 changes: 21 additions & 1 deletion qiskit/pulse/library/pulse.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,30 @@ class Pulse(ABC):
modulation phase and frequency are specified separately from ``Pulse``s.
"""

limit_amplitude = True

@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,
):
"""Abstract base class for pulses
Args:
duration: Duration of the pulse
name: Optional name for the pulse
limit_amplitude: If ``True``, then limit the amplitude of the waveform to 1.
The default value of ``None`` causes the flag value to be
derived from :py:attr:`~limit_amplitude` which is ``True``
by default but may be set by the user to disable amplitude
checks globally.
"""

self.duration = duration
self.name = name
if limit_amplitude is not None:
self.limit_amplitude = limit_amplitude

@property
def id(self) -> int: # pylint: disable=invalid-name
Expand Down
12 changes: 9 additions & 3 deletions qiskit/pulse/library/waveform.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(
samples: Union[np.ndarray, List[complex]],
name: Optional[str] = None,
epsilon: float = 1e-7,
limit_amplitude: Optional[bool] = None,
):
"""Create new sample pulse command.

Expand All @@ -41,12 +42,13 @@ def __init__(
If any sample's norm exceeds unity by less than or equal to epsilon
it will be clipped to unit norm. If the sample
norm is greater than 1+epsilon an error will be raised.
limit_amplitude: Passed to parent Pulse
"""

super().__init__(duration=len(samples), name=name, limit_amplitude=limit_amplitude)
samples = np.asarray(samples, dtype=np.complex_)
self.epsilon = epsilon
self._samples = self._clip(samples, epsilon=epsilon)
super().__init__(duration=len(samples), name=name)

@property
def samples(self) -> np.ndarray:
Expand Down Expand Up @@ -95,8 +97,12 @@ def _clip(self, samples: np.ndarray, epsilon: float = 1e-7) -> np.ndarray:
samples[clip_where] = clipped_samples
samples_norm[clip_where] = np.abs(clipped_samples)

if np.any(samples_norm > 1.0):
raise PulseError("Pulse contains sample with norm greater than 1+epsilon.")
if np.any(samples_norm > 1.0) and self.limit_amplitude:
amp = np.max(samples_norm)
raise PulseError(
f"Pulse contains sample with norm {amp} greater than 1+epsilon."
" This can be overruled by setting Pulse.limit_amplitude."
)

return samples

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
Adds a global option `limit_amplitude` to the Pulse class to enable or disable the limit of 1. on the waveform
amplitude. Fixes #6012.
With the option enabled, the `Waveform` class does not allow amplitudes larger than 1. This is
enforced in several subclasses such as `Gaussian` and `Constant`.
19 changes: 19 additions & 0 deletions test/python/pulse/test_pulse_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
"""Unit tests for pulse waveforms."""

import unittest
from unittest.mock import patch
import numpy as np

import qiskit
from qiskit.pulse.library import (
Waveform,
Constant,
Expand Down Expand Up @@ -79,6 +81,17 @@ def test_pulse_limits(self):
with self.assertRaises(PulseError):
Waveform(invalid_const * np.exp(1j * 2 * np.pi * np.linspace(0, 1, 1000)))

invalid_const = 1.1
Waveform.limit_amplitude = False
wave = Waveform(invalid_const * np.exp(1j * 2 * np.pi * np.linspace(0, 1, 1000)))
self.assertGreater(np.max(np.abs(wave.samples)), 1.0)
with self.assertRaises(PulseError):
wave = Waveform(
invalid_const * np.exp(1j * 2 * np.pi * np.linspace(0, 1, 1000)),
limit_amplitude=True,
)
Waveform.limit_amplitude = True

# Test case where data is converted to python types with complex as a list
# with form [re, im] and back to a numpy array.
# This is how the transport layer handles samples in the qobj so it is important
Expand Down Expand Up @@ -199,6 +212,12 @@ def test_constant_samples(self):
self.assertEqual(const.get_waveform().samples[0], 0.1 + 0.4j)
self.assertEqual(len(const.get_waveform().samples), 150)

with self.assertRaises(PulseError):
const = Constant(duration=150, amp=1.1 + 0.4j)

with patch("qiskit.pulse.library.parametric_pulses.Pulse.limit_amplitude", new=False):
Comment thread
peendebak marked this conversation as resolved.
const = qiskit.pulse.library.parametric_pulses.Constant(duration=150, amp=0.1 + 0.4j)

def test_parameters(self):
"""Test that the parameters can be extracted as a dict through the `parameters`
attribute."""
Expand Down