-
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
Reorder Pauli terms before Trotterization #12925
Conversation
Reordering the terms of a Pauli operator can reduce the depth of the evolution circuit if using the Lie-Trotter or Suzuki-Trotter methods. This commit adds a method `synthesis.evolution.product_formula.reorder_paulis` that does just that, based on a greedy graph coloring heuristic. This commit also adds the `reorder` option in the `ProductFormula`, `LieTrotter` and `SuzukiTrotter` constructors to allow for reordering before synthesis.
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 following people are relevant to this code:
|
Pull Request Test Coverage Report for Build 11729926405Details
💛 - Coveralls |
@altaris are you still pursuing this or do would you like us to help? 🙂 |
Sure! I'd love to see it through 💪
|
Before that, if reorder_paulis was given a single-term SparsePauliOp object, it would return it encapsulated in a list. Now, it returns it as is.
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.
Overall the PR looks very nice! I left some comments below, in particular about the handling of lists of operators. Could you also add a release note describing the new argument? 🙂
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.
Just adding my 2 cents here
If `reorder_paulis` is given a list of operators, then they are reordered and returned individually. Before this co mmit, they used to be added all together and then reordered, which always resulted in a single operator.
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. thanks for the nice contribution to Qiskit. Some release notes are needed.
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 @Cryoris and the original contributor @altaris! I think allowing Pauli reordering is a useful option for the PauliEvolutionGate
synthesis algorithms.
I have left a few minor comments and questions inline.
One more question: do you think that for Rustiq-based synthesis algorithm (and the plugin already accepts "preserve_order"), it might be beneficial to rearrange Paulis before passing the pauli network to Rustiq?
That is already possible to do with this PR, since the re-ordering happens before |
I think it makes sense to expose this to Rustiq plugin as well. And I think it makes sense to let Rustiq do the additional reordering. |
- add reno - docs - safer list concat
56e619c includes this option in the Rustiq plugin too 👍🏻 |
@@ -60,6 +60,7 @@ def __init__( | |||
| None | |||
) = None, | |||
wrap: bool = False, | |||
preserve_order: bool = False, |
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 thought the consensus here was to not reorder terms by default because of the potential performance overhead. Shouldn't the default be to True
?
@@ -63,6 +69,7 @@ def __init__( | |||
| None | |||
) = None, | |||
wrap: bool = False, | |||
preserve_order: bool = False, |
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.
Same question here
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.
preserve_order: bool = False, | |
preserve_order: bool = True, |
if "preserve_order" in options and isinstance(algo, ProductFormula): | ||
algo.preserve_order = options["preserve_order"] | ||
|
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 adding this. A very small nitpick: we don't need another call to isinstance(also, ProductFormula)
here, since we've just checked this on the line above.
I think given the open questions and the proximity to 1.3.0 (ie this is the last PR being tracked) it's probably better to defer this to 2.0.0 rather than force it in. This feature is a nice to have, but I don't think it's absolutely necessary for 1.3.0 |
Pushing to 2.0.0 after further discussion... |
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 @Cryoris. This PR very nicely concludes the work that was done to improve the support for Pauli evolutions: representing them as gates, improving expansion methods, adding the plugin interface, new synthesis algorithms and new options, porting relevant code to Rust.
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'm fine with merging this as is. I just have 2 small nits inline, but they can be fixed in a followup without issue and aren't worth blocking this over.
preserve_order: If ``False``, allows reordering the terms of the operator to | ||
potentially yield a shallower evolution circuit. Not relevant | ||
when synthesizing operator with a single term. |
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 think from a docs perspective it would be good to explain the tradeoffs here, especially around runtime performance.
terms = sorted(paulis, key=_term_sort_key) | ||
graph = rx.PyGraph() | ||
graph.add_nodes_from(terms) | ||
indexed_nodes = list(enumerate(graph.nodes())) |
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 think you don't actually need to cast this is as a list, it should all work fine without it and save a copy.
Summary
Reordering the terms of a Pauli operator can reduce the depth of the evolution circuit if using the Lie-Trotter or Suzuki-Trotter methods. This PR adds the option to do just that.
Details and comments
This PR adds
synthesis.evolution.product_formula.reorder_paulis
that reorders Pauli terms based on a greedy graph coloring heuristic;reorder
option in theProductFormula
,LieTrotter
andSuzukiTrotter
constructors to allow for reordering before synthesis.