Skip to content

Commit eb4c5cb

Browse files
authored
Start deprecation of complex parameters in Qiskit Pulse (#9735)
* Add warning and update tests * Release notes * Move warning to all Pulse objects. * Fix releasenote typo * Move warning to format_parameter_value
1 parent 6cec912 commit eb4c5cb

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

qiskit/pulse/parameter_manager.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ def _assign_parameter_expression(self, param_expr: ParameterExpression):
256256
updated = param_expr.parameters & self._param_map.keys()
257257
for param in updated:
258258
new_value = new_value.assign(param, self._param_map[param])
259-
260-
return format_parameter_value(new_value)
259+
new_value = format_parameter_value(new_value)
260+
return new_value
261261

262262
def _update_parameter_manager(self, node: Union[Schedule, ScheduleBlock]):
263263
"""A helper function to update parameter manager of pulse program."""

qiskit/pulse/utils.py

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"""Module for common pulse programming utilities."""
1414
import functools
1515
from typing import List, Dict, Union
16+
import warnings
1617

1718
import numpy as np
1819

@@ -65,6 +66,19 @@ def format_parameter_value(
6566
evaluated = float(evaluated.real)
6667
if evaluated.is_integer():
6768
evaluated = int(evaluated)
69+
else:
70+
warnings.warn(
71+
"Assignment of complex values to ParameterExpression in Qiskit Pulse objects is "
72+
"now pending deprecation. This will align the Pulse module with other modules "
73+
"where such assignment wasn't possible to begin with. The typical use case for complex "
74+
"parameters in the module was the SymbolicPulse library. As of Qiskit-Terra "
75+
"0.23.0 all library pulses were converted from complex amplitude representation"
76+
" to real representation using two floats (amp,angle), as used in the "
77+
"ScalableSymbolicPulse class. This eliminated the need for complex parameters. "
78+
"Any use of complex parameters (and particularly custom-built pulses) should be "
79+
"converted in a similar fashion to avoid the use of complex parameters.",
80+
PendingDeprecationWarning,
81+
)
6882

6983
return evaluated
7084
except TypeError:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
deprecations:
3+
- |
4+
Assignment of complex values to ``ParameterExpression`` in any Qiskit Pulse object
5+
now raises a ``PendingDeprecationWarning``. This will align the Pulse module with
6+
other modules where such assignment wasn't possible to begin with. The typical use
7+
case for complex parameters in the module was the SymbolicPulse library. As of
8+
Qiskit-Terra 0.23.0 all library pulses were converted from complex amplitude
9+
representation to real representation using two floats (amp,angle), as used in the
10+
``ScalableSymbolicPulse`` class. This eliminated the need for complex parameters.
11+
Any use of complex parameters (and particularly custom-built pulses) should be
12+
converted in a similar fashion to avoid the use of complex parameters.

test/python/pulse/test_parameter_manager.py

+18-11
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class TestParameterSetter(ParameterTestBase):
201201
"""Test setting parameters."""
202202

203203
def test_set_parameter_to_channel(self):
204-
"""Test get parameters from channel."""
204+
"""Test set parameters from channel."""
205205
test_obj = pulse.DriveChannel(self.ch1 + self.ch2)
206206

207207
value_dict = {self.ch1: 1, self.ch2: 2}
@@ -214,7 +214,7 @@ def test_set_parameter_to_channel(self):
214214
self.assertEqual(assigned, ref_obj)
215215

216216
def test_set_parameter_to_pulse(self):
217-
"""Test get parameters from pulse instruction."""
217+
"""Test set parameters from pulse instruction."""
218218
test_obj = self.parametric_waveform1
219219

220220
value_dict = {self.amp1_1: 0.1, self.amp1_2: 0.2, self.dur1: 160}
@@ -336,42 +336,47 @@ def test_nested_assignment_partial_bind(self):
336336
self.assertEqual(assigned, ref_obj)
337337

338338
def test_complex_valued_parameter(self):
339-
"""Test complex valued parameter can be casted to a complex value."""
339+
"""Test complex valued parameter can be casted to a complex value,
340+
but raises PendingDeprecationWarning.."""
340341
amp = Parameter("amp")
341342
test_obj = pulse.Constant(duration=160, amp=1j * amp)
342343

343344
value_dict = {amp: 0.1}
344345

345346
visitor = ParameterSetter(param_map=value_dict)
346-
assigned = visitor.visit(test_obj)
347+
with self.assertWarns(PendingDeprecationWarning):
348+
assigned = visitor.visit(test_obj)
347349

348350
ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)
349351

350352
self.assertEqual(assigned, ref_obj)
351353

352354
def test_complex_value_to_parameter(self):
353-
"""Test complex value can be assigned to parameter object."""
355+
"""Test complex value can be assigned to parameter object,
356+
but raises PendingDeprecationWarning."""
354357
amp = Parameter("amp")
355358
test_obj = pulse.Constant(duration=160, amp=amp)
356359

357360
value_dict = {amp: 0.1j}
358361

359362
visitor = ParameterSetter(param_map=value_dict)
360-
assigned = visitor.visit(test_obj)
363+
with self.assertWarns(PendingDeprecationWarning):
364+
assigned = visitor.visit(test_obj)
361365

362366
ref_obj = pulse.Constant(duration=160, amp=1j * 0.1)
363367

364368
self.assertEqual(assigned, ref_obj)
365369

366370
def test_complex_parameter_expression(self):
367-
"""Test assignment of complex-valued parameter expression to parameter."""
371+
"""Test assignment of complex-valued parameter expression to parameter,
372+
but raises PendingDeprecationWarning."""
368373
amp = Parameter("amp")
369374

370375
mag = Parameter("A")
371376
phi = Parameter("phi")
372377

373378
test_obj = pulse.Constant(duration=160, amp=amp)
374-
379+
test_obj_copy = deepcopy(test_obj)
375380
# generate parameter expression
376381
value_dict = {amp: mag * np.exp(1j * phi)}
377382
visitor = ParameterSetter(param_map=value_dict)
@@ -380,13 +385,15 @@ def test_complex_parameter_expression(self):
380385
# generate complex value
381386
value_dict = {mag: 0.1, phi: 0.5}
382387
visitor = ParameterSetter(param_map=value_dict)
383-
assigned = visitor.visit(assigned)
388+
with self.assertWarns(PendingDeprecationWarning):
389+
assigned = visitor.visit(assigned)
384390

385391
# evaluated parameter expression: 0.0877582561890373 + 0.0479425538604203*I
386392
value_dict = {amp: 0.1 * np.exp(0.5j)}
387-
visitor = ParameterSetter(param_map=value_dict)
388-
ref_obj = visitor.visit(test_obj)
389393

394+
visitor = ParameterSetter(param_map=value_dict)
395+
with self.assertWarns(PendingDeprecationWarning):
396+
ref_obj = visitor.visit(test_obj_copy)
390397
self.assertEqual(assigned, ref_obj)
391398

392399
def test_invalid_pulse_amplitude(self):

0 commit comments

Comments
 (0)