Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate complex amp support for ScalableSymbolicPulse #10357

Merged
merged 8 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
46 changes: 23 additions & 23 deletions qiskit/pulse/library/symbolic_pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import numpy as np

from qiskit.circuit.parameterexpression import ParameterExpression
from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
from qiskit.pulse.exceptions import PulseError
from qiskit.pulse.library.pulse import Pulse
from qiskit.pulse.library.waveform import Waveform
Expand Down Expand Up @@ -595,16 +595,16 @@ class ScalableSymbolicPulse(SymbolicPulse):
additional_msg=(
"Instead, use a float for ``amp`` (for the magnitude) and a float for ``angle``"
),
since="0.23.0",
pending=True,
since="0.25.0",
pending=False,
TsafrirA marked this conversation as resolved.
Show resolved Hide resolved
predicate=lambda amp: isinstance(amp, complex),
)
def __init__(
self,
pulse_type: str,
duration: Union[ParameterExpression, int],
amp: Union[ParameterExpression, float, complex],
angle: Union[ParameterExpression, float],
amp: ParameterValueType,
angle: ParameterValueType,
parameters: Optional[Dict[str, Union[ParameterExpression, complex]]] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
Expand Down Expand Up @@ -739,9 +739,9 @@ class Gaussian(metaclass=_PulseType):
def __new__(
cls,
duration: Union[int, ParameterExpression],
amp: Union[complex, float, ParameterExpression],
sigma: Union[float, ParameterExpression],
angle: Optional[Union[float, ParameterExpression]] = None,
amp: ParameterValueType,
sigma: ParameterValueType,
angle: Optional[ParameterValueType] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
) -> ScalableSymbolicPulse:
Expand All @@ -750,7 +750,7 @@ def __new__(
Args:
duration: Pulse length in terms of the sampling period `dt`.
amp: The magnitude of the amplitude of the Gaussian envelope.
Complex amp support will be deprecated.
Complex amp support is deprecated.
sigma: A measure of how wide or narrow the Gaussian peak is; described mathematically
in the class docstring.
angle: The angle of the complex amplitude of the Gaussian envelope. Default value 0.
Expand Down Expand Up @@ -835,11 +835,11 @@ class GaussianSquare(metaclass=_PulseType):
def __new__(
cls,
duration: Union[int, ParameterExpression],
amp: Union[complex, float, ParameterExpression],
sigma: Union[float, ParameterExpression],
width: Optional[Union[float, ParameterExpression]] = None,
angle: Optional[Union[float, ParameterExpression]] = None,
risefall_sigma_ratio: Optional[Union[float, ParameterExpression]] = None,
amp: ParameterValueType,
sigma: ParameterValueType,
width: Optional[ParameterValueType] = None,
angle: Optional[ParameterValueType] = None,
risefall_sigma_ratio: Optional[ParameterValueType] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
) -> ScalableSymbolicPulse:
Expand All @@ -848,7 +848,7 @@ def __new__(
Args:
duration: Pulse length in terms of the sampling period `dt`.
amp: The magnitude of the amplitude of the Gaussian and square pulse.
Complex amp support will be deprecated.
Complex amp support is deprecated.
sigma: A measure of how wide or narrow the Gaussian risefall is; see the class
docstring for more details.
width: The duration of the embedded square pulse.
Expand Down Expand Up @@ -1378,10 +1378,10 @@ class Drag(metaclass=_PulseType):
def __new__(
cls,
duration: Union[int, ParameterExpression],
amp: Union[complex, float, ParameterExpression],
sigma: Union[float, ParameterExpression],
beta: Union[float, ParameterExpression],
angle: Optional[Union[float, ParameterExpression]] = None,
amp: ParameterValueType,
sigma: ParameterValueType,
beta: ParameterValueType,
angle: Optional[ParameterValueType] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
) -> ScalableSymbolicPulse:
Expand All @@ -1390,7 +1390,7 @@ def __new__(
Args:
duration: Pulse length in terms of the sampling period `dt`.
amp: The magnitude of the amplitude of the DRAG envelope.
Complex amp support will be deprecated.
Complex amp support is deprecated.
sigma: A measure of how wide or narrow the Gaussian peak is; described mathematically
in the class docstring.
beta: The correction amplitude.
Expand Down Expand Up @@ -1449,8 +1449,8 @@ class Constant(metaclass=_PulseType):
def __new__(
cls,
duration: Union[int, ParameterExpression],
amp: Union[complex, float, ParameterExpression],
angle: Optional[Union[float, ParameterExpression]] = None,
amp: ParameterValueType,
angle: Optional[ParameterValueType] = None,
name: Optional[str] = None,
limit_amplitude: Optional[bool] = None,
) -> ScalableSymbolicPulse:
Expand All @@ -1459,7 +1459,7 @@ def __new__(
Args:
duration: Pulse length in terms of the sampling period `dt`.
amp: The magnitude of the amplitude of the square envelope.
Complex amp support will be deprecated.
Complex amp support is deprecated.
angle: The angle of the complex amplitude of the square envelope. Default value 0.
name: Display name for this pulse envelope.
limit_amplitude: If ``True``, then limit the amplitude of the
Expand Down
16 changes: 16 additions & 0 deletions releasenotes/notes/deprecate-complex-amp-41381bd9722bc878.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
deprecations:
- |
Initializing a :class:`~qiskit.pulse.library.ScalableSymbolicPulse` with complex `amp` value is now deprecated.
This change also affects the following library pulses:

* :class:`~qiskit.pulse.library.Gaussian`
* :class:`~qiskit.pulse.library.GaussianSquare`
* :class:`~qiskit.pulse.library.Drag`
* :class:`~qiskit.pulse.library.Constant`

Initializing them with complex `amp` is now deprecated as well.

Instead, one should use two floats for the `amp` and `angle` parameters, where `amp` represents the
magnitude of the complex amplitude, and `angle` represents the angle of the complex amplitude. i.e. the
complex amplitude is given by `amp` * exp(1j * `angle`).
39 changes: 29 additions & 10 deletions test/python/compiler/test_assembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1278,12 +1278,21 @@ def test_assemble_schedule_enum(self):

def test_assemble_parametric(self):
"""Test that parametric pulses can be assembled properly into a PulseQobj."""
amp = [0.5, 0.6, 1, 0.2]
angle = [np.pi / 2, 0.6, 0, 0]
sched = pulse.Schedule(name="test_parametric")
sched += Play(pulse.Gaussian(duration=25, sigma=4, amp=0.5j), DriveChannel(0))
sched += Play(pulse.Drag(duration=25, amp=0.2 + 0.3j, sigma=7.8, beta=4), DriveChannel(1))
sched += Play(pulse.Constant(duration=25, amp=1), DriveChannel(2))
sched += Play(
pulse.Gaussian(duration=25, sigma=4, amp=amp[0], angle=angle[0]), DriveChannel(0)
)
sched += Play(
pulse.Drag(duration=25, amp=amp[1], angle=angle[1], sigma=7.8, beta=4), DriveChannel(1)
)
sched += Play(pulse.Constant(duration=25, amp=amp[2], angle=angle[2]), DriveChannel(2))
sched += (
Play(pulse.GaussianSquare(duration=150, amp=0.2, sigma=8, width=140), MeasureChannel(0))
Play(
pulse.GaussianSquare(duration=150, amp=amp[3], angle=angle[3], sigma=8, width=140),
MeasureChannel(0),
)
<< sched.duration
)
backend = FakeOpenPulse3Q()
Expand All @@ -1302,24 +1311,34 @@ def test_assemble_parametric(self):
self.assertEqual(qobj_insts[1].pulse_shape, "drag")
self.assertEqual(qobj_insts[2].pulse_shape, "constant")
self.assertEqual(qobj_insts[3].pulse_shape, "gaussian_square")
self.assertDictEqual(qobj_insts[0].parameters, {"duration": 25, "sigma": 4, "amp": 0.5j})
self.assertDictEqual(
qobj_insts[1].parameters, {"duration": 25, "sigma": 7.8, "amp": 0.2 + 0.3j, "beta": 4}
qobj_insts[0].parameters,
{"duration": 25, "sigma": 4, "amp": amp[0] * np.exp(1j * angle[0])},
)
self.assertDictEqual(qobj_insts[2].parameters, {"duration": 25, "amp": 1})
self.assertDictEqual(
qobj_insts[3].parameters, {"duration": 150, "sigma": 8, "amp": 0.2, "width": 140}
qobj_insts[1].parameters,
{"duration": 25, "sigma": 7.8, "amp": amp[1] * np.exp(1j * angle[1]), "beta": 4},
)
self.assertDictEqual(
qobj_insts[2].parameters, {"duration": 25, "amp": amp[2] * np.exp(1j * angle[2])}
)
self.assertDictEqual(
qobj_insts[3].parameters,
{"duration": 150, "sigma": 8, "amp": amp[3] * np.exp(1j * angle[3]), "width": 140},
)
self.assertEqual(
qobj.to_dict()["experiments"][0]["instructions"][0]["parameters"]["amp"], 0.5j
qobj.to_dict()["experiments"][0]["instructions"][0]["parameters"]["amp"],
amp[0] * np.exp(1j * angle[0]),
)

def test_assemble_parametric_unsupported(self):
"""Test that parametric pulses are translated to Waveform if they're not supported
by the backend during assemble time.
"""
sched = pulse.Schedule(name="test_parametric_to_sample_pulse")
sched += Play(pulse.Drag(duration=25, amp=0.2 + 0.3j, sigma=7.8, beta=4), DriveChannel(1))
sched += Play(
pulse.Drag(duration=25, amp=0.5, angle=-0.3, sigma=7.8, beta=4), DriveChannel(1)
)
sched += Play(pulse.Constant(duration=25, amp=1), DriveChannel(2))

backend = FakeOpenPulse3Q()
Expand Down
6 changes: 4 additions & 2 deletions test/python/pulse/test_parameter_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ def test_complex_valued_parameter(self):
with self.assertWarns(PendingDeprecationWarning):
assigned = visitor.visit(test_obj)

ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)
with self.assertWarns(DeprecationWarning):
ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)

self.assertEqual(assigned, ref_obj)

Expand All @@ -368,7 +369,8 @@ def test_complex_value_to_parameter(self):
with self.assertWarns(PendingDeprecationWarning):
assigned = visitor.visit(test_obj)

ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)
with self.assertWarns(DeprecationWarning):
ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)

self.assertEqual(assigned, ref_obj)

Expand Down
Loading