Skip to content
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

Implementing pluggable HighLevelSynthesis #8548

Merged
merged 42 commits into from
Sep 30, 2022

Conversation

alexanderivrii
Copy link
Contributor

@alexanderivrii alexanderivrii commented Aug 15, 2022

Summary

Implementing "pluggable" high-level synthesis, based on previous feedback and discussions. Further feedback is welcome.

[Updated on Sept. 12]

Details and comments

The transpile function has a new argument hls_config (possibly better name is needed) that gets propagated all the way to HighLevelSynthesis transpiler pass. This requires minor changes to transpiler.py, passmanager_config.py, preset_passmanagers/__init__.py, preset_passmanagers/common.py and preset_passmanagers/level*.py. This is similar to how unitary_synthesis_method and unitary_synthesis_plugin_config arguments are propagated, except that we put all the arguments for all higher-level objects of interest in a single HLSConfig class.

The HLSConfig allows to specify for each higher-level-object of interest, a list of synthesis methods and their arguments to use.
For instance,

hls_config = HLSConfig(use_default_on_unspecified=True,
                       linear_function=[("depth_opt", {}), ("count_opt", {})],
                       clifford=[])
qct = transpile(qc, optimization_level=1, hls_config=hls_config)

says to synthesize LinearFunctions using depth_opt (with no additional arguments), and if this fails -- then with count_opt (with no additional arguments); to skip synthesis for Cliffords (since the passed list is empty); and to use default method for every other higher-level-object (when such adefault method is available).

HighLevelSynthesis transpiler pass is now very generic, only based on the name of the dag node, hls_config, and available plugins. There are still multiple things to sort out there, but the idea is that this transpiler pass should not change each time that a new higher-level-object or synthesis method is added.

For each higher-level-object of interest in Qiskit, we write synthesis algorithms for this object, and register them via entry points in setup.py as

"qiskit.synthesis": [
        "clifford.default = qiskit.transpiler.passes.synthesis.high_level_synthesis_plugins:DefaultSynthesisClifford",
        "linear_function.default = qiskit.transpiler.passes.synthesis.high_level_synthesis_plugins:DefaultSynthesisLinearFunction",
        "linear_function.depth_opt = test_stuff:LinearFunctionSynthesisPluginForDepth",    
],

Here the "group name" qiskit.synthesis is always the same, and the strings such as linear_function.depth_opt consist of the higher-level-object name (linear_function) and the synthesis method (depth_opt).

The high_level_synthesis_plugins.py contains two new default plugins DefaultSynthesisClifford and DefaultSynthesisLinearFunction for synthesizing Cliffords and LinearFunctions respectively , and can be extended in the future to cover more higher-level-objects. Possibly we should make a directory for plugins instead.

The depth_opt and count_opt entry points in setup.py correspond to what the user may write, and are not be a part of Qiskit. A slightly better example with two Operations OpA and OpB and their synthesis methods (mimicking what a user may potentially write) appears in test/python/transpiler/test_high_level_synthesis.py.

Some possible use-cases

  • The user wants to use the "default" method for every higher-level operation. This is the default behavior of transpile, without needing to pass hls_config parameter. Alternatively one can pass to transpile the argument hls_config = HLSConfig(use_default_on_unspecified=True) or hls_config = HLSConfig().

  • The user wants to use the "default" method for every higher-level operation, except for linear_functions, for which the user wrote a special synthesis algorithm (e.g., LinearFunctionSynthesisPluginForDepth). This needs to be registered in entry points (under the name linear_function.depth_opt). Then one can create

hls_config = HLSConfig(linear_function=[("depth_opt", {})])

and pass that to transpile. All the higher-level-objects not mentioned in the hls_config are synthesized using the "default" method (when available) or skipped (when not available).

  • The user wants to synthesize only linear functions using depth_opt and leave all the other higher-level objects as they are. This is accomplished by
hls_config = HLSConfig(use_default_on_unspecified=False, linear_function=[("depth_opt", {})])
  • The user wants to synthesize every higher-level object, except for linear functions. This is accomplished by:
hls_config = HLSConfig(linear_function=[])

