Fix Statevector.evolve modifying input state in-place (Fixes 15750)#15905
Fix Statevector.evolve modifying input state in-place (Fixes 15750)#15905conradhaupt wants to merge 9 commits intoQiskit:mainfrom
Conversation
…difying 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.
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
|
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:
|
Cryoris
left a comment
There was a problem hiding this comment.
Thanks for the fix -- I would've expected a deepcopy to be the right solution, but it seems that explicit steps were taken to not deepcopy here, so I think your solution works for fixing the bug now.
releasenotes/notes/fix-statevector-evolve-inplace-modification-be2f31976d5a2e1d.yaml
Outdated
Show resolved
Hide resolved
releasenotes/notes/fix-statevector-evolve-inplace-modification-be2f31976d5a2e1d.yaml
Outdated
Show resolved
Hide resolved
…-be2f31976d5a2e1d.yaml Co-authored-by: Julien Gacon <gaconju@gmail.com>
…-be2f31976d5a2e1d.yaml Co-authored-by: Julien Gacon <gaconju@gmail.com>
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.