RL agent that learns bespoke Qiskit transpiler optimization pass sequences
Project description
Quetsal
A GNN+PPO agent that adaptively sequences Qiskit optimization-stage passes — a learned replacement for the fixed pass pools behind opt_level=1/2/3.
Quetsal is named after the Quetzal — a bird known for navigating dense forest canopies with precision. Quetsal navigates the dense space of Qiskit transpilation passes, finding the optimal pass sequence through the optimization stage for each quantum circuit.
What is Quetsal?
Quetsal is a reinforcement learning agent that learns to sequence Qiskit transpilation passes adaptively per circuit, replacing the fixed pass pools behind optimization_level=1/2/3.
What it is:
- A
PassManagerStagePlugin-compatible RL agent - Takes a
DAGCircuitgraph encoding as input (via GINEConv) - Outputs a ranked sequence of Qiskit optimization passes
- Plugs into Qiskit's existing transpiler via the
pyproject.tomlentry point system
What it is not:
- Not a from-scratch transpiler or routing solver
- Not a standalone ZX-calculus rewriter — ZX-calculus (
ZXFullReducevia PyZX) is one selectable action among five; the RL agent decides when and whether to invoke it - Not a replacement for Qiskit's layout or routing stages
Target metric: Reduce 2-qubit gate count below optimization_level=3 across diverse circuit families — Quantum Volume, QAOA, Clifford-SU4, Clifford-SU4-SU8, RandomClifford, IQP, EfficientSU2, and RealAmplitudes, without increasing circuit depth.
Architecture
DAGCircuit → GINEConv Graph Encoder → PPO Policy (SB3) → Pass Selection Action
| Component | Implementation |
|---|---|
| Graph encoder | 4-layer GINEConv (PyTorch Geometric); node features: gate one-hot[6], is_clifford, norm param, topo_pos, last_pass (dim=10); edge features: qubit role one-hot src+dst (dim=6) |
| RL policy | PPO (Stable-Baselines3); QuetsalGNNPolicy — shared GINEConv trunk + separate actor/critic linear heads |
| Action space | Discrete(5): Optimize1qGatesDecomposition, ConsolidateAndSynthesize (macro: ConsolidateBlocks→UnitarySynthesis), CommutativeCancellation, ZXFullReduce (pyzx), DoNothing (learned termination) |
| Reward | Non-parametric families: (prev_2q − cur_2q) / initial_2q + 0.03·Δdepth − step_penalty. Depth-primary families (IQP/QAOA/EfficientSU2/RealAmplitudes): 0.35·Δdepth + 0.10·Δ2q − step_penalty. Terminal bonus on DoNothing, normalized by per-family achievable ceiling. |
| Target basis | IBM Heron r2 — cz, id, rx, rz, rzz, sx, x (Kingston, Marrakesh, Fez, Torino) |
| Integration | PassManagerStagePlugin registered via [project.entry-points."qiskit.transpiler.optimization"]; drop-in replacement for the optimization stage |
Quick Start
Install
pip install quetsal
The trained agent (3–10 qubit regime) ships inside the package, so the plugin works with no extra downloads.
Train, benchmark & analyze
These modules ship with the package, so they work after pip install quetsal as well as from a source checkout.
# Train — full staged curriculum (Stage 1 non-param → 2 parametric blend → 3 all families, ~500K steps)
python -m quetsal.training.train --mode 1 --curriculum
# Quick smoke-test (~2-3 min, verifies the pipeline end-to-end)
python -m quetsal.training.train --mode 0
# Benchmark against Qiskit baselines (opt_level 1/2/3)
python -m quetsal.benchmarks.eval \
--model runs/quetsal/best_model/<timestamp>/best_model.zip \
--n-circuits 100 --save-csv
# Baseline only (no model required)
python -m quetsal.benchmarks.eval --baseline-only
# Log a completed run's hyperparameters + results to CSV for comparison
python -m quetsal.experiments.track \
--model runs/quetsal/best_model/<timestamp>/best_model.zip \
--mode 1 --notes "curriculum r13"
Use via plugin
After pip install quetsal, the entry point is registered automatically — select it through Qiskit's preset pass manager:
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(
optimization_level=1, # layout + routing + translation
optimization_plugin="quetsal", # ← Quetsal replaces the optimization stage
basis_gates=["cz", "id", "rx", "rz", "rzz", "sx", "x"],
coupling_map=cm,
)
optimized_circuit = pm.run(raw_circuit)
Or drive it directly (uses the bundled agent by default; pass model_path=... to override):
from quetsal.src.plugin.quetsal_plugin import QuetsalPlugin
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
plugin = QuetsalPlugin() # bundled 3–10 qubit agent
pm = generate_preset_pass_manager(optimization_level=1, basis_gates=..., coupling_map=cm)
pm.optimization = plugin.pass_manager(pass_manager_config=None)
optimized_circuit = pm.run(raw_circuit)
Reminder: the bundled agent is trained for 3–10 qubit circuits. See Scope & Limitations before using it on larger circuits.
Current Results
Trained agent: 500K-step staged-curriculum run, evaluated on 716 held-out circuits (100 Clifford-SU4 + 57 Clifford-SU4-SU8 + 59 QV + 100 RandomClifford + 100 IQP + 100 EfficientSU2 + 100 QAOA + 100 RealAmplitudes), 3-10 qubits, Heron r2 basis. All optimizers receive the same pre-transpiled input (post layout+routing+translation, pre-optimization). Depth figures are reductions (higher = shallower). Means are circuit-count-weighted.
Non-parametric circuits — 2q gate reduction (%)
| Optimizer | Clifford-SU4 | Clifford-SU4-SU8 | QV | RandomClifford | Mean (316) |
|---|---|---|---|---|---|
| opt_level=1 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| opt_level=2 | 13.9 | 10.9 | 14.8 | 6.5 | 11.2 |
| opt_level=3 | 13.9 | 10.9 | 14.8 | 6.5 | 11.2 |
| Quetsal | 23.6 | 13.7 | 27.7 | 21.5 | 21.9 |
~2x opt_level=2/3 (+10.7pp overall). Largest gains: RandomClifford +15.0pp, QV +12.9pp, Clifford-SU4 +9.7pp.
Non-parametric circuits — depth reduction (%)
| Optimizer | Clifford-SU4 | Clifford-SU4-SU8 | QV | RandomClifford | Mean |
|---|---|---|---|---|---|
| opt_level=1 | 64.1 | 52.8 | 65.6 | 27.7 | 50.8 |
| opt_level=2 | 68.8 | 58.2 | 70.1 | 35.8 | 56.7 |
| opt_level=3 | 68.8 | 58.2 | 70.1 | 35.8 | 56.7 |
| Quetsal | 71.2 | 58.0 | 75.3 | 45.1 | 61.3 |
Quetsal reduces depth further overall (61.3% vs 56.7%) while delivering the 2q gains above — largest depth gains on RandomClifford (+9.3pp), QV (+5.2pp), and Clifford-SU4 (+2.4pp). Clifford-SU4-SU8 tracks opt_level=2/3 depth (58.0 vs 58.2) while improving 2q reduction.
Parametric circuits — depth reduction (%)
Parametric families have near-zero 2q gate reduction across all optimizers; the meaningful comparison is depth.
| Optimizer | IQP | EfficientSU2 | QAOA | RealAmplitudes | Mean |
|---|---|---|---|---|---|
| opt_level=1 | 11.7 | 29.0 | 2.0 | 23.2 | 16.5 |
| opt_level=2 | 11.7 | 48.5 | 2.0 | 45.7 | 27.0 |
| opt_level=3 | 11.7 | 48.5 | 2.0 | 45.7 | 27.0 |
| Quetsal | 9.8 | 49.4 | 2.0 | 45.7 | 26.7 |
Overall (716 circuits, all families)
| Metric | opt_level=2/3 | Quetsal |
|---|---|---|
| Mean 2q reduction | 5.0% | 9.7% |
| Mean depth reduction | 40.1% | 42.0% |
The 9.7% overall 2q figure is diluted by the four parametric families (400 circuits, ~0% reduction each by construction). On the 316 non-parametric circuits the mean is 21.9% — roughly double opt_level=2/3.
Scope & Limitations
Quetsal is trained and validated on 3–10 qubit circuits, and is intended for use in that range. Every result above is on 3–10 qubit Heron r2 circuits — the distribution the agent was trained on. Within this range it reliably beats opt_level=2/3 on both 2q-gate and depth reduction for non-parametric families and with no depth regression for parametric families.
Scalability is the primary limitation. The reference paper (arXiv:2601.21629) reports that a model trained on small circuits can be deployed on much larger ones. In the Qiskit-native setting I find this small-train / large-deploy generalization holds only modestly, and degrades as circuit size grows past the training range:
The degradation is architectural rather than a tuning artifact:
- Fixed receptive field — the GNN runs a fixed number of message-passing hops regardless of circuit size, so on large/deep DAGs each node sees a shrinking fraction of the circuit.
Related Work
- Mills et al. (Quantinuum, Jan 2026): "Reinforcement Learning for Adaptive Composition of Quantum Circuit Optimisation Passes" — arXiv:2601.21629. Uses GINConv + PPO over PyTKET passes on the Quantinuum native gateset.
- Quetschlich et al. (TU Munich): MQT Predictor — selects among preset compilation flows across Qiskit/TKET.
- IBM Research (2024): RL for Clifford synthesis and SABRE routing — individual sub-task RL.
- ZX+GNN papers: gate-level rewriting via graph rewrite rules — operates below the pass abstraction layer.
License
Apache 2.0 — see LICENSE.
AI Disclosure
Developed with assistance from Claude Code (Claude Opus 4.8).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quetsal-0.1.0.tar.gz.
File metadata
- Download URL: quetsal-0.1.0.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2378ce0e6ea6b53e521349b26015d620d71d99d3f35a5bdcfdc9fdeeba472885
|
|
| MD5 |
3da44000d2bd1d5dede9d6859731919f
|
|
| BLAKE2b-256 |
a27b3f8ceda5ae95bba434cefaf40c06ae873a8f934f8daa49438b2c5c2662c2
|
File details
Details for the file quetsal-0.1.0-py3-none-any.whl.
File metadata
- Download URL: quetsal-0.1.0-py3-none-any.whl
- Upload date:
- Size: 1.6 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35bd0c3c50ee0d18da49332d21bd59bda2c5d1c6f27b34d7c8603576898ef122
|
|
| MD5 |
e1a6b9bc1e7a73dc12963a04046982d3
|
|
| BLAKE2b-256 |
61bbbc77eedbf0f15af626ca781729e81279f42e0534a9842247c271c9d98670
|