Skip to content

Fix parameter deserialization bugs in QPY #13727

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

Merged
merged 26 commits into from
Jun 4, 2025
Merged

Conversation

ElePT
Copy link
Contributor

@ElePT ElePT commented Jan 23, 2025

Summary

This PR fixes a series of reported issues in QPY:

The common denominator for these issues is the assumption that parameter names are unique within a circuit. This may not be true in cases where parameter re-assignment has taken place and both the old and new parameters share a name (but have different uuids). In these cases, the substitution operation is recorded in the qpy_replay field and should be taken into account during serialization. The bug materialized in two flavors:

  1. name clash when deserializing the ParameterVector component of a ParameterExpression (for which a new from_expr flag has been added to read_parameter_vec). This came up with NLocal implementations (including subclasses).
  2. name clash when deserializing the ParameterExpression directly. This use case is tested in test_duplicated_param_name, and fix by tweaking the encoded mapping to use uuids as keys instead of names.

This fix tweaks the way ParameterExpressions are stored, so it probably needs a QPY version bump.

Details and comments

@coveralls
Copy link

coveralls commented Jan 23, 2025

Pull Request Test Coverage Report for Build 15437163816

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 24 of 24 (100.0%) changed or added relevant lines in 3 files are covered.
  • 240 unchanged lines in 5 files lost coverage.
  • Overall coverage increased (+0.03%) to 87.911%

Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 1 92.48%
crates/synthesis/src/two_qubit_decompose.rs 1 91.63%
qiskit/synthesis/multi_controlled/mcx_synthesis.py 4 97.7%
crates/qasm2/src/parse.rs 6 97.61%
qiskit/visualization/circuit/matplotlib.py 228 48.79%
Totals Coverage Status
Change from base Build 15415448813: 0.03%
Covered Lines: 81413
Relevant Lines: 92608

💛 - Coveralls

@ElePT ElePT force-pushed the fix-qpy-blueprint branch from 0de998b to 457068f Compare January 24, 2025 10:44
@ElePT ElePT changed the title Fix bug in QPY with PauliFeatureMap class Fix bug in qpy with PauliFeatureMap class Jan 27, 2025
@ElePT ElePT added the Changelog: Bugfix Include in the "Fixed" section of the changelog label Jan 28, 2025
@ElePT ElePT force-pushed the fix-qpy-blueprint branch from 934fa78 to 36835f7 Compare January 28, 2025 13:45
@ElePT ElePT added this to the 2.0.0 milestone Jan 28, 2025
@ElePT ElePT marked this pull request as ready for review January 28, 2025 13:45
@ElePT ElePT requested a review from a team as a code owner January 28, 2025 13:45
@qiskit-bot
Copy link
Collaborator

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core
  • @mtreinish
  • @nkanazawa1989

@ElePT ElePT added the stable backport potential The bug might be minimal and/or import enough to be port to stable label Jan 28, 2025
@Cryoris
Copy link
Contributor

Cryoris commented Jan 28, 2025

It seems like this should also be reproducible outside of the NLocal, or do you think this only happens in that context? 🤔

…yaml

Co-authored-by: Julien Gacon <gaconju@gmail.com>
@ElePT
Copy link
Contributor Author

ElePT commented Jan 28, 2025

I know what you mean, the parameter replay sequence should be reproducible, but I have not been able to reproduce it outside of NLocal. I did stop trying after a while so it's something I guess could be retried in the future.

@Cryoris
Copy link
Contributor

Cryoris commented Feb 14, 2025

I don't fully understand how this bug is triggered and why we weren't able to reproduce it outside of the PauliFeatureMap, which makes me a bit worried that we don't 100% understand what's going on and that we might fix a symptom but not the full bug. E.g. could this also happen for Parameters instead of ParameterVectors, if we used these in PauliFeatureMap? I think I'd slightly prefer holding off a merge until we really understood this since it's touching a quite fundamental bit, but I'm happy to be overvoted if people think otherwise 🙂

@ElePT ElePT force-pushed the fix-qpy-blueprint branch from 4f30d29 to 4b8942a Compare May 12, 2025 11:55
@ElePT
Copy link
Contributor Author

ElePT commented May 12, 2025

To summarize the changes in this PR:

  1. It modifies the parameter serialization format to use uuid instead of name to avoid overwriting data in the case where two parameters with the same name have been used in the same circuit (it is not possible to have 2 parameters with the same name simultaneously, but any parameter used in the circuit is encoded in the parameter expression replay and it is possible to have two different parameters with the same name at different points in time, for example, if a parameter is substituted by one of the same name)
  2. Because the change in (1) is a breaking change (QPY 14 would not be able to load a circuit generated with this change, the opposite is still possible), it bumps the QPY format to 15
  3. The change in (1) meant that now "intermediate" parameter vectors (not necessarily used in the present circuit) can raise a partial initialization user warning. To avoid this, I introduced the initialize_full_vec flag that counts the full parameter vector as initialized if the parameter vector is part of a parameter expression. This avoided the warning for new n_local circuit library components (zz_feature_map, pauli_feature_map...) but did not prevent the warning for the blueprint circuit counterparts (ZZFeatureMap, PauliFeatureMap), because they do this partial initialization of standalone parameter vectors that are not detected as part of any parameter expression. I believe that this is indistinguishable from the use case that we are testing where a parameter vector is used directly and we want the user warning to be raised.
  4. The only solution I could find for bypassing this warning was adding a manual exception for the 3 known classes: ZZFeatureMap, ZFeatureMap, PauliFeatureMap. This bypass actually also affects the new circuit library counterparts, because they share the same name, but I figured that we should keep the more general solution applied in (3) in case we stop supporting loading blueprint circuits and we want to get rid of this exceptional handling by gate name.

@ElePT ElePT requested a review from t-imamichi May 12, 2025 13:23
@t-imamichi
Copy link
Member

Thank you for fixing the issue. I added a minor comment.

Co-authored-by: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com>
@t-imamichi
Copy link
Member

LGTM. I would like someone of qpy team to review it.

Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it took so long to review -- this looks like a good solution to me (it should maybe be noted I'm a QPY padawan still tho). I have one main concern/question about the hardcoded exceptions below 🙂

@ElePT ElePT removed the stable backport potential The bug might be minimal and/or import enough to be port to stable label Jun 4, 2025
Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

@Cryoris Cryoris enabled auto-merge June 4, 2025 08:21
@Cryoris Cryoris added this pull request to the merge queue Jun 4, 2025
Merged via the queue into Qiskit:main with commit 1dd1983 Jun 4, 2025
26 checks passed
rahaman-quantum pushed a commit to rahaman-quantum/qiskit that referenced this pull request Jun 20, 2025
* Don't assume parameter vector names are unique

* Add from_expr flag

* Add reno

* Specify issue number

Fix black

* Update releasenotes/notes/fix-qpy-fauli-feature-map-33292033755879ee.yaml

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update fix, add tests

* Update reno

* Update comment

* Update test_circuit_load_from_qpy.py

Co-authored-by: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com>

* Bump qiskit version, update docs

* Avoid new warning

* Assert user warning is not raised during regression tests (currently fails for legacy ZZFeatureMap)

* Rename flag and add comments

* Remove unnecessary logic

* Document new option

* Document new option

* Apply suggestions from Imamichi-san's code review

Co-authored-by: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com>

* Update qiskit/qpy/__init__.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Cleaner implementation: use parameter vector ROOT uuid as key, resolve element uuids from root uuid

* Improve docs and comments

* Fix lint

* Add parameter equality tests

---------

Co-authored-by: Julien Gacon <gaconju@gmail.com>
Co-authored-by: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: Bugfix Include in the "Fixed" section of the changelog mod: qpy Related to QPY serialization
Projects
None yet
Development

Successfully merging this pull request may close these issues.

QAOA circuit dumped to QPY 13 raises an error when loading ZZFeatureMap dumped to QPY 13 raises an error when loading
8 participants