forked from qiskit-community/qiskit-experiments
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fast transpilation method to
BaseExperiment
- Loading branch information
Showing
9 changed files
with
235 additions
and
80 deletions.
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
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
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
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,149 @@ | ||
# 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. | ||
""" | ||
Functions for preparing circuits for execution | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
from collections.abc import Sequence | ||
|
||
from qiskit import QuantumCircuit, QuantumRegister | ||
from qiskit.exceptions import QiskitError | ||
from qiskit.providers import Backend | ||
from qiskit.pulse.calibration_entries import CalibrationPublisher | ||
from qiskit.transpiler import Target | ||
|
||
|
||
def map_qubits( | ||
circuit: QuantumCircuit, | ||
physical_qubits: Sequence[int], | ||
n_qubits: int | None = None, | ||
) -> QuantumCircuit: | ||
"""Generate a new version of a circuit with new qubit indices | ||
This function iterates through the instructions of ``circuit`` and copies | ||
them into a new circuit with qubit indices replaced according to the | ||
entries in ``physical_qubits``. So qubit 0's instructions are applied to | ||
``physical_qubits[0]`` and qubit 1's to ``physical_qubits[1]``, etc. | ||
This function behaves similarly to passing ``initial_layout`` to | ||
:func:`qiskit.transpile` but does not use a Qiskit | ||
:class:`~qiskit.transpiler.PassManager` and does not fill the circuit with | ||
ancillas. | ||
Args: | ||
circuit: The :class:`~qiskit.QuantumCircuit` to re-index. | ||
physical_qubits: The list of new indices for ``circuit``'s qubit indices. | ||
n_qubits: Optional qubit size to use for the output circuit. If | ||
``None``, then the maximum of ``physical_qubits`` will be used. | ||
Returns: | ||
The quantum circuit with new qubit indices | ||
""" | ||
if len(physical_qubits) != circuit.num_qubits: | ||
raise QiskitError( | ||
f"Circuit to map has {circuit.num_qubits} qubits, but " | ||
f"{len(physical_qubits)} physical qubits specified for mapping." | ||
) | ||
|
||
# if all(p == r for p, r in zip(physical_qubits, range(circuit.num_qubits))): | ||
# # No mapping necessary | ||
# return circuit | ||
|
||
circ_size = n_qubits if n_qubits is not None else (max(physical_qubits) + 1) | ||
p_qregs = QuantumRegister(circ_size) | ||
p_circ = QuantumCircuit( | ||
p_qregs, | ||
*circuit.cregs, | ||
name=circuit.name, | ||
metadata=circuit.metadata, | ||
global_phase=circuit.global_phase, | ||
) | ||
p_circ.compose( | ||
circuit, | ||
qubits=physical_qubits, | ||
inplace=True, | ||
copy=False, | ||
) | ||
return p_circ | ||
|
||
|
||
def _has_calibration(target: Target, name: str, qubits: tuple[int, ...]) -> bool: | ||
"""Wrapper to work around bug in Target.has_calibration""" | ||
try: | ||
has_cal = target.has_calibration(name, qubits) | ||
except AttributeError: | ||
has_cal = False | ||
|
||
return has_cal | ||
|
||
|
||
def check_transpilation_needed( | ||
circuits: Sequence[QuantumCircuit], | ||
backend: Backend, | ||
) -> bool: | ||
"""Test if circuits are already compatible with backend | ||
This function checks if circuits are able to be executed on ``backend`` | ||
without transpilation. It loops through the circuits to check if any gate | ||
instructions are not included in the backend's | ||
:class:`~qiskit.transpiler.Target`. The :class:`~qiskit.transpiler.Target` | ||
is also checked for custom pulse gate calibrations for circuit's | ||
instructions. If all gates are included in the target and there are no | ||
custom calibrations, the function returns ``False`` indicating that | ||
transpilation is not needed. | ||
This function returns ``True`` if the version of ``backend`` is less than | ||
2. | ||
The motivation for this function is that when no transpilation is necessary | ||
it is faster to check the circuits in this way than to run | ||
:func:`~qiskit.transpile` and have it do nothing. | ||
Args: | ||
circuits: The circuits to prepare for the backend. | ||
backend: The backend for which the circuits should be prepared. | ||
Returns: | ||
``True`` if transpilation is needed. Otherwise, ``False``. | ||
""" | ||
transpilation_needed = False | ||
|
||
if getattr(backend, "version", 0) <= 1: | ||
# Fall back to transpilation for BackendV1 | ||
return True | ||
|
||
target = backend.target | ||
|
||
for circ in circuits: | ||
for inst in circ.data: | ||
if inst.operation.name == "barrier": | ||
continue | ||
qubits = tuple(circ.find_bit(q).index for q in inst.qubits) | ||
if not target.instruction_supported(inst.operation.name, qubits): | ||
transpilation_needed = True | ||
break | ||
if not circ.has_calibration_for(inst) and _has_calibration( | ||
target, inst.operation.name, qubits | ||
): | ||
cal = target.get_calibration(inst.operation.name, qubits, *inst.operation.params) | ||
if ( | ||
cal.metadata.get("publisher", CalibrationPublisher.QISKIT) | ||
!= CalibrationPublisher.BACKEND_PROVIDER | ||
): | ||
transpilation_needed = True | ||
break | ||
if transpilation_needed: | ||
break | ||
|
||
return transpilation_needed |
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
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
Oops, something went wrong.