-
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
Directly construct CircuitData in TwoQubitWeylDecomposition #12809
Directly construct CircuitData in TwoQubitWeylDecomposition #12809
Conversation
In the recently merged Qiskit#12740 a path was added for constructing the `CircuitData` in rust when synthesizing to a `QuantumCircuit` directly. However, in that PR this was done through a layer of indirection by first collecting the gates into an intermediate `Vec` and then passing an iterator of that into `CircuitData::from_standard_gates()`. However this resulted in an unecessary allocation for two `Vec`s and it would have been better to just directly construct the `CircuitData` object directly. However, to accomplish this we needed more rust space methods for creating and manipulating a `CircuitData` object as it's mostly being constructed from Python space or using `CircuitData::from_standard_gates()` with an iterator so far. This commit makes those additions and then updates the `TwoQubitWeylDecomposition` code to directly construct the `CircuitData` object instead of using an intermediate `Vec`.
One or more of the following people are relevant to this code:
|
let no_clbit_index = (&mut self.cargs_interner) | ||
.intern(InternerKey::Value(Vec::new()))? | ||
.index; |
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'm not super happy with this, it feels like unnecessary overhead on every call. It's why I didn't update from_standard_gates()
to call this new method because it does this outside the loop. It feels like maybe we should have an implicit empty index that's a constant in the interner so we can avoid 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.
I have a change to the interners I want to make once the DAGCircuit
PR merges that will avoid the need for the Vec
here in favour of the static empty slice (which is at least a small saving), but I think the idea of the special "intern key to the 'zero' object" is a good one too. I can see it coming up a lot, and I think it's doable without losing any particular generality in the interners - we can make it like
pub struct Interner<T> { ... };
pub struct InternKey<T> {
index: u32,
_phantom: PhantomData<T>,
};
impl<T: Default> InternKey<T> {
pub fn empty() -> Self {
Self {
val: 0,
_phantom: PhantomData,
}
}
}
or something like that, and arrange that the 0 index of Interner<T: Default>
always corresponds to <T as Default>::default()
.
I've run a quick little benchmark script: import statistics
import time
from qiskit.synthesis.two_qubit import TwoQubitWeylDecomposition
from qiskit.circuit.library import CXGate
from qiskit.quantum_info import random_unitary
unitaries = [random_unitary(4) for _ in range(10000)]
runtimes = []
for mat in unitaries:
start = time.perf_counter()
TwoQubitWeylDecomposition(mat).circuit()
stop = time.perf_counter()
runtimes.append(stop - start)
print(f"Mean runtime per unitary: {statistics.geometric_mean(runtimes)} sec.")
print(f"Total runtime for 10k unitary matrices: {sum(runtimes)} sec.") to compare the performance with and without this PR. There is a consistent small speedup I'm seeing with this PR applied. With this PR:
on current main:
There is some fluctuation in the numbers obviously especially with fully random unitaries, but I haven't seen a case where the PR is slower (or the same speed) than main. Not that |
Pull Request Test Coverage Report for Build 10305567368Details
💛 - 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 seems like a good idea to me, thanks for the updates.
…pacity`(backport #12943 + part of #12809) (#13038) * Allow `CircuitData` construction from `PackedOperation`s (#12943) * ``CircuitData::from_packed_operations`` * missing import * remove redundant `to_vec` (cherry picked from commit b1e7ffe) * Add with_capacity * Add CLBIT import * Run cargo fmt --------- Co-authored-by: Julien Gacon <[email protected]> Co-authored-by: Elena Peña Tapia <[email protected]> Co-authored-by: Elena Peña Tapia <[email protected]>
Summary
In the recently merged #12740 a path was added for constructing the
CircuitData
in rust when synthesizing to aQuantumCircuit
directly. However, in that PR this was done through a layer of indirection by first collecting the gates into an intermediateVec
and then passing an iterator of that intoCircuitData::from_standard_gates()
. However this resulted in an unecessary allocation for twoVec
s and it would have been better to just directly construct theCircuitData
object directly. However, to accomplish this we needed more rust space methods for creating and manipulating aCircuitData
object as it's mostly being constructed from Python space or usingCircuitData::from_standard_gates()
with an iterator so far. This commit makes those additions and then updates theTwoQubitWeylDecomposition
code to directly construct theCircuitData
object instead of using an intermediateVec
.Details and comments