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 pulse parameter scoping #11691

Merged
merged 4 commits into from
Feb 1, 2024
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
33 changes: 33 additions & 0 deletions qiskit/pulse/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from qiskit.pulse.instructions import Instruction, Reference
from qiskit.pulse.utils import instruction_duration_validation
from qiskit.pulse.reference_manager import ReferenceManager
from qiskit.utils.deprecation import deprecate_func
from qiskit.utils.multiprocessing import is_main_process


Expand Down Expand Up @@ -880,6 +881,12 @@ class ScheduleBlock:

.. rubric:: Program Scoping

.. note::

The :meth:`~ScheduleBlock.scoped_parameters` and
:meth:`~ScheduleBlock.search_parameters` methods described in this
section are deprecated.

When you call a subroutine from another subroutine, or append a schedule block
to another schedule block, the management of references and parameters
can be a hard task. Schedule block offers a convenient feature to help with this
Expand Down Expand Up @@ -1225,9 +1232,22 @@ def parameters(self) -> Set[Parameter]:

return out_params

@deprecate_func(
additional_msg=(
"There is no alternative to this method. Parameters must be mapped "
"to references by checking the reference schedules directly."
),
since="0.46.0",
removal_timeline="in the Qiskit 1.0 release",
)
def scoped_parameters(self) -> Tuple[Parameter]:
"""Return unassigned parameters with scoped names.

.. warning::

Scoped parameters do not work correctly with Qiskit's data model for parameter
assignment. This implementation is consequently being removed in Qiskit 1.0.

.. note::

If a parameter is defined within a nested scope,
Expand Down Expand Up @@ -1623,9 +1643,22 @@ def get_parameters(self, parameter_name: str) -> List[Parameter]:
matched = [p for p in self.parameters if p.name == parameter_name]
return matched

@deprecate_func(
additional_msg=(
"There is no alternative to this method. Parameters must be mapped "
"to references by checking the reference schedules directly."
),
since="0.46.0",
removal_timeline="in the Qiskit 1.0 release",
)
def search_parameters(self, parameter_regex: str) -> List[Parameter]:
"""Search parameter with regular expression.

.. warning::

Scoped parameters do not work correctly with Qiskit's data model for parameter
assignment. This implementation is consequently being removed in Qiskit 1.0.

This method looks for the scope-aware parameters.
For example,

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
deprecations:
- |
The :meth:`.ScheduleBlock.scoped_parameters` and
:meth:`.ScheduleBlock.search_parameters` methods have been deprecated.
These methods produce :class:`.Parameter` objects with names modified to
indicate pulse scoping. The original intention of the methods was that
these objects would still link to the original unscoped :class:`.Parameter`
objects. However, the modification of the name breaks the link so that
assigning using the scoped version does not work. See `#11654
<https://github.com/Qiskit/qiskit/issues/11654>`__ for more context.
81 changes: 49 additions & 32 deletions test/python/pulse/test_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ def test_append_schedule_parameter_scope(self):
with pulse.build() as sched_z1:
builder.append_schedule(sched_y1)

sched_param = next(iter(sched_z1.scoped_parameters()))
with self.assertWarns(DeprecationWarning):
sched_param = next(iter(sched_z1.scoped_parameters()))
self.assertEqual(sched_param.name, "root::name")

# object equality
self.assertEqual(
sched_z1.search_parameters("root::name")[0],
param,
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
sched_z1.search_parameters("root::name")[0],
param,
)

def test_refer_schedule(self):
"""Test refer to schedule by name.
Expand Down Expand Up @@ -108,20 +110,23 @@ def test_refer_schedule_parameter_scope(self):
sched_y1.assign_references({("x1", "d0"): sched_x1})
sched_z1.assign_references({("y1", "d0"): sched_y1})

sched_param = next(iter(sched_z1.scoped_parameters()))
with self.assertWarns(DeprecationWarning):
sched_param = next(iter(sched_z1.scoped_parameters()))
self.assertEqual(sched_param.name, "root::y1,d0::x1,d0::name")

# object equality
self.assertEqual(
sched_z1.search_parameters("root::y1,d0::x1,d0::name")[0],
param,
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
sched_z1.search_parameters("root::y1,d0::x1,d0::name")[0],
param,
)

# regex
self.assertEqual(
sched_z1.search_parameters(r"\S::x1,d0::name")[0],
param,
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
sched_z1.search_parameters(r"\S::x1,d0::name")[0],
param,
)

def test_call_schedule(self):
"""Test call schedule.
Expand Down Expand Up @@ -160,20 +165,23 @@ def test_call_schedule_parameter_scope(self):
with pulse.build() as sched_z1:
builder.call(sched_y1, name="y1")

sched_param = next(iter(sched_z1.scoped_parameters()))
with self.assertWarns(DeprecationWarning):
sched_param = next(iter(sched_z1.scoped_parameters()))
self.assertEqual(sched_param.name, "root::y1::x1::name")

# object equality
self.assertEqual(
sched_z1.search_parameters("root::y1::x1::name")[0],
param,
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
sched_z1.search_parameters("root::y1::x1::name")[0],
param,
)

# regex
self.assertEqual(
sched_z1.search_parameters(r"\S::x1::name")[0],
param,
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
sched_z1.search_parameters(r"\S::x1::name")[0],
param,
)

def test_append_and_call_schedule(self):
"""Test call and append schedule.
Expand Down Expand Up @@ -368,7 +376,8 @@ def test_special_parameter_name(self):
pulse.reference("sub", "q0")
sched_y1.assign_references({("sub", "q0"): sched_x1})

ret_param = sched_y1.search_parameters(r"\Ssub,q0::my.parameter_object")[0]
with self.assertWarns(DeprecationWarning):
ret_param = sched_y1.search_parameters(r"\Ssub,q0::my.parameter_object")[0]

self.assertEqual(param, ret_param)

Expand All @@ -392,10 +401,13 @@ def test_parameter_in_multiple_scope(self):
pulse.call(sched_y1, name="y1")

self.assertEqual(len(sched_z1.parameters), 1)
self.assertEqual(len(sched_z1.scoped_parameters()), 2)
with self.assertWarns(DeprecationWarning):
self.assertEqual(len(sched_z1.scoped_parameters()), 2)

self.assertEqual(sched_z1.search_parameters("root::x1::name")[0], param)
self.assertEqual(sched_z1.search_parameters("root::y1::name")[0], param)
with self.assertWarns(DeprecationWarning):
self.assertEqual(sched_z1.search_parameters("root::x1::name")[0], param)
with self.assertWarns(DeprecationWarning):
self.assertEqual(sched_z1.search_parameters("root::y1::name")[0], param)

def test_parallel_alignment_equality(self):
"""Testcase for potential edge case.
Expand Down Expand Up @@ -558,7 +570,8 @@ def test_lazy_ecr(self):
self.assertSetEqual(params, {"cr"})

# Parameter names are scoepd
scoped_params = {p.name for p in sched.scoped_parameters()}
with self.assertWarns(DeprecationWarning):
scoped_params = {p.name for p in sched.scoped_parameters()}
self.assertSetEqual(scoped_params, {"root::cr"})

# Assign CR and XP schedule to the empty reference
Expand All @@ -571,7 +584,8 @@ def test_lazy_ecr(self):
self.assertEqual(assigned_refs[("xp", "q0")], self.xp_sched)

# Parameter added from subroutines
scoped_params = {p.name for p in sched.scoped_parameters()}
with self.assertWarns(DeprecationWarning):
scoped_params = {p.name for p in sched.scoped_parameters()}
ref_params = {
# This is the cr parameter that belongs to phase_offset instruction in the root scope
"root::cr",
Expand All @@ -594,7 +608,8 @@ def test_lazy_ecr(self):
self.assertEqual(len(params), 2)

# Get parameter with scope, only xp amp
params = sched.search_parameters(parameter_regex="root::xp,q0::amp")
with self.assertWarns(DeprecationWarning):
params = sched.search_parameters(parameter_regex="root::xp,q0::amp")
self.assertEqual(len(params), 1)

def test_cnot(self):
Expand All @@ -614,11 +629,13 @@ def test_cnot(self):
pulse.call(ecr_sched, name="ecr")

# get parameter with scope, full scope is not needed
xp_amp = cx_sched.search_parameters(r"\S:xp::amp")[0]
with self.assertWarns(DeprecationWarning):
xp_amp = cx_sched.search_parameters(r"\S:xp::amp")[0]
self.assertEqual(self.xp_amp, xp_amp)

# get parameter with scope, of course full scope can be specified
xp_amp_full_scoped = cx_sched.search_parameters("root::ecr::xp::amp")[0]
with self.assertWarns(DeprecationWarning):
xp_amp_full_scoped = cx_sched.search_parameters("root::ecr::xp::amp")[0]
self.assertEqual(xp_amp_full_scoped, xp_amp)

# assign parameters
Expand Down
Loading