Fix Statevector.evolve modifying input state in-place (Fixes 15750) (backport #15905)#16227
Open
mergify[bot] wants to merge 1 commit into
Open
Fix Statevector.evolve modifying input state in-place (Fixes 15750) (backport #15905)#16227mergify[bot] wants to merge 1 commit into
mergify[bot] wants to merge 1 commit into
Conversation
…15905) * [quantum_info.states] Add tests (1 failing) for Statevector.evolve modifying original state Statevector.evolve() is meant to return the evolved state, with the original state remaining unmodified. However, some instructions result in the state being modified. The added tests validate Statevector.evolve() with various gates, Operator, and QuantumCircuit. The only instance where the original state is modified is with DiagonalGate. * [quantum_info.states] Use new _data array when applying global phase The _data array of Statevector may be a shallow copy of another Statevector. Applying a global phase in-place would modify the other instances. A deep copy doesn't work as this breaks another test: - test.python.primitives.test_statevector_estimator.TestStatevectorEstimator.test_reset * [reno] Add bugfix releasenote * Update releasenotes/notes/fix-statevector-evolve-inplace-modification-be2f31976d5a2e1d.yaml Co-authored-by: Julien Gacon <gaconju@gmail.com> * Update releasenotes/notes/fix-statevector-evolve-inplace-modification-be2f31976d5a2e1d.yaml Co-authored-by: Julien Gacon <gaconju@gmail.com> * [tests] Fix test names not being snake-case * [tests] Fix lint black failing --------- Co-authored-by: Julien Gacon <gaconju@gmail.com> (cherry picked from commit a8d3aef)
Collaborator
|
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 following people are relevant to this code:
|
Coverage Report for CI Build 26231217034Coverage increased (+1.1%) to 88.822%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions18 previously-covered lines in 4 files lost coverage.
Coverage Stats
💛 - Coveralls |
Cryoris
approved these changes
May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Statevector.evolve(gate)should leave the input state untouched. However, the input state is currently modified withDiagonalGateas an argument (see #15750). This is caused by a shallow copy and an in-place-array modification whengatehas a global phase. This PR adds failing tests, a fix for the failing tests, and a reno release note for the bug fix.Details and comments
Proof and cause of bug
Statevector.evolvecallsStatevector._evolve_instructionwhere the following code is run (lines 1029-1030)This is an in-place modification of
statevec._data. However, whenStatevector.evolveis called, a shallow copy is made (line 461). This means that a gate with a global phase modifies the original input state. This is verified with the following short script:Possible fixes and implemented fix
statevec._datawhen applying the global phase, instead of an in-place multiplication. This comes at the cost of copying the_dataarray but only when the instruction has a global phase._copy.copy(shallow copy) at the beginning ofStatevector.evolve, we could callself.copy(). However, this causestest.python.primitives.test_statevector_estimator.TestStatevectorEstimator.test_resetto fail. I tracked this down to the internal rng being copied and the behaviour for resets changing. Instead of fixing the deep copy of the rng, the first fix was chosen.Implemented Tests
I implemented four tests which verify that five different instructions do not modify the input state to
Statevector.evolve. Only the one withDiagonalGatefailed. With the fix it passes.XGate: Passes.CXGate: Passes.Operator(XGate()): Passes.QuantumCircuit(Bell-state preparation): Passes.DiagonalGate([1.0, -1.0, -1.0, 1.0]): Failed but now passes.This is an automatic backport of pull request Fix Statevector.evolve modifying input state in-place (Fixes 15750) #15905 done by Mergify.