Skip to content

Add stage plugin interface for transpile#8305

Merged
mergify[bot] merged 42 commits into
Qiskit:mainfrom
mtreinish:add-transpile-plugins
Aug 30, 2022
Merged

Add stage plugin interface for transpile#8305
mergify[bot] merged 42 commits into
Qiskit:mainfrom
mtreinish:add-transpile-plugins

Conversation

@mtreinish
Copy link
Copy Markdown
Member

@mtreinish mtreinish commented Jul 6, 2022

Summary

This commit adds a new plugin interface to qiskit for enabling external
packages to write plugins that will replace a stage in the transpilation
pipeline. For example, if an external package had a custom layout pass
that they wanted to integrate into transpile() they could export a
plugin using this new interface and then users would just need to run

transpile(.., layout_method=foo)

This adds long asked for extensibility to the transpiler so that to
cleanly integrate new transpiler passes we're no longer required to
merge the features into terra. This should hopefully make it easier for
downstream pass authors to integrate their passes into terra and make it
easier for the terra maintainers to evaluate new transpiler passes.

Details and comments

TODO:

  • Add release notes
  • Fix docs build
  • Add support to opt level 0 and 3
  • Add test coverage for plugin functions
  • Rework some stages as built-in plugins?

This commit adds a new plugin interface to qiskit for enabling external
packages to write plugins that will replace a stage in the transpilation
pipeline. For example, if an external package had a custom layout pass
that they wanted to integrate into transpile() they could export a
plugin using this new interface and then users would just need to run

transpile(.., layout_method=foo)

This adds long asked for extensibility to the transpiler so that to
cleanly integrate new transpiler passes we're no longer required to
merge the features into terra. This should hopefully make it easier for
downstream pass authors to integrate their passes into terra and make it
easier for the terra maintainers to evaluate new transpiler passes.
@mtreinish mtreinish added the Changelog: Added Add an "Added" entry in the GitHub Release changelog. label Jul 6, 2022
@mtreinish mtreinish added this to the 0.22 milestone Jul 6, 2022
@mtreinish mtreinish requested a review from a team as a code owner July 6, 2022 18:09
@qiskit-bot
Copy link
Copy Markdown
Collaborator

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:

  • @Qiskit/terra-core

@coveralls
Copy link
Copy Markdown

coveralls commented Jul 6, 2022

Pull Request Test Coverage Report for Build 2958142026

  • 269 of 302 (89.07%) changed or added relevant lines in 9 files are covered.
  • 3 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.01%) to 84.139%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/transpiler/preset_passmanagers/builtin_plugins.py 87 91 95.6%
qiskit/transpiler/preset_passmanagers/level0.py 21 26 80.77%
qiskit/transpiler/preset_passmanagers/level1.py 30 35 85.71%
qiskit/transpiler/preset_passmanagers/level2.py 28 33 84.85%
qiskit/transpiler/preset_passmanagers/plugin.py 49 54 90.74%
qiskit/transpiler/preset_passmanagers/level3.py 38 47 80.85%
Files with Coverage Reduction New Missed Lines %
qiskit/pulse/library/waveform.py 3 89.36%
Totals Coverage Status
Change from base Build 2958133494: 0.01%
Covered Lines: 56980
Relevant Lines: 67721

💛 - Coveralls

@alexanderivrii
Copy link
Copy Markdown
Member

@mtreinish. This looks very useful. I am trying to better understand what we would or would not be able to do, so a few questions, if I may:

  • Suppose we want to run transpile with optimization_level=2 but replace the layout stage by a layout method that is already in Qiskit (e.g., "noise_adaptive"). In this case, we would not need to write any plugin, and would simply pass layout_method = 'noise_adaptive' as an argument to transpile. This is correct so far?
  • Suppose we want to run transpile with optimization_level=2 but replace the layout stage by a layout method that is not part of Qiskit. Then how to do it is precisely your example in plugin.py, correct?
  • The above is the same for the optimization stage (instead of the layout stage), for instance if we want to replace the optimization stage by an algorithm that is not part of Qiskit. But suppose we don't want to fully replace the optimization stage, but simply add the external algorithm to the current set of optimization algorithms. Can we do that?
  • We already have plugins for unitary synthesis algorithms, and unitary synthesis is used both in the init and optimization stages, I think. Should we specify unitary synthesis plugins independently, or as part of the stages?
  • Suppose that we want to integrate an external Clifford synthesis algorithm in Qiskit. In some sense, this would be similar to how we do unitary synthesis. What would be the steps to do that? If this derails the discussion too much, we can take this offline or to a different thread.