To do

  • Agree and potentially simplify the current API
  • Possibly expand on documentation (or maybe just link to how to write plugins for unitary synthesis)
  • Understand which additional parameters it makes sense to pass to HighLevelSynthesis transformation pass (for example,coupling_map or min_qubits), and whether to extend the required interface of HighLevelSynthesisPlugin with certain support_* functions. Though maybe we can start simple, and add these once relevant synthesis algorithms become available.

@qiskit-bot
Copy link
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

Copy link
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.

Few quick comments, this looks good so far. It would be good to see if this can be further consolidated with UnitarySynthesis.

@coveralls
Copy link

coveralls commented Sep 9, 2022

Pull Request Test Coverage Report for Build 3160677768

  • 70 of 74 (94.59%) changed or added relevant lines in 13 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.008%) to 84.654%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/transpiler/passes/synthesis/plugin.py 19 20 95.0%
qiskit/transpiler/passes/synthesis/high_level_synthesis.py 39 42 92.86%
Totals Coverage Status
Change from base Build 3160676990: 0.008%
Covered Lines: 61482
Relevant Lines: 72627

💛 - Coveralls

@alexanderivrii alexanderivrii changed the title [WIP] Initial implementation of pluggable HighLevelSynthesis Implementing pluggable HighLevelSynthesis Sep 12, 2022
@alexanderivrii alexanderivrii marked this pull request as ready for review September 12, 2022 11:35
@alexanderivrii alexanderivrii requested a review from a team as a code owner September 12, 2022 11:35
@kdk kdk added this to the 0.22 milestone Sep 13, 2022
@alexanderivrii
Copy link
Contributor Author

I have tweaked the documentation following @kdk's comments.

I think that the suggestion to combine high-level-synthesis plugin file and unitary-synthesis plugin file into one, and to extend documentation to cover both cases makes sense, but I would like to get @mtreinish opinion before starting to change things.

@kdk raised some very interesting questions:

  • how can we (adjust the current infrastructure) to synthesize linear functions with synthesis methods for cliffords (which in theory can be easily done)?
  • how do we collect-and-resynthesize blocks of linear or clifford gates in the optimization loop?

I don't have great answers for these, so suggestions are highly welcome!

@Aerylia
Copy link

Aerylia commented Sep 22, 2022

I find it difficult to grasp the current state of the plugin, so I will simply list what I'd like to use it for and you can discuss which of those should make it in if they are not already.

First and for most, I'd use it for the purposes of solving qubit routing (without really routing), so I need a coupling map. For this part, I will assume that is done.

  • LinearFucntions (done)
  • Re-synthesising CNOT+X, similar to LinearFunctions see this paper
  • Re-synthesising phase polynomials, similar to graysynth - uses Linearfunctions.
  • Re-synthesising PauliStrings, generalisation of Graysynth and universal. However, you are not synthesizing from the unitary, so I would use this plugin for it. See PauliHedral
  • Re-synthesising the full circuit by representing it as a sequence of phase polynomials with Hadamards in between and optimizing it using simulated annealing like they did here
  • Turning the circuit into a ZX diagram and extracting it back out

I think most of these uses require some specific representation of (part of) the circuit. From there, you can make many different algorithms that synthesize from that representation. I expect it would make sense to have various different subclasses of the HighLevelSynthesis class, for each representation, such that we can call the LinearFunction plugin from the GraySynth plugin (for example). While some of the different strategies for full-circuit synthesis require very different representation from each other.

Then, when I have those, I'd like to play around with different heuristics in each of these algorithms and maybe take gate fidelities into account.

Hope my ramble is useful.

@ShellyGarion
Copy link
Member

@Aerylia - it seems that you have a great plan! I hope that this PR will get merged soon, so that you can continue with your suggested work.
We have a code for graysynth in qiskit, which is currently not being used by any of the transpiler passes:
https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/transpiler/synthesis/graysynth.py
There is also a community PR on Paulihedral #8539 (but I'm not sure about its current status).

@mtreinish mtreinish added the Changelog: New Feature Include in the "Added" section of the changelog label Sep 28, 2022
Copy link
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.

Thanks for the updates! I think after the documentation consolidation from #8548 (comment), this will be good to go.

setup.py Outdated Show resolved Hide resolved
Co-authored-by: Kevin Krsulich <kevin@krsulich.net>
Copy link
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.

Thanks for the updates, this LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog synthesis
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants