From 0a7de31f22db7f9a353f00721cbaad22d491b991 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Thu, 17 Mar 2022 15:11:33 +0100 Subject: [PATCH 01/18] * Added the following consistency fixes for Calibrations: - check consistency between coupling map and control channel map - made date times as time zone - added qubits arg to update inst map - fixed issue with qubits in update_inst_map --- .../calibration_management/calibrations.py | 42 +++++++++++---- .../calibration_management/parameter_value.py | 2 + test/calibration/test_calibrations.py | 52 +++++++++++++++++-- 3 files changed, 81 insertions(+), 15 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 8949609a80..ddb94f1dd0 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -96,7 +96,8 @@ def __init__( qubits is :code:`[[0, 1], [1, 0], [1, 2], [2, 1], [2, 0], [0, 2]]`. control_channel_map: A configuration dictionary of any control channels. The keys are tuples of qubits and the values are a list of ControlChannels - that correspond to the qubits in the keys. + that correspond to the qubits in the keys. If a control_channel_map is given + then the qubits must be in the coupling_map. library: A library instance from which to get template schedules to register as well as default parameter values. add_parameter_defaults: A boolean to indicate weather the default parameter values of @@ -174,15 +175,32 @@ def __init__( self._register_parameter(self.meas_freq, ()) # Backends with a single qubit may not have a coupling map. - num_qubits = max(max(coupling_map)) + 1 if coupling_map is not None else 1 - - self._qubits = list(range(num_qubits)) - self._coupling_map = coupling_map + self._coupling_map = coupling_map or [] self._operated_qubits = self._get_operated_qubits() + self._check_consistency() # Push the schedules to the instruction schedule map. self.update_inst_map() + def _check_consistency(self): + """Check that the attributes defined in self are consistent. + + Raises: + CalibrationError: If there is a control channel map but no coupling map. + CalibrationError: If a qubit in the control channel map is not in the + coupling map. + """ + if not self._coupling_map and self._control_channel_map: + raise CalibrationError("No coupling map but a control channel map was found.") + + if self._coupling_map and self._control_channel_map: + cmap_qubits = set(qubit for pair in self._coupling_map for qubit in pair) + for qubits in self._control_channel_map: + if not set(qubits).issubset(cmap_qubits): + raise CalibrationError( + f"Qubits {qubits} of control_channel_map are not in the coupling map." + ) + @property def backend_name(self) -> str: """Return the name of the backend.""" @@ -268,8 +286,12 @@ def _get_operated_qubits(self) -> Dict[int, List[int]]: operated_qubits = defaultdict(list) # Single qubits - for qubit in self._qubits: - operated_qubits[1].append([qubit]) + if self._coupling_map: + for qubit in set(qubit for coupled in self._coupling_map for qubit in coupled): + operated_qubits[1].append([qubit]) + else: + # Edge case for single-qubit device. + operated_qubits[1].append([0]) # Multi-qubit couplings if self._coupling_map is not None: @@ -353,7 +375,7 @@ def update_inst_map( if schedules is not None and sched_name not in schedules: continue - if qubits is not None: + if qubits: self._robust_inst_map_add(inst_map, sched_name, qubits, group, cutoff_date) else: for qubits_ in self._operated_qubits[self._schedules_qubits[key]]: @@ -770,7 +792,7 @@ def add_parameter_value( if update_inst_map and schedule is not None: param_obj = self.calibration_parameter(param_name, qubits, sched_name) schedules = set(key.schedule for key in self._parameter_map_r[param_obj]) - self.update_inst_map(schedules) + self.update_inst_map(schedules, qubits=qubits) def _get_channel_index(self, qubits: Tuple[int, ...], chan: PulseChannel) -> int: """Get the index of the parameterized channel. @@ -816,7 +838,7 @@ def _get_channel_index(self, qubits: Tuple[int, ...], chan: PulseChannel) -> int indices = [int(sub_channel) for sub_channel in qubit_channels.split(".")] ch_qubits = tuple(qubits[index] for index in indices) - chs_ = self._control_channel_map[ch_qubits] + chs_ = self._control_channel_map.get(ch_qubits, []) control_index = 0 if len(channel_index_parts) == 2: diff --git a/qiskit_experiments/calibration_management/parameter_value.py b/qiskit_experiments/calibration_management/parameter_value.py index ed28373c0c..06685c2012 100644 --- a/qiskit_experiments/calibration_management/parameter_value.py +++ b/qiskit_experiments/calibration_management/parameter_value.py @@ -69,6 +69,8 @@ def __post_init__(self): f"Cannot parse {self.date_time} in either of {formats} formats." ) + self.date_time = self.date_time.astimezone() + if not isinstance(self.value, (int, float, complex)): raise CalibrationError(f"Values {self.value} must be int, float or complex.") diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index 111a322d9f..9da9b1c010 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -116,6 +116,20 @@ def test_setup(self): self.assertEqual(self.cals.get_parameter_value("amp", 3, "x90p"), 0.1) self.assertEqual(self.cals.get_parameter_value("amp", 3, "y90p"), 0.08) + def test_improper_setup(self): + """Check that an error is raised when coupling map and control channel map do not match.""" + controls = { + (3, 2): [ControlChannel(10), ControlChannel(123)], + (2, 3): [ControlChannel(15), ControlChannel(23)], + } + coupling_map = [[0, 1], [1, 0]] + + with self.assertRaises(CalibrationError): + Calibrations(coupling_map=coupling_map, control_channel_map=controls) + + with self.assertRaises(CalibrationError): + Calibrations(control_channel_map=controls) + def test_preserve_template(self): """Test that the template schedule is still fully parametric after we get a schedule.""" @@ -774,7 +788,8 @@ def setUp(self): (3, 2): [ControlChannel(10), ControlChannel(123)], (2, 3): [ControlChannel(15), ControlChannel(23)], } - self.cals = Calibrations(control_channel_map=controls) + coupling_map = [[0, 1], [1, 0], [1, 2], [2, 1], [2, 3], [3, 2]] + self.cals = Calibrations(coupling_map=coupling_map, control_channel_map=controls) self.amp_cr = Parameter("amp") self.amp_rot = Parameter("amp_rot") @@ -894,6 +909,33 @@ def test_single_control_channel(self): self.assertEqual(self.cals.get_schedule("tcp", (3, 2)), expected) + def test_inst_map_stays_consistent(self): + """Check that get schedule and inst map are in sync in a complex ECR case. + + This needs to be in a subclass of CrossResonanceTest. Note, that this test + will fail if the coupling_map and the control_channel_map are not consistent + with each other. This is because the coupling_map is used to build the + _operated_qubits variable which determines the qubits of the instruction to + which a schedule is associated. + """ + + # Check that the ECR schedules from get_schedule and the instmap are the same + sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) + self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2,3))) + + # Ensure that sigma is 40 + insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions + self.assertEqual(insts[0][1].pulse.sigma, 40) + + # Update sigma to 5 and check that change is propagated through. + date_time2 = datetime.strptime("15/09/19 10:22:35", "%d/%m/%y %H:%M:%S") + self.cals.add_parameter_value(ParameterValue(5, date_time2), "σ", schedule="xp") + + sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) + self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2,3))) + insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions + self.assertEqual(insts[0][1].pulse.sigma, 5) + class TestAssignment(QiskitExperimentsTestCase): """Test simple assignment""" @@ -903,8 +945,8 @@ def setUp(self): super().setUp() controls = {(3, 2): [ControlChannel(10)]} - - self.cals = Calibrations(control_channel_map=controls) + coupling_map = [[2, 3], [3, 2]] + self.cals = Calibrations(coupling_map=coupling_map, control_channel_map=controls) self.amp_xp = Parameter("amp") self.ch0 = Parameter("ch0") @@ -1109,8 +1151,8 @@ def setUp(self): super().setUp() controls = {(3, 2): [ControlChannel(10)]} - - self.cals = Calibrations(control_channel_map=controls) + coupling_map = [[2, 3], [3, 2]] + self.cals = Calibrations(coupling_map=coupling_map, control_channel_map=controls) self.amp_cr = Parameter("amp") self.amp_xp = Parameter("amp") From 558c5ea4074609e2f9e460652e893439de810796 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Thu, 17 Mar 2022 18:23:52 +0100 Subject: [PATCH 02/18] * Extra timezone fix and black --- qiskit_experiments/calibration_management/calibrations.py | 1 + test/calibration/test_calibrations.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index ddb94f1dd0..ceb6251252 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -932,6 +932,7 @@ def get_parameter_value( candidates = [val for val in candidates if val.group == group] if cutoff_date: + cutoff_date = cutoff_date.astimezone() candidates = [val for val in candidates if val.date_time <= cutoff_date] if len(candidates) == 0: diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index 9da9b1c010..3aed82f5e5 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -921,7 +921,7 @@ def test_inst_map_stays_consistent(self): # Check that the ECR schedules from get_schedule and the instmap are the same sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) - self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2,3))) + self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2, 3))) # Ensure that sigma is 40 insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions @@ -932,7 +932,7 @@ def test_inst_map_stays_consistent(self): self.cals.add_parameter_value(ParameterValue(5, date_time2), "σ", schedule="xp") sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) - self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2,3))) + self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2, 3))) insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions self.assertEqual(insts[0][1].pulse.sigma, 5) From d0695d68bc5d90c786e49b1e8a334b8ee4016742 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 21 Mar 2022 18:21:57 +0100 Subject: [PATCH 03/18] * Removed unneeded check. --- qiskit_experiments/calibration_management/calibrations.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index ceb6251252..6a114816d9 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -294,9 +294,8 @@ def _get_operated_qubits(self) -> Dict[int, List[int]]: operated_qubits[1].append([0]) # Multi-qubit couplings - if self._coupling_map is not None: - for coupling in self._coupling_map: - operated_qubits[len(coupling)].append(coupling) + for coupling in self._coupling_map: + operated_qubits[len(coupling)].append(coupling) return operated_qubits From eace06eeff7c9d09e923b77274c6b41369fe32ea Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 21 Mar 2022 18:28:35 +0100 Subject: [PATCH 04/18] * Added more robust test. --- test/calibration/test_calibrations.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index 3aed82f5e5..d1fb1d00a9 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -912,7 +912,9 @@ def test_single_control_channel(self): def test_inst_map_stays_consistent(self): """Check that get schedule and inst map are in sync in a complex ECR case. - This needs to be in a subclass of CrossResonanceTest. Note, that this test + Test that when a parameter value is updated for a parameter that is used in a + schedule nested inside a call instruction of an outer schedule that that outer + schedule is also updated in the instruction schedule map. For example, this test will fail if the coupling_map and the control_channel_map are not consistent with each other. This is because the coupling_map is used to build the _operated_qubits variable which determines the qubits of the instruction to @@ -925,16 +927,16 @@ def test_inst_map_stays_consistent(self): # Ensure that sigma is 40 insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions - self.assertEqual(insts[0][1].pulse.sigma, 40) + self.assertEqual(insts[0][1].pulse.amp, 0.15) # Update sigma to 5 and check that change is propagated through. date_time2 = datetime.strptime("15/09/19 10:22:35", "%d/%m/%y %H:%M:%S") - self.cals.add_parameter_value(ParameterValue(5, date_time2), "σ", schedule="xp") + self.cals.add_parameter_value(ParameterValue(0.25, date_time2), "amp", (2,), schedule="xp") sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2, 3))) insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions - self.assertEqual(insts[0][1].pulse.sigma, 5) + self.assertEqual(insts[0][1].pulse.amp, 0.25) class TestAssignment(QiskitExperimentsTestCase): From f3b76b9982f22e9079287de674149fa1068721dc Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 22 Mar 2022 10:56:17 +0100 Subject: [PATCH 05/18] * Added utility functions for Calibrations. * Added extra test. * Added methodology to deal with parameter updating in Calls. --- .../calibration_utils.py | 63 ++++++++++++++++ .../calibration_management/calibrations.py | 72 ++++++++++++++++--- test/calibration/test_calibration_utils.py | 66 +++++++++++++++++ test/calibration/test_calibrations.py | 8 +++ 4 files changed, 198 insertions(+), 11 deletions(-) create mode 100644 qiskit_experiments/calibration_management/calibration_utils.py create mode 100644 test/calibration/test_calibration_utils.py diff --git a/qiskit_experiments/calibration_management/calibration_utils.py b/qiskit_experiments/calibration_management/calibration_utils.py new file mode 100644 index 0000000000..90b1f8c7f4 --- /dev/null +++ b/qiskit_experiments/calibration_management/calibration_utils.py @@ -0,0 +1,63 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019-2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Calibration helper functions""" + +from typing import List, Set +from qiskit.pulse import ScheduleBlock, Call + + +class CalUtils: + """A collection of utility functions for for calibration management.""" + + @staticmethod + def used_in_calls(schedule_name: str, schedules: List[ScheduleBlock]) -> Set[str]: + """Find the schedules in the given list that call a given schedule by name. + + Args: + schedule_name: The name of the callee to identify. + schedules: A list of schedule over which to search. + + Returns: + A set of schedule names that call the given schedule. + """ + sub_routines = set() + + for schedule in schedules: + if CalUtils._used_in_calls(schedule_name, schedule): + sub_routines.add(schedule.name) + + return sub_routines + + @staticmethod + def _used_in_calls(schedule_name: str, schedule: ScheduleBlock): + """Recursively find if the schedule calls a schedule with name ``schedule_name``. + + Args: + schedule_name: The name of the callee to identify. + schedule: The schedule to parse. + """ + blocks_have_schedule = set() + + for block in schedule.blocks: + if isinstance(block, Call): + if block.subroutine.name == schedule_name: + blocks_have_schedule.add(True) + else: + blocks_have_schedule.add( + CalUtils._used_in_calls(schedule_name, block.subroutine) + ) + + if isinstance(block, ScheduleBlock): + blocks_have_schedule.add(CalUtils._used_in_calls(schedule_name, block)) + + return any(blocks_have_schedule) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 6a114816d9..c15d59a78b 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -43,6 +43,7 @@ from qiskit_experiments.calibration_management.basis_gate_library import BasisGateLibrary from qiskit_experiments.calibration_management.parameter_value import ParameterValue from qiskit_experiments.calibration_management.control_channel_map import ControlChannelMap +from qiskit_experiments.calibration_management.calibration_utils import CalUtils from qiskit_experiments.calibration_management.calibration_key_types import ( ParameterKey, ParameterValueType, @@ -176,6 +177,9 @@ def __init__( # Backends with a single qubit may not have a coupling map. self._coupling_map = coupling_map or [] + + # An dict extension of the coupling map where the key is the number of qubits and + # the values are a list of qubits coupled. self._operated_qubits = self._get_operated_qubits() self._check_consistency() @@ -392,23 +396,65 @@ def _robust_inst_map_add( get_schedule may raise an error if not all parameters have values or default values. In this case we ignore and continue updating inst_map. + Note that ``qubits`` may only be a sub-set of the qubits of the schedule that + we want to update. This may arise in cases such as an ECR gate schedule that calls + an X-gate schedule. When updating the X-gate schedule we need to also update the + corresponding ECR schedules which operate on a larger number of qubits. Args: sched_name: The name of the schedule. - qubits: The qubit to which the schedule applies. + qubits: The qubit to which the schedule applies. Note, these may be only a + subset of the qubits in the schedule. For example, if the name of the + schedule is `"cr"` we may have `qubits` be `(3, )` and this function + will update the CR schedules on all schedules which involve qubit 3. group: The calibration group. cutoff: The cutoff date. """ - try: - inst_map.add( - instruction=sched_name, - qubits=qubits, - schedule=self.get_schedule(sched_name, qubits, group=group, cutoff_date=cutoff), - ) - except CalibrationError: - # get_schedule may raise an error if not all parameters have values or - # default values. In this case we ignore and continue updating inst_map. - pass + for update_qubits in self._get_full_qubits_of_schedule(sched_name, qubits): + try: + schedule = self.get_schedule( + sched_name, update_qubits, group=group, cutoff_date=cutoff + ) + inst_map.add(instruction=sched_name, qubits=update_qubits, schedule=schedule) + except CalibrationError: + # get_schedule may raise an error if not all parameters have values or + # default values. In this case we ignore and continue updating inst_map. + pass + + def _get_full_qubits_of_schedule( + self, schedule_name: str, partial_qubits: Tuple[int, ...] + ) -> List[Tuple[int, ...]]: + """Find all qubits for which there is a schedule ``schedule_name`` on ``partial_qubits``. + + This method will uses the map between the schedules and the number of qubits that they + operate on as well as the extension of the coupling map ``_operated_qubits`` to find + which qubits are involved in the schedule named ``schedule_name`` involving the + ``partial_qubits``. + + Args: + schedule_name: The name of the schedule as registered in ``self``. + partial_qubits: A sub-set of qubits on which the schedule applies. + + Returns: + A list of tuples. Each tuple is the set of qubits for which there is a schedule + named ``schedule_name`` and ``partial_qubits`` is a sub-set of said qubits. + """ + for key, circuit_inst_num_qubits in self._schedules_qubits.items(): + if key.schedule == schedule_name: + + if len(partial_qubits) == circuit_inst_num_qubits: + return [partial_qubits] + + else: + candidates = self._operated_qubits[circuit_inst_num_qubits] + qubits_for_update = [] + for candidate_qubits in candidates: + if set(partial_qubits).issubset(set(candidate_qubits)): + qubits_for_update.append(tuple(candidate_qubits)) + + return qubits_for_update + + return [] def inst_map_add( self, @@ -791,6 +837,10 @@ def add_parameter_value( if update_inst_map and schedule is not None: param_obj = self.calibration_parameter(param_name, qubits, sched_name) schedules = set(key.schedule for key in self._parameter_map_r[param_obj]) + + # Find schedules that may call the schedule we want to update. + schedules.update(CalUtils.used_in_calls(sched_name, list(self._schedules.values()))) + self.update_inst_map(schedules, qubits=qubits) def _get_channel_index(self, qubits: Tuple[int, ...], chan: PulseChannel) -> int: diff --git a/test/calibration/test_calibration_utils.py b/test/calibration/test_calibration_utils.py new file mode 100644 index 0000000000..07c5724099 --- /dev/null +++ b/test/calibration/test_calibration_utils.py @@ -0,0 +1,66 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Class to test utility functions for calibrations.""" + +import qiskit.pulse as pulse + +from test.base import QiskitExperimentsTestCase +from qiskit_experiments.calibration_management.calibration_utils import CalUtils + + +class TestCalibrationUtils(QiskitExperimentsTestCase): + """Test the function in CalUtils.""" + + def test_used_in_calls(self): + """Test that we can identify schedules by name when calls are present.""" + + with pulse.build(name="xp") as xp: + pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(1)) + + with pulse.build(name="xp2") as xp2: + pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(1)) + + with pulse.build(name="call_xp") as xp_call: + pulse.call(xp) + + with pulse.build(name="call_call_xp") as xp_call_call: + pulse.play(pulse.Drag(160, 0.5, 40, 0.2), pulse.DriveChannel(1)) + pulse.call(xp_call) + + self.assertSetEqual(CalUtils.used_in_calls("xp", [xp_call]), {"call_xp"}) + self.assertSetEqual(CalUtils.used_in_calls("xp", [xp2]), set()) + self.assertSetEqual( + CalUtils.used_in_calls("xp", [xp_call, xp_call_call]), {"call_xp", "call_call_xp"} + ) + + with pulse.build(name="xp") as xp: + pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(2)) + + cr_tone_p = pulse.GaussianSquare(640, 0.2, 64, 500) + rotary_p = pulse.GaussianSquare(640, 0.1, 64, 500) + + cr_tone_m = pulse.GaussianSquare(640, -0.2, 64, 500) + rotary_m = pulse.GaussianSquare(640, -0.1, 64, 500) + + with pulse.build(name="cr") as cr: + with pulse.align_sequential(): + with pulse.align_left(): + pulse.play(rotary_p, pulse.DriveChannel(3)) # Rotary tone + pulse.play(cr_tone_p, pulse.ControlChannel(2)) # CR tone. + pulse.call(xp) + with pulse.align_left(): + pulse.play(rotary_m, pulse.DriveChannel(3)) + pulse.play(cr_tone_m, pulse.ControlChannel(2)) + pulse.call(xp) + + self.assertSetEqual(CalUtils.used_in_calls("xp", [cr]), {"cr"}) diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index d1fb1d00a9..00ce82ad1c 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -938,6 +938,14 @@ def test_inst_map_stays_consistent(self): insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions self.assertEqual(insts[0][1].pulse.amp, 0.25) + # Test linked parameters. + self.cals.add_parameter_value(ParameterValue(2, date_time2), "σ", (2,), schedule="xp") + + sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) + self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2, 3))) + insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions + self.assertEqual(insts[0][1].pulse.sigma, 2) + class TestAssignment(QiskitExperimentsTestCase): """Test simple assignment""" From 3a5953c9a9a275717553c26e42e03b3c4f4be2fc Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 22 Mar 2022 11:07:35 +0100 Subject: [PATCH 06/18] * Lint and docs. --- .../calibration_management/calibration_utils.py | 15 +++++++++------ .../calibration_management/calibrations.py | 2 +- test/calibration/test_calibration_utils.py | 3 +-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibration_utils.py b/qiskit_experiments/calibration_management/calibration_utils.py index 90b1f8c7f4..4fa5da1777 100644 --- a/qiskit_experiments/calibration_management/calibration_utils.py +++ b/qiskit_experiments/calibration_management/calibration_utils.py @@ -17,7 +17,7 @@ class CalUtils: - """A collection of utility functions for for calibration management.""" + """A collection of utility functions to help calibration management.""" @staticmethod def used_in_calls(schedule_name: str, schedules: List[ScheduleBlock]) -> Set[str]: @@ -25,26 +25,29 @@ def used_in_calls(schedule_name: str, schedules: List[ScheduleBlock]) -> Set[str Args: schedule_name: The name of the callee to identify. - schedules: A list of schedule over which to search. + schedules: A list of potential caller schedules to search. Returns: A set of schedule names that call the given schedule. """ - sub_routines = set() + caller_names = set() for schedule in schedules: if CalUtils._used_in_calls(schedule_name, schedule): - sub_routines.add(schedule.name) + caller_names.add(schedule.name) - return sub_routines + return caller_names @staticmethod - def _used_in_calls(schedule_name: str, schedule: ScheduleBlock): + def _used_in_calls(schedule_name: str, schedule: ScheduleBlock) -> bool: """Recursively find if the schedule calls a schedule with name ``schedule_name``. Args: schedule_name: The name of the callee to identify. schedule: The schedule to parse. + + Returns: + True if ``schedule``calls a ``ScheduleBlock`` with name ``schedule_name``. """ blocks_have_schedule = set() diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index c15d59a78b..fa77b2b433 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -178,7 +178,7 @@ def __init__( # Backends with a single qubit may not have a coupling map. self._coupling_map = coupling_map or [] - # An dict extension of the coupling map where the key is the number of qubits and + # A dict extension of the coupling map where the key is the number of qubits and # the values are a list of qubits coupled. self._operated_qubits = self._get_operated_qubits() self._check_consistency() diff --git a/test/calibration/test_calibration_utils.py b/test/calibration/test_calibration_utils.py index 07c5724099..a2c5595cfd 100644 --- a/test/calibration/test_calibration_utils.py +++ b/test/calibration/test_calibration_utils.py @@ -12,9 +12,8 @@ """Class to test utility functions for calibrations.""" -import qiskit.pulse as pulse - from test.base import QiskitExperimentsTestCase +import qiskit.pulse as pulse from qiskit_experiments.calibration_management.calibration_utils import CalUtils From 56a9b70080156bcf147227a3df0489eba9fbdc98 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 22 Mar 2022 11:20:23 +0100 Subject: [PATCH 07/18] * Require coupling map. --- .../calibration_management/calibrations.py | 4 ++-- test/calibration/test_calibrations.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index fa77b2b433..6046818b67 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -70,7 +70,7 @@ class Calibrations: def __init__( self, - coupling_map: Optional[List[List[int]]] = None, + coupling_map: List[List[int]], control_channel_map: Optional[Dict[Tuple[int, ...], List[ControlChannel]]] = None, library: Optional[Union[BasisGateLibrary, List[BasisGateLibrary]]] = None, add_parameter_defaults: bool = True, @@ -243,7 +243,7 @@ def from_backend( backend_name = None cals = Calibrations( - getattr(backend.configuration(), "coupling_map", None), + getattr(backend.configuration(), "coupling_map", []), getattr(backend.configuration(), "control_channels", None), library, add_parameter_defaults, diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index 00ce82ad1c..674100f61d 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -45,7 +45,7 @@ def setUp(self): """Create the setting to test.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.sigma = Parameter("σ") self.amp_xp = Parameter("amp") @@ -128,7 +128,7 @@ def test_improper_setup(self): Calibrations(coupling_map=coupling_map, control_channel_map=controls) with self.assertRaises(CalibrationError): - Calibrations(control_channel_map=controls) + Calibrations(coupling_map=[], control_channel_map=controls) def test_preserve_template(self): """Test that the template schedule is still fully parametric after we get a schedule.""" @@ -282,7 +282,7 @@ def setUp(self): """Create the setting to test.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.sigma = Parameter("σ") self.amp_xp = Parameter("amp") @@ -475,7 +475,7 @@ def test_concurrent_values(self): Ensure that if the max time has multiple entries we take the most recent appended one. """ - cals = Calibrations() + cals = Calibrations(coupling_map=[]) amp = Parameter("amp") ch0 = Parameter("ch0") @@ -536,7 +536,7 @@ def setUp(self): pulse.call(xp, value_dict={ch0: ch1}) pulse.call(meas, value_dict={ch0: ch1}) - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.cals.add_schedule(meas, num_qubits=1) self.cals.add_schedule(xp, num_qubits=1) self.cals.add_schedule(xp_meas, num_qubits=1) @@ -675,7 +675,7 @@ def setUp(self): pulse.call(xp) pulse.call(xp12) - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.cals.add_schedule(xp, num_qubits=1) self.cals.add_schedule(xp12, num_qubits=1) self.cals.add_schedule(xp02, num_qubits=1) @@ -711,7 +711,7 @@ def setUp(self): """Create the setting to test.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.d0_ = DriveChannel(Parameter("ch0")) def test_call_registering(self): @@ -1107,7 +1107,7 @@ def setUp(self): """Create the setting to test.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.amp = Parameter("amp") self.dur = Parameter("duration") @@ -1311,7 +1311,7 @@ def setUp(self): """Setup a calibration.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.sigma = Parameter("σ") self.amp = Parameter("amp") From fc39a1b8670c277be137e0309caf05190757478b Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 22 Mar 2022 11:28:22 +0100 Subject: [PATCH 08/18] * Test fix. --- test/calibration/test_base_calibration_experiment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/calibration/test_base_calibration_experiment.py b/test/calibration/test_base_calibration_experiment.py index fbb57218a8..030bf49e7e 100644 --- a/test/calibration/test_base_calibration_experiment.py +++ b/test/calibration/test_base_calibration_experiment.py @@ -32,7 +32,7 @@ class CorrectOrder(BaseCalibrationExperiment, QubitSpectroscopy): def __init__(self): """A dummy class for parent order testing.""" - super().__init__(Calibrations(), 0, [0, 1, 2]) + super().__init__(Calibrations(coupling_map=[]), 0, [0, 1, 2]) CorrectOrder() @@ -44,4 +44,4 @@ class WrongOrder(QubitSpectroscopy, BaseCalibrationExperiment): def __init__(self): """A dummy class for parent order testing.""" - super().__init__(Calibrations(), 0, [0, 1, 2]) + super().__init__(Calibrations(coupling_map=[]), 0, [0, 1, 2]) From d804a1b9a73dfc69f2557d1a7ba7b8ad2d168162 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 22 Mar 2022 11:48:09 +0100 Subject: [PATCH 09/18] * Lint. --- test/calibration/test_update_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/calibration/test_update_library.py b/test/calibration/test_update_library.py index ab31018a6a..51d1deb50a 100644 --- a/test/calibration/test_update_library.py +++ b/test/calibration/test_update_library.py @@ -31,7 +31,7 @@ class TestAmplitudeUpdate(QiskitExperimentsTestCase): def setUp(self): """Setup amplitude values.""" super().setUp() - self.cals = Calibrations() + self.cals = Calibrations(coupling_map=[]) self.qubit = 1 axp = Parameter("amp") From 84be06d4e7ae32f03e51930e782b048c84663a9c Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 28 Mar 2022 09:18:01 +0200 Subject: [PATCH 10/18] * Type hint. --- qiskit_experiments/calibration_management/calibrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 6046818b67..88a3adc65a 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -70,7 +70,7 @@ class Calibrations: def __init__( self, - coupling_map: List[List[int]], + coupling_map: Optional[List[List[int]]] = None, control_channel_map: Optional[Dict[Tuple[int, ...], List[ControlChannel]]] = None, library: Optional[Union[BasisGateLibrary, List[BasisGateLibrary]]] = None, add_parameter_defaults: bool = True, From 54c0a68b608fbb3d2de688a153dad02243d06bd5 Mon Sep 17 00:00:00 2001 From: "Daniel J. Egger" <38065505+eggerdj@users.noreply.github.com> Date: Mon, 28 Mar 2022 09:18:45 +0200 Subject: [PATCH 11/18] Update qiskit_experiments/calibration_management/calibrations.py Co-authored-by: Will Shanks --- qiskit_experiments/calibration_management/calibrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 88a3adc65a..229059296a 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -176,7 +176,7 @@ def __init__( self._register_parameter(self.meas_freq, ()) # Backends with a single qubit may not have a coupling map. - self._coupling_map = coupling_map or [] + self._coupling_map = coupling_map if coupling_map is not None else [] # A dict extension of the coupling map where the key is the number of qubits and # the values are a list of qubits coupled. From 66df2fa2292d62c013f82b82565eded50923b2c9 Mon Sep 17 00:00:00 2001 From: "Daniel J. Egger" <38065505+eggerdj@users.noreply.github.com> Date: Mon, 28 Mar 2022 09:20:40 +0200 Subject: [PATCH 12/18] Update qiskit_experiments/calibration_management/calibrations.py Co-authored-by: Will Shanks --- qiskit_experiments/calibration_management/calibrations.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 229059296a..33061c8373 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -291,8 +291,7 @@ def _get_operated_qubits(self) -> Dict[int, List[int]]: # Single qubits if self._coupling_map: - for qubit in set(qubit for coupled in self._coupling_map for qubit in coupled): - operated_qubits[1].append([qubit]) + operated_qubits[1] = sorted(set(qubit for coupled in self._coupling_map for qubit in coupled)) else: # Edge case for single-qubit device. operated_qubits[1].append([0]) From 7b835d8700b19d8444e2290c0a21e5b1be20c505 Mon Sep 17 00:00:00 2001 From: "Daniel J. Egger" <38065505+eggerdj@users.noreply.github.com> Date: Mon, 28 Mar 2022 09:20:51 +0200 Subject: [PATCH 13/18] Update qiskit_experiments/calibration_management/calibrations.py Co-authored-by: Will Shanks --- qiskit_experiments/calibration_management/calibrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 33061c8373..5bcc6aca21 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -425,7 +425,7 @@ def _get_full_qubits_of_schedule( ) -> List[Tuple[int, ...]]: """Find all qubits for which there is a schedule ``schedule_name`` on ``partial_qubits``. - This method will uses the map between the schedules and the number of qubits that they + This method uses the map between the schedules and the number of qubits that they operate on as well as the extension of the coupling map ``_operated_qubits`` to find which qubits are involved in the schedule named ``schedule_name`` involving the ``partial_qubits``. From aacba9a665a7b8c07b451674732b15c54aab8586 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 28 Mar 2022 09:28:30 +0200 Subject: [PATCH 14/18] * Reverted commit 66df2fa --- qiskit_experiments/calibration_management/calibrations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index 5bcc6aca21..d03857859b 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -291,7 +291,8 @@ def _get_operated_qubits(self) -> Dict[int, List[int]]: # Single qubits if self._coupling_map: - operated_qubits[1] = sorted(set(qubit for coupled in self._coupling_map for qubit in coupled)) + for qubit in set(qubit for coupled in self._coupling_map for qubit in coupled): + operated_qubits[1].append([qubit]) else: # Edge case for single-qubit device. operated_qubits[1].append([0]) From 29bd57f8777bac88928960b2f92b8d6499b96d7d Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 28 Mar 2022 11:13:38 +0200 Subject: [PATCH 15/18] * Return value for CalibrationUtils. --- qiskit_experiments/calibration_management/calibration_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/calibration_management/calibration_utils.py b/qiskit_experiments/calibration_management/calibration_utils.py index 4fa5da1777..7f5ffe7998 100644 --- a/qiskit_experiments/calibration_management/calibration_utils.py +++ b/qiskit_experiments/calibration_management/calibration_utils.py @@ -54,7 +54,7 @@ def _used_in_calls(schedule_name: str, schedule: ScheduleBlock) -> bool: for block in schedule.blocks: if isinstance(block, Call): if block.subroutine.name == schedule_name: - blocks_have_schedule.add(True) + return True else: blocks_have_schedule.add( CalUtils._used_in_calls(schedule_name, block.subroutine) From a26b5b76c9608eb604399c5f4441c0003672773d Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 28 Mar 2022 16:31:18 +0200 Subject: [PATCH 16/18] * Refactor of internals of _used_in_calls --- .../calibration_management/calibration_utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibration_utils.py b/qiskit_experiments/calibration_management/calibration_utils.py index 7f5ffe7998..18e43d7c9e 100644 --- a/qiskit_experiments/calibration_management/calibration_utils.py +++ b/qiskit_experiments/calibration_management/calibration_utils.py @@ -49,18 +49,20 @@ def _used_in_calls(schedule_name: str, schedule: ScheduleBlock) -> bool: Returns: True if ``schedule``calls a ``ScheduleBlock`` with name ``schedule_name``. """ - blocks_have_schedule = set() + blocks_have_schedule = False for block in schedule.blocks: if isinstance(block, Call): if block.subroutine.name == schedule_name: return True else: - blocks_have_schedule.add( - CalUtils._used_in_calls(schedule_name, block.subroutine) + blocks_have_schedule = blocks_have_schedule or CalUtils._used_in_calls( + schedule_name, block.subroutine ) if isinstance(block, ScheduleBlock): - blocks_have_schedule.add(CalUtils._used_in_calls(schedule_name, block)) + blocks_have_schedule = blocks_have_schedule or CalUtils._used_in_calls( + schedule_name, block + ) - return any(blocks_have_schedule) + return blocks_have_schedule From d48dd49779bc7e3131afc7cb31fc10b7ed455679 Mon Sep 17 00:00:00 2001 From: "Daniel J. Egger" <38065505+eggerdj@users.noreply.github.com> Date: Mon, 28 Mar 2022 16:33:10 +0200 Subject: [PATCH 17/18] Apply suggestions from code review Co-authored-by: Will Shanks --- test/calibration/test_calibrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/calibration/test_calibrations.py b/test/calibration/test_calibrations.py index 674100f61d..dfe9d85fd2 100644 --- a/test/calibration/test_calibrations.py +++ b/test/calibration/test_calibrations.py @@ -925,11 +925,11 @@ def test_inst_map_stays_consistent(self): sched_inst = self.cals.default_inst_map.get("cr", (2, 3)) self.assertEqual(sched_inst, self.cals.get_schedule("cr", (2, 3))) - # Ensure that sigma is 40 + # Ensure that amp is 0.15 insts = block_to_schedule(sched_inst).filter(channels=[DriveChannel(2)]).instructions self.assertEqual(insts[0][1].pulse.amp, 0.15) - # Update sigma to 5 and check that change is propagated through. + # Update amp to 0.25 and check that change is propagated through. date_time2 = datetime.strptime("15/09/19 10:22:35", "%d/%m/%y %H:%M:%S") self.cals.add_parameter_value(ParameterValue(0.25, date_time2), "amp", (2,), schedule="xp") From 6035069e0aba3fbf1e080dfaa91d61c67e5b9da3 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Mon, 28 Mar 2022 16:51:25 +0200 Subject: [PATCH 18/18] * Moved to stand-alone functions in the cal utils. --- .../calibration_utils.py | 72 +++++++++---------- .../calibration_management/calibrations.py | 4 +- test/calibration/test_calibration_utils.py | 10 +-- 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/qiskit_experiments/calibration_management/calibration_utils.py b/qiskit_experiments/calibration_management/calibration_utils.py index 18e43d7c9e..f89cc6d15d 100644 --- a/qiskit_experiments/calibration_management/calibration_utils.py +++ b/qiskit_experiments/calibration_management/calibration_utils.py @@ -16,53 +16,47 @@ from qiskit.pulse import ScheduleBlock, Call -class CalUtils: - """A collection of utility functions to help calibration management.""" +def used_in_calls(schedule_name: str, schedules: List[ScheduleBlock]) -> Set[str]: + """Find the schedules in the given list that call a given schedule by name. - @staticmethod - def used_in_calls(schedule_name: str, schedules: List[ScheduleBlock]) -> Set[str]: - """Find the schedules in the given list that call a given schedule by name. + Args: + schedule_name: The name of the callee to identify. + schedules: A list of potential caller schedules to search. - Args: - schedule_name: The name of the callee to identify. - schedules: A list of potential caller schedules to search. + Returns: + A set of schedule names that call the given schedule. + """ + caller_names = set() - Returns: - A set of schedule names that call the given schedule. - """ - caller_names = set() + for schedule in schedules: + if _used_in_calls(schedule_name, schedule): + caller_names.add(schedule.name) - for schedule in schedules: - if CalUtils._used_in_calls(schedule_name, schedule): - caller_names.add(schedule.name) + return caller_names - return caller_names - @staticmethod - def _used_in_calls(schedule_name: str, schedule: ScheduleBlock) -> bool: - """Recursively find if the schedule calls a schedule with name ``schedule_name``. +def _used_in_calls(schedule_name: str, schedule: ScheduleBlock) -> bool: + """Recursively find if the schedule calls a schedule with name ``schedule_name``. - Args: - schedule_name: The name of the callee to identify. - schedule: The schedule to parse. + Args: + schedule_name: The name of the callee to identify. + schedule: The schedule to parse. - Returns: - True if ``schedule``calls a ``ScheduleBlock`` with name ``schedule_name``. - """ - blocks_have_schedule = False + Returns: + True if ``schedule``calls a ``ScheduleBlock`` with name ``schedule_name``. + """ + blocks_have_schedule = False - for block in schedule.blocks: - if isinstance(block, Call): - if block.subroutine.name == schedule_name: - return True - else: - blocks_have_schedule = blocks_have_schedule or CalUtils._used_in_calls( - schedule_name, block.subroutine - ) - - if isinstance(block, ScheduleBlock): - blocks_have_schedule = blocks_have_schedule or CalUtils._used_in_calls( - schedule_name, block + for block in schedule.blocks: + if isinstance(block, Call): + if block.subroutine.name == schedule_name: + return True + else: + blocks_have_schedule = blocks_have_schedule or _used_in_calls( + schedule_name, block.subroutine ) - return blocks_have_schedule + if isinstance(block, ScheduleBlock): + blocks_have_schedule = blocks_have_schedule or _used_in_calls(schedule_name, block) + + return blocks_have_schedule diff --git a/qiskit_experiments/calibration_management/calibrations.py b/qiskit_experiments/calibration_management/calibrations.py index d03857859b..8446ca931b 100644 --- a/qiskit_experiments/calibration_management/calibrations.py +++ b/qiskit_experiments/calibration_management/calibrations.py @@ -43,7 +43,7 @@ from qiskit_experiments.calibration_management.basis_gate_library import BasisGateLibrary from qiskit_experiments.calibration_management.parameter_value import ParameterValue from qiskit_experiments.calibration_management.control_channel_map import ControlChannelMap -from qiskit_experiments.calibration_management.calibration_utils import CalUtils +from qiskit_experiments.calibration_management.calibration_utils import used_in_calls from qiskit_experiments.calibration_management.calibration_key_types import ( ParameterKey, ParameterValueType, @@ -839,7 +839,7 @@ def add_parameter_value( schedules = set(key.schedule for key in self._parameter_map_r[param_obj]) # Find schedules that may call the schedule we want to update. - schedules.update(CalUtils.used_in_calls(sched_name, list(self._schedules.values()))) + schedules.update(used_in_calls(sched_name, list(self._schedules.values()))) self.update_inst_map(schedules, qubits=qubits) diff --git a/test/calibration/test_calibration_utils.py b/test/calibration/test_calibration_utils.py index a2c5595cfd..cdab105676 100644 --- a/test/calibration/test_calibration_utils.py +++ b/test/calibration/test_calibration_utils.py @@ -14,7 +14,7 @@ from test.base import QiskitExperimentsTestCase import qiskit.pulse as pulse -from qiskit_experiments.calibration_management.calibration_utils import CalUtils +from qiskit_experiments.calibration_management.calibration_utils import used_in_calls class TestCalibrationUtils(QiskitExperimentsTestCase): @@ -36,10 +36,10 @@ def test_used_in_calls(self): pulse.play(pulse.Drag(160, 0.5, 40, 0.2), pulse.DriveChannel(1)) pulse.call(xp_call) - self.assertSetEqual(CalUtils.used_in_calls("xp", [xp_call]), {"call_xp"}) - self.assertSetEqual(CalUtils.used_in_calls("xp", [xp2]), set()) + self.assertSetEqual(used_in_calls("xp", [xp_call]), {"call_xp"}) + self.assertSetEqual(used_in_calls("xp", [xp2]), set()) self.assertSetEqual( - CalUtils.used_in_calls("xp", [xp_call, xp_call_call]), {"call_xp", "call_call_xp"} + used_in_calls("xp", [xp_call, xp_call_call]), {"call_xp", "call_call_xp"} ) with pulse.build(name="xp") as xp: @@ -62,4 +62,4 @@ def test_used_in_calls(self): pulse.play(cr_tone_m, pulse.ControlChannel(2)) pulse.call(xp) - self.assertSetEqual(CalUtils.used_in_calls("xp", [cr]), {"cr"}) + self.assertSetEqual(used_in_calls("xp", [cr]), {"cr"})