-
Notifications
You must be signed in to change notification settings - Fork 3k
Bug fix macros.measure with backendv2 #9987
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
Changes from 16 commits
4bab6a6
9d109d0
a40211c
25d0719
11f734b
ca3f032
2d2ff79
0d4b715
d223f4f
d29025f
68ec213
d19464b
5930369
e53f226
c1a51d5
f31ae23
3926200
4029849
381a8e6
b075cb3
df4c4c7
d4ff655
952f865
f487cfe
9fe1944
f35ed36
25f2ac9
acb0c93
9f973ea
c2bed42
f5fb919
9986e7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,14 +11,29 @@ | |||||||||||||||||||||||||
| # 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 | ||||||||||||||||||||||||||
| from qiskit.utils.deprecation import deprecate_arg | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if TYPE_CHECKING: | ||||||||||||||||||||||||||
| from qiskit.transpiler import Target | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @deprecate_arg( | ||||||||||||||||||||||||||
| "backend", | ||||||||||||||||||||||||||
| deprecation_description=( | ||||||||||||||||||||||||||
| "Depricating ``backendV1`` as the type of measure's `backend` argument." | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| additional_msg=("Instead use ``backendV2``as the type of measure's `backend` argument."), | ||||||||||||||||||||||||||
| since="0.25.0", | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
0.25 or 0.24?
Member
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. TBH, I would just drop the That being said I don't think we need this at all.
Contributor
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. That's true
Contributor
Author
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. I deleted the deprecate decorator because "since" field must be provided.
Contributor
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. @Eric-Arellano here is another case we need to consider :) just fyi
Contributor
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. Yes, the Sphinx The docstring for
I encourage you to still use it and set
|
||||||||||||||||||||||||||
| pending=True, | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| def measure( | ||||||||||||||||||||||||||
| qubits: List[int], | ||||||||||||||||||||||||||
| backend=None, | ||||||||||||||||||||||||||
|
|
@@ -30,6 +45,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. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| If the backend has an attribute ``target``, the function uses the measurement logic, | ||||||||||||||||||||||||||
| "_measure_v2" that takes ``target`` of the ``backend``, ``meas_map`` and ``qubit_mem_slots`` | ||||||||||||||||||||||||||
| assignment. | ||||||||||||||||||||||||||
| Otherwise, if the backend is None or ``backendV1``, the function uses the | ||||||||||||||||||||||||||
| measurement logic, "_measure_v1" including ``instruction_schedule_map`` and ``meas_map`` | ||||||||||||||||||||||||||
| as inputs. | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
This doesn't need to be written here. Note that this is API document that end-users read, so implementation details must be avoided.
Contributor
Author
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. I fixed at 4029849. |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 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 +69,62 @@ def measure( | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||
| A measurement schedule corresponding to the inputs provided. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # backend is V2. | ||||||||||||||||||||||||||
| if hasattr(backend, "target"): | ||||||||||||||||||||||||||
| target = backend.target | ||||||||||||||||||||||||||
| return _measure_v2( | ||||||||||||||||||||||||||
| qubits=qubits, | ||||||||||||||||||||||||||
| target=target, | ||||||||||||||||||||||||||
| meas_map=meas_map or target.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 +158,63 @@ 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 | ||||||||||||||||||||||||||
|
Contributor
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. 💯 |
||||||||||||||||||||||||||
| target and measure map, or by using the defaults provided by the backendV2. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||
| qubits: List of qubits to be measured. | ||||||||||||||||||||||||||
| backend (Union[Backend, BaseBackend]): A backend instance, which contains | ||||||||||||||||||||||||||
| hardware-specific data required for scheduling. | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
This doesn't exist.
Contributor
Author
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. I fixed at 4029849. |
||||||||||||||||||||||||||
| 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)) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 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 exceptions.PulseError as ex: | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
Target doesn't raise PulseError
Contributor
Author
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. I fixed at 4029849. |
||||||||||||||||||||||||||
| 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) | ||||||||||||||||||||||||||
|
Contributor
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. 💯 |
||||||||||||||||||||||||||
| return schedule | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def measure_all(backend) -> Schedule: | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Return a Schedule which measures all qubits of the given backend. | ||||||||||||||||||||||||||
|
|
@@ -104,3 +227,33 @@ 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: | ||||||||||||||||||||||||||
|
Contributor
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. @TsafrirA are you happy with this API? This is public so we cannot easily change after release. If you have any concern we can turn this into protected.
Member
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. I would make this private just at this point in the release cycle if you want to include this for 0.24.0. It's best not to commit to something like this when there is a pending deadline like this. If we make it
Contributor
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. Make perfect sense :)
Contributor
Author
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. I changed at b075cb3. |
||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Return a Schedule which is remapped by given qubit_mem_slots. | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
Contributor
Author
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. I fixed at 4029849. |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||
| schedule: A measurement schedule. | ||||||||||||||||||||||||||
| qubit_mem_slots: Mapping of measured qubit index to classical bit index. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||
| A schedule remapped by qubit_mem_slots as the input provided. | ||||||||||||||||||||||||||
|
Contributor
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.
Suggested change
Contributor
Author
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. I fixed at 4029849. |
||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| 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, 0) | ||||||||||||||||||||||||||
|
Contributor
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. The unittest you wrote made me think this should be
Suggested change
because all acquisition instruction might store results in the slot0 when you specify |
||||||||||||||||||||||||||
| new_schedule.insert( | ||||||||||||||||||||||||||
| t0, | ||||||||||||||||||||||||||
| instructions.Acquire( | ||||||||||||||||||||||||||
| inst.duration, | ||||||||||||||||||||||||||
| channels.AcquireChannel(qubit_index), | ||||||||||||||||||||||||||
| mem_slot=channels.MemorySlot(reg_index), | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| inplace=True, | ||||||||||||||||||||||||||
|
Contributor
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 | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -232,6 +232,7 @@ class Target(Mapping): | |
| "_non_global_strict_basis", | ||
| "qubit_properties", | ||
| "_global_operations", | ||
| "_meas_map", | ||
| ) | ||
|
|
||
| @deprecate_arguments({"aquire_alignment": "acquire_alignment"}, since="0.23.0") | ||
|
|
@@ -245,6 +246,7 @@ def __init__( | |
| pulse_alignment=1, | ||
| acquire_alignment=1, | ||
| qubit_properties=None, | ||
| meas_map=None, | ||
| ): | ||
| """ | ||
| Create a new Target object | ||
|
|
@@ -280,6 +282,7 @@ def __init__( | |
| matches the qubit number the properties are defined for. If some | ||
| qubits don't have properties available you can set that entry to | ||
| ``None`` | ||
| meas_map (list): List of sets of qubits that must be measured together. | ||
|
Contributor
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. Please revert this file
Contributor
Author
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. I fixed it at 3926200. |
||
| Raises: | ||
| ValueError: If both ``num_qubits`` and ``qubit_properties`` are both | ||
| defined and the value of ``num_qubits`` differs from the length of | ||
|
|
@@ -315,6 +318,7 @@ def __init__( | |
| "length of the input qubit_properties list" | ||
| ) | ||
| self.qubit_properties = qubit_properties | ||
| self._meas_map = meas_map | ||
|
|
||
| def add_instruction(self, instruction, properties=None, name=None): | ||
| """Add a new instruction to the :class:`~qiskit.transpiler.Target` | ||
|
|
@@ -1045,6 +1049,11 @@ def build_coupling_map(self, two_q_gate=None): | |
| else: | ||
| return None | ||
|
|
||
| @property | ||
| def meas_map(self): | ||
| """Returns the grouping of measurements which are multiplexed""" | ||
| return self._meas_map | ||
|
|
||
| @property | ||
| def physical_qubits(self): | ||
| """Returns a sorted list of physical_qubits""" | ||
|
|
||
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.
Please revert this change.
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.
I fixed it at 3926200.