-
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
Improve transpiler documentation #9087
Conversation
This commit expands the module documentation for the qiskit.transpiler module to explain details of working with preset pass managers and how to modify stages for custom workflows. It also updates some of the details about the stages which were a bit stale on the exact behavior of the transpiler.
Thank you for opening a new pull request. Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient. While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone. One or more of the the following people are requested to review this:
|
Pull Request Test Coverage Report for Build 4016054745
💛 - Coveralls |
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.
This looks like a good (and probably a bit overdue!) change to the documentation to me. I've left some typo fixes and stuff like that.
I was commenting more on some of the stuff in the scheduling stage, then I realised that it was just unchanged from the previous version, so we don't necessarily try to fix everything about it in a single PR right now.
.. _stage_generators: | ||
|
||
Stage Generator Functions | ||
------------------------- | ||
|
||
.. autosummary:: | ||
:toctree: ../stubs/ | ||
|
||
~qiskit.transpiler.preset_passmanagers.common.generate_control_flow_options_check | ||
~qiskit.transpiler.preset_passmanagers.common.generate_error_on_control_flow | ||
~qiskit.transpiler.preset_passmanagers.common.generate_unroll_3q | ||
~qiskit.transpiler.preset_passmanagers.common.generate_embed_passmanager | ||
~qiskit.transpiler.preset_passmanagers.common.generate_routing_passmanager | ||
~qiskit.transpiler.preset_passmanagers.common.generate_pre_op_passmanager | ||
~qiskit.transpiler.preset_passmanagers.common.generate_translation_passmanager | ||
~qiskit.transpiler.preset_passmanagers.common.generate_scheduling |
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.
This documentation is a bit misleading - the currentmodule
is qiskit.transpiler.preset_passmanagers
, but these functions aren't actually available from that namespace. We either need to change the module
for the documentation of these, or import them into the top-level namespace (my preferred choice - I like packages to properly define a public API, and not require users to go searching in the code for the module stuff happens to be defined it).
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 was on the fence about re-exporting it form the root here. I opted to not do it in this PR since I wanted to leave this as purely documentation changes. But I can add it if you think it's necessary here. Otherwise I think we can do this in a follow up PR. TBH, I'm not really sure why I didn't re-export these functions when I added these in #6403.
The scheduling of a circuit involves two parts, analysis and constraint mapping followed by a | ||
padding pass. The first part requires running a scheduling analysis pass such as | ||
:class:`~.ALAPSchedulingAnalysis` or :class:`~.ASAPSchedulingAnalysis` which analyzes the circuit | ||
and records the start time of each instruction in the circuit using a scheduling algorithm ("as late | ||
as possible" for :class:`~.ALAPSchedulingAnalysis` and "as soon as possible" for | ||
:class:`~.ASAPSchedulingAnalysis`) in the property set. Once the circuit has an initial scheduling | ||
additional passes can be run to account for any timing constraints on the target backend, such | ||
as alignment constraints. This is typically done with the | ||
:class:`~.ConstrainedReschedule` pass which will adjust the scheduling | ||
set in the property set to the constraints of the target backend. Once all | ||
the scheduling and adjustments/rescheduling are finished a padding pass, | ||
such as :class:`~.PadDelay` or :class:`~.PadDynamicalDecoupling` is run | ||
to insert the instructions into the circuit, which completes the scheduling. |
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.
The first sentence says "two parts", but the rest of the paragraph makes it sound like a minimum of three components to me.
Hi @mtreinish and @jakelishman, Related to this, in the transpiler documentation page, under "Mapping circuits to hardware topology", the "bad" initial_layout fails to create a wider distribution of depths. Essentially, all the different iterations lead to Please let me know if I should create a separate issue for this. Thanks. |
Thanks for pointing that out, I hadn't realized that I expect it maybe an artifact of changing the default algorithm to SabreSwap and it now converging on the same solution regardless of seed. I need to fix lint on this anyway I'll modify the example to have it better show the stochastic nature of the routing algorithm. |
I updated the examples in: 2b7e998 and it is showing more of a distribution now: |
c2d5197
to
2b7e998
Compare
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.
Up to the Routing
section, these sections looks great.
qiskit/transpiler/__init__.py
Outdated
To be able to compile a :class:`~.QuantumCircuit` for a target backend the compiler needs to | ||
be able to represent that backend for the compiler. There are a few data structures for doing |
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.
It seems like we're using backend, target and target backend interchangeably throughout. Is there a distinction to be made between them?
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.
In this context not so much, there is a distinction between a Target
and a Backend
(as in the classes) but for the purposes of the transpiler module, pass managers, and pass managers the target, backend, and target backend I was referring to the the same thing (the compilation target backend).
optimization level 1 if there are control flow operations (such as | ||
:class:`~.IfElseOp`) present in the circuit. |
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.
Similarly, this will likely be outdated following #9417 .
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.
Yeah, after this merges we should make a note to update this doc after when #9417 is fixed
minimum number of swap gates needed to map a circuit onto a given device, is an important | ||
step (if not the most important) in the whole execution process. | ||
|
||
However, as with many important things in life, finding the optimal swap mapping is hard. |
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.
❤️
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.
#MyLifeIsNPHard
keyword argument, where the index labels the virtual qubit in the circuit and the | ||
corresponding value is the label for the physical qubit to map onto: |
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.
keyword argument, where the index labels the virtual qubit in the circuit and the | |
corresponding value is the label for the physical qubit to map onto: | |
keyword argument where the index labels the virtual qubit in the circuit and the | |
corresponding value is the label for the physical qubit to map onto: |
This has to be the hardest-to-describe kwarg
input format in all Qiskit. Maybe something like "where each integer specifies a physical qubit index onto which the corresponding virtual qubit (following the order in circuit.qubits
will be mapped"?
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.
Heh, I know the array of physical bits is Paul's preferred input format (I'm also fond of it too). But initial_layout
supports like every way imaginable to describe the mapping. It might make more sense to use the dict format:
{ghz.qubits[0]: 3, ghz.qubits[1]: 4. ghz.qubits[2]: 2}
which is a bit easier to describe.
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.
Agree, and I think the example below does a good job of clarifying the format should be used. I'm just wondering if there's a clearer text explanation we can give (but I wouldn't be surprised if not, there isn't one in e.g. the transpile
docstring).
Co-authored-by: Kevin Krsulich <[email protected]>
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.
Partially reviewed, more to come. Adding comments so far to reduce conflicts with other reviewers.
qiskit/transpiler/__init__.py
Outdated
When writing a quantum circuit you are free to use any quantum gate (unitary operator) that | ||
you like, along with a collection of non-gate operations such as qubit measurements and | ||
reset operations. However, when running a circuit on a real quantum device one no longer | ||
has this flexibility. Due to limitations in, for example, the physical interactions | ||
between qubits, difficulty in implementing multi-qubit gates, control electronics etc, | ||
a quantum computing device can only natively support a handful of quantum gates and non-gate | ||
operations. The allowed instructions for a given backend can be found by querying the | ||
:class:`~.Target` for the devices: |
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.
When writing a quantum circuit you are free to use any quantum gate (unitary operator) that | |
you like, along with a collection of non-gate operations such as qubit measurements and | |
reset operations. However, when running a circuit on a real quantum device one no longer | |
has this flexibility. Due to limitations in, for example, the physical interactions | |
between qubits, difficulty in implementing multi-qubit gates, control electronics etc, | |
a quantum computing device can only natively support a handful of quantum gates and non-gate | |
operations. The allowed instructions for a given backend can be found by querying the | |
:class:`~.Target` for the devices: | |
Users are free to write quantum circuits using any quantum gate (unitary operator) in addition | |
to non-gate operations such as qubit measurements and reset operations. However, when | |
running a circuit on real quantum hardware, these operations must be translated to the native | |
set of operations supported by the device, which is often limited. The allowed instructions for a | |
given backend can be found by querying the :class:`~.Target` for the devices: |
qiskit/transpiler/__init__.py
Outdated
We have :math:`H`, :math:`X`, and controlled-:math:`P` gates, all of which are | ||
not in our devices basis gate set, and must be expanded. This expansion is taken | ||
care of for us in the :func:`qiskit.execute` function. However, we can | ||
decompose the circuit to show what it would look like in the native gate set of | ||
the IBM Quantum devices (the :class:`~.FakeVigoV2` backend is a fake backend that | ||
models the historical IBM Vigo 5 qubit device for test purposes): |
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.
We have :math:`H`, :math:`X`, and controlled-:math:`P` gates, all of which are | |
not in our devices basis gate set, and must be expanded. This expansion is taken | |
care of for us in the :func:`qiskit.execute` function. However, we can | |
decompose the circuit to show what it would look like in the native gate set of | |
the IBM Quantum devices (the :class:`~.FakeVigoV2` backend is a fake backend that | |
models the historical IBM Vigo 5 qubit device for test purposes): | |
We have :math:`H`, :math:`X`, and controlled-:math:`P` gates, none of which are | |
in our device's basis gate set, and thus must be expanded. This expansion is taken | |
care of for us in the :func:`qiskit.execute` function. However, we can | |
decompose the circuit to show what it would look like in the native gate set of | |
the IBM Quantum device (the :class:`~.FakeVigoV2` backend is a fake backend that | |
models the historical IBM Vigo 5 qubit device for test purposes): |
qiskit/transpiler/__init__.py
Outdated
As a product of three CNOT gates, swap gates are expensive operations to perform on a | ||
noisy quantum devices. However, such operations are usually necessary for embedding a | ||
circuit into the limited entangling gate connectivities of actual devices. Thus, | ||
minimizing the number of swap gates in a circuit is a primary goal in the | ||
transpilation process. |
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.
As a product of three CNOT gates, swap gates are expensive operations to perform on a | |
noisy quantum devices. However, such operations are usually necessary for embedding a | |
circuit into the limited entangling gate connectivities of actual devices. Thus, | |
minimizing the number of swap gates in a circuit is a primary goal in the | |
transpilation process. | |
Swap gates are expensive operations to perform on a noisy quantum devices because | |
each one is decomposed to three CNOT gates. However, swaps are usually necessary | |
for embedding a circuit to match the limited connectivity of actual devices. | |
Thus, a primary goal of the transpilation process is to minimize the number of swap gates | |
required to make the circuit compatible with the target device. |
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.
LGTM
Overall LGTM. I have one comment on Overview section. When I first read it, I was a bit confused about the misalignment between "steps" in the first figure and "stages" defined in preset pass manager. Some reader would expect one-on-one mapping between the six steps in the figure and the six stages in the main text but in fact the first two steps will be implemented in the |
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.
Last few comments, then looks good to me! Didn't review through the Scheduling
section as I think it was unchanged.
keyword argument, where the index labels the virtual qubit in the circuit and the | ||
corresponding value is the label for the physical qubit to map onto: |
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.
Agree, and I think the example below does a good job of clarifying the format should be used. I'm just wondering if there's a clearer text explanation we can give (but I wouldn't be surprised if not, there isn't one in e.g. the transpile
docstring).
try a few different methods to find the best layout. Typically this involves 2 stages, first | ||
trying to find a "perfect" layout (a layout which does not require any swap operations) and | ||
a heuristic pass that tries to find the best layout to use if a perfect layout can not be found. | ||
For the first stage there are 2 passes typically used for this: |
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.
True, but even with translation, there are the unroll
and synthesis
methods which we could highlight here, likewise routing has stochastic
and lookahead
. I suppose I'm saying if we're going to document the pass behaviors and available *_method
options for layout here, we should do the same for translation
and routing
.
As an alternative, the documentation here could be at the level of "here are the default stages and the problems they solve" and then for folks to understand the implementation of those stages at each optimization level, we could move the descriptions of the passes being run (and corresponding *_method
options) to the documentation of the preset pass manager generators.
Co-authored-by: Kevin Krsulich <[email protected]>
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.
Thanks for the updates, LGTM.
* Improve transpiler documentation This commit expands the module documentation for the qiskit.transpiler module to explain details of working with preset pass managers and how to modify stages for custom workflows. It also updates some of the details about the stages which were a bit stale on the exact behavior of the transpiler. * Apply suggestions from code review Co-authored-by: Jake Lishman <[email protected]> * More refactors from code review * Update reference label for stages section * Add section headers to scheduling stage docs * Fix lint * Fix typo * Update examples to show stochastic passes * Fix rebase typos and example issues * Update qiskit/transpiler/__init__.py * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Fix trailing whitespace * Expand init stage definition * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Simplify target section intro * Highlight legacy views are for backwards compatibility * Updating layout and routing for extra details * Apply suggestions from code review Co-authored-by: Kevin Hartman <[email protected]> * Update qiskit/transpiler/preset_passmanagers/__init__.py Co-authored-by: Kevin Hartman <[email protected]> * More updates from code review * Fix line length lint failure * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Expand sabre layout explanation * Explain pass description in stage details header Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: Kevin Krsulich <[email protected]> Co-authored-by: Kevin Hartman <[email protected]> (cherry picked from commit 925f9f3)
* Improve transpiler documentation This commit expands the module documentation for the qiskit.transpiler module to explain details of working with preset pass managers and how to modify stages for custom workflows. It also updates some of the details about the stages which were a bit stale on the exact behavior of the transpiler. * Apply suggestions from code review Co-authored-by: Jake Lishman <[email protected]> * More refactors from code review * Update reference label for stages section * Add section headers to scheduling stage docs * Fix lint * Fix typo * Update examples to show stochastic passes * Fix rebase typos and example issues * Update qiskit/transpiler/__init__.py * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Fix trailing whitespace * Expand init stage definition * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Simplify target section intro * Highlight legacy views are for backwards compatibility * Updating layout and routing for extra details * Apply suggestions from code review Co-authored-by: Kevin Hartman <[email protected]> * Update qiskit/transpiler/preset_passmanagers/__init__.py Co-authored-by: Kevin Hartman <[email protected]> * More updates from code review * Fix line length lint failure * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]> * Expand sabre layout explanation * Explain pass description in stage details header Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: Kevin Krsulich <[email protected]> Co-authored-by: Kevin Hartman <[email protected]> (cherry picked from commit 925f9f3) Co-authored-by: Matthew Treinish <[email protected]>
Summary
This commit expands the module documentation for the qiskit.transpiler module to explain details of working with preset pass managers and how to modify stages for custom workflows. It also updates some of the details about the stages which were a bit stale on the exact behavior of the transpiler.
Details and comments