-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add qk_obs_apply_layout to apply layouts to QkObs
#14106
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
|
One or more of the following people are relevant to this code:
|
crates/accelerate/src/nlayout.rs
Outdated
| pub struct NLayout { | ||
| virt_to_phys: Vec<PhysicalQubit>, | ||
| phys_to_virt: Vec<VirtualQubit>, | ||
| pub virt_to_phys: Vec<PhysicalQubit>, |
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.
These are made public to be able to easily call SparseObservable::apply_layout, which takes the virt_to_phys vector. This could be worked around by using the available public methods, but I think that would require a copy that I wanted to avoid.
crates/cext/src/sparse_observable.rs
Outdated
|
|
||
| // Cast the slice of PhysicalQubit (which is u32) to plain u32, which is required | ||
| // by the apply_layout method. | ||
| let as_slice: &[u32] = ::bytemuck::cast_slice(&layout.virt_to_phys); |
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 line (and the NoUninit for PhysicalQubit) warrants extra care since it's the first time I'm using bytemuck 😄
Pull Request Test Coverage Report for Build 17462696448Warning: 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 |
jakelishman
left a comment
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.
Honestly, exposing NLayout like this feels premature to me. The low-level Rust interface to SparseObservable::apply_layout doesn't take NLayout, only layout: Option<&[u32]>, num_qubits: u32, and NLayout doesn't represent everything that TranspileLayout does. Right now, C still has to completely manually build the NLayout, so if anything, exposing NLayout makes it harder, not easier.
I'd suggest we wait til we actually know what we're going to be returning from any form of the transpiler. NLayout might be accessible, but the "high-level" return type from the transpiler representing layouts is still presumably going to be a TranspileLayout-like wrapper. SparseObservable.apply_layout doesn't take a Layout in Python space, which is the analogue.
|
Just using an array instead of But won't we have to introduce equivalents of both |
|
We'll likely need something akin to |
|
My point is: we're not at a point yet where we can know what will be ergonomic. Let's not guess - there's no harm in presenting a low-level interface and then waiting a bit til we're more sure to present a high-level one. |
This commit adds a Rust TranspileLayout object which is analgous to the Python space object. It is a self contained struct that is only for Rust and will be used by the C API for the C transpiler so that users will be able to reason about the permutations caused by the transpiler. This will also be used by Qiskit#14106 to apply a transpilation layout to the SparseObservable in C. This commit only adds the rust struct and it's associated tests, a subsequent PR will add the C API on top. This won't be used until we have a full path transpiler in C though (see Qiskit#14760).
* Add TranspileLayout struct to rust This commit adds a Rust TranspileLayout object which is analgous to the Python space object. It is a self contained struct that is only for Rust and will be used by the C API for the C transpiler so that users will be able to reason about the permutations caused by the transpiler. This will also be used by #14106 to apply a transpilation layout to the SparseObservable in C. This commit only adds the rust struct and it's associated tests, a subsequent PR will add the C API on top. This won't be used until we have a full path transpiler in C though (see #14760). * Add routing permutation composition method * Improve routing permutation APIs and make more rust native This commit improves the routing permutation method to make them more rust native. It updates the return to be a slice of PhysicalQubits instead of an owned vec. To get the explicit trivial permutation in the case of None a new method explicit_routing_permutation is added that returns `Cow<[PhysicalQubits]>` and only allocates in the None case. * Update final layout methods This commit updates the final layout method to return a NLayout and a new method final_index_layout is added to return a Vec. * Improve documentation * Fix lint * Add support for python interop This commit adds methods to convert to and from the Python space transpile layout class. This requires changing the data in the rust struct slightly so that we are tracking the virtual bits to build the view that the Python struct needs. This isn't strictly needed for a pure rust view of the data, but doesn't add much overhead to track it to support python. * Fix lint * Make initial_layout optional This commit updates the initial_layout attribute to make it optional. In the transpiler a layout doesn't necessarily need to be set so to account for that this the attribute is made optional. * Rename routing_permutation -> output_permutation * Make output_permutation use Qubit instead of PhysicalQubit Now that output_permutation is storing the abstract permutation whether there is a layout or not it means the PhysicalQubit type doesn't accurately reflect the purpose of the field anymore since it might not be a physical qubit. This commit fixes this by using the Qubit type which just represent the index in the circuit which is all the permutation is. * Fix Python accesses in `TranspileLayout::from_py_native` --------- Co-authored-by: Jake Lishman <[email protected]>
mtreinish
left a comment
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 needs a rebase pretty badly, it predates the crate re-organization apparently since nlayout and sabre layout are still in accelerate. Besides the rebase I think this PR can be greatly simplified now that we have TranspileLayout in rust and C. You can just use that directly as an input for your apply_layout() function and it's all pretty straightforward from there.
That's why this PR had no movement for several months and is way out of date - it was waiting for |
|
Julien and I talked offline, and we think that going to: QkObs *qk_obs_apply_layout(const QkObs *obs, uint32_t *layout, uint32_t num_qubits);is the best trade-off for C, with the option to add a variant QkObs *qk_obs_apply_transpile_layout(const QkObs *obs, const QkTranspileLayout *layout);later if there's direct demand. The action on let obs: SparseObservable;
let layout: TranspileLayout;
let new_obs = obs.apply_layout(&layout.final_index_layout(false), layout.num_output_qubits());and C space has direct equivalents. I think this is simple enough that we can simply teach it by documentation, and that gives C more control over its allocations and low-level access to the |
qk_obs_apply_layout plus necessary toolingqk_obs_apply_layout to apply layouts to QkObs
crates/cext/src/sparse_observable.rs
Outdated
|
|
||
| let obs_with_layout = match obs.apply_layout(layout, num_qubits) { | ||
| Ok(obs_with_layout) => obs_with_layout, | ||
| Err(_) => return ExitCode::TranspilerError, |
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 actually a transpiler error if the user is providing a pointer to the layout array? It's more the input is invalid and probably came from the transpiler but they could have just generated an invalid layout right?
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.
Yeah good question, it uses CoherenceError Rust side, saying e.g. that the qubit index is invalid. The nicest thing would be to match the error variants and give some actual information.
mtreinish
left a comment
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 this is good to go now, just one small comment about the docs for the new function besides that I think we can move forward with this.
| /// @param layout A pointer to the layout. The pointer must point to an array to | ||
| /// ``qk_obs_num_qubits(obs)`` elements of type ``uint32_t``. Each element must have values | ||
| /// in ``[0, num_qubits)``. |
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.
What does the array passed to layout represent? I assume it's mapping index i to the physical qubit. But it's good to be explicit here about what the alayout array is besides just the data types.
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.
good point, I added an explanation to the docstring in cf65b46 👍🏻
mtreinish
left a comment
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 was going to approve it but I caught a few more small things.
| num_failed += RUN_TEST(test_direct_fail); | ||
| num_failed += RUN_TEST(test_obs_str); | ||
| num_failed += RUN_TEST(test_obsterm_str); | ||
| num_failed += RUN_TEST(test_apply_layout); |
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.
| num_failed += RUN_TEST(test_apply_layout); | |
| num_failed += RUN_TEST(test_apply_layout); | |
| num_failed += RUN_TEST(test_apply_layout_too_small); |
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.
Uff good catch! We should add a bash script that checks this...
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.
Fixed 👍🏻
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 we get in the habit of declaring our test functions as static, I think the linter should warn about it being unused.
crates/circuit/src/nlayout.rs
Outdated
| layout.phys_to_virt[self.index()] | ||
| } | ||
| } | ||
| unsafe impl ::bytemuck::NoUninit for PhysicalQubit {} |
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 don't think this is actually needed anymore (not sure when it was). Testing it locally nothing fails if you remove this.
| unsafe impl ::bytemuck::NoUninit for PhysicalQubit {} |
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 was needed since I wanted to cast u32 to PhysicalQubit using bytemuck -- but we don't need that anymore 🙂
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.
Removed!
test/c/test_sparse_observable.c
Outdated
| int err = qk_obs_apply_layout(obs, layout, 3000); | ||
| qk_obs_free(obs); | ||
|
|
||
| return err == QkExitCode_MismatchedQubits ? Ok : EqualityError; |
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 this is going to fail, in my local testing it's returning an IndexErrror
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.
Oh yeah the MismatchedQubits would only be raised if the layout was too small to accommodate the qubits -- here we don't have enough indices instead. Fixed!
- NoUninit no longer needed - missed a test
* Add TranspileLayout struct to rust This commit adds a Rust TranspileLayout object which is analgous to the Python space object. It is a self contained struct that is only for Rust and will be used by the C API for the C transpiler so that users will be able to reason about the permutations caused by the transpiler. This will also be used by Qiskit#14106 to apply a transpilation layout to the SparseObservable in C. This commit only adds the rust struct and it's associated tests, a subsequent PR will add the C API on top. This won't be used until we have a full path transpiler in C though (see Qiskit#14760). * Add routing permutation composition method * Improve routing permutation APIs and make more rust native This commit improves the routing permutation method to make them more rust native. It updates the return to be a slice of PhysicalQubits instead of an owned vec. To get the explicit trivial permutation in the case of None a new method explicit_routing_permutation is added that returns `Cow<[PhysicalQubits]>` and only allocates in the None case. * Update final layout methods This commit updates the final layout method to return a NLayout and a new method final_index_layout is added to return a Vec. * Improve documentation * Fix lint * Add support for python interop This commit adds methods to convert to and from the Python space transpile layout class. This requires changing the data in the rust struct slightly so that we are tracking the virtual bits to build the view that the Python struct needs. This isn't strictly needed for a pure rust view of the data, but doesn't add much overhead to track it to support python. * Fix lint * Make initial_layout optional This commit updates the initial_layout attribute to make it optional. In the transpiler a layout doesn't necessarily need to be set so to account for that this the attribute is made optional. * Rename routing_permutation -> output_permutation * Make output_permutation use Qubit instead of PhysicalQubit Now that output_permutation is storing the abstract permutation whether there is a layout or not it means the PhysicalQubit type doesn't accurately reflect the purpose of the field anymore since it might not be a physical qubit. This commit fixes this by using the Qubit type which just represent the index in the circuit which is all the permutation is. * Fix Python accesses in `TranspileLayout::from_py_native` --------- Co-authored-by: Jake Lishman <[email protected]>
* apply transpile layout * raw interface * docs * clippy + memleak * add reno * review comments * fix tests * variable with arrays not valid for GCC/MSVC * explain the ``layout`` array better * Review comments - NoUninit no longer needed - missed a test
* apply transpile layout * raw interface * docs * clippy + memleak * add reno * review comments * fix tests * variable with arrays not valid for GCC/MSVC * explain the ``layout`` array better * Review comments - NoUninit no longer needed - missed a test
* Add TranspileLayout struct to rust This commit adds a Rust TranspileLayout object which is analgous to the Python space object. It is a self contained struct that is only for Rust and will be used by the C API for the C transpiler so that users will be able to reason about the permutations caused by the transpiler. This will also be used by Qiskit#14106 to apply a transpilation layout to the SparseObservable in C. This commit only adds the rust struct and it's associated tests, a subsequent PR will add the C API on top. This won't be used until we have a full path transpiler in C though (see Qiskit#14760). * Add routing permutation composition method * Improve routing permutation APIs and make more rust native This commit improves the routing permutation method to make them more rust native. It updates the return to be a slice of PhysicalQubits instead of an owned vec. To get the explicit trivial permutation in the case of None a new method explicit_routing_permutation is added that returns `Cow<[PhysicalQubits]>` and only allocates in the None case. * Update final layout methods This commit updates the final layout method to return a NLayout and a new method final_index_layout is added to return a Vec. * Improve documentation * Fix lint * Add support for python interop This commit adds methods to convert to and from the Python space transpile layout class. This requires changing the data in the rust struct slightly so that we are tracking the virtual bits to build the view that the Python struct needs. This isn't strictly needed for a pure rust view of the data, but doesn't add much overhead to track it to support python. * Fix lint * Make initial_layout optional This commit updates the initial_layout attribute to make it optional. In the transpiler a layout doesn't necessarily need to be set so to account for that this the attribute is made optional. * Rename routing_permutation -> output_permutation * Make output_permutation use Qubit instead of PhysicalQubit Now that output_permutation is storing the abstract permutation whether there is a layout or not it means the PhysicalQubit type doesn't accurately reflect the purpose of the field anymore since it might not be a physical qubit. This commit fixes this by using the Qubit type which just represent the index in the circuit which is all the permutation is. * Fix Python accesses in `TranspileLayout::from_py_native` --------- Co-authored-by: Jake Lishman <[email protected]>
* apply transpile layout * raw interface * docs * clippy + memleak * add reno * review comments * fix tests * variable with arrays not valid for GCC/MSVC * explain the ``layout`` array better * Review comments - NoUninit no longer needed - missed a test
Summary
This PR adds support to apply layouts to
QkObsin the C API.Details and comments
This is done by exposing
NLayoutto represent the layout, which we also expect to be the result type of routing passes like VF2Layout. It would also be possible to use plain&[u32]but this wayqk_obs_apply_layoutalways uses a consistent type. The layout is exposed as opaque pointer calledQkLayoutwith associated functionsqk_layout_newandqk_layout_free.