-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Bug fix macros.measure with backendv2 #9987
Merged
nkanazawa1989
merged 32 commits into
Qiskit:main
from
to24toro:feature/bug_fix_schedule_with_backendv2
Apr 20, 2023
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
4bab6a6
create measuregrouping class
to24toro 9d109d0
add meas_map.setter in MeasureGrouping class
to24toro a40211c
macros.measure
to24toro 25d0719
get_qubit_groups
to24toro 11f734b
generate_schedule
to24toro ca3f032
target.add_measuregrouping in backend_compat
to24toro 2d2ff79
target.add_measuregrouping in backend_converter
to24toro 0d4b715
reformat and add docs
to24toro d223f4f
Merge remote-tracking branch 'origin/main' into feature/add_meas_grou…
to24toro d29025f
on the way of working on generate_schedule_in_measure
to24toro 68ec213
split measure into measure_v1 and measure_v2
to24toro d19464b
macros.py
to24toro 5930369
test_measuregrouping
to24toro e53f226
bug fix schedule with backendV2 for 0.25.0
to24toro c1a51d5
modify comments
to24toro f31ae23
fix name of schedule in test_macros
to24toro 3926200
delete meas_map as a Target attribute
to24toro 4029849
minor changes in macros.py
to24toro 381a8e6
add test to test_macros.py
to24toro b075cb3
make schedule_remapping_memory_slot private
to24toro df4c4c7
delete since field from deprecate_arg
to24toro d4ff655
delete deprecate depcorator
to24toro 952f865
black macros.py
to24toro f487cfe
revert about target
to24toro 9fe1944
modify implementation of qubit_mem_slots
to24toro f35ed36
change the definition of meas_group_set
to24toro 25f2ac9
black macros.py
to24toro acb0c93
fix meas_group_set
to24toro 9f973ea
fix qubit_mem_slots
to24toro c2bed42
reno
to24toro f5fb919
modify unassigned_qubit_indices
to24toro 9986e7f
remove list() from unassigned_qubit_indices and unassigned_reg_indices
to24toro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,14 +11,19 @@ | |
# that they have been altered from the originals. | ||
|
||
"""Module for common pulse programming macros.""" | ||
from __future__ import annotations | ||
|
||
from typing import Dict, List, Optional, Union | ||
from typing import Dict, List, Optional, Union, TYPE_CHECKING | ||
|
||
from qiskit.pulse import channels, exceptions, instructions, utils | ||
from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap | ||
from qiskit.pulse.schedule import Schedule | ||
|
||
|
||
if TYPE_CHECKING: | ||
from qiskit.transpiler import Target | ||
|
||
|
||
def measure( | ||
qubits: List[int], | ||
backend=None, | ||
|
@@ -30,6 +35,13 @@ def measure( | |
"""Return a schedule which measures the requested qubits according to the given | ||
instruction mapping and measure map, or by using the defaults provided by the backend. | ||
|
||
.. note:: | ||
This function internally dispatches schedule generation logic depending on input backend model. | ||
For the :class:`.BackendV1`, it considers conventional :class:`.InstructionScheduleMap` | ||
and utilizes the backend calibration defined for a group of qubits in the `meas_map`. | ||
For the :class:`.BackendV2`, it assembles calibrations of single qubit measurement | ||
defined in the backend target to build a composite measurement schedule for `qubits`. | ||
|
||
By default, the measurement results for each qubit are trivially mapped to the qubit | ||
index. This behavior is overridden by qubit_mem_slots. For instance, to measure | ||
qubit 0 into MemorySlot(1), qubit_mem_slots can be provided as {0: 1}. | ||
|
@@ -47,18 +59,67 @@ def measure( | |
|
||
Returns: | ||
A measurement schedule corresponding to the inputs provided. | ||
""" | ||
|
||
# backend is V2. | ||
if hasattr(backend, "target"): | ||
try: | ||
meas_map = backend.configuration().meas_map | ||
except AttributeError: | ||
# TODO add meas_map to Target in 0.25 | ||
meas_map = [list(range(backend.num_qubits))] | ||
|
||
return _measure_v2( | ||
qubits=qubits, | ||
target=backend.target, | ||
meas_map=meas_map, | ||
qubit_mem_slots=qubit_mem_slots or dict(zip(qubits, range(len(qubits)))), | ||
measure_name=measure_name, | ||
) | ||
# backend is V1 or backend is None. | ||
else: | ||
try: | ||
return _measure_v1( | ||
qubits=qubits, | ||
inst_map=inst_map or backend.defaults().instruction_schedule_map, | ||
meas_map=meas_map or backend.configuration().meas_map, | ||
qubit_mem_slots=qubit_mem_slots, | ||
measure_name=measure_name, | ||
) | ||
except AttributeError as ex: | ||
raise exceptions.PulseError( | ||
"inst_map or meas_map, and backend cannot be None simultaneously" | ||
) from ex | ||
|
||
|
||
def _measure_v1( | ||
qubits: List[int], | ||
inst_map: InstructionScheduleMap, | ||
meas_map: Union[List[List[int]], Dict[int, List[int]]], | ||
qubit_mem_slots: Optional[Dict[int, int]] = None, | ||
measure_name: str = "measure", | ||
) -> Schedule: | ||
"""Return a schedule which measures the requested qubits according to the given | ||
instruction mapping and measure map, or by using the defaults provided by the backendV1. | ||
|
||
Args: | ||
qubits: List of qubits to be measured. | ||
backend (Union[Backend, BaseBackend]): A backend instance, which contains | ||
hardware-specific data required for scheduling. | ||
inst_map: Mapping of circuit operations to pulse schedules. If None, defaults to the | ||
``instruction_schedule_map`` of ``backend``. | ||
meas_map: List of sets of qubits that must be measured together. If None, defaults to | ||
the ``meas_map`` of ``backend``. | ||
qubit_mem_slots: Mapping of measured qubit index to classical bit index. | ||
measure_name: Name of the measurement schedule. | ||
Returns: | ||
A measurement schedule corresponding to the inputs provided. | ||
Raises: | ||
PulseError: If both ``inst_map`` or ``meas_map``, and ``backend`` is None. | ||
""" | ||
|
||
schedule = Schedule(name=f"Default measurement schedule for qubits {qubits}") | ||
try: | ||
inst_map = inst_map or backend.defaults().instruction_schedule_map | ||
meas_map = meas_map or backend.configuration().meas_map | ||
except AttributeError as ex: | ||
raise exceptions.PulseError( | ||
"inst_map or meas_map, and backend cannot be None simultaneously" | ||
) from ex | ||
|
||
if isinstance(meas_map, list): | ||
meas_map = utils.format_meas_map(meas_map) | ||
|
||
|
@@ -92,6 +153,68 @@ def measure( | |
return schedule | ||
|
||
|
||
def _measure_v2( | ||
qubits: List[int], | ||
target: Target, | ||
meas_map: Union[List[List[int]], Dict[int, List[int]]], | ||
qubit_mem_slots: Dict[int, int], | ||
measure_name: str = "measure", | ||
) -> Schedule: | ||
"""Return a schedule which measures the requested qubits according to the given | ||
target and measure map, or by using the defaults provided by the backendV2. | ||
|
||
Args: | ||
qubits: List of qubits to be measured. | ||
target: The :class:`~.Target` representing the target backend. | ||
meas_map: List of sets of qubits that must be measured together. | ||
qubit_mem_slots: Mapping of measured qubit index to classical bit index. | ||
measure_name: Name of the measurement schedule. | ||
|
||
Returns: | ||
A measurement schedule corresponding to the inputs provided. | ||
""" | ||
schedule = Schedule(name=f"Default measurement schedule for qubits {qubits}") | ||
|
||
if isinstance(meas_map, list): | ||
meas_map = utils.format_meas_map(meas_map) | ||
meas_group = set() | ||
for qubit in qubits: | ||
meas_group |= set(meas_map[qubit]) | ||
meas_group = sorted(list(meas_group)) | ||
|
||
meas_group_set = set(range(max(meas_group) + 1)) | ||
unassigned_qubit_indices = sorted(set(meas_group) - qubit_mem_slots.keys()) | ||
unassigned_reg_indices = sorted(meas_group_set - set(qubit_mem_slots.values()), reverse=True) | ||
if set(qubit_mem_slots.values()).issubset(meas_group_set): | ||
for qubit in unassigned_qubit_indices: | ||
qubit_mem_slots[qubit] = unassigned_reg_indices.pop() | ||
|
||
for measure_qubit in meas_group: | ||
try: | ||
if measure_qubit in qubits: | ||
default_sched = target.get_calibration(measure_name, (measure_qubit,)).filter( | ||
channels=[ | ||
channels.MeasureChannel(measure_qubit), | ||
channels.AcquireChannel(measure_qubit), | ||
] | ||
) | ||
else: | ||
default_sched = target.get_calibration(measure_name, (measure_qubit,)).filter( | ||
channels=[ | ||
channels.AcquireChannel(measure_qubit), | ||
] | ||
) | ||
except KeyError as ex: | ||
raise exceptions.PulseError( | ||
"We could not find a default measurement schedule called '{}'. " | ||
"Please provide another name using the 'measure_name' keyword " | ||
"argument. For assistance, the instructions which are defined are: " | ||
"{}".format(measure_name, target.instructions) | ||
) from ex | ||
schedule += _schedule_remapping_memory_slot(default_sched, qubit_mem_slots) | ||
return schedule | ||
|
||
|
||
def measure_all(backend) -> Schedule: | ||
""" | ||
Return a Schedule which measures all qubits of the given backend. | ||
|
@@ -104,3 +227,35 @@ def measure_all(backend) -> Schedule: | |
A schedule corresponding to the inputs provided. | ||
""" | ||
return measure(qubits=list(range(backend.configuration().n_qubits)), backend=backend) | ||
|
||
|
||
def _schedule_remapping_memory_slot( | ||
schedule: Schedule, qubit_mem_slots: Dict[int, int] | ||
) -> Schedule: | ||
""" | ||
A helper function to overwrite MemorySlot index of :class:`.Acquire` instruction. | ||
|
||
Args: | ||
schedule: A measurement schedule. | ||
qubit_mem_slots: Mapping of measured qubit index to classical bit index. | ||
|
||
Returns: | ||
A measurement schedule with new memory slot index. | ||
""" | ||
new_schedule = Schedule() | ||
for t0, inst in schedule.instructions: | ||
if isinstance(inst, instructions.Acquire): | ||
qubit_index = inst.channel.index | ||
reg_index = qubit_mem_slots.get(qubit_index, qubit_index) | ||
new_schedule.insert( | ||
t0, | ||
instructions.Acquire( | ||
inst.duration, | ||
channels.AcquireChannel(qubit_index), | ||
mem_slot=channels.MemorySlot(reg_index), | ||
), | ||
inplace=True, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
) | ||
else: | ||
new_schedule.insert(t0, inst, inplace=True) | ||
return new_schedule |
5 changes: 5 additions & 0 deletions
5
releasenotes/notes/fix-macros-measure-with-backendV2-4354f00ab4f1cd3e.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
fixes: | ||
- | | ||
Fixed failure in using :func:`~qiskit.pulse.macros.measure` | ||
with :class:`.BackendV2` backends. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