@mtreinish
Copy link
Copy Markdown
Member Author

mtreinish commented Jul 7, 2022

@mtreinish. This looks very useful. I am trying to better understand what we would or would not be able to do, so a few questions, if I may:

* Suppose we want to run `transpile` with `optimization_level=2` but replace the `layout` stage by a layout method that is already in Qiskit (e.g., "noise_adaptive"). In this case, we would not need to write any plugin, and would simply pass `layout_method = 'noise_adaptive'` as an argument to `transpile`. This is correct so far?

Yes, that's correct. One thing I'm debating is whether I want to bundle things like noise_adaptive layout as a plugin (so we're using our own plugin interface) or just leave it as a standalone thing. But that's an implementation detail and doesn't effect the end user interface or what we include with terra.

* Suppose we want to run `transpile` with `optimization_level=2` but replace the `layout` stage by a layout method that is not part of Qiskit. Then how to do it is precisely your example in `plugin.py`, correct?

Yes exactly, the idea is exactly that. A custom layout method (or any stage) that isn't part of qiskit can cleanly integrate into transpile() by creating a plugin. Then the end user can just do transpile(layout_method='custom') (or whatever the plugin name is) and it will work just as if it were one of the built in layout methods.

* The above is the same for the optimization stage (instead of the layout stage), for instance if we want to replace the optimization stage by an algorithm that is not part of Qiskit. But suppose we don't want to fully replace the optimization stage, but simply add the external algorithm to the current set of optimization algorithms. Can we do that?

Not with this, the unit of a plugin is a stage. This enables an external package to advertise that they have a custom pass manager which can be used for an optimization stage. So using this model you'd have to have your plugin return the full pass manager including the existing default stage contents. That being said in the last release we made this sort of modification easy to do. For example something like:

from qiskit.transpiler.preset_passmanager import generate_preset_pass_manager
from qiskit.providers.fake_provider import FakeLagosV2

backend = FakeLagosV2()
pass_manager = generate_preset_pass_manager(3, backend)
pass_manager.optimization.append(CustomPass())
pass_manager.run(qc)

You could embed something similar in your plugin but optimization is a weird case because there isn't a handy generator function like the other stages as each optimization level is custom. I guess you could have your plugin call generate_preset_pass_manager() and return a modified .optimization from it.

* We already have plugins for unitary synthesis algorithms, and unitary synthesis is used both in the `init` and `optimization` stages, I think. Should we specify unitary synthesis plugins independently, or as part of the stages?

Unitary synthesis plugins are already handled separately with an existing (for about a year now) plugin interface. https://qiskit.org/documentation/apidoc/transpiler_plugins.html?highlight=plugin#module-qiskit.transpiler.passes.synthesis.plugin this enables synthesis method authors to hook into the existing UnitarySynthesis pass at a lower level and replace how the circuits are synthesized for a unitary. I guess I'm saying this doesn't supersede this already existing plugin interface, it just gives people another hook point to swap out a larger chunk of functionality from the transpiler to an external package.

Since the unit of the plugins added in this PR are stages the specific passes used as part of the returned PassManager is up to the plugin author. We pass the full context the preset pass managers get (the PassManagerConfig) to the plugin so if the plugin stage is using the UnitarySynthesis pass the burden is on the plugin author to ensure the user specified unitary_synthesis_method argument is passed to the constructor for UnitarySynthesis in the returned stage PassManager.

* Suppose that we want to integrate an external Clifford synthesis algorithm in Qiskit. In some sense, this would be similar to how we do unitary synthesis. What would be the steps to do that? If this derails the discussion too much, we can take this offline or to a different thread.

My plan for clifford synthesis was to probably add a specific plugin interface for this once the dedicated clifford synthesis pass exists. We have this mechanism specifically for unitary synthesis already so having a dual for clifford synthesis makes sense to me. You could leverage this using this interface though and write a custom plugin for the init or translation stage that used a custom synthesis pass if you wanted, but that would add a lot of boiler plate if all you're really looking for is an interface that gets a black box plugin/function that takes a clifford in and returns a dag circuit.

This commit converts all the built-in routing method options into
separate plugins and also adds a default plugin for the default behavior
at each optimization level. To support using plugins for routing method
adding the optimization_level to the passmanager config was necessary so
that the plugin has sufficient context on how to construct the routing
pass used for the routing stage. As depending on the optimization level
the settings for each pass differs. For example on stochastic swap the
number of stochastic trials increases for level 3 to try and find a
better solution at the cost of more runtime.
@mtreinish mtreinish changed the title [WIP] Add stage plugin interface for transpile Add stage plugin interface for transpile Jul 22, 2022
@mtreinish
Copy link
Copy Markdown
Member Author

This is ready for review now, I've added the pieces I thought were missing.

The only open question is whether I should massage the additional built-in stages for the preset pass managers (init, layout, translation, optimization, and scheduling) into plugins. I started with just routing since it was fairly self contained. Although given the size of this PR already we can save the plugin refactor for the remaining stages into follow up PRs.

@alexanderivrii
Copy link
Copy Markdown
Member

@mtreinish, can I volunteer to review this (partly for self-educational purposes)?

@mtreinish mtreinish requested a review from alexanderivrii July 24, 2022 10:40
Comment thread releasenotes/notes/stage-plugin-interface-47daae40f7d0ad3c.yaml Outdated
Comment thread releasenotes/notes/stage-plugin-interface-47daae40f7d0ad3c.yaml Outdated
Comment thread qiskit/transpiler/preset_passmanagers/builtin_plugins.py Outdated
Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>
@mtreinish mtreinish dismissed 1ucian0’s stale review August 23, 2022 15:18

Comments addressed

Comment thread qiskit/transpiler/passmanager_config.py
basis_gates. This will be a plugin name if an external translation stage
plugin is being used.
scheduling_method (str): the pass to use for scheduling instructions. This will
be a plugin name if an external scheduling stage plugin is being used.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any plan to replace *_method with the plugin interface?

Comment thread qiskit/transpiler/preset_passmanagers/level3.py
Comment thread qiskit/transpiler/preset_passmanagers/plugin.py Outdated
Comment thread test/python/transpiler/test_stage_plugin.py Outdated
Comment thread test/python/transpiler/test_stage_plugin.py Outdated
Comment thread qiskit/transpiler/preset_passmanagers/plugin.py Outdated
Copy link
Copy Markdown
Member

@1ucian0 1ucian0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good. I would add some more testing of the included plugins (therefore, the request to change). And I'm still uncomfortable with the level being part of the PassManagerConfig (non-blocking). The rest is good to merge for me.

@mtreinish mtreinish requested a review from 1ucian0 August 25, 2022 17:50
@mtreinish
Copy link
Copy Markdown
Member Author

I think this looks good. I would add some more testing of the included plugins (therefore, the request to change). And I'm still uncomfortable with the level being part of the PassManagerConfig (non-blocking). The rest is good to merge for me.

@1ucian0 I moved the optimization level out of the PassManagerConfig in d731d06 and add test coverage for the built-in plugins in f185c59

Copy link
Copy Markdown
Member

@kdk kdk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there somewhere we've documented how to implement a transpiler stage from the perspective of a pass developer or backend vendor?

@kevinhartman
Copy link
Copy Markdown
Contributor

It's probably worth documenting this as something for plugin authors to watch out for. Alternatively, I guess we can detect the duplicates right after we build the extension manager object and raise. What do you think?

Documenting would be nice. Is there a way we could log a warning when the transpilation is run to log which one was selected? I think raising would be troublesome since it'd force users to uninstall something to continue. Packages could contain multiple packages, so forcing the user to uninstall might leave them in a situation where it's impossible to set up the pipeline they want.

@kdk
Copy link
Copy Markdown
Member

kdk commented Aug 30, 2022

Is there somewhere we've documented how to implement a transpiler stage from the perspective of a pass developer or backend vendor?

@mtreinish pointed me to https://github.com/Qiskit/qiskit-terra/blob/6d344c068c7e3605d735f3efa654b9f1e406a0cb/qiskit/transpiler/preset_passmanagers/plugin.py#L89 .

Copy link
Copy Markdown
Member

@1ucian0 1ucian0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: Added Add an "Added" entry in the GitHub Release changelog.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants