-
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
Copy circuits and parameters when adding them to the EquivalenceLibrary
in Rust.
#13532
Conversation
One or more of the following people are relevant to this code:
|
Something seems strange about this. Why does the equivalence lookup mutate any part of the circuit at all, and why does serialisation/deserialisation via pickle not already produce separated instances? Is there any chance that the bug fix of #13482 helped here, before this PR? Maybe I just don't understand the mechanism of the fix here, but it doesn't seem right to copy a circuit when adding it as an equivalence - adding the equivalence should be transferring ownership, and once it's a part of the rule graph, it absolutely should not be being mutated by anything (edit: so my point is that it shouldn't matter even if the |
Pull Request Test Coverage Report for Build 12187010225Details
💛 - Coveralls |
I don't think anything is being mutated within the circuit here, but we do perform that extra copy when storing things within the As mentioned in the PR details, I suspected it had to do with some stale address being re-used during deserialization, but this shouldn't necessarily break the previous calls to Also, #13482 was what exposed this bug (described in #13504) as some parameters during The only change that seemed to have broken things in between was the copying over Update: Seems like copying the circuit is what makes it work here, not copying the |
- Remove the import of `copy`.
4fd00ba
to
fa1b056
Compare
I'm trying to have a little look, but copying the circuit is the more worrying part to me - the only live reference to the circuit after a call to
I think the This might work, but it probably isn't actually the root problem. I think there probably is some mistake lurking in I don't know 100% precisely, but I have strong suspicions that we have problems around the ownership model in the Python-object cache surrounding Rust-space
I imagine we quite possibly use both in Qiskit. I think, though, that given that |
I strongly suspect this is the root cause of the issue too or something similar. My assumption around |
Ok, here's a much more minimal reproducer of the problem without this PR: from qiskit.circuit import QuantumCircuit, StandardEquivalenceLibrary
from qiskit.transpiler.passes import BasisTranslator
rx_key = next(key for key in StandardEquivalenceLibrary.keys() if key.name == "rx")
# The circuit doesn't need to be parametric.
qc = QuantumCircuit(1)
qc.rx(0.5, 0)
BasisTranslator(
equivalence_library=StandardEquivalenceLibrary,
target_basis=["cx", "id", "rz", "sx", "x"],
)(qc)
inst = StandardEquivalenceLibrary._get_equivalences(rx_key)[0].circuit.data[0]
print(inst.params, inst.operation.params) A cached gate's parameters are getting mutated in the equivalence library by the basis translator, which is staying visible in the library. The So my updated suspicions: |
Matt: just saw your message now. I think I think we need to |
Hmm, no, actually I can be convinced by your way, Matt - it shakes out cheaper in memory usage, and it's cleaner to never attempt to mutate Python objects from Rust other than clean rebuilds. I was worried about custom gates needing to be updated, but if we update the Python object via the |
But that also means that |
Right now the closest thing we could do without introducing big changes is to re-implement the Is there anywhere else where we perform similar caching and might want to look at? |
This will be superceded by #13543 |
Fixes #13504
Summary
Adds a missing call to
copy
when adding equivalencies in theEquivalenceLibrary
, which solves the parallel failures happening with #13504.Details and comments
When
EquivalenceLibrary
was ported to rust, we missed the specific calls tocopy()
when adding an instance ofEquivalence
into the graph. This although harmless at first could break operability in parallel because, during serialization and de-serialization, the memory slot occupied by said parameter would not be available anymore and, therefore, when theBasisTranslator
tries to re-assign this parameter via lookup, the search would fail due to said parameter being linked to a memory address that may not exist in that instance.The following commits add the missing
copy()
calls for both the parameters and the instance ofCircuitData
, but also add a test-case for it in theBasisTranslator
. Although the failure happens within theEquivalenceLibrary
, we should keep the test there because theBasisTranslator
is what detects the dead parameter trying to be replaced.Tasks
Co-authored-by: Julien Gacon gaconju@gmail.com