You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
QasmModule.reverse_qubit_order() raises KeyError on any program whose unrolled AST contains aliased operand nodes — the same root cause as #331, surfacing one method below the fix in #332.
Found during adversarial review of #332: the visited-set guard added there fixes _remap_qubits, but reverse_qubit_order (src/pyqasm/modules/base.py:533-555) walks the same statements and mutates bit.indices[0][0].value in place with a negative-marker trick. On a node shared by k statements, the second visit reads the already-negated value and looks up new_qubit_mappings[reg][-2] → KeyError: -1.
Root cause: have unroll() / the decomposer emit fresh (deep-copied) operand nodes so no AST node is shared across statements. This retires the whole class of bug — every in-place index mutation in modules/base.py is currently exposed to aliasing.
Point fix: apply the same visited-node-id guard from fix: remove_idle_qubits KeyError on shared operand nodes #332 to both passes in reverse_qubit_order. Note the marker pass and the unmark pass each need their own guard (or the method should be rewritten to build the mapping without the negative-marker trick, which only exists to survive double visits it doesn't actually survive).
Option 1 is the better long-term fix; if we take it, the guard added in #332 becomes harmless belt-and-braces.
Summary
QasmModule.reverse_qubit_order()raisesKeyErroron any program whose unrolled AST contains aliased operand nodes — the same root cause as #331, surfacing one method below the fix in #332.Found during adversarial review of #332: the visited-set guard added there fixes
_remap_qubits, butreverse_qubit_order(src/pyqasm/modules/base.py:533-555) walks the same statements and mutatesbit.indices[0][0].valuein place with a negative-marker trick. On a node shared by k statements, the second visit reads the already-negated value and looks upnew_qubit_mappings[reg][-2]→KeyError: -1.Reproduction
Reproduces on
main(pre-dates #332; that PR did not touch this method).Fix options
Same two options as #331, not mutually exclusive:
unroll()/ the decomposer emit fresh (deep-copied) operand nodes so no AST node is shared across statements. This retires the whole class of bug — every in-place index mutation inmodules/base.pyis currently exposed to aliasing.reverse_qubit_order. Note the marker pass and the unmark pass each need their own guard (or the method should be rewritten to build the mapping without the negative-marker trick, which only exists to survive double visits it doesn't actually survive).Option 1 is the better long-term fix; if we take it, the guard added in #332 becomes harmless belt-and-braces.
🤖 Filed with Claude Code