-
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
Fully port InverseCancellation to Rust #13013
Conversation
One or more of the following people are relevant to this code:
|
98e6159
to
7614689
Compare
Pull Request Test Coverage Report for Build 10745716091Details
💛 - Coveralls |
This commit builds off of Qiskit#13013 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for creating `UnitaryGate` instances and `ParameterExpression` for global phase. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different gates so we should be able to increase the throughput of the pass by leveraging multithreading to handle each gate in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Part of Qiskit#12208
7614689
to
00c7e10
Compare
This commit builds off of Qiskit#13013 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for creating `UnitaryGate` instances and `ParameterExpression` for global phase. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different gates so we should be able to increase the throughput of the pass by leveraging multithreading to handle each gate in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Part of Qiskit#12208
This commit builds off of Qiskit#12959 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for handling parameter expressions. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different inverse gates/pairs so we should be able to the throughput of the pass by leveraging multithreading to handle each inverse option in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Fixes Qiskit#12271 Part of Qiskit#12208
00c7e10
to
170148c
Compare
This commit builds off of Qiskit#13013 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for creating `UnitaryGate` instances and `ParameterExpression` for global phase. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different gates so we should be able to increase the throughput of the pass by leveraging multithreading to handle each gate in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Part of Qiskit#12208
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.
Looks good so far!
Let me know what you think about the comments (they're mostly minor and not blocking).
} | ||
let mut collect_set: HashSet<String> = HashSet::with_capacity(1); | ||
collect_set.insert(gate.operation.name().to_string()); | ||
let gate_runs: Vec<Vec<NodeIndex>> = dag.collect_runs(collect_set).unwrap().collect(); |
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.
It looks like DAGCircuit::collect_runs
returns an Option
only because it directly returns the result of the Rustworkx core function, which uses None
to represent a cycle in the graph (...which is questionable lol).
Perhaps it is beyond the scope of this PR, but it might be nice if you can change DAGCircuit::collect_runs
to unwrap that option internally. If it fails, it should be on DAGCircuit
for getting itself into an invalid state.
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, I'm fine with making this change to collect_runs()
but I'd say lets save this for a follow-up PR so we can do it in isolation.
} else { | ||
panic!("Not an op node") | ||
}; | ||
if inst.qubits != next_qargs { |
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.
Cool! I think this is the first example I've seen of the intern IDs saving us some time :)
.and_modify(|count| *count += value) | ||
.or_insert(*value); | ||
} | ||
let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); |
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.
Maybe it's worth adding a count_ops
method to CircuitData
, and calling that directly instead of converting to a DAGCircuit
first.
I'm not saying that we should necessarily bother maintaining op counts in CircuitData
like we do in a DAGCircuit
, but computing on the fly should still be faster than recursively converting everything to a DAGCircuit
.
Not necessary for this PR, but I wouldn't be opposed to doing it here either.
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.
It's funny you mention this, that was added last week: 5fc1635
but the implementation there is governed by the api of the python space method and not how I would implement it for performance in the transpiler.
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 changes! We can fix the result type of DAGCircuit::collect_runs
in a follow-up PR.
* Fully port Split2QUnitaries to rust This commit builds off of #13013 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for creating `UnitaryGate` instances and `ParameterExpression` for global phase. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different gates so we should be able to increase the throughput of the pass by leveraging multithreading to handle each gate in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Part of #12208 * Update pass logic with changes from #13095 Some of the logic inside the Split2QUnitaries pass was updated in a recently merged PR. This commit makes those changes so the rust implementation matches the current state of the previous python version. * Use op_nodes() instead of topological_op_nodes() * Use Fn trait instead of FnMut for callback We don't need the callback to be mutable currently so relax the trait to just be `Fn` instead of `FnMut`. If we have a need for a mutable environment callback in the future we can change this easily enough without any issues. * Avoid extra edge operations in replace_on_incoming_qubits * Rename function
Summary
This commit builds off of #12959 and the other data model in Rust
infrastructure and migrates the InverseCancellation pass to
operate fully in Rust. The full path of the transpiler pass now never
leaves Rust until it has finished modifying the DAGCircuit. There is
still some python interaction necessary to handle parts of the data
model that are still in Python, mainly for handling parameter
expressions. But otherwise the entirety of the pass
operates in rust now.
This is just a first pass at the migration here, it moves the pass to
use loops in rust. The next steps here are to look at operating
the pass in parallel. There is no data dependency between the
optimizations being done for different inverse gates/pairs so we should
be able to the throughput of the pass by leveraging multithreading to
handle each inverse option in parallel. This commit does not attempt
this though, because of the Python dependency and also the data
structures around gates and the dag aren't really setup for
multithreading yet and there likely will need to be some work to
support that.
Details and comments
This PR is based on top of #12959 and as such github shows the entire contents of #12959 in addition to the contents of this PR. To see the contents of this PR you can look at HEAD on this branch, or just look at:rebased00c7e10
Fixes #12271
Part of #12208
TODO: