From 988a179a67ab6a92bce7e471cd4add6b5180fa8b Mon Sep 17 00:00:00 2001 From: Naoki Kanazawa Date: Tue, 31 Jan 2023 14:01:11 +0900 Subject: [PATCH] Manage edge case of pickling instmap. --- qiskit/pulse/calibration_entries.py | 7 ++++++ ...p-add-with-arguments-250de2a7960565dc.yaml | 12 +++++++++ .../pulse/test_instruction_schedule_map.py | 25 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 releasenotes/notes/fix-instmap-add-with-arguments-250de2a7960565dc.yaml diff --git a/qiskit/pulse/calibration_entries.py b/qiskit/pulse/calibration_entries.py index c2f991936e10..78b8598f6055 100644 --- a/qiskit/pulse/calibration_entries.py +++ b/qiskit/pulse/calibration_entries.py @@ -78,7 +78,14 @@ def __init__(self, arguments: Optional[Sequence[str]] = None): Args: arguments: User provided argument names for this entry, if parameterized. + + Raises: + PulseError: When `arguments` is not a sequence of string. """ + if arguments and not all(isinstance(arg, str) for arg in arguments): + raise PulseError(f"Arguments must be name of parameters. Not {arguments}.") + if arguments: + arguments = list(arguments) self._user_arguments = arguments self._definition = None diff --git a/releasenotes/notes/fix-instmap-add-with-arguments-250de2a7960565dc.yaml b/releasenotes/notes/fix-instmap-add-with-arguments-250de2a7960565dc.yaml new file mode 100644 index 000000000000..929c6296e9da --- /dev/null +++ b/releasenotes/notes/fix-instmap-add-with-arguments-250de2a7960565dc.yaml @@ -0,0 +1,12 @@ +--- +fixes: + - | + An edge case of pickle :class:`.InstructionScheduleMap` with + non-picklable iterable ``arguments`` is supported. + When :meth:`InstructionScheduleMap.add` is called with + ``arguments``, this method typecasts the user value to a python list + to guarantee the added entry is picklable. + For example, a user may supply a python dict keys as ``arguments``. + This also guarantees parallel transpile works with such a custom + instruction schedule map, where the map object is pickled and + distributed to every parallel threads. diff --git a/test/python/pulse/test_instruction_schedule_map.py b/test/python/pulse/test_instruction_schedule_map.py index c7091a89e25c..1179b805f3dd 100644 --- a/test/python/pulse/test_instruction_schedule_map.py +++ b/test/python/pulse/test_instruction_schedule_map.py @@ -551,6 +551,31 @@ def test_instmap_picklable(self): self.assertEqual(instmap, deser_instmap) + def test_instmap_picklable_with_arguments(self): + """Test instmap pickling with an edge case. + + This test attempts to pickle instmap with custom entry, + in which arguments are provided by users in the form of + python dict key object that is not picklable. + """ + instmap = FakeAthens().defaults().instruction_schedule_map + + param1 = Parameter("P1") + param2 = Parameter("P2") + sched = Schedule() + sched.insert(0, Play(Constant(100, param1), DriveChannel(0)), inplace=True) + sched.insert(0, Play(Constant(100, param2), DriveChannel(1)), inplace=True) + to_assign = {"P1": 0.1, "P2": 0.2} + + # Note that dict keys is not picklable + # Instmap should typecast it into list to pickle itself. + instmap.add("custom", (0, 1), sched, arguments=to_assign.keys()) + + ser_obj = pickle.dumps(instmap) + deser_instmap = pickle.loads(ser_obj) + + self.assertEqual(instmap, deser_instmap) + def test_check_backend_provider_cals(self): """Test if schedules provided by backend provider is distinguishable.""" instmap = FakeOpenPulse2Q().defaults().instruction_schedule_map