Repository navigation
Stop OptimizeSwapBeforeMeasure recursing into control-flow blocks - #17012
Open
Eduardo Alcantara (edubraqd) wants to merge 1 commit into
Open
Eduardo Alcantara (edubraqd) wants to merge 1 commit into
Eduardo Alcantara (edubraqd) wants to merge 1 commit into
Conversation
The pass was decorated with `control_flow.trivial_recurse`, so each control-flow block was optimized as an independent DAG. Inside a block the `DAGOutNode`s are only the block boundary, not the end of the program, so a terminal swap (or a swap followed only by in-block measurements) was removed while the swapped qubits were still live after the block, and measurements outside the block observed the wrong state. Remove the recursion: the pass now only acts on the top level of the circuit and leaves control-flow blocks untouched. Fixes Qiskit#16853 Co-Authored-By: Claude Opus 5 <[email protected]>
Eduardo Alcantara (edubraqd)
requested a review
from a team
as a code owner
September 19, 2026 10:54
Eduardo Alcantara (edubraqd)
requested a review
from Julien Gacon (Cryoris)
September 19, 2026 10:54
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:
|
This branch has not been deployed
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
Fixes #16853
OptimizeSwapBeforeMeasureremoves a terminalSWAPinside a control-flow block even though the swapped state is observed by measurements after the block:Cause
The pass is decorated with
control_flow.trivial_recurse, so each block is optimized as an independentDAGCircuit. Within a block theDAGOutNodes are only the block boundary, not the end of the program, but the eligibility check treats them as terminal and removes the swap. The same problem exists when the swap is followed only by measurements inside the block: retargeting the in-block measurements keeps the classical results, but the qubits remain live after the block in the swapped positions, so any later measurement of them outside the block is wrong.Fix
Remove the recursion. The pass now only acts on the top level of the circuit and leaves control-flow blocks untouched, which is the conservative behaviour discussed in #7642 (a terminal swap of a complete program has no observable effect; a terminal swap of a block does). The pass is not part of the preset pass managers, so this only affects explicit use.
The two existing tests that asserted the recursion (
test_if_else,test_nested_control_flow) are replaced by tests asserting that a block is left unchanged, plus the regression case from the issue, the "swap followed by in-block measurements" case, and a check that a top-level swap after a control-flow block is still optimized.Details and comments
Verified with a
BasicSimulatorrun onmainvs this branch: the issue's reproducer returns{'10': 1024}before and after the pass with this change (was{'01': 1024}after).AI/LLM disclosure
🤖 Generated with Claude Code