-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Rust implementation of the QPY module #14166
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
base: main
Are you sure you want to change the base?
Conversation
One or more of the following people are relevant to this code:
|
…g for QuantumCircuit parameters)
Hi @gadial, this is still in draft mode so I just gave it a brief look. I have a few general questions and comments at this stage:
|
Thanks @eliarbel
|
Pull Request Test Coverage Report for Build 16703840999Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - 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.
Hey @gadial, thanks for doing all of this.
This isn't a complete review by any means, but I just wanted to give you some comments to work through ahead of your holiday. I'll continue reviewing this coming week.
The general questions I have so far are:
- Are there any changes to the current QPY format to support any of this, or is it compatible without introducing a new version?
- This PR is quite a bit larger than I was expecting. Are there any more meaningful chunks that you might be able to split this into to make reviewing it easier to understand architecturally? I think when we spoke about it before, you mentioned that testing was easier if both reader and writer were in place. But that leads me to the third point:
- Should we have Rust-level unit testing for any of this? Or, is there some amount of stress testing we could do, i.e. generating complex circuits with both the old and new serializers and making sure the outputs are equivalent? I have some doubt that our existing QPY test coverage is sufficient to detect potential differences introduced here (but perhaps I am wrong). How confident are you that the new code is sufficiently exercised by what we've got?
} | ||
} | ||
|
||
impl TryFrom<&Bytes> for f64 { |
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 looks a bit suspect to me. What use-case do we have where we need to interpret a raw byte sequence as a big endian float? Shouldn't binrw
handle that automatically for us if one of our storage structs has an f64
field?
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.
That's used when converting a general dumped value to python: https://github.com/gadial/qiskit/blob/cc1f0fbd07cb6c38c123c078523fcf4636d18fc5/crates/qpy/src/value.rs#L554
I do think this can be avoided with smarter handling of DumpedValue
as a binrw enum, but I think it's best to save this for a future PR.
crates/qpy/src/circuits.rs
Outdated
pack_param(py, &target.extract::<Param>()?, qpy_data)?, | ||
pack_param(py, &cases_tuple.extract::<Param>()?, qpy_data)?, |
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.
We should be careful here since these aren't actually Param
s. We're trying to get rid of Param::Obj
(the control flow PR gets us most of the way there). I think they'd need to just be PyObject
for now 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.
Ok, changed pack_param
to handle Bound<PyAny>
objects instead. I still need to handle Param
objects here, though, so I renamed the previous pack_param
to pack_param_obj
.
|
Summary
Adds a rust-based implementation of qpy serialization.
Addresses #13131
Details and comments
We use rust structs along with the
binrw
library to specify and write the byte representation of data (this turns out to be somewhat simpler than how it's currently done in python). There are still many python-dependent elements we need to take into consideration:write_circuit
andread_circuit
(this is being kept until a later PR adds backward compatability)XGate
. Currently all the class names are obtained by accessing the__name__
field of the python class; for standard gates and instructions we'll need to switch to a python-independent solution (an ad-hoc dictionary is currently used for the reader component; there may be a better solution).Expr
was only recently moved to rust, after most of this PR was complete, we do not have a native Rust serialization yet; rather, we rely on the python serialization code (the_write_expr
and_read_expr
methods). There are many more places where Rust might be used but Python is used instead.save
.In this PR we make the distinction between
packing
an object andserializing
it:serializing
an object means generating a bytes representation for it (aVec<u8>
object, aliased toBytes
in the module.packing
an object means extracting its data fields and generating a corresponding rust struct, taken from theformats.rs
files. This might involve serializing some of the object's fields, and packing other fields.Our goal is to minimize serialization as much as possible, allowing us to generate a large packed struct reflecting the structure of the qpy file as much as possible before serializing; the code can be further improved to reflect this, although I think this can wait to a future PR.