-
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
Fix QPY handling of registers #9095
Conversation
Thank you for opening a new pull request. Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient. While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone. One or more of the the following people are requested to review this:
|
QPY previously had rather complicated logic to handle deserialisation of registers that was heavily couched in the old model of registers "owning" the bits they contained. This is no longer the data model of the circuit, so the code was naturally complex to try and make it work. Instead, in deserialisation now we just add the correct number of bit instances to the circuit at the start, and then build up any required registers by using the `indices` field. It's not clear to me how an index ever could be negative here; it's not clear how a register could be in the circuit but its bits aren't added, so it feels like there might be the possibility of a bug I've missed.
a6d417e
to
4dbcaba
Compare
Pull Request Test Coverage Report for Build 3432228181
💛 - 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.
TBH, this whole code path for trying to recreate the exact bit and register combination was always super sketchy. In the original version we were trying to exactly recreate the same combination of registers and bits was recreated exactly. IIRC we added QPY around the same time as standalone bits and it complicated everything especially around bit ownership which has definitely been refined since then. But, I still get a bit anxious touching this code path.
That being said I think this is ok, I did some manual tests of different mixes of register bits and standalone and they all worked. We also have some pretty extensive unit tests with different combinations of bits and registers which we had to cover all the weird edge cases I came up with. But before we move forward on this I think it would be good if we had two more test cases I just realized was missing coverage before, we should test the round trip of a circuit with empty registers and a mix of an empty register with standalone bits. I know it works with this PR (I tested it) but I just want to make sure we're asserting that.
Sounds good - I added those new cases in 03d802c. |
If we're nervous about the scope of the change to the logic here, we could consider holding the bugfix until 0.23. |
Yeah, I think that would be wise. Or at least let it sit on main a bit longer than typically to ensure we've tested it sufficiently even if we decide to backport it eventually. |
* Fix QPY handling of registers QPY previously had rather complicated logic to handle deserialisation of registers that was heavily couched in the old model of registers "owning" the bits they contained. This is no longer the data model of the circuit, so the code was naturally complex to try and make it work. Instead, in deserialisation now we just add the correct number of bit instances to the circuit at the start, and then build up any required registers by using the `indices` field. It's not clear to me how an index ever could be negative here; it's not clear how a register could be in the circuit but its bits aren't added, so it feels like there might be the possibility of a bug I've missed. * Remove unused import * Add tests cases of empty registers Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
A major bugfix for QPY's handling of loose circuit bits in c0ac5fb (Qiskitgh-9095) caused the deprecated bit properties `index` and `register` to be lost after the QPY roundtrip. As far as Terra's data model is concerned, the two circuits would still compare equal after this loss; the output registers would still be equal to the inputs, and bit equality is not considered directly since it general bit instances are not expected to be equal between circuits. Losing this information caused some downstream issues for the IBM runtime, which was still relying on `Bit.index` working in some cases, despite it issuing a deprecating warning since Terra 0.17 (April 2021). While this can be corrected downstream, QPY can still do a better job of roundtripping the deprecated information while it is still present. The QPY format does not currently store enough information to _completely_ roundtrip this information in cases that some but not all owned bits from a register are present in the circuit. (This partial data is a decent part of the cause of the bugs that Qiskitgh-9095 fixed.) Since this is just in the support of deprecated functionality that Terra's data model does not even require for circuit equality (QPY's goal), it seems not worth it to produce a new QPY binary format version to store this, when the deprecated properties being removed would obsolete the format again immediately.
This allows complete round-tripping of all the deprecated register+index information in the `Bit` instances through QPY, restoring us to the _intended_ behaviour before Qiskitgh-9095. The behaviour in the dumper before that did not allow full reconstruction, because some of the information was lost for bits that were encountered in more than one register. This fixes the dumper to always output all the indexing information for all bits, not to use `-1` whenever a bit _is_ in the circuit but has previously been encountered. The `standalone` field on a register is sufficient to tell whether the bits contained in it should have their "owner" information set; it's not possible (in valid Qiskit code) to have a register that owns only _some_ of its bits. To accomodate this, the register reader now needs to be two-pass.
* Retain more deprecated Bit properties in QPY roundtrip A major bugfix for QPY's handling of loose circuit bits in c0ac5fb (gh-9095) caused the deprecated bit properties `index` and `register` to be lost after the QPY roundtrip. As far as Terra's data model is concerned, the two circuits would still compare equal after this loss; the output registers would still be equal to the inputs, and bit equality is not considered directly since it general bit instances are not expected to be equal between circuits. Losing this information caused some downstream issues for the IBM runtime, which was still relying on `Bit.index` working in some cases, despite it issuing a deprecating warning since Terra 0.17 (April 2021). While this can be corrected downstream, QPY can still do a better job of roundtripping the deprecated information while it is still present. The QPY format does not currently store enough information to _completely_ roundtrip this information in cases that some but not all owned bits from a register are present in the circuit. (This partial data is a decent part of the cause of the bugs that gh-9095 fixed.) Since this is just in the support of deprecated functionality that Terra's data model does not even require for circuit equality (QPY's goal), it seems not worth it to produce a new QPY binary format version to store this, when the deprecated properties being removed would obsolete the format again immediately. * Fix lint * Correct deprecated bit information in QPY This allows complete round-tripping of all the deprecated register+index information in the `Bit` instances through QPY, restoring us to the _intended_ behaviour before gh-9095. The behaviour in the dumper before that did not allow full reconstruction, because some of the information was lost for bits that were encountered in more than one register. This fixes the dumper to always output all the indexing information for all bits, not to use `-1` whenever a bit _is_ in the circuit but has previously been encountered. The `standalone` field on a register is sufficient to tell whether the bits contained in it should have their "owner" information set; it's not possible (in valid Qiskit code) to have a register that owns only _some_ of its bits. To accomodate this, the register reader now needs to be two-pass. * Add deprecated-bit checks to backwards compatibility tests * Rewrite release note * Improve internal documentation --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* Retain more deprecated Bit properties in QPY roundtrip A major bugfix for QPY's handling of loose circuit bits in c0ac5fb (gh-9095) caused the deprecated bit properties `index` and `register` to be lost after the QPY roundtrip. As far as Terra's data model is concerned, the two circuits would still compare equal after this loss; the output registers would still be equal to the inputs, and bit equality is not considered directly since it general bit instances are not expected to be equal between circuits. Losing this information caused some downstream issues for the IBM runtime, which was still relying on `Bit.index` working in some cases, despite it issuing a deprecating warning since Terra 0.17 (April 2021). While this can be corrected downstream, QPY can still do a better job of roundtripping the deprecated information while it is still present. The QPY format does not currently store enough information to _completely_ roundtrip this information in cases that some but not all owned bits from a register are present in the circuit. (This partial data is a decent part of the cause of the bugs that gh-9095 fixed.) Since this is just in the support of deprecated functionality that Terra's data model does not even require for circuit equality (QPY's goal), it seems not worth it to produce a new QPY binary format version to store this, when the deprecated properties being removed would obsolete the format again immediately. * Fix lint * Correct deprecated bit information in QPY This allows complete round-tripping of all the deprecated register+index information in the `Bit` instances through QPY, restoring us to the _intended_ behaviour before gh-9095. The behaviour in the dumper before that did not allow full reconstruction, because some of the information was lost for bits that were encountered in more than one register. This fixes the dumper to always output all the indexing information for all bits, not to use `-1` whenever a bit _is_ in the circuit but has previously been encountered. The `standalone` field on a register is sufficient to tell whether the bits contained in it should have their "owner" information set; it's not possible (in valid Qiskit code) to have a register that owns only _some_ of its bits. To accomodate this, the register reader now needs to be two-pass. * Add deprecated-bit checks to backwards compatibility tests * Rewrite release note * Improve internal documentation --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit b6aba59)
* Retain more deprecated Bit properties in QPY roundtrip A major bugfix for QPY's handling of loose circuit bits in c0ac5fb (gh-9095) caused the deprecated bit properties `index` and `register` to be lost after the QPY roundtrip. As far as Terra's data model is concerned, the two circuits would still compare equal after this loss; the output registers would still be equal to the inputs, and bit equality is not considered directly since it general bit instances are not expected to be equal between circuits. Losing this information caused some downstream issues for the IBM runtime, which was still relying on `Bit.index` working in some cases, despite it issuing a deprecating warning since Terra 0.17 (April 2021). While this can be corrected downstream, QPY can still do a better job of roundtripping the deprecated information while it is still present. The QPY format does not currently store enough information to _completely_ roundtrip this information in cases that some but not all owned bits from a register are present in the circuit. (This partial data is a decent part of the cause of the bugs that gh-9095 fixed.) Since this is just in the support of deprecated functionality that Terra's data model does not even require for circuit equality (QPY's goal), it seems not worth it to produce a new QPY binary format version to store this, when the deprecated properties being removed would obsolete the format again immediately. * Fix lint * Correct deprecated bit information in QPY This allows complete round-tripping of all the deprecated register+index information in the `Bit` instances through QPY, restoring us to the _intended_ behaviour before gh-9095. The behaviour in the dumper before that did not allow full reconstruction, because some of the information was lost for bits that were encountered in more than one register. This fixes the dumper to always output all the indexing information for all bits, not to use `-1` whenever a bit _is_ in the circuit but has previously been encountered. The `standalone` field on a register is sufficient to tell whether the bits contained in it should have their "owner" information set; it's not possible (in valid Qiskit code) to have a register that owns only _some_ of its bits. To accomodate this, the register reader now needs to be two-pass. * Add deprecated-bit checks to backwards compatibility tests * Rewrite release note * Improve internal documentation --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit b6aba59) Co-authored-by: Jake Lishman <[email protected]>
Summary
QPY previously had rather complicated logic to handle deserialisation of registers that was heavily couched in the old model of registers "owning" the bits they contained. This is no longer the data model of the circuit, so the code was naturally complex to try and make it work.
Instead, in deserialisation now we just add the correct number of bit instances to the circuit at the start, and then build up any required registers by using the
indices
field.It's not clear to me how an index ever could be negative here; it's not clear how a register could be in the circuit but its bits aren't added, so it feels like there might be the possibility of a bug I've missed.
Details and comments
Fix #9094.