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

ParameterVector support for pulse parameter assignment #12045

Merged
merged 24 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fc3bd83
Added test and release notes update
arthurostrauss Dec 10, 2023
436f86b
Reformatting
arthurostrauss Dec 12, 2023
50bdf28
Added test and release notes update
arthurostrauss Dec 10, 2023
0e8619a
Reformatting
arthurostrauss Dec 12, 2023
269f7a7
Merge branch 'main' of https://github.com/arthurostrauss/qiskit
arthurostrauss Mar 20, 2024
5c0bf9b
Added compatibility of pulse ParameterManager with ParameterVector
arthurostrauss Mar 20, 2024
c754ff2
Commit requested changes
arthurostrauss Mar 21, 2024
0d91204
Update pulse_parameter_manager_compat_with_ParameterVector-7d31395fd4…
arthurostrauss Mar 21, 2024
a6f9de7
Added tests for Schedule and case of mix Parameter+numeric values
arthurostrauss Mar 21, 2024
7e9b724
Corrected error for schedule test
arthurostrauss Mar 22, 2024
a8098f9
Correction to test schedule
arthurostrauss Mar 22, 2024
a221faf
Added test and release notes update
arthurostrauss Dec 10, 2023
9b5730f
Reformatting
arthurostrauss Dec 12, 2023
7b4b031
Added test and release notes update
arthurostrauss Dec 10, 2023
6713579
Reformatting
arthurostrauss Dec 12, 2023
d705d24
Added compatibility of pulse ParameterManager with ParameterVector
arthurostrauss Mar 20, 2024
27f91cc
Commit requested changes
arthurostrauss Mar 21, 2024
bf91f02
Update pulse_parameter_manager_compat_with_ParameterVector-7d31395fd4…
arthurostrauss Mar 21, 2024
d3dddda
Added tests for Schedule and case of mix Parameter+numeric values
arthurostrauss Mar 21, 2024
35f2fb9
Corrected error for schedule test
arthurostrauss Mar 22, 2024
69cf343
Correction to test schedule
arthurostrauss Mar 22, 2024
c8c3b82
Merge branch 'ParameterVector_pulse' of https://github.com/arthurostr…
arthurostrauss Mar 22, 2024
b398844
Update releasenotes/notes/pulse_parameter_manager_compat_with_Paramet…
arthurostrauss Mar 22, 2024
2b3541f
Merge branch 'main' into ParameterVector_pulse
arthurostrauss Mar 23, 2024
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
47 changes: 44 additions & 3 deletions qiskit/pulse/parameter_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@
"""
from __future__ import annotations
from copy import copy
from typing import Any
from typing import Any, Mapping

from qiskit.circuit import ParameterVector
from qiskit.circuit.parameter import Parameter
from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
from qiskit.pulse import instructions, channels
Expand Down Expand Up @@ -360,7 +361,9 @@ def get_parameters(self, parameter_name: str) -> list[Parameter]:
def assign_parameters(
self,
pulse_program: Any,
value_dict: dict[ParameterExpression, ParameterValueType],
value_dict: dict[
ParameterExpression | ParameterVector, ParameterValueType | list[ParameterValueType]
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
],
) -> Any:
"""Modify and return program data with parameters assigned according to the input.

