-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Remove Python dependency from circuit construction #13986
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
In preparation for providing a C API for building and interacting with circuits this commit removes the required Python component from the circuit construction APIs on CircuitData. After Qiskit#13860 the only use case of Python in the circuit constructor is to manipulate a ParameterExpression global phase as ParameterExpression is still a Python only construct. This moves to using Python::with_gil() in those places only when it's needed. This gives us a path for building a circuit without the Python interpreter for the C API.
One or more of the following people are relevant to this code:
|
Pull Request Test Coverage Report for Build 13820220898Details
💛 - 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 looks like a nice start, it'll allow us to add C API functions to generate a circuit and add standard gates. I left one comment about copying below and another question is how we can allow circuit inspection; e.g. it would be nice if we can give index access to CircuitInstruction
s -- but these are very py-heavy right now 😅
crates/circuit/src/circuit_data.rs
Outdated
self_.reserve(py, reserve); | ||
self_.extend(py, data)?; | ||
self_.reserve(reserve); | ||
Python::with_gil(|py| -> PyResult<()> { self_.extend(py, 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.
It would be nice if we could also do this without the py token to enable copying circuits. What do you think about moving the with_gil
inside extend
in a way that we check if an instruction has parameter expressions and only then acquire the GIL? Maybe this has too much overhead and we can just wait for the Rust parameter expressions, too 😄
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 left it here because extend()
was being passed a Bound<PyAny>
I can drop the py here and just use it from the bound.
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 in 004b7b8 If we need to call extend()
in a no python context we'll probably want to split the method into two variants, one for rust data types the other for python. We can save that for a follow up PR though.
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.
The other, longer-term solution would be to wait until ParameterExpression
is in Rust and have a clean Circuit - PyCircuit split, then extend
would naturally be py-free. But I'm good as is for now 👍🏻
@@ -159,7 +158,7 @@ impl CircuitData { | |||
qubit_indices: BitLocator::new(), |
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.
The BitLocator
has a cached: OnceLock<Py<PyDict>>
, can this become an issue at runtime or is this fine since there's no way we can populate the cache with Python objects?
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 shouldn't be a problem we should only be initializing or working with the cached attribute when returning to python. There shouldn't be any code paths we access from cext where we could use this (or BitLocator
more broadly tbh). We can refactor more if we do encounter issues though.
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, I just have one question that can be answered in parallel: how expensive is a repetitive call to Py::with_gil
compared to passing the py token? I'm thinking e.g. of a circuit construction where we have a parameterized global phase and repeatedly add to this phase.
There is definitely an overhead to this, |
I ran asv with this PR (rebased on current main) against main and this was the result:
I'm not sure how reliable some of the numbers are TBH, for some of the benchmarks we're in a time scale where 5-6% is ~1 μs. I didn't run these on an idle system so other system noise can cause discrepencies like that. It's not showing any major regression though. |
Thanks for running the benchmarks! Seems like it doesn't change much and it'll enable the C circuits 👍🏻 We'll get a clean py-token-flow again once we correctly split the Python interface off I guess, so any slow down would only be an intermediate state 🙂 |
* Remove Python dependency from circuit construction In preparation for providing a C API for building and interacting with circuits this commit removes the required Python component from the circuit construction APIs on CircuitData. After Qiskit#13860 the only use case of Python in the circuit constructor is to manipulate a ParameterExpression global phase as ParameterExpression is still a Python only construct. This moves to using Python::with_gil() in those places only when it's needed. This gives us a path for building a circuit without the Python interpreter for the C API. * Remove with_gil for calling extend() in new()
Summary
In preparation for providing a C API for building and interacting with circuits this commit removes the required Python component from the circuit construction APIs on CircuitData. After #13860 the only use case of Python in the circuit constructor is to manipulate a ParameterExpression global phase as ParameterExpression is still a Python only construct. This moves to using Python::with_gil() in those places only when it's needed. This gives us a path for building a circuit without the Python interpreter for the C API.
Details and comments