-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Fixing definition method for PyGate
and PyInstruction
#13777
Conversation
One or more of the following people are relevant to this code:
|
Pull Request Test Coverage Report for Build 13430994521Details
💛 - 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.
Going via QuantumCircuitData
seems like it would work (though I would ask whether the case of definition
being None
still returns None
with this new solution?) but this will populate a lot fields we don't return in the end (since we only return .data
but e.g. .qregs
and many others are being built).
Couldn't we fix the previous code by removing the .call0
and directly trying to cast the definition into a CircuitData
? This way we'd only build the data we actually return from the function.
Thanks @Cryoris: the fix looks even better after applying your suggestion to avoid constructing the full Unfortunately, creating a test from within Rust space seems impossible before the problems mentioned in #13776 are solved. The only thing I managed to do is creating a regular function in |
PyGate
and PyInstruction
PyGate
, PyInstruction
and UnitaryGate
crates/circuit/src/operations.rs
Outdated
Python::with_gil(|py| -> Option<CircuitData> { | ||
let py_op = self | ||
.create_py_op(py, &ExtraInstructionAttributes::default()) | ||
.unwrap(); | ||
match py_op.getattr(py, intern!(py, "definition")) { | ||
Ok(definition) => definition | ||
.getattr(py, intern!(py, "_data")) | ||
.ok()? | ||
.extract::<CircuitData>(py) | ||
.ok(), | ||
Err(_) => None, |
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.
Do we need a definition for UnitaryGate at all? I purposely didn't define it here because the python space one is to call unitary synthesis. In rust it's a bit of a layer violation to do that since it lives in the accelerate crate. While going through python avoids that issue, I'm wondering if it's really necessary because it's not a definition in the strict sense like it is for a concrete gate.
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 need this to handle certain corner-cases arising when porting HighLevelSynthesis
to Rust. Even if HighLevelSynthesis
runs right after UnitarySynthesis
, there may be gates whose plugins / definitions include UnitaryGates
, which then need to be recursively synthesized (this is for instance the case for Isometry
gates). The current HighLevelSynthesis
code in Python handles this by extracting definition
for these unitary gates, and proceeding recursively, so it made sense for the Rust code to do so as well. I would be happy to hear alternative approaches.
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.
Why not just call the two qubit decomposer on the matrix if you encounter a unitary gate in hls during recursion? Realistically that's what you are doing here, just via a very inefficient path that goes back and forth through python.
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.
To make sure I understand this correctly, for 1- or 2- qubit unitaries we can use the decomposers already available in rust, and so we can completely avoid going through python; but for larger unitaries the _define
method of UnitaryGate
uses qs_decomposition
, which is only available in python, and so we would still have to go through the python space.
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.
Sure, we will have to rely on qsd in python for 3 or more qubit UnitaryGate
instances. But that's easy to both encapsulate to only use python when we need it and also substitute the python usage for a rust function if/when we have an implementation of qsd in rust. You can just do something like:
if matches!(inst.view(), OperationRef::Unitary(gate) {
match gate.num_qubits() {
0 => panic!(),
1 => call_euler_decomposer(),
2 => call_two_qubit_basis_decomposer_with_cx(),
_ => py_call_qsd(),
}
}
in hls.
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 makes sense. So I should revert the change to handle unitary gates? Alternatively, I could close this PR, and only keep the HLS PR, since it's the only consumer for the definition method.
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 having a standalone PR to fix definition is good. Just revert the unitary gate piece and I think we can merge 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.
Reverted in 5079541.
PyGate
, PyInstruction
and UnitaryGate
PyGate
and PyInstruction
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 fixing this.
Summary
This commit fixes a problem when calling
definition
for aPyGate
andPyInstruction
. Update: forUnitaryGate
we have decided to returningNone
is the best option.Details and comments
I have stumbled on this problem while working on porting
HighLevelSynthesis
to Rust, with thedefinition
method for a custom gate incorrectly returningNone
(instead of the expectedCircuitData
), e.g., on the following circuit:Looking at the code for
PyGate
the problem is that
circuit.definition
[in the Python space] is aQuantumCircuit
and not a callable, withdefinition.call0(...)
returning precisely this error message.The only question is how can I add a test for this fix? I don't see how I can add something to the Rust space and I don't see how I can add it to the Python space.