-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Rework BasisTranslator
for faster basis search.
#7211
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
Conversation
Closes Qiskit#5539. This commit reworks the logic of `BasisTranslator._basis_search` to perform a modified BFS (instead of A* search) while searching for a set of transformation that maps source basis to target basis. In more detail, we build a directed graph `G = (V, E)` where `V` is the set of gates in the library and we add an edge `(ga, gb)` if there is an equivalence rule in the library `R = gb -> C_gb` and `ga in C_gb` (in the edge we also attach the rule `R`). Then, we do a BFS starting from the gates in the target basis. We traverse an edge `(ga, gb, R)` only if we have previously visited all the gates appearing in the right side of `R`. We terminate early if we've reached all gates in the original circuit. Otherwise, we can't map the given circuit in this basis. The performance improvement here mainly shows up when we attempt to target an unreachable basis, since in other cases the previously used A* search was already fast and after all, the real bottleneck of `BasisTranslator` for larger circuits is when we actually apply the basis transformation rules.
Tagging as on hold because this is blocked on the next retworkx release (which will include Qiskit/rustworkx#469) |
Running with this PR the examples from #5539 (comment):
|
Pull Request Test Coverage Report for Build 2030486720
💛 - 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 is cool! I just came by because it was top of my notifications and I need to get graph algorithms more solid in my head, but I left a couple of super minor comments that may make it a bit easier to read.
Co-authored-by: Jake Lishman <jake@binhbar.com>
I ran the asv basis translator benchmarks (mainly out of curiosity) on my workstation and got these results:
It looks like there is a nice performance improvement here across the board. Definitely more than just the negative case where there is no path found. |
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 this LGTM, I'm happy with how this looks. The one thing I'm wondering though is as a future optimization instead of building the graph on demand in the pass would it makes sense to incrementally build it in the equivalence library itself as we add rules. Then for the pass we can just add the dummy node and edges for the target basis (and remove them at the end of the pass). We can look at that in a future PR though or I might be missing something that's blocking us from doing that.
|
||
qarg_local_basis_transforms = {} | ||
for qarg, local_source_basis in qargs_local_source_basis.items(): | ||
expanded_target = target_basis | self._qargs_with_non_global_operation[qarg] | ||
expanded_target = set(target_basis) |
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.
Is this just to avoid the double add to the set for 1q gates? Or was this causing a bug somewhere?
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 previous line had actually no effect since self._qargs_with_non_global_operation
is indexed by a tuple
but qarg
is a frozenset.
# This is only neccessary since gates in target basis are currently reported by | ||
# their names and we need to have in addition the number of qubits they act on. |
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.
If a target is set we can get this via:
gate_num_qubits = target.operation_from_name(name).num_qubits
but that doesn't cover the non-target path.
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 mentioning that but since we still need this for the non-target case I guess it doesn't hurt much to leave it as is.
Actually one thing is it might be good to have a release note for this, since we're fixing some issues and maybe advertise the performance improvement too |
Yeah, I thought about that too but since Release note added in 908f66b. I didn't advertise fixing #7219 since this issue seems already fixed in main (probably by #7279) |
Well it looks like that function only exists internally for drawing the equivalence library so it's not super critical. I think we can either split it out that existing graph method as |
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 LGTM now, thanks for doing this
Summary
Closes #5539. Fixes #7219.
This commit reworks the logic of
BasisTranslator._basis_search
to perform a modifiedBFS (instead of A* search) while searching for a set of transformation that maps source
basis to target basis. In more detail, we build a directed graph
G = (V, E)
whereV
is the set of gates in the library and we add an edge
(ga, gb)
if there is an equivalencerule in the library
R = gb -> C_gb
andga in C_gb
(in the edge we also attach the ruleR
).Then, we do a BFS starting from the gates in the target basis. We traverse an edge
(ga, gb, R)
only if we have previously visited all the gates appearing in the right side of
R
. We terminateearly if we've reached all gates in the original circuit. Otherwise, we can't map the given
circuit in this basis.
The performance improvement here mainly shows up when we attempt to target an unreachable basis,
since in other cases the previously used A* search was already fast and after all, the real
bottleneck of
BasisTranslator
for larger circuits is when we actually apply the basis transformationrules.