Skip to main content

Q-PROOF Compact

The verified quantum circuit optimizer. Smaller circuits, proven. Compact takes a quantum circuit and returns an equivalent one that is smaller and shallower — with a machine-checked proof attached to every answer.

import compactq
from compactq.benchmarks import qft

opt = compactq.optimize_search(qft(4))
print(opt.stats())

pip install compactq — no dependencies, no account, no cloud. Pure Python ≥ 3.9. (From source: pip install git+https://github.com/Q-PROOF/Compact.git.)

Why

Every gate you remove from a quantum circuit removes noise. Compact takes a circuit and returns an equivalent one that is smaller (fewer gates), shallower (lower depth), with priority on cutting 2-qubit gates — the dominant error source on today's hardware.

Correctness model (the part that matters)

  • Every rewrite is exact: the unitary is preserved up to global phase.
  • For circuits ≤ 8 qubits (6 without the optional native kernel), optimize_search() proves equivalence via full-unitary comparison before returning; on any numerical doubt it returns your circuit unchanged. (verify=False skips the proof for large circuits — and is itself fuzzed against a Qiskit referee up to 10 qubits.)
  • The KAK/Weyl re-synthesiser is cross-validated against Qiskit's Rust implementation (Weyl coordinates agree to ~1e-15 on randomized SU(4)s) and every re-synthesized block is re-verified against its own 4×4 unitary before it can replace anything.
  • Clifford blocks are re-synthesized with tableau proofs, exact at any qubit count.
  • The test suite (76 test functions; python tests/run_tests.py) includes property tests over thousands of random circuits and a regression suite for the classic optimizer bugs (gate-order reversals, reversed-CX "cancellations", Euler-angle wrapping, ZZ-identity sign errors). scripts/gauntlet.py adds a 1,018-check end-to-end gauntlet: 61 realistic algorithm families × every public entry point, QASMBench through compactq's own importer, >8q no-verify soundness and CLI/bridge/round-trip checks — all refereed by Qiskit's Operator, never by compactq's own math.

What's inside

  • Peephole folding — maximal 1-qubit runs resynthesized to ≤3 canonical gates (named-Clifford recognition, single-RX/RY recovery, exact H·P / P·H two-gate forms, RZ-RY-RZ Euler), with a final single-u3 fold for gate-count polish.
  • Commutation engine — self-inverse CX/CZ cancellation across provably-commuting gates, X-on-target / diagonal-on-control slides, SWAP templates, generalized diagonal sliding, cross-pair commutative window merging.
  • CP engineCX·RZ_t(θ)·CX = RZ_c(θ)·RZ_t(θ)·CP(−2θ): exact ZZ-phase extraction that halves the CX count of QAOA/QFT/PEA-style phase ladders; adjacent CP merging; phase-polynomial re-synthesis of diagonal cores.
  • Pure-Python KAK/Weyl synthesis (compactq/kak.py) — the numerically-stable simultaneous-diagonalization algorithm (Cross et al., arXiv:1811.12926 App. B): real-symmetric Jacobi eigensolver of Re/Im magic-basis parts, Weyl-chamber canonicalization, and minimal-CX circuit templates (0/1/2/3 CX by exact fidelity test). No numpy, no qiskit, no pytket needed in the core.
  • Clifford stabilizer tableaux (compactq/stabilizer.py) — Aaronson-Gottesman CHP with phase-exact Pauli conjugation (single-qubit gates conjugated numerically, so a wrong sign convention cannot ship silently) and AG block resynthesis with GF(2) sign correction. is_clifford and clifford_equal give exact Clifford equality at any qubit count without building 2ⁿ unitaries.
  • Approximate mode (compactq.approximate, compactq.target) — 2q blocks re-synthesized into cheaper CX classes with measured per-block fidelity guarantees; hardware-aware Target objective (per-pair CX fidelities, CX-direction flipping) and greedy fidelity-budget allocation. Reported fidelities include the approximation cost.
  • Hardware-aware routing (compactq/hardware.py) — SABRE-lite SWAP insertion with error-weighted look-ahead, optional permutation restore, rz-sx-x 1q translation.
  • Multi-controlled gatesmcx/mcp expanded via parity networks; the Qiskit bridge boundary-decomposes anything else a QuantumCircuit may carry (mcphase, ccx, ecr, iswap, cu, rxx, ...) loss-free into the supported basis.
  • Verification net — full-unitary fidelity proofs for ≤8-qubit circuits.
  • Optional Rust kernels (native/) — a PyO3 wheel (compactq-native, abi3 stable ABI, Python ≥3.9) that accelerates the KAK hot path (block unitaries, determinants) and raises the exact-proof ceiling to 8 qubits (sim_unitary). Windows wheels ship with each release; other platforms build from source with maturin (see Development). compactq auto-detects the kernel and silently falls back to the pure-Python path — the zero-dependency contract never changes.

How Compact competes

Three axes, all measured on identical inputs (QASMBench unitary cores, level-0 normalized, same basis, 2026-09-08 run unless noted):

1. Optimization quality — win-or-tie on 2-qubit count vs Qiskit L3 on 30/32 QASMBench small circuits (11 wins / 19 ties / 2 losses). One loss (basis_test_n4, 12 vs "6") is an accounting artifact: Qiskit L3 elides 2 SWAP gates into its layout metadata instead of the circuit — reified, they cost 6 CX-equivalents, i.e. parity with compactq's 12; the other (basis_trotter_n4, 240 vs 179) is a genuine open case, on the roadmap. Vs pytket FullPeepholeOptimise, see axis 2: its headline 2q numbers on small kernels come from invalid outputs. On freshly generated MQT Bench algorithm circuits (44 circuits, every output refereed, table below) compactq wins 25 / ties 19 / loses 0 vs Qiskit L3 — QAOA 2q cut in half at every size (8→4, 28→14, 56→28), QFT 14→8, QPE 9→5, Grover 52→44 — and 25 / 19 / 0 vs Cirq's CZTargetGateset optimizer. The v1.3 CX-phase rewrite (matched CX pairs around folded T/phase runs collapse to CP) closes every previously-lost 2q account: adder_n10 65→57, adder_n4 10→7, toffoli 6→5, cdkm adders 15/29 vs pytket's 16/31, Grover −16%.

2. Precision — Compact proves every output before returning (full-unitary fidelity proof ≤ 8q, tableau proofs for Clifford blocks at any size; it returns your input unchanged rather than ship an unprovable result). An independent referee (Qiskit Operator, |Tr(A†B)|/d) over 29 QASMBench circuits:

tool inequivalent outputs what the user must do to be safe
Compact 0 / 29 (proof attached in-product) nothing
Qiskit 2.5 L3 1 / 29 as shipped: basis_trotter_n4 returns fid 0.25 because 2 SWAPs sit in qc.layout metadata, not the circuit inspect qc.layout and re-apply elided permutations
pytket FullPeepholeOptimise() (default) 6 / 30 wrong circuits (fresh 2.18.1 referee: basis_test_n4 fid 0.50, grover_n2 0.50, hs4_n4 0.25, iswap_n2 0.50, qec_en_n5 0.25, sat_n7 0.016); replace_implicit_wire_swaps() does not repair them run in allow_swaps=False mode — but 2.18.1's safe mode is itself inequivalent on 2/30 (basis_trotter_n4, sat_n7), and its valid outputs still never beat compactq (9 / 19 / 0)
pytket safe mode 2 / 30 (basis_trotter_n4 fid 0.5, sat_n7 fid 0.016) re-referee before trusting

3. Latency — the honest metric is the same job: an optimized circuit you can trust. compactq's price includes the proof; competitors need an external Operator-fidelity check afterwards (which is exactly what caught the failures above).

same job (optimize + verify) compactq (proof included) Qiskit L3 raw Qiskit + verify compactq wins pytket + verify (compactq wins)
QASMBench, 29 circuits 1.86 s 0.52 s 0.88 s 18/29 11.0 s, 29/29
MQT Bench, 44 circuits 4.88 s 0.85 s 1.97 s 22/44

(timings from the 2026-09-08 instrumentation run; the correctness side was re-verified fresh on 2026-09-16/17 — the full gauntlet passes 1018/1018 on the current code, and the referee counts above are from that run.)

compactq wins the same-job race on the majority of circuits (18/29 QASMBench, 22/44 MQT — tally per the table above) and is always 4–6x faster than pytket; Qiskit's Rust pass engine keeps the raw-speed crown, especially on large circuits (closing that gap needs compactq's pass engine itself in Rust — on the roadmap). End-to-end optimizer+prover throughput doubled across the prototyping phase: the 1,018-check gauntlet runs 150 s → 75 s and the trotter6 search 4.9x (1.18 s → 0.24 s), via native-kernel verification at all qubit counts, a value-keyed unitary memo, fused 1q-matrix comparison, memoized gate matrices, and the Rust trace2 fidelity kernel.

Competitor landscape (measured columns from the runs above; others qualitative):

tool scope output verification 2q optimization notes
Compact 0.1 (Q-PROOF) logical optimization, exact + approximate yes — in-product proof best measured (30/32 win-or-tie QASMBench; 25/19/0 vs Qiskit and Cirq on MQT; 9/19/0 vs pytket-2.18 safe mode) same-job latency won on the majority of circuits; zero-dependency core, optional Rust
Qiskit 2.5 transpiler (L3) full transpilation stack (layout/routing/noise-adaptive) none strong; parity with compactq once permutations are reified Rust-fast, huge ecosystem
pytket 2.18 (FullPeepholeOptimise) logical optimization none — 6/30 wrong by default (fresh referee; safe mode now also 2/30 wrong: basis_trotter_n4, sat_n7) on its 24 valid default-mode outputs: compactq wins 8 / ties 15 / loses 1 (basis_trotter_n4); safe mode: compactq 9 / 19 / 0 the SWAP-elision pitfall persists in 2.18.1
Cirq 1.7 (optimize_for_target_gateset) construction + target-gateset optimization none — but its optimizer is exact on our whole MQT run weak: 23 losses / 0 wins vs compactq on MQT; grows some circuits fast (tens of ms)
staq (softwareqinc) synthesis/optimization toolchain n/a n/a not measurable in this environment: no PyPI distribution (the PyPI staq package is an unrelated C decompiler) and building it needs a C++17 toolchain that is absent here
MQT Bench (mqt-bench, ALG level) benchmark generator (44 circuits run here) integrated as a first-class suite: python scripts/mqtbench_run.py

DD sequences, every surface — suppression goes deeper and ships everywhere: a dynamical-decoupling sequence family (DD_SEQUENCES: xy4, xy8, xzx, pdd4) with auto selection by window length (dd_sequence= through suppress_plan/suppress_execute, sequence gate --dd-sequences); the pipeline is reachable from every surfacecompactq in.qasm --suppress [--noise noise.json] [--report report.json] [--json] on the CLI, and make_suppression_pass() / suppress_qiskit() in the qiskit plugin (calibration ingestion from a BackendV2, coupling-map aware, proof-verified variant 0).

End-to-end pipeline — noise-aware layout + SABRE-lite routing wired into suppress_plan (device-space mapping with per-edge calibration sight), a SuppressionReport artifact (per-stage gate/depth/proof-level records + measured suppression factor), MLE measurement mitigation (Richardson-Lucy EM - always a physical distribution, beats clipped inversion 3-5x on injected confusion), thin execution adapters (compactq.adapters.qiskit_runtime / braket_device), model-gated twirling (coherent_fraction) with portfolio twirl_fraction, an optimization regression gate (scripts/bench_gate.py), a CHP stabilizer scale simulator (compactq.stabsim, n~60; Y-convention audit discharged by the fuzz suite) with a gate-checked n=16..24 scale benchmark (scripts/scale_bench.py), and exact zero-noise extrapolation (compactq.zne - provable identity folding + Richardson/poly fits).

Error suppression — the open stack, one call

Fire Opal (Q-CTRL) sells automated error suppression as a closed cloud service: transpilation, fidelity-aware layout, dynamical decoupling, Pauli twirling, measurement mitigation — one function call, no knobs, results that cannot be audited. Compact ships the same technique stack as an open, zero-dependency, exactly provable library that runs locally against any noise model:

Fire Opal Compact suppression
closed cloud, paid usage open source, free, local — data never leaves the machine
transformed circuits unauditable every pass exact up to global phase, proof-net verified before use
only on their supported backends any NoiseModel (plain dict, or live IBM calibration loading)
black-box pipeline automated default + every layer available standalone
suppression only on their stack composes with any compiler — works on qiskit-O3 output too
from compactq import Circuit, Gate, suppress_execute, default_model

circ  = Circuit(4, [Gate("h", (), (0,))] + [Gate("cx", (), (j, j+1)) for j in range(3)])
noise = default_model(4)                      # or NoiseModel.from_qiskit_backend(backend)
result = suppress_execute(circ, noise)        # plan -> run -> mitigate
best   = max(result["probabilities"], key=result["probabilities"].get)

Pipeline (fixed order, each layer exact and gated): optimize → expand untwirlable CP entanglers → K Pauli-twirled variants → dynamical decoupling placed on each variant's own schedule → tensored readout mitigation. DD is benefit-gated: a window is decoupled only when the model's refocusable noise (quasi-static drift + dephasing) beats 3x the pulse overhead, so the pass can never be a net loss. Every variant is proven equivalent to your input before it is used.

Measured (density-matrix noise simulation — coherent overrotation per 2q gate with per-site axes, gate depolarizing, T1/T2 with ASAP scheduling, quasi-static drift, readout confusion; fixed seeds; reproducible with python scripts/suppress_bench.py and python scripts/head_to_head.py):

  • full pipeline vs raw execution: wins in every scenario — success probability x1.00–1.01 (coherent-dominated), x1.04–2.72 (decoherence), x1.17–1.31 (readout-dominated), x1.06–1.13 (combined)
  • head-to-head (head_to_head_results.json): raw vs qiskit-O3 vs qiskit-O3+suppression vs compact-full — mean success probability coherent 0.825 (qiskit-O3 0.822, raw 0.808), decoherence 0.660 (0.431, 0.418), combined 0.766 (0.688, 0.677); single best cell BV n=6 decoherence 0.729 vs 0.138 (5.3x). The suppression stack also lifts qiskit-O3 output when composed onto it.
  • one-cell honesty note: on coherent-dominated QAOA n=4, bare qiskit-O3 beats every suppressed pipeline (including qiskit-O3+suppression) — randomized compiling trades coherent-error cancellation for stochastic robustness; the aggregate still favors the pipeline.

The zero-dependency trajectory simulator (compactq.simulate_counts) reproduces the same physics for n <= 14 without numpy, so the whole pipeline runs — and is tested — anywhere Python runs.

Honesty line: Fire Opal's headline numbers come from real hardware; ours are simulator-based by construction (the techniques are the published ones — Mundada et al. randomized compiling, XY4 decoupling, tensored readout inversion). What we add is what no closed service can offer: per-layer exactness proofs, benefit gating with a no-net-loss argument, and a protocol anyone can re-run.

All numbers below are from a single re-run (2026-09-16, Python 3.11.9, qiskit 2.5.2, pytket 2.18.1, Windows 11 x64, compactq 0.1.0 + native kernels 0.1.0) and are reproducible with the commands shown. gates / 2q / depth.

Synthetic suite (python -m compactq.bench; same input QASM, same basis, fixed seeds):

circuit raw Compact qiskit L3 2q gain
ghz-5 5 / 4 / 5 5 / 4 / 5 5 / 4 / 5 -0%
qft-3 18 / 6 / 14 14 / 6 / 11 14 / 6 / 11 -0%
qft-4 34 / 12 / 22 25 / 12 / 17 25 / 12 / 17 -0%
clifford-ladder-4 12 / 7 / 8 12 / 7 / 8 12 / 7 / 8 -0%
clifford-ladder-5 15 / 8 / 13 13 / 8 / 11 13 / 8 / 11 -0%
brickwork-4x4 44 / 12 / 16 40 / 12 / 17 40 / 12 / 16 -0%
random-4q-40 40 / 18 / 24 37 / 18 / 21 40 / 22 / 27 -18%
random-5q-60 60 / 22 / 37 49 / 22 / 30 62 / 28 / 37 -21%

Real circuits — QASMBench small suite (python scripts/realbench.py; unitary cores only — circuits with classical control flow or mid-circuit measurement are out of scope for a unitary optimizer and are skipped with a stated reason; 31 of 42 ran). Every compactq row ≤ 8q is unitary-verified before being reported (0 inequivalent outputs, refereed by scripts/bench_json.py); Qiskit L3 and pytket are unverified. QASMBench assets are vendored in-tree (third_party/QASMBench — the small suite plus the medium/large circuits tabulated below, pinned at pnnl/QASMBench 357b942, attribution in its LICENSE/NOTICE), so every number here is reproducible from a fresh clone with no submodule step.

circuit Compact qiskit L3 pytket FullPeephole
adder_n10 110 / 57 / 95 137 / 65 / 99 165 / 61† / 118
adder_n4 16 / 7 / 9 23 / 10 / 11 25 / 10 / 14
basis_change_n3 34 / 10 / 22 49 / 10 / 28 79 / 10 / 50
basis_test_n4 34 / 12 / 15 34 / 6¹ / 12 42 / 5† / 16
basis_trotter_n4 773 / 240 / 352 794 / 179 / 361 969 / 159 / 419
bell_n4 18 / 5 / 7 27 / 5 / 11 29 / 5 / 12
cat_state_n4 4 / 3 / 4 4 / 3 / 4 6 / 3 / 6
deutsch_n2 4 / 1 / 3 4 / 1 / 3 9 / 1 / 6
dnn_n2 12 / 3 / 8 20 / 3 / 13 29 / 3 / 17
dnn_n8 216 / 64 / 37 345 / 64 / 60 464 / 64 / 75
error_correctiond3_n5 23 / 8 / 13 91 / 35 / 65 40 / 9 / 20
fredkin_n3 19 / 8 / 11 19 / 8 / 11 22 / 8 / 13
grover_n2 7 / 2 / 5 7 / 2 / 5 9 / 1† / 7
hhl_n7 191 / 72 / 128 254 / 92 / 168 421 / 92 / 310
hs4_n4 12 / 4 / 5 12 / 4 / 5 14 / 2† / 7
ising_n10 166 / 49 / 29 260 / 90 / 46 370 / 90 / 58
iswap_n2 7 / 2 / 5 8 / 2 / 6 9 / 1† / 7
linearsolver_n3 11 / 4 / 9 17 / 4 / 12 25 / 4 / 19
lpn_n5 7 / 2 / 4 7 / 2 / 4 15 / 2 / 8
pea_n5 34 / 10 / 21 51 / 17 / 32 62 / 17 / 41
qaoa_n6 114 / 36 / 47 166 / 36 / 63 197 / 36 / 83
qec_en_n5 23 / 10 / 15 23 / 10 / 15 24 / 8† / 14
qft_n4 20 / 6 / 10 34 / 12 / 20 39 / 12 / 23
qrng_n4 4 / 0 / 1 4 / 0 / 1 12 / 0 / 3
quantumwalks_n2 8 / 2 / 5 20 / 3 / 13 36 / 3 / 22
sat_n7 125 / 52 / 71 158 / 60 / 86 193 / 60 / 107
simon_n6 30 / 12 / 22 43 / 14 / 27 58 / 14 / 37
teleportation_n3 5 / 2 / 4 6 / 2 / 4 12 / 2 / 8
toffoli_n3 14 / 5 / 10 18 / 6 / 12 21 / 6 / 14
variational_n4 29 / 8 / 14 44 / 8 / 18 51 / 8 / 24
vqe_n4 25 / 9 / 11 46 / 9 / 18 75 / 9 / 23
wstate_n3 18 / 6 / 12 22 / 6 / 15 30 / 6 / 21

† pytket 2.18.1's default-mode output fails unitary verification on this circuit (fresh referee, scripts/referee_pytket.py: 6 of 30 ≤8q outputs inequivalent — basis_test_n4 fid 0.50, grover_n2 0.50, hs4_n4 0.25, iswap_n2 0.50, qec_en_n5 0.25, sat_n7 0.016; adder_n10 exceeds the 8q referee ceiling) — those counts are not comparable. ¹ Qiskit L3 elides 2 SWAPs into qc.layout metadata here; reified they cost 6 CX-equivalents — parity with compactq's 12.

Tallies vs Qiskit L3 (32 comparable rows from python scripts/bench_json.py, same run): 2q win-or-tie 30/32 (11 wins / 19 ties / 2 losses), total-gate win 23 / tie 9 / lose 0, depth win 22 / tie 9 / lose 1. Zero compactq outputs flagged INEQUIVALENT by the referee; Qiskit L3 is referee-flagged on basis_test_n4 (the SWAP-elision above). The two 2q accounts not won: basis_test_n4 (12 vs 6 raw — accounting parity once Qiskit's 2 elided SWAPs are reified) and basis_trotter_n4 (240 vs 179 — a pi/4-quantized Clifford+T ring whose optimization needs a CliffordSimp-class fragment-resynthesis pass; on the roadmap).

Vs pytket 2.18.1 (fresh referee, same protocol, scripts/referee_pytket.py): default mode is inequivalent on 6 of 30 refereed circuits; of its 24 valid outputs compactq wins the 2q count on 8 / ties 15 / loses 1 (basis_trotter_n4 — the roadmap item above). In pytket's safe (allow_swaps=False) mode — now itself inequivalent on 2 of 30 (basis_trotter_n4 fid 0.5, sat_n7 fid 0.016) — the valid-output tally is compactq 9 / tie 19 / lose 0: zero valid 2q losses.

QASMBench medium (≤ 12 qubits; python scripts/realbench.py --size medium --max-qubits 12 — most medium files are ≥ 14q or carry classical control flow):

circuit Compact qiskit L3 pytket
sat_n11 486 / 212 / 355 599 / 252 / 403 713 / 250 / 507

(sat_n11 improved again this run: 212 2q vs the 252 of the 2026-09-08 run and a 252-vs-252 tie before that — the cross-pair/KAK pipeline keeps finding more.)

QASMBench large (≤ 32 qubits; python scripts/realbench.py --size large --max-qubits 32; > 8q runs the no-verify path, soundness of which is fuzzed against a Qiskit referee up to 10 qubits in the gauntlet):

circuit Compact qiskit L3 pytket
adder_n28 328 / 171 / 185 412 / 195 / 189 526 / 183 / 231
bv_n30 55 / 18 / 20 79 / 18 / 20 197 / 18 / 24
knn_n31 226 / 90 / 96 290 / 105 / 125 365 / 105 / 129
qft_n29 805 / 370 / 85 1261 / 602 / 194 1699 / 806 / 197

(cc_n32 and vqe_uccsd_n28 skipped: classical control flow / non-standard QASM. adder_n28 flipped from a 2026-09-08 loss (422/195 vs 412/195) to a clear win (328/171 vs 412/195) with the current pass pipeline.)

MQT Bench — freshly generated algorithm-level circuits (python scripts/mqtbench_run.py; mqt-bench, 44 circuits run, every tool's output refereed at ≤8q; all four tools exact unless marked ‡). gates / 2q / depth:

circuit Compact qiskit L3 pytket FullPeephole cirq CZTargetGateset
ghz_n4 4 / 3 / 4 4 / 3 / 4 6 / 3 / 6 11 / 3 / 7
ghz_n6 6 / 5 / 6 6 / 5 / 6 8 / 5 / 8 17 / 5 / 11
ghz_n8 8 / 7 / 8 8 / 7 / 8 10 / 7 / 10 23 / 7 / 15
wstate_n4 13 / 6 / 8 13 / 6 / 8 25 / 6 / 14 21 / 6 / 11
wstate_n6 21 / 10 / 12 21 / 10 / 12 41 / 10 / 20 35 / 10 / 17
graphstate_n4 8 / 4 / 4 8 / 4 / 4 16 / 4 / 9 8 / 4 / 4
graphstate_n6 12 / 6 / 4 12 / 6 / 4 24 / 6 / 12 12 / 6 / 4
graphstate_n8 16 / 8 / 6 16 / 8 / 6 32 / 8 / 17 16 / 8 / 6
qaoa_n4 20 / 4 / 10 23 / 8 / 15 50 / 8 / 33 25 / 8 / 17
qaoa_n6 54 / 14 / 16 60 / 28 / 24 114 / 28 / 41 79 / 28 / 30
qaoa_n8 100 / 28 / 36 108 / 56 / 54 182 / 56 / 66 163 / 56 / 70
qft_n4 21 / 8 / 11 31 / 12 / 21 33 / 12 / 23 ‡ 53 / 18 / 28
qft_n6 44 / 18 / 17 71 / 30 / 35 73 / 30 / 37 ‡ 110 / 39 / 45
qft_n8 75 / 32 / 23 127 / 56 / 49 129 / 56 / 51 ‡ 187 / 68 / 62
qftentangled_n4 25 / 11 / 15 35 / 15 / 23 38 / 15 / 26 ‡ 63 / 21 / 32
qftentangled_n6 50 / 23 / 21 77 / 35 / 37 80 / 35 / 40 ‡ 126 / 44 / 49
vqe_real_amp_n4 25 / 9 / 11 25 / 9 / 11 73 / 9 / 26 33 / 9 / 15
vqe_real_amp_n6 39 / 15 / 13 39 / 15 / 13 111 / 15 / 30 53 / 15 / 19
vqe_real_amp_n8 53 / 21 / 15 53 / 21 / 15 149 / 21 / 34 73 / 21 / 23
vqe_two_local_n4 34 / 18 / 17 34 / 18 / 17 82 / 18 / 29 59 / 18 / 28
vqe_two_local_n6 69 / 45 / 25 69 / 45 / 25 141 / 45 / 37 130 / 45 / 44
qnn_n4 11 / 3 / 5 20 / 3 / 8 39 / 3 / 15 13 / 3 / 7
qnn_n6 17 / 5 / 7 29 / 5 / 9 59 / 5 / 19 21 / 5 / 11
qpeexact_n4 18 / 5 / 10 20 / 7 / 13 25 / 7 / 15 ‡ 30 / 10 / 21
qpeexact_n6 51 / 16 / 20 64 / 27 / 37 76 / 27 / 42 ‡ 96 / 33 / 49
qpeinexact_n4 25 / 7 / 14 32 / 12 / 24 41 / 12 / 27 ‡ 43 / 15 / 31
qpeinexact_n6 52 / 17 / 22 72 / 30 / 44 87 / 30 / 47 ‡ 103 / 36 / 56
qwalk_n4 250 / 108 / 194 262 / 114 / 200 288 / 114 / 224 316 / 114 / 212
qwalk_n6 1529 / 715 / 1261 1838 / 798 / 1382 2131 / 798 / 1653 2246 / 798 / 1416
randomcircuit_n4 86 / 42 / 66 125 / 53 / 96 109 / 41 / 82 157 / 53 / 102
randomcircuit_n6 180 / 78 / 104 229 / 95 / 134 272 / 94 / 151 269 / 95 / 146
randomcircuit_n8 389 / 170 / 170 522 / 208 / 247 582 / 207 / 272 ‡ 657 / 208 / 289
cdkm_ripple_carry_adder_n4 27 / 15 / 25 34 / 17 / 26 43 / 16 / 30 48 / 17 / 32
cdkm_ripple_carry_adder_n6 53 / 29 / 48 67 / 33 / 50 86 / 31 / 59 92 / 33 / 59
draper_qft_adder_n4 15 / 5 / 11 20 / 8 / 17 25 / 8 / 23 23 / 8 / 17
draper_qft_adder_n6 37 / 12 / 19 48 / 21 / 35 60 / 21 / 40 59 / 21 / 38
grover_n4 97 / 44 / 77 135 / 52 / 95 158 / 52 / 109 143 / 52 / 95
grover_n6 897 / 412 / 713 1098 / 456 / 818 1317 / 456 / 998 1287 / 456 / 810
bv_n5 7 / 2 / 4 7 / 2 / 4 18 / 2 / 8 7 / 2 / 4
bv_n7 4 / 3 / 4 10 / 3 / 5 24 / 3 / 9 10 / 3 / 5
dj_n5 13 / 4 / 6 13 / 4 / 6 27 / 4 / 9 13 / 4 / 6
dj_n7 19 / 6 / 8 19 / 6 / 8 39 / 6 / 11 19 / 6 / 8
ae_n4 35 / 11 / 22 41 / 12 / 28 78 / 12 / 51 55 / 18 / 37
ae_n6 66 / 24 / 36 92 / 30 / 55 145 / 30 / 91 125 / 42 / 62

Tallies (2-qubit count, invalid competitor outputs excluded): compactq wins 25 / ties 19 / loses 0 vs Qiskit L3, 25 / 19 / 0 vs Cirq, and 14 / 19 / 1 vs pytket — whose default-pipeline output is inequivalent on 10 of 44 circuits (‡; the same SWAP-elision pitfall the QASMBench referee shows on pytket 2.18.1; Cirq's optimizer was exact on all 44). Reproducibility note: cirq's QASM importer and pytket's converter order qubits per register rather than by global wire index, so the harness flattens every input onto a single q register first — without that, both tools silently optimize the wrong unitary on multi-register circuits.

Honest reading: on the unitary QASMBench suite compactq wins or ties Qiskit L3 on 2-qubit count on every circuit except basis_trotter_n4 (240 vs 179 — its pi/4-quantized iSWAP-ring structure needs deep template analysis; cross-pair merging took compactq from 16 to 12 and it is a named roadmap item). At larger scales the gap widens: on qft_n29 compactq cuts the 2q count a further 38% below Qiskit L3 (370 vs 602) at less than half the depth, on ising_n10 it is the only tool that finds non-trivial 2q reductions (49 vs 90), and adder_n28 flipped from the 2026-09-08 loss (422/195 vs 412/195) to a clear win (328/171 vs 412/195). On latency, Qiskit's Rust core is still the fastest raw optimizer on mid-size circuits, but for the same job — an optimized circuit you can actually trust — compactq's proof-included time wins the majority of head-to-head circuits, and pytket needs external verification on every output (its default mode is inequivalent on 10 of 44 MQT and 6 of 30 refereed QASMBench circuits this run).

CLI

Input policy: trailing measurements are dropped (the unitary core is optimized); mid-circuit measurement and reset are rejected with UnsupportedCircuitError; the Qiskit bridge rejects them outright (strip them first). The CLI never crashes on width: circuits above the dense proof limit are routed to randomized verification, and every run reports its proof status

compact in.qasm -o out.qasm        # optimize an OpenQASM 2.0 file
compact in.qasm --stats            # print gate-count/depth deltas
compact in.qasm --approx 0.99      # bounded-fidelity approximate mode
python -m compactq.bench            # full benchmark vs Qiskit (if installed)
python -m compactq.bench --quick    # 3-circuit CI guard
compact-bench --out results.md     # installed console script

API

import compactq
compactq.optimize(circuit, verify=True)        # Circuit -> Circuit (smaller, verified)
compactq.optimize_deep(circuit)                # KAK cascade, best for dense circuits
compactq.optimize_search(circuit)              # multi-pipeline search, keeps the best
compactq.approximate(circuit, min_fidelity=0.99)  # trade bounded fidelity for fewer 2q gates
from compactq.target import Target, optimize_for
t = Target(cx_fidelity={(0, 1): 0.999, (1, 0): 0.98})
best, est_fid = optimize_for(circuit, t)      # least-noisy circuit for YOUR machine
from compactq.target import approximate_for_target
best, est_fid = approximate_for_target(circuit, t)  # greedy fidelity-budget allocation
compactq.to_qasm(circuit) / compactq.from_qasm(t)  # OpenQASM 2.0 round-trip
compactq.from_qasm3(t)                         # OpenQASM 3 import (common subset)
compactq.to_qasm3(circuit)                     # OpenQASM 3.0 export
compactq.benchmarks.qft / ghz / brickwork / random_circuit / clifford_ladder
compactq.param / compactq.structure_optimize / compactq.bind   # symbolic angles: optimize the structure once, bind later
compactq.optimize_large(circ)   # verified optimization to ~30q (randomized K-state proof; numpy)

from_qasm understands the full extended-qelib1 set (u1/u2/u3/u, sx, sxdg, cy, cz, swap, cswap, ccx, crz, cu1/cp, rzz, rxx, id), multiple registers with global wire numbering, register-wide operands (h q;) and user gate definitions. from_qiskit accepts any QuantumCircuit: gates inside compactq's IR pass through untouched, everything else (mcphase, ccx, ecr, iswap, cu, rxx, ...) is decomposed at the boundary into the supported basis via Qiskit's own equivalence library — loss-free, and the result gets optimized instead of crashing.

Hardware-aware passes (compactq.hardware):

from compactq.hardware import route, route_aware, flip_cx, translate_1q_to_rz_sx_x
routed, final_map = route(circuit, coupling=[{0,1},{1,2}])
routed, final_map = route_aware(circuit, coupling, target=t, restore=True)

route inserts SWAPs along shortest paths and returns the final logical-on-physical mapping (apply it to your measurements); route_aware adds SABRE-style re-routing with error-weighted look-ahead and optional permutation restore. Optional bridges: compactq.qiskit_bridge (compactq_pass, to_qiskit, from_qiskit) and compactq.cirq_bridge (to_cirq).

Native hardware bases: Target(native_2q="ecr" | "cz" | "iswap") with optimize_for, or compact --native ecr on the CLI (verified gate-count parity with Qiskit's own basis decomposer).

Supported gates: h x y z s sdg t tdg rx ry rz p sx sxdg u/u3 cx cz swap cp, plus mcx/mcp (expanded on use). Multi-controlled and exotic gates arriving via from_qiskit are boundary-decomposed automatically.

Project history

  • v0.1.0 — initial public release (2026-09-17). The verified optimizer (peephole / commutation / CP / pure-Python KAK / Clifford-tableau / phase-polynomial passes, multi-pipeline search, exact + approximate modes, hardware targets, routing, QASM2/3 IO, Qiskit bridge + plugin, optional Rust kernels) plus the open error-suppression stack (twirling, benefit-gated DD, MLE mitigation, ZNE, CDR, simulators, device metrics, execution adapters). See CHANGELOG.md for the full inventory.

    The public version series starts at 0.1.0. An earlier private prototyping sprint (local iterations, 2026-09-10 → 2026-09-16) produced the engine; those internal numbers are retired and the git history keeps the full trail.

Roadmap

  • basis_trotter_n4 final disposition: qiskit's 179 and pytket's 159 are both permutation-elided (unverified outputs; this is exactly the circuit where their refereed fidelity was 0.25/0.5). Our 240 is exact; matching them requires layer-boundary content-permutation search with swap-network payoff at the output (roadmap). basis_test_n4 (the pi/4-quantized ring) has a Clifford+T normal-form pass in compactq/cliffordt.py; the REAL trotter file contains arbitrary-angle PhasedISWAPs and needs a different attack.
  • Rust parity-network BFS kernel: packed u64 wire-mask states; exactness fuzzed against the phase-polynomial reference (0 failures); parity_pass 302ms -> 25ms on parity-heavy shapes; finds windows the Python budget quirk misses
  • port the pass-engine hot path (peephole/KAK driving loops) to Rust to close the remaining raw-latency gap vs Qiskit on large circuits
  • MQT Bench in CI (currently a local script: scripts/mqtbench_run.py)

Development

git clone https://github.com/Q-PROOF/Compact && cd Compact
python tests/run_tests.py     # zero-dependency test suite
python scripts/gauntlet.py    # 1,018-check end-to-end gauntlet (needs qiskit)
pip install -e .[bench]       # optional: qiskit for the comparison column
python scripts/realbench.py --size small            # QASMBench vs Qiskit/pytket
python scripts/realbench.py --size large --max-qubits 32
pip install mqt-bench cirq ply   # extras for the fourth suite, then:
python scripts/mqtbench_run.py   # MQT Bench: compactq vs Qiskit/pytket/Cirq

Building the optional Rust wheel:

cd native && pip install maturin && maturin build --release -o dist
pip install dist/compactq_native-*.whl

MIT licensed. Contributions welcome — every PR must keep the property tests green.

Release files for compactq 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for compactq 0.1.0
File Size Uploaded
compactq-0.1.0.tar.gz 142.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for compactq 0.1.0
File Interpreter ABI Platform
compactq-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size:276.9 kB

Release files / compactq-0.1.0.tar.gz

Download URL compactq-0.1.0.tar.gz
Size 142.1 kB
Tags Source
SHA-256 checksum
How to use checksums
2d72cc69f0267144df452e3cedc2bf82c4101b8dff100b6136c97636296f8d70
BLAKE2b-256 checksum
How to use checksums
2de7fd5a8ce286cbd28e6c1a1087d26e36b780f1fdc10a3c62f0b9933c24f386
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / compactq-0.1.0-py3-none-any.whl

Download URL compactq-0.1.0-py3-none-any.whl
Size 134.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c25b75d79b6ddd529f9c07259b034a3ead6abddd24204adef51b87eadebda6ed
BLAKE2b-256 checksum
How to use checksums
1e8427922451b80c9ff11bb12d855dd8b3f8b005e88ab142a867b7474edfa06b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

0.1.7

1 release file

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page