-
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
Performance improvement of _DiagonalEstimator
#9229
Conversation
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:
|
Pull Request Test Coverage Report for Build 3618715227
💛 - Coveralls |
It would be great if this PR is backport stable because Qiskit optimization relies on |
LGTM, but I'll let @mtreinish or @jakelishman comment on the backporting part 🙂 From my side backporting would be fine considering this a "performance bug".... 😁 |
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 we can include this in a backport safely enough, as long as there's direct test coverage that the change produces correct results.
Every time I get tagged in one of these I always end up getting performance nerd-sniped. Here's my offering:
_PARITY = np.array([-1 if bin(i).count("1") % 2 else 1 for i in range(256)], dtype=np.complex128)
def _evaluate_sparsepauli(state: int, observable: SparsePauliOp) -> complex:
packed_uint8 = np.packbits(observable.paulis.z, axis=1, bitorder="little")
state_bytes = np.frombuffer(state.to_bytes(packed_uint8.shape[1], "little"), dtype=np.uint8)
reduced = np.bitwise_xor.reduce(packed_uint8 & state_bytes, axis=1)
return np.sum(observable.coeffs * _PARITY[reduced])
For small numbers of qubits and operators in the list, it's about ~10-20% faster, but say for an observable with 100q and 100 Paulis, it's nearly 10x faster due to avoiding the Python object conversions. For the optimisation code block given in the top comment, on my machine the evaluation went from 11.5s on main
to 1.1s with the version in this PR, and about 0.8s with my version of this function (I didn't time very accurately).
Co-authored-by: Jake Lishman <[email protected]>
Thank you, Jake. Your code is much faster than mine. Cool! |
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 improvement (and nerd-sniping 😉)!
* performance improvement of _DiagonalEstimator * optimize Co-authored-by: Jake Lishman <[email protected]> * add reno Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit 0df0d29)
* performance improvement of _DiagonalEstimator * optimize Co-authored-by: Jake Lishman <[email protected]> * add reno Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* performance improvement of _DiagonalEstimator * optimize Co-authored-by: Jake Lishman <[email protected]> * add reno Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit 0df0d29) Co-authored-by: Takashi Imamichi <[email protected]> Co-authored-by: Julien Gacon <[email protected]> Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* performance improvement of _DiagonalEstimator * optimize Co-authored-by: Jake Lishman <[email protected]> * add reno Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* performance improvement of _DiagonalEstimator * optimize Co-authored-by: Jake Lishman <[email protected]> * add reno Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Summary
I notice that
SamplingVQE
is slower than the formerVQE
when I update a tutorial of Qiskit optimization.The bottleneck is
_DiagonalEstimator._evaluate_sparsepuali
. See qiskit-community/qiskit-optimization#448 (comment) for details.I optimized that part with numpy.
Details and comments
microbenchmark
main
this PR
benchmark with QAOA
main
this PR