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
{{ message }}
Repository navigation
negctrl expansion emits the same QuantumGate object twice, aliasing operand nodes #350
The negctrl modifier expansion in visitor.py places the sameQuantumGate object at two positions in the emitted statement list, rather than two equal copies:
Every transformation that rewrites qubit indices in place (remove_idle_qubits(), reverse_qubit_order()) therefore reaches the same operand node more than once.
Reproduction
frompyqasmimportloadsqasm="""OPENQASM 3.0;include "stdgates.inc";qubit[3] q;negctrl @ x q[0], q[1];"""m=loads(qasm)
m.unroll()
print([id(s) forsinm._unrolled_ast.statementsifhasattr(s, "qubits")])
# [4362757584, 4362758224, 4362757584] <- statements 0 and 2 are the same objectm.reverse_qubit_order() # KeyError: -2
remove_idle_qubits() on the same circuit survives only because of the visited_node_ids guard in Modules._remap_qubits; removing that guard raises KeyError: 0. Nothing in the test suite covers either path.
Scope
Pre-existing, not a regression. #335 fixed the equivalent aliasing for decomposition-emitted statements (maps/gates.py constructors and Decomposer), but deliberately did not touch the modifier expansion path.
Suggested fix
Build a second negs list for the trailing position rather than reusing the first, and run the control operand through fresh_qubits() so the two x gates own distinct operand nodes. Add a regression test asserting no shared statement or operand nodes after unroll() for negctrl @ x, and that reverse_qubit_order() succeeds on it.
Activity
fix: emit distinct x gates with fresh operands in negctrl expansion (#…
Merge branch 'main' into fix-qasm2-gphase [no ci]