-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Oxidize commutation checker #12870
Oxidize commutation checker #12870
Conversation
One or more of the following people are relevant to this code:
|
Do you already have some profilings for this? 🚀 |
No :-( The part responsible for composing the commutator by using |
One or more of the following people are relevant to this code:
|
Ready for review, I'm running benchmarks later. :-) |
This commit removes the pending deprecation decorator from the python class definition as the Python class just internally is using the rust implementation now. This also removes directly using the rust implementation for the standard commutation library global as using the python class is exactly the same now. We can revisit if there is anything we want to deprecate and remove in 2.0 in a follow up PR. Personally, I think the cache management methods are all we really want to remove as the cache should be an internal implementation detail and not part of the public interface.
This commit makes the pickling of cache entries explicit. Previously it was relying on conversion traits which hid some of the complexity but this uses a pair of conversion functions instead.
Now that the python commutation checker and the rust commutation checker are the same thing the ddt parameterization of the commutation checker tests was unecessary duplication. This commit removes the ddt usage to restore having a single run of all the tests.
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 I'm happy enough with the current state of the PR to move forward here. But since I've touched a fair amount of this code now I don't think that I should approve it anymore. I think there are probably some things we could cleanup or improve in follow ups but nothing worth blocking over in particular. Especially considering this is more of an incremental step to enable #12995.
Hmm, it looks like there might be a logic bug in the new code somewhere and it's not cancelling something that it used to. I ran a quick asv run to see the speedup (which is looking pretty good) but the depth for the qft example has regressed:
|
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.
Thank you for working on this @Cryoris, I just have a couple of inline comments, mostly just speaking about a lot of precedures that could panic!
and could be handled with a Result
or PyResult
return value. Some of these already return PyResult
so it wouldn't be too hard to just make those work and return Python error types.
The reason why we should prefer PyResult
s over panic!
for python exposed API, is that Python cannot serialize PanicException
instances, thus these are taken with more severity and can't be handled properly. Now, this is only for python exposed API, for rust based api's it should be fine as long as the panic!
is produced due to a programming error in rust and not necessarily something coming from Python.
That could maybe point to different handling of gates with minuscule rotation angles -- maybe the old code considered things as commuting that the new one does not. We can check by looking at gates with tiny angles on both branches... Edit: Yes that indeed differs. For example: |
Co-authored-by: Raynel Sanchez <raynelfss@hotmail.com>
9235004 adds backward compatible handling of the tolerances, and some further error propagation instead of eager unwrapping (in spirit of @raynelfss previous comments). If CI passes, I think it should be good to go 🙂 |
such as the relative placement and the parameter hash
I reran asv after @Cryoris's recent changes and the performance is looking quite good:
|
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.
Thank you @sbrandhsn and @Cryoris for working on this. LGTM!
Summary
fixes #12702
Details and comments
This PR implements the commutation checker with a commutation cache and library as well as a helper function for composing unitary matrices in Rust. I left a couple of things for future work:
Operator.compose
but can be generalized fairly easily whenOperator
is implemented in Rust, too.DAGOpNode
are aPyTuple
and I wanted to get rid of Python objects as early as possible. :-) The signatures can be shortened when qubits and clbits are also in Rust space.Two things are changed lower in the Qiskit stack in
circuit_instruction.rs
andoperations.rs
:is_conditioned
returns whether an instruction is conditioned on classical bits and has been added tocircuit_instruction.rs
The- removed after further discussionto_matrix
method ofPyGate
andPyOperation
has been extended to include a call to python-sideOperator(self)
in case the python-sideto_matrix
call fails. This is a change in behavior and I can pull up that code into thecommutation_checker.rs
but I wanted to hear everyone's opinion here. I think that if we have all the necessary information to return a matrix, we should attempt to do that even if it comes at an increase in runtime.I'm fairly unfamiliar with Rust so if some of the behavior can be describe more succinctly please let me know. :-)
Speedups
We can see a speedup of up to 5x depending on the type of input circuit that should be evaluated for commutation relations. I suspect that we do not see a 10x speedup, as some may have expected, because: the heavy-lifting (matrix multiplications) is done by high-performance numpy code, the incorporated commutation caching quickly turns most commutation resolutions into a constant-time lookup the larger the circuit becomes, and the commutation library already contains most of the gates that we have in rust.
Random circuits with parameterized gates only benefit the most from the rust implementation:

Followed by random circuits with any kind of gate:

The speedup becomes larger for Clifford circuits on larger circuits as gate checks outweigh the contant-time lookup of clifford gates in the commutation library by far