Expand All @@ -372,7 +375,10 @@ def assign_parameters(
Returns:
Updated program data.
"""
valid_map = {k: value_dict[k] for k in value_dict.keys() & self._parameters}
unrolled_value_dict = self._unroll_param_dict(value_dict)
valid_map = {
k: unrolled_value_dict[k] for k in unrolled_value_dict.keys() & self._parameters
}
if valid_map:
visitor = ParameterSetter(param_map=valid_map)
return visitor.visit(pulse_program)
Expand All @@ -387,3 +393,38 @@ def update_parameter_table(self, new_node: Any):
visitor = ParameterGetter()
visitor.visit(new_node)
self._parameters |= visitor.parameters

def _unroll_param_dict(
self,
parameter_binds: Mapping[
Parameter | ParameterVector, ParameterValueType | list[ParameterValueType]
],
) -> Mapping[Parameter, ParameterValueType]:
"""
Unroll parameter dictionary to a map from parameter to value.

Args:
parameter_binds: A dictionary from parameter to value or a list of values.

Returns:
A dictionary from parameter to value.
"""
out = {}
for parameter, value in parameter_binds.items():
if isinstance(parameter, ParameterVector):
if not isinstance(value, (list, tuple)):
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
raise PulseError(
f"Parameter vector '{parameter.name}' has length {len(parameter)},"
f" but was assigned to a single value."
)
if len(parameter) != len(value):
raise PulseError(
f"Parameter vector '{parameter.name}' has length {len(parameter)},"
f" but was assigned to {len(value)} values."
)
out.update(zip(parameter, value))
elif isinstance(parameter, str):
out[self.get_parameters(parameter)] = value
else:
out[parameter] = value
return out
21 changes: 15 additions & 6 deletions qiskit/pulse/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import numpy as np
import rustworkx as rx

from qiskit.circuit import ParameterVector
from qiskit.circuit.parameter import Parameter
from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
from qiskit.pulse.channels import Channel
Expand Down Expand Up @@ -711,13 +712,18 @@ def is_parameterized(self) -> bool:
return self._parameter_manager.is_parameterized()

def assign_parameters(
self, value_dict: dict[ParameterExpression, ParameterValueType], inplace: bool = True
self,
value_dict: dict[
ParameterExpression | ParameterVector, ParameterValueType | list[ParameterValueType]
],
inplace: bool = True,
) -> "Schedule":
"""Assign the parameters in this schedule according to the input.

Args:
value_dict: A mapping from Parameters to either numeric values or another
Parameter expression.
value_dict: A mapping from Parameters (ParameterVectors) to either
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
numeric values (list of numeric values)
or another Parameter expression (list of Parameter expressions).
inplace: Set ``True`` to override this instance with new parameter.

Returns:
Expand Down Expand Up @@ -1408,14 +1414,17 @@ def is_referenced(self) -> bool:

def assign_parameters(
self,
value_dict: dict[ParameterExpression, ParameterValueType],
value_dict: dict[
ParameterExpression | ParameterVector, ParameterValueType | list[ParameterValueType]
],
inplace: bool = True,
) -> "ScheduleBlock":
"""Assign the parameters in this schedule according to the input.

Args:
value_dict: A mapping from Parameters to either numeric values or another
Parameter expression.
value_dict: A mapping from Parameters (ParameterVectors) to either numeric values
(list of numeric values)
or another Parameter expression (list of Parameter expression).
inplace: Set ``True`` to override this instance with new parameter.

Returns:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
prelude: >
Compatibility of pulse parameter assignment with `ParameterVector` class.
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
features:
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
- |
The `ParameterManager` now supports the `ParameterVector` class. This enables
the use of `ParameterVector` in pulse `Schedule`and `ScheduleBlock` objects when using their method
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved
`assign_parameters` to assign simultaneously a list of parameter values.
- |
An additional method `_unroll_param_dict`has been added to the `ParameterManager` class to unroll the
parameter dictionary into a list of parameter values. This method is used to convert the parameter dictionary
into a list of parameter values when using the `ParameterVector` class. This method is a replication of the
analogous method `_unroll_param_dict` in `QuantumCircuit` class.
arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved

18 changes: 17 additions & 1 deletion test/python/pulse/test_parameter_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import numpy as np

from qiskit import pulse
from qiskit.circuit import Parameter
from qiskit.circuit import Parameter, ParameterVector
from qiskit.pulse.exceptions import PulseError, UnassignedDurationError
from qiskit.pulse.parameter_manager import ParameterGetter, ParameterSetter
from qiskit.pulse.transforms import AlignEquispaced, AlignLeft, inline_subroutines
Expand Down Expand Up @@ -483,6 +483,22 @@ def test_parametric_pulses(self):
self.assertEqual(block.blocks[0].pulse.amp, 0.2)
self.assertEqual(block.blocks[0].pulse.sigma, 4.0)

def test_parametric_pulses_with_parameter_vector(self):
"""Test Parametric Pulses with parameters determined by a ParameterVector
in the Play instruction."""
param_vec = ParameterVector("param_vec", 3)

waveform = pulse.library.Gaussian(duration=128, sigma=param_vec[0], amp=param_vec[1])

block = pulse.ScheduleBlock()
block += pulse.Play(waveform, pulse.DriveChannel(10))
block += pulse.ShiftPhase(param_vec[2], pulse.DriveChannel(10))
block.assign_parameters({param_vec: [4, 0.2, 0.1]}, inplace=True)

self.assertEqual(block.blocks[0].pulse.amp, 0.2)
self.assertEqual(block.blocks[0].pulse.sigma, 4.0)
self.assertEqual(block.blocks[1].phase, 0.1)

arthurostrauss marked this conversation as resolved.
Show resolved Hide resolved

class TestScheduleTimeslots(QiskitTestCase):
"""Test for edge cases of timing overlap on parametrized channels.
Expand Down
Loading