Environment
- staq commit:
a2acd39e60ed0e5f1978fa530df7e1e0c7cedf7a (main branch, current upstream HEAD as of 2026-09-18)
- Built with
cmake -S . -B build && cmake --build build --target staq
- Ubuntu 22.04.5 LTS (WSL2), g++ 11.4.0, cmake 3.22.1
What is happening?
A bare pair of identical, adjacent ccx gates (the identity) is removed entirely by --simplify and -O1, but -O2 and -O3 leave a nonempty residue behind instead.
How can we reproduce the issue?
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[3];
ccx q[0],q[1],q[2];
ccx q[0],q[1],q[2];
measure q -> c;
$ ./build/staq --simplify in.qasm # -> no unitary gates remain
$ ./build/staq -O1 in.qasm # -> no unitary gates remain
$ ./build/staq -O3 in.qasm # -> h q[2]; s q[1]; s q[2]; cx q[1],q[2]; sdg q[2]; ...
-O3's output has 6 cx and 9 single-qubit gates. It is still unitarily equivalent to the input (checked with Operator.equiv), so this is a missed-optimization issue rather than a correctness one. Re-running --simplify, -O1, or -O3 on the resulting circuit leaves the same 15 unitary gates, so the missed cancellation is not recovered by a subsequent pass.
What should happen?
Ideally, running optimizations in -O2/-O3 should not prevent an adjacent inverse pair from being removed when --simplify can already eliminate it directly.
Possible mitigation
-O1 runs simplify before any inlining, whereas -O2/-O3 run inline before their first simplify. Since simplify detects this cancellation structurally by gate name, expanding ccx first removes the pattern it would otherwise match.
We prototyped adding an initial simplify before inline in both -O2 and -O3. This resolves the reproducer, and all 123 existing unit tests still pass.
Environment
a2acd39e60ed0e5f1978fa530df7e1e0c7cedf7a(main branch, current upstream HEAD as of 2026-09-18)cmake -S . -B build && cmake --build build --target staqWhat is happening?
A bare pair of identical, adjacent
ccxgates (the identity) is removed entirely by--simplifyand-O1, but-O2and-O3leave a nonempty residue behind instead.How can we reproduce the issue?
-O3's output has 6cxand 9 single-qubit gates. It is still unitarily equivalent to the input (checked withOperator.equiv), so this is a missed-optimization issue rather than a correctness one. Re-running--simplify,-O1, or-O3on the resulting circuit leaves the same 15 unitary gates, so the missed cancellation is not recovered by a subsequent pass.What should happen?
Ideally, running optimizations in
-O2/-O3should not prevent an adjacent inverse pair from being removed when--simplifycan already eliminate it directly.Possible mitigation
-O1runssimplifybefore any inlining, whereas-O2/-O3runinlinebefore their firstsimplify. Sincesimplifydetects this cancellation structurally by gate name, expandingccxfirst removes the pattern it would otherwise match.We prototyped adding an initial
simplifybeforeinlinein both-O2and-O3. This resolves the reproducer, and all 123 existing unit tests still pass.