Kompilierungsmethoden für Hamilton-Simulationsschaltungen
Geschätzte QPU-Nutzung: keine Ausführung wurde in diesem Tutorial durchgeführt, da es sich auf den Transpilationsprozess konzentriert.
Hintergrund
Die Quantenschaltungskompilierung ist ein entscheidender Schritt im Quantencomputing-Workflow. Sie umfasst die Transformation eines hochrangigen Quantenalgorithmus in eine physische Quantenschaltung, die den Einschränkungen der Ziel-Quantenhardware entspricht. Effektive Kompilierung kann die Leistung von Quantenalgorithmen erheblich beeinflussen, indem sie Schaltungstiefe, Gate-Anzahl und Ausführungszeit reduziert. Dieses Tutorial untersucht drei unterschiedliche Ansätze zur Quantenschaltungskompilierung in Qiskit und zeigt ihre Stärken und Anwendungen durch praktische Beispiele auf.
Das Ziel dieses Tutorials ist es, Benutzern beizubringen, wie sie drei Kompilierungsmethoden in Qiskit anwenden und bewerten: den SABRE-Transpiler, den AI-gestützten Transpiler und das Rustiq-Plugin. Benutzer werden lernen, wie sie jede Methode effektiv einsetzen und wie sie ihre Leistung über verschiedene Quantenschaltungen hinweg benchmarken. Am Ende dieses Tutorials werden Benutzer in der Lage sein, Kompilierungsstrategien basierend auf spezifischen Optimierungszielen wie der Reduzierung der Schaltungstiefe, der Minimierung der Gate-Anzahl oder der Verbesserung der Laufzeit zu wählen und anzupassen.
Was du lernen wirst
- Wie du den Qiskit-Transpiler mit SABRE für Layout- und Routing-Optimierung verwendest.
- Wie du den AI-Transpiler für fortgeschrittene, automatisierte Schaltungsoptimierung nutzt.
- Wie du das Rustiq-Plugin für Schaltungen einsetzt, die eine präzise Synthese von Operationen erfordern, insbesondere bei Hamilton-Simulationsaufgaben.
Dieses Tutorial verwendet drei Beispielschaltungen nach dem Qiskit Patterns-Workflow, um die Leistung jeder Kompilierungsmethode zu veranschaulichen. Am Ende dieses Tutorials werden Benutzer in der Lage sein, die geeignete Kompilierungsstrategie basierend auf ihren spezifischen Anforderungen und Einschränkungen zu wählen.
Übersicht über Kompilierungsmethoden
1. Qiskit-Transpiler mit SABRE
Der Qiskit-Transpiler verwendet den SABRE (SWAP-based BidiREctional heuristic search)-Algorithmus zur Optimierung von Schaltungslayout und -routing. SABRE konzentriert sich auf die Minimierung von SWAP-Gates und deren Auswirkungen auf die Schaltungstiefe, während Hardware-Konnektivitätsbeschränkungen eingehalten werden. Diese Methode ist hochvielseitig und für allgemeine Schaltungsoptimierung geeignet und bietet ein Gleichgewicht zwischen Leistung und Rechenzeit. Um die neuesten Verbesserungen in SABRE zu nutzen, die in [1] detailliert beschrieben sind, kannst du die Anzahl der Versuche erhöhen (zum Beispiel layout_trials=400, swap_trials=400). Für die Zwecke dieses Tutorials verwenden wir die Standardwerte für die Anzahl der Versuche, um mit dem Standard-Transpiler von Qiskit zu vergleichen. Die Vorteile und Parameter-Exploration von SABRE werden in einem separaten Deep-Dive-Tutorial behandelt.
2. AI-Transpiler
Der AI-gestützte Transpiler in Qiskit verwendet maschinelles Lernen, um optimale Transpilationsstrategien vorherzusagen, indem er Muster in der Schaltungsstruktur und Hardware-Einschränkungen analysiert, um die beste Sequenz von Optimierungen für eine gegebene Eingabe auszuwählen. Diese Methode ist besonders effektiv für groß angelegte Quantenschaltungen und bietet ein hohes Maß an Automatisierung und Anpassungsfähigkeit an diverse Problemtypen. Zusätzlich zur allgemeinen Schaltungsoptimierung kann der AI-Transpiler mit dem AIPauliNetworkSynthesis-Pass verwendet werden, der Pauli-Netzwerkschaltungen – Blöcke bestehend aus H-, S-, SX-, CX-, RX-, RY- und RZ-Gates – anvisiert und einen auf Reinforcement Learning basierenden Syntheseansatz anwendet. Weitere Informationen zum AI-Transpiler und seinen Synthese-Strategien findest du in [2] und [3].
3. Rustiq-Plugin
Das Rustiq-Plugin führt fortgeschrittene Synthesetechniken speziell für PauliEvolutionGate-Operationen ein, die Pauli-Rotationen repräsentieren, die häufig in Trotterisierter Dynamik verwendet werden. Dieses Plugin ist wertvoll für Schaltungen, die Hamilton-Simulation implementieren, wie sie in Quantenchemie- und Physikproblemen verwendet werden, bei denen genaue Pauli-Rotationen für die effektive Simulation von Problem-Hamiltonians wesentlich sind. Rustiq bietet präzise, niedrig-tiefe Schaltungssynthese für diese spezialisierten Operationen. Weitere Details zur Implementierung und Leistung von Rustiq findest du in [4].
Durch die eingehende Untersuchung dieser Kompilierungsmethoden bietet dieses Tutorial Benutzern die Werkzeuge, um die Leistung ihrer Quantenschaltungen zu verbessern und den Weg für effizientere und praktischere Quantenberechnungen zu ebnen.
Anforderungen
Stelle vor Beginn dieses Tutorials sicher, dass du Folgendes installiert hast:
- Qiskit SDK v1.3 oder höher, mit Unterstützung für Visualisierung
- Qiskit Runtime v0.28 oder höher (
pip install qiskit-ibm-runtime) - Qiskit IBM Transpiler (
pip install qiskit-ibm-transpiler) - Qiskit AI Transpiler Lokalmodus (
pip install qiskit_ibm_ai_local_transpiler) - Networkx-Graphenbibliothek (
pip install networkx)
Einrichtung
# Added by doQumentation — required packages for this notebook
!pip install -q IPython matplotlib numpy pandas qiskit qiskit-ibm-runtime qiskit-ibm-transpiler requests
from qiskit.circuit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit.library import (
efficient_su2,
PauliEvolutionGate,
)
from qiskit_ibm_transpiler import generate_ai_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
from collections import Counter
from IPython.display import display
import time
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import json
import requests
import logging
# Suppress noisy loggers
logging.getLogger(
"qiskit_ibm_transpiler.wrappers.ai_local_synthesis"
).setLevel(logging.ERROR)
seed = 42 # Seed for reproducibility
Teil 1: Efficient SU2-Schaltung
Schritt 1: Klassische Eingaben auf ein Quantenproblem abbilden
In diesem Abschnitt untersuchen wir die efficient_su2-Schaltung, einen hardwareeffizienten Ansatz, der häufig in variationellen Quantenalgorithmen (wie VQE) und Quantum-Machine-Learning-Aufgaben verwendet wird. Die Schaltung besteht aus abwechselnden Schichten von Ein-Qubit-Rotationen und verschränkenden Gates, die in einem kreisförmigen Muster angeordnet sind und dazu konzipiert sind, den Quantenzustandsraum effektiv zu erkunden, während eine überschaubare Tiefe beibehalten wird.
Wir beginnen mit der Konstruktion einer efficient_su2-Schaltung, um zu demonstrieren, wie verschiedene Kompilierungsmethoden verglichen werden. Nach Teil 1 werden wir unsere Analyse auf einen größeren Satz von Schaltungen erweitern, um einen umfassenden Benchmark zur Bewertung der Leistung verschiedener Kompilierungstechniken zu ermöglichen.
qubit_size = list(range(10, 101, 10))
qc_su2_list = [
efficient_su2(n, entanglement="circular", reps=1)
.decompose()
.copy(name=f"SU2_{n}")
for n in qubit_size
]
# Draw the first circuit
qc_su2_list[0].draw(output="mpl")
Schritt 2: Problem für die Ausführung auf Quantenhardware optimieren
Dieser Schritt ist der Hauptfokus des Tutorials. Hier wollen wir Quantenschaltungen für die effiziente Ausführung auf echter Quantenhardware optimieren. Unser primäres Ziel ist es, Schaltungstiefe und Gate-Anzahl zu reduzieren, die Schlüsselfaktoren zur Verbesserung der Ausführungstreue und zur Minderung von Hardware-Rauschen sind.
- SABRE-Transpiler: Verwendet den Standard-Transpiler von Qiskit mit dem SABRE-Layout- und Routing-Algorithmus.
- AI-Transpiler (Lokalmodus): Der Standard-AI-gestützte Transpiler mit lokaler Inferenz und der Standard-Synthesestrategie.
- Rustiq-Plugin: Ein Transpiler-Plugin für niedrig-tiefe Kompilierung, das auf Hamilton-Simulationsaufgaben zugeschnitten ist.
Das Ziel dieses Schritts ist es, die Ergebnisse dieser Methoden hinsichtlich Tiefe und Gate-Anzahl der transpilierten Schaltung zu vergleichen. Eine weitere wichtige Metrik, die wir berücksichtigen, ist die Transpilationslaufzeit. Durch die Analyse dieser Metriken können wir die relativen Stärken jeder Methode bewerten und bestimmen, welche die effizienteste Schaltung für die Ausführung auf der ausgewählten Hardware produziert.
Hinweis: Für das anfängliche SU2-Schaltungsbeispiel werden wir nur den SABRE-Transpiler mit dem Standard-AI-Transpiler vergleichen. Im anschließenden Benchmark mit Hamlib-Schaltungen werden wir jedoch alle drei Transpilationsmethoden vergleichen.
# QiskitRuntimeService.save_account(channel="ibm_quantum_platform", token="<YOUR-API-KEY>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService(channel="ibm_quantum_platform")
backend = service.backend("ibm_torino")
print(f"Using backend: {backend}")
qiskit_runtime_service._get_crn_from_instance_name:WARNING:2025-07-30 21:46:30,843: Multiple instances found. Using all matching instances.
Using backend: <IBMBackend('ibm_torino')>
Qiskit-Transpiler mit SABRE:
pm_sabre = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
AI-Transpiler:
# Standard AI transpiler pass manager, using the local mode
pm_ai = generate_ai_pass_manager(
backend=backend, optimization_level=3, ai_optimization_level=3
)
Rustiq-Plugin:
hls_config = HLSConfig(
PauliEvolution=[
(
"rustiq",
{
"nshuffles": 400,
"upto_phase": True,
"fix_clifford": True,
"preserve_order": False,
"metric": "depth",
},
)
]
)
pm_rustiq = generate_preset_pass_manager(
optimization_level=3,
backend=backend,
hls_config=hls_config,
seed_transpiler=seed,
)
Transpilieren und Metriken erfassen
Um die Leistung der Kompilierungsmethoden zu vergleichen, definieren wir eine Funktion, die die Eingabeschaltung transpiliert und relevante Metriken auf konsistente Weise erfasst. Dies umfasst die Gesamtschaltungstiefe, die Gesamt-Gate-Anzahl und die Transpilationszeit.
Zusätzlich zu diesen Standardmetriken zeichnen wir auch die 2-Qubit-Gate-Tiefe auf, die eine besonders wichtige Metrik zur Bewertung der Ausführung auf Quantenhardware ist. Im Gegensatz zur Gesamttiefe, die alle Gates einschließt, spiegelt die 2-Qubit-Tiefe die tatsächliche Ausführungsdauer der Schaltung auf Hardware genauer wider. Dies liegt daran, dass 2-Qubit-Gates typischerweise das Zeit- und Fehlerbudget in den meisten Quantengeräten dominieren. Daher ist die Minimierung der 2-Qubit-Tiefe entscheidend für die Verbesserung der Fidelität und die Reduzierung von Dekohärenzeffekten während der Ausführung.
Wir werden diese Funktion verwenden, um die Leistung der verschiedenen Kompilierungsmethoden über mehrere Schaltungen hinweg zu analysieren.
def capture_transpilation_metrics(
results, pass_manager, circuits, method_name
):
"""
Capture transpilation metrics for a list of circuits and stores the results in a DataFrame.
Args:
results (pd.DataFrame): DataFrame to store the results.
pass_manager: Pass manager used for transpilation.
circuits (list): List of quantum circuits to transpile.
method_name (str): Name of the transpilation method.
Returns:
list: List of transpiled circuits.
"""
transpiled_circuits = []
for i, qc in enumerate(circuits):
# Transpile the circuit
start_time = time.time()
transpiled_qc = pass_manager.run(qc)
end_time = time.time()
# Needed for AI transpiler to be consistent with other methods
transpiled_qc = transpiled_qc.decompose(gates_to_decompose=["swap"])
# Collect metrics
transpilation_time = end_time - start_time
circuit_depth = transpiled_qc.depth(
lambda x: x.operation.num_qubits == 2
)
circuit_size = transpiled_qc.size()
# Append results to DataFrame
results.loc[len(results)] = {
"method": method_name,
"qc_name": qc.name,
"qc_index": i,
"num_qubits": qc.num_qubits,
"ops": transpiled_qc.count_ops(),
"depth": circuit_depth,
"size": circuit_size,
"runtime": transpilation_time,
}
transpiled_circuits.append(transpiled_qc)
print(
f"Transpiled circuit index {i} ({qc.name}) in {transpilation_time:.2f} seconds with method {method_name}, "
f"depth {circuit_depth}, and size {circuit_size}."
)
return transpiled_circuits
results_su2 = pd.DataFrame(
columns=[
"method",
"qc_name",
"qc_index",
"num_qubits",
"ops",
"depth",
"size",
"runtime",
]
)
tqc_sabre = capture_transpilation_metrics(
results_su2, pm_sabre, qc_su2_list, "sabre"
)
tqc_ai = capture_transpilation_metrics(results_su2, pm_ai, qc_su2_list, "ai")
Transpiled circuit index 0 (SU2_10) in 0.06 seconds with method sabre, depth 13, and size 167.
Transpiled circuit index 1 (SU2_20) in 0.24 seconds with method sabre, depth 20, and size 299.
Transpiled circuit index 2 (SU2_30) in 10.72 seconds with method sabre, depth 72, and size 627.
Transpiled circuit index 3 (SU2_40) in 16.16 seconds with method sabre, depth 40, and size 599.
Transpiled circuit index 4 (SU2_50) in 76.89 seconds with method sabre, depth 77, and size 855.
Transpiled circuit index 5 (SU2_60) in 86.12 seconds with method sabre, depth 60, and size 899.
Transpiled circuit index 6 (SU2_70) in 94.46 seconds with method sabre, depth 79, and size 1085.
Transpiled circuit index 7 (SU2_80) in 69.05 seconds with method sabre, depth 80, and size 1199.
Transpiled circuit index 8 (SU2_90) in 88.25 seconds with method sabre, depth 105, and size 1420.
Transpiled circuit index 9 (SU2_100) in 83.80 seconds with method sabre, depth 100, and size 1499.
Transpiled circuit index 0 (SU2_10) in 0.17 seconds with method ai, depth 10, and size 168.
Transpiled circuit index 1 (SU2_20) in 0.29 seconds with method ai, depth 20, and size 299.
Transpiled circuit index 2 (SU2_30) in 13.56 seconds with method ai, depth 36, and size 548.
Transpiled circuit index 3 (SU2_40) in 15.95 seconds with method ai, depth 40, and size 599.
Transpiled circuit index 4 (SU2_50) in 80.70 seconds with method ai, depth 54, and size 823.
Transpiled circuit index 5 (SU2_60) in 75.99 seconds with method ai, depth 60, and size 899.
Transpiled circuit index 6 (SU2_70) in 64.96 seconds with method ai, depth 74, and size 1087.
Transpiled circuit index 7 (SU2_80) in 68.25 seconds with method ai, depth 80, and size 1199.
Transpiled circuit index 8 (SU2_90) in 75.07 seconds with method ai, depth 90, and size 1404.
Transpiled circuit index 9 (SU2_100) in 63.97 seconds with method ai, depth 100, and size 1499.
Zeige transpilierte Ergebnisse einer der Schaltungen an.
print("Sabre transpilation")
display(tqc_sabre[0].draw("mpl", fold=-1, idle_wires=False))
print("AI transpilation")
display(tqc_ai[0].draw("mpl", fold=-1, idle_wires=False))
Sabre transpilation

AI transpilation

Ergebnistabelle:
summary_su2 = (
results_su2.groupby("method")[["depth", "size", "runtime"]]
.mean()
.round(2)
)
print(summary_su2)
results_su2
depth size runtime
method
ai 56.4 852.5 45.89
sabre 64.6 864.9 52.57
method qc_name qc_index num_qubits ops \
0 sabre SU2_10 0 10 {'rz': 81, 'sx': 70, 'cz': 16}
1 sabre SU2_20 1 20 {'rz': 160, 'sx': 119, 'cz': 20}
2 sabre SU2_30 2 30 {'sx': 295, 'rz': 242, 'cz': 90}
3 sabre SU2_40 3 40 {'rz': 320, 'sx': 239, 'cz': 40}
4 sabre SU2_50 4 50 {'rz': 402, 'sx': 367, 'cz': 86}
5 sabre SU2_60 5 60 {'rz': 480, 'sx': 359, 'cz': 60}
6 sabre SU2_70 6 70 {'rz': 562, 'sx': 441, 'cz': 82}
7 sabre SU2_80 7 80 {'rz': 640, 'sx': 479, 'cz': 80}
8 sabre SU2_90 8 90 {'rz': 721, 'sx': 585, 'cz': 114}
9 sabre SU2_100 9 100 {'rz': 800, 'sx': 599, 'cz': 100}
10 ai SU2_10 0 10 {'rz': 81, 'sx': 71, 'cz': 16}
11 ai SU2_20 1 20 {'rz': 160, 'sx': 119, 'cz': 20}
12 ai SU2_30 2 30 {'sx': 243, 'rz': 242, 'cz': 63}
13 ai SU2_40 3 40 {'rz': 320, 'sx': 239, 'cz': 40}
14 ai SU2_50 4 50 {'rz': 403, 'sx': 346, 'cz': 74}
15 ai SU2_60 5 60 {'rz': 480, 'sx': 359, 'cz': 60}
16 ai SU2_70 6 70 {'rz': 563, 'sx': 442, 'cz': 82}
17 ai SU2_80 7 80 {'rz': 640, 'sx': 479, 'cz': 80}
18 ai SU2_90 8 90 {'rz': 721, 'sx': 575, 'cz': 108}
19 ai SU2_100 9 100 {'rz': 800, 'sx': 599, 'cz': 100}
depth size runtime
0 13 167 0.058845
1 20 299 0.238217
2 72 627 10.723922
3 40 599 16.159262
4 77 855 76.886604
5 60 899 86.118255
6 79 1085 94.458287
7 80 1199 69.048184
8 105 1420 88.254809
9 100 1499 83.795482
10 10 168 0.171532
11 20 299 0.291691
12 36 548 13.555931
13 40 599 15.952733
14 54 823 80.702141
15 60 899 75.993404
16 74 1087 64.960162
17 80 1199 68.253280
18 90 1404 75.072412
19 100 1499 63.967446
Ergebnisgraph
Da wir eine Funktion definieren, um Metriken konsistent zu erfassen, werden wir auch eine definieren, um die Metriken grafisch darzustellen. Hier werden wir die Zwei-Qubit-Tiefe, Gate-Anzahl und Laufzeit für jede Kompilierungsmethode über die Schaltungen hinweg darstellen.
def plot_transpilation_metrics(results, overall_title, x_axis="qc_index"):
"""
Plots transpilation metrics (depth, size, runtime) for different transpilation methods.
Parameters:
results (DataFrame): Data containing columns ['num_qubits', 'method', 'depth', 'size', 'runtime']
overall_title (str): The title of the overall figure.
x_axis (str): The x-axis label, either 'num_qubits' or 'qc_index'.
"""
fig, axs = plt.subplots(1, 3, figsize=(24, 6))
metrics = ["depth", "size", "runtime"]
titles = ["Circuit Depth", "Circuit Size", "Transpilation Runtime"]
y_labels = ["Depth", "Size (Gate Count)", "Runtime (s)"]
methods = results["method"].unique()
colors = plt.colormaps["tab10"]
markers = ["o", "^", "s", "D", "P", "*", "X", "v"]
color_list = [colors(i % colors.N) for i in range(len(methods))]
color_map = {method: color_list[i] for i, method in enumerate(methods)}
marker_map = {
method: markers[i % len(markers)] for i, method in enumerate(methods)
}
jitter_factor = 0.1 # Small x-axis jitter for visibility
handles, labels = [], [] # Unique handles for legend
# Plot each metric
for i, metric in enumerate(metrics):
for method in methods:
method_data = results[results["method"] == method]
# Introduce slight jitter to avoid exact overlap
jitter = np.random.uniform(
-jitter_factor, jitter_factor, len(method_data)
)
scatter = axs[i].scatter(
method_data[x_axis] + jitter,
method_data[metric],
color=color_map[method],
label=method,
marker=marker_map[method],
alpha=0.7,
edgecolors="black",
s=80,
)
if method not in labels:
handles.append(scatter)
labels.append(method)
axs[i].set_title(titles[i])
axs[i].set_xlabel(x_axis)
axs[i].set_ylabel(y_labels[i])
axs[i].grid(axis="y", linestyle="--", alpha=0.7)
axs[i].tick_params(axis="x", rotation=45)
axs[i].set_xticks(sorted(results[x_axis].unique()))
fig.suptitle(overall_title, fontsize=16)
fig.legend(
handles=handles,
labels=labels,
loc="upper right",
bbox_to_anchor=(1.05, 1),
)
plt.tight_layout()
plt.show()
plot_transpilation_metrics(
results_su2, "Transpilation Metrics for SU2 Circuits", x_axis="num_qubits"
)

Analyse der SU2-Schaltungskompilierungsergebnisse
In diesem Experiment vergleichen wir zwei Transpilationsmethoden – Qiskits SABRE-Transpiler und den AI-gestützten Transpiler – an einem Satz von efficient_su2-Schaltungen. Da diese Schaltungen keine PauliEvolutionGate-Operationen enthalten, ist das Rustiq-Plugin in diesem Vergleich nicht enthalten.
Im Durchschnitt schneidet der AI-Transpiler hinsichtlich der Schaltungstiefe besser ab, mit einer Verbesserung von mehr als 10% über die gesamte Bandbreite der SU2-Schaltungen hinweg. Für Gate-Anzahl (Schaltungsgröße) und Transpilationslaufzeit erzielen beide Methoden insgesamt ähnliche Ergebnisse.
Die Inspektion der einzelnen Datenpunkte offenbart jedoch eine tiefere Einsicht:
- Für die meisten Qubit-Größen produzieren sowohl SABRE als auch AI nahezu identische Ergebnisse, was darauf hindeutet, dass beide Methoden in vielen Fällen zu ähnlich effizienten Lösungen konvergieren.
- Für bestimmte Schaltungsgrößen, speziell bei 30, 50, 70 und 90 Qubits, findet der AI-Transpiler deutlich flachere Schaltungen als SABRE. Dies zeigt, dass der lernbasierte Ansatz von AI in der Lage ist, optimalere Layouts oder Routing-Pfade in Fällen zu entdecken, in denen die SABRE-Heuristik dies nicht tut.
Dieses Verhalten hebt eine wichtige Erkenntnis hervor:
Während SABRE und AI oft vergleichbare Ergebnisse produzieren, kann der AI-Transpiler gelegentlich viel bessere Lösungen entdecken, insbesondere hinsichtlich der Tiefe, was zu deutlich verbesserter Leistung auf Hardware führen kann.
Teil 2: Hamilton-Simulationsschaltung
Schritt 1: Untersuchung von Schaltungen mit PauliEvolutionGate
In diesem Abschnitt untersuchen wir Quantenschaltungen, die unter Verwendung von PauliEvolutionGate konstruiert wurden, das eine effiziente Simulation von Hamiltonians ermöglicht. Wir werden analysieren, wie verschiedene Kompilierungsmethoden diese Schaltungen über verschiedene Hamiltonians hinweg optimieren.
In diesem Benchmark verwendete Hamiltonians
Die in diesem Benchmark verwendeten Hamiltonians beschreiben paarweise Interaktionen zwischen Qubits, einschließlich Termen wie , und . Diese Hamiltonians werden häufig in Quantenchemie, Festkörperphysik und Materialwissenschaft verwendet, wo sie Systeme interagierender Teilchen modellieren.
Als Referenz können Benutzer einen breiteren Satz von Hamiltonians in diesem Paper erkunden: Efficient Hamiltonian Simulation on Noisy Quantum Devices.
Benchmark-Quelle: Hamlib und Benchpress
Die in diesem Benchmark verwendeten Schaltungen stammen aus dem Hamlib-Benchmark-Repository, das realistische Hamilton-Simulations-Workloads enthält.
Diese gleichen Schaltungen wurden zuvor mit Benchpress benchmarked, einem Open-Source-Framework zur Bewertung der Quanten-Transpilationsleistung. Durch die Verwendung dieses standardisierten Satzes von Schaltungen können wir die Effektivität verschiedener Kompilierungsstrategien bei repräsentativen Simulationsproblemen direkt vergleichen.
Hamilton-Simulation ist eine grundlegende Aufgabe im Quantencomputing mit Anwendungen in Molekülsimulationen, Optimierungsproblemen und Quanten-Vielteilchenphysik. Das Verständnis, wie verschiedene Kompilierungsmethoden diese Schaltungen optimieren, kann Benutzern helfen, die praktische Ausführung solcher Schaltungen auf kurzfristigen Quantengeräten zu verbessern.
# Obtain the Hamiltonian JSON from the benchpress repository
url = "https://raw.githubusercontent.com/Qiskit/benchpress/e7b29ef7be4cc0d70237b8fdc03edbd698908eff/benchpress/hamiltonian/hamlib/100_representative.json"
response = requests.get(url)
response.raise_for_status() # Raise an error if download failed
ham_records = json.loads(response.text)
# Remove circuits that are too large for the backend
ham_records = [
h for h in ham_records if h["ham_qubits"] <= backend.num_qubits
]
# Remove the circuits that are large to save transpilation time
ham_records = sorted(ham_records, key=lambda x: x["ham_terms"])[:35]
qc_ham_list = []
for h in ham_records:
terms = h["ham_hamlib_hamiltonian_terms"]
coeff = h["ham_hamlib_hamiltonian_coefficients"]
num_qubits = h["ham_qubits"]
name = h["ham_problem"]
evo_gate = PauliEvolutionGate(SparsePauliOp(terms, coeff))
qc_ham = QuantumCircuit(num_qubits)
qc_ham.name = name
qc_ham.append(evo_gate, range(num_qubits))
qc_ham_list.append(qc_ham)
print(f"Number of Hamiltonian circuits: {len(qc_ham_list)}")
# Draw the first Hamiltonian circuit
qc_ham_list[0].draw("mpl", fold=-1)
Number of Hamiltonian circuits: 35
Schritt 2: Problem für die Ausführung auf Quantenhardware optimieren
Wie im vorherigen Beispiel verwenden wir dasselbe Backend, um Konsistenz in unseren Vergleichen sicherzustellen. Da die Pass-Manager (pm_sabre, pm_ai und pm_rustiq) bereits initialisiert wurden, können wir direkt mit der Transpilation der Hamilton-Schaltungen mit jeder Methode fortfahren.
Dieser Schritt konzentriert sich ausschließlich auf die Durchführung der Transpilation und die Aufzeichnung der resultierenden Schaltungsmetriken, einschließlich Tiefe, Gate-Anzahl und Transpilationslaufzeit. Durch die Analyse dieser Ergebnisse wollen wir die Effizienz jeder Transpilationsmethode für diesen Schaltungstyp bestimmen.
Transpilieren und Metriken erfassen:
results_ham = pd.DataFrame(
columns=[
"method",
"qc_name",
"qc_index",
"num_qubits",
"ops",
"depth",
"size",
"runtime",
]
)
tqc_sabre = capture_transpilation_metrics(
results_ham, pm_sabre, qc_ham_list, "sabre"
)
tqc_ai = capture_transpilation_metrics(results_ham, pm_ai, qc_ham_list, "ai")
tqc_rustiq = capture_transpilation_metrics(
results_ham, pm_rustiq, qc_ham_list, "rustiq"
)
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method sabre, depth 6, and size 58.
Transpiled circuit index 1 (all-vib-c2h) in 1.10 seconds with method sabre, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method sabre, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.03 seconds with method sabre, depth 18, and size 115.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.02 seconds with method sabre, depth 24, and size 129.
Transpiled circuit index 5 (all-vib-fccf) in 0.05 seconds with method sabre, depth 14, and size 134.
Transpiled circuit index 6 (all-vib-hno) in 8.39 seconds with method sabre, depth 6, and size 174.
Transpiled circuit index 7 (all-vib-bhf2) in 3.92 seconds with method sabre, depth 22, and size 220.
Transpiled circuit index 8 (LiH) in 0.03 seconds with method sabre, depth 67, and size 290.
Transpiled circuit index 9 (uf20-ham) in 0.04 seconds with method sabre, depth 50, and size 340.
Transpiled circuit index 10 (all-vib-fccf) in 0.62 seconds with method sabre, depth 30, and size 286.
Transpiled circuit index 11 (all-vib-fccf) in 0.04 seconds with method sabre, depth 67, and size 339.
Transpiled circuit index 12 (all-vib-ch2) in 0.04 seconds with method sabre, depth 87, and size 421.
Transpiled circuit index 13 (tfim) in 0.05 seconds with method sabre, depth 36, and size 222.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 9.51 seconds with method sabre, depth 22, and size 345.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.05 seconds with method sabre, depth 128, and size 704.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 13.83 seconds with method sabre, depth 2, and size 242.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.05 seconds with method sabre, depth 106, and size 609.
Transpiled circuit index 18 (tfim) in 0.29 seconds with method sabre, depth 73, and size 399.
Transpiled circuit index 19 (all-vib-h2co) in 21.97 seconds with method sabre, depth 30, and size 572.
Transpiled circuit index 20 (Be2) in 0.09 seconds with method sabre, depth 324, and size 1555.
Transpiled circuit index 21 (graph-complete_bipart) in 0.12 seconds with method sabre, depth 250, and size 1394.
Transpiled circuit index 22 (all-vib-f2) in 0.07 seconds with method sabre, depth 215, and size 1027.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 41.22 seconds with method sabre, depth 30, and size 1144.
Transpiled circuit index 24 (TSP_Ncity-5) in 1.89 seconds with method sabre, depth 175, and size 1933.
Transpiled circuit index 25 (H2) in 0.32 seconds with method sabre, depth 1237, and size 5502.
Transpiled circuit index 26 (uuf100-ham) in 0.20 seconds with method sabre, depth 385, and size 4303.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 0.20 seconds with method sabre, depth 311, and size 3654.
Transpiled circuit index 28 (tfim) in 0.15 seconds with method sabre, depth 276, and size 3213.
Transpiled circuit index 29 (uuf100-ham) in 0.21 seconds with method sabre, depth 520, and size 5250.
Transpiled circuit index 30 (flat100-ham) in 0.15 seconds with method sabre, depth 131, and size 3157.
Transpiled circuit index 31 (uf100-ham) in 0.24 seconds with method sabre, depth 624, and size 7378.
Transpiled circuit index 32 (OH) in 0.88 seconds with method sabre, depth 2175, and size 9808.
Transpiled circuit index 33 (HF) in 0.66 seconds with method sabre, depth 2206, and size 9417.
Transpiled circuit index 34 (BH) in 0.89 seconds with method sabre, depth 2177, and size 9802.
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method ai, depth 6, and size 58.
Transpiled circuit index 1 (all-vib-c2h) in 1.11 seconds with method ai, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method ai, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.11 seconds with method ai, depth 18, and size 94.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.11 seconds with method ai, depth 22, and size 129.
Transpiled circuit index 5 (all-vib-fccf) in 0.06 seconds with method ai, depth 22, and size 177.
Transpiled circuit index 6 (all-vib-hno) in 8.62 seconds with method ai, depth 10, and size 198.
Transpiled circuit index 7 (all-vib-bhf2) in 3.71 seconds with method ai, depth 18, and size 195.
Transpiled circuit index 8 (LiH) in 0.19 seconds with method ai, depth 62, and size 267.
Transpiled circuit index 9 (uf20-ham) in 0.22 seconds with method ai, depth 47, and size 321.
Transpiled circuit index 10 (all-vib-fccf) in 0.71 seconds with method ai, depth 38, and size 369.
Transpiled circuit index 11 (all-vib-fccf) in 0.24 seconds with method ai, depth 65, and size 315.
Transpiled circuit index 12 (all-vib-ch2) in 0.24 seconds with method ai, depth 91, and size 430.
Transpiled circuit index 13 (tfim) in 0.15 seconds with method ai, depth 12, and size 251.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 8.50 seconds with method ai, depth 18, and size 311.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.25 seconds with method ai, depth 117, and size 659.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 16.11 seconds with method ai, depth 2, and size 242.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.39 seconds with method ai, depth 98, and size 564.
Transpiled circuit index 18 (tfim) in 0.38 seconds with method ai, depth 23, and size 437.
Transpiled circuit index 19 (all-vib-h2co) in 24.97 seconds with method ai, depth 38, and size 707.
Transpiled circuit index 20 (Be2) in 1.07 seconds with method ai, depth 293, and size 1392.
Transpiled circuit index 21 (graph-complete_bipart) in 0.61 seconds with method ai, depth 229, and size 1437.
Transpiled circuit index 22 (all-vib-f2) in 0.57 seconds with method ai, depth 178, and size 964.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 50.89 seconds with method ai, depth 34, and size 1425.
Transpiled circuit index 24 (TSP_Ncity-5) in 1.61 seconds with method ai, depth 171, and size 2020.
Transpiled circuit index 25 (H2) in 6.39 seconds with method ai, depth 1148, and size 5208.
Transpiled circuit index 26 (uuf100-ham) in 3.97 seconds with method ai, depth 376, and size 5048.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 3.54 seconds with method ai, depth 357, and size 4451.
Transpiled circuit index 28 (tfim) in 1.72 seconds with method ai, depth 216, and size 3026.
Transpiled circuit index 29 (uuf100-ham) in 4.45 seconds with method ai, depth 426, and size 5399.
Transpiled circuit index 30 (flat100-ham) in 7.02 seconds with method ai, depth 86, and size 3108.
Transpiled circuit index 31 (uf100-ham) in 12.85 seconds with method ai, depth 623, and size 8354.
Transpiled circuit index 32 (OH) in 15.19 seconds with method ai, depth 2084, and size 9543.
Transpiled circuit index 33 (HF) in 17.51 seconds with method ai, depth 2063, and size 9446.
Transpiled circuit index 34 (BH) in 15.33 seconds with method ai, depth 2094, and size 9730.
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method rustiq, depth 13, and size 83.
Transpiled circuit index 1 (all-vib-c2h) in 1.11 seconds with method rustiq, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method rustiq, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.01 seconds with method rustiq, depth 13, and size 79.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.02 seconds with method rustiq, depth 31, and size 131.
Transpiled circuit index 5 (all-vib-fccf) in 0.04 seconds with method rustiq, depth 50, and size 306.
Transpiled circuit index 6 (all-vib-hno) in 14.03 seconds with method rustiq, depth 22, and size 276.
Transpiled circuit index 7 (all-vib-bhf2) in 3.15 seconds with method rustiq, depth 13, and size 155.
Transpiled circuit index 8 (LiH) in 0.03 seconds with method rustiq, depth 54, and size 270.
Transpiled circuit index 9 (uf20-ham) in 0.04 seconds with method rustiq, depth 65, and size 398.
Transpiled circuit index 10 (all-vib-fccf) in 0.16 seconds with method rustiq, depth 41, and size 516.
Transpiled circuit index 11 (all-vib-fccf) in 0.02 seconds with method rustiq, depth 34, and size 189.
Transpiled circuit index 12 (all-vib-ch2) in 0.03 seconds with method rustiq, depth 49, and size 240.
Transpiled circuit index 13 (tfim) in 0.05 seconds with method rustiq, depth 20, and size 366.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 9.08 seconds with method rustiq, depth 16, and size 277.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.04 seconds with method rustiq, depth 116, and size 612.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 13.89 seconds with method rustiq, depth 2, and size 257.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.05 seconds with method rustiq, depth 133, and size 737.
Transpiled circuit index 18 (tfim) in 0.11 seconds with method rustiq, depth 25, and size 680.
Transpiled circuit index 19 (all-vib-h2co) in 27.19 seconds with method rustiq, depth 66, and size 983.
Transpiled circuit index 20 (Be2) in 0.07 seconds with method rustiq, depth 215, and size 1030.
Transpiled circuit index 21 (graph-complete_bipart) in 0.14 seconds with method rustiq, depth 328, and size 1918.
Transpiled circuit index 22 (all-vib-f2) in 0.05 seconds with method rustiq, depth 114, and size 692.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 62.25 seconds with method rustiq, depth 74, and size 2348.
Transpiled circuit index 24 (TSP_Ncity-5) in 0.20 seconds with method rustiq, depth 436, and size 3605.
Transpiled circuit index 25 (H2) in 0.21 seconds with method rustiq, depth 643, and size 3476.
Transpiled circuit index 26 (uuf100-ham) in 0.24 seconds with method rustiq, depth 678, and size 6120.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 0.22 seconds with method rustiq, depth 588, and size 5241.
Transpiled circuit index 28 (tfim) in 0.34 seconds with method rustiq, depth 340, and size 5901.
Transpiled circuit index 29 (uuf100-ham) in 0.33 seconds with method rustiq, depth 881, and size 7667.
Transpiled circuit index 30 (flat100-ham) in 0.31 seconds with method rustiq, depth 279, and size 4910.
Transpiled circuit index 31 (uf100-ham) in 0.38 seconds with method rustiq, depth 1138, and size 10607.
Transpiled circuit index 32 (OH) in 0.38 seconds with method rustiq, depth 1148, and size 6512.
Transpiled circuit index 33 (HF) in 0.37 seconds with method rustiq, depth 1090, and size 6256.
Transpiled circuit index 34 (BH) in 0.37 seconds with method rustiq, depth 1148, and size 6501.
Ergebnistabelle (Visualisierung wird übersprungen, da die Ausgabeschaltungen sehr groß sind):
summary_ham = (
results_ham.groupby("method")[["depth", "size", "runtime"]]
.mean()
.round(2)
)
print(summary_ham)
results_ham
depth size runtime
method
ai 316.86 2181.26 5.97
rustiq 281.94 2268.80 3.86
sabre 337.97 2120.14 3.07
method qc_name qc_index num_qubits \
0 sabre all-vib-o3 0 4
1 sabre all-vib-c2h 1 4
2 sabre all-vib-bh 2 2
3 sabre all-vib-c2h 3 3
4 sabre graph-gnp_k-2 4 4
.. ... ... ... ...
100 rustiq flat100-ham 30 90
101 rustiq uf100-ham 31 46
102 rustiq OH 32 10
103 rustiq HF 33 10
104 rustiq BH 34 10
ops depth size runtime
0 {'rz': 28, 'sx': 24, 'cz': 6} 6 58 0.016597
1 {'rz': 17, 'sx': 16, 'cz': 4, 'x': 2} 2 39 1.102089
2 {'sx': 14, 'rz': 13, 'cz': 3} 3 30 0.011042
3 {'sx': 46, 'rz': 45, 'cz': 18, 'x': 6} 18 115 0.025816
4 {'sx': 49, 'rz': 47, 'cz': 24, 'x': 9} 24 129 0.023077
.. ... ... ... ...
100 {'sx': 2709, 'cz': 1379, 'rz': 817, 'x': 5} 279 4910 0.309448
101 {'sx': 6180, 'cz': 3120, 'rz': 1303, 'x': 4} 1138 10607 0.380977
102 {'sx': 3330, 'cz': 1704, 'rz': 1455, 'x': 23} 1148 6512 0.383564
103 {'sx': 3213, 'cz': 1620, 'rz': 1406, 'x': 17} 1090 6256 0.368578
104 {'sx': 3331, 'cz': 1704, 'rz': 1447, 'x': 19} 1148 6501 0.374822
[105 rows x 8 columns]
Visualisiere die Leistung basierend auf dem Schaltungsindex:
plot_transpilation_metrics(
results_ham, "Transpilation Metrics for Hamiltonian Circuits"
)

Visualisiere den Prozentsatz der Schaltungen, für die jede Methode am besten abgeschnitten hat.
def analyze_and_plot_best_methods(results, metric):
"""
Analyze the best-performing methods for a given metric and plot a pie chart.
Parameters:
results (DataFrame): The input DataFrame containing method performance data.
metric (str): The metric to evaluate ("depth" or "size").
"""
method_counts = Counter()
for qc_idx, group in results.groupby("qc_index"):
min_value = group[metric].min()
# Find all methods that achieved this minimum value
best_methods = group[group[metric] == min_value]["method"]
# Update counts for all best methods (handling ties)
method_counts.update(best_methods)
best_method_counts = dict(
sorted(method_counts.items(), key=lambda x: x[1], reverse=True)
)
# Print summary
print(f"Best-performing methods based on {metric}:")
for method, count in best_method_counts.items():
print(f" {method}: {count} circuit(s)")
# Plot pie chart
num_methods = len(best_method_counts)
colors = plt.cm.viridis_r(range(0, 256, 256 // num_methods))
plt.figure(figsize=(5, 5))
plt.pie(
best_method_counts.values(),
labels=best_method_counts.keys(),
autopct="%1.1f%%",
startangle=140,
wedgeprops={"edgecolor": "black"},
textprops={"fontsize": 10},
colors=colors,
)
plt.title(
f"Percentage of Circuits Method Performed Best for {metric.capitalize()}",
fontsize=12,
fontweight="bold",
)
plt.show()
analyze_and_plot_best_methods(results_ham, "depth")
analyze_and_plot_best_methods(results_ham, "size")
Best-performing methods based on depth:
ai: 16 circuit(s)
rustiq: 16 circuit(s)
sabre: 10 circuit(s)
Best-performing methods based on size:
sabre: 18 circuit(s)
rustiq: 14 circuit(s)
ai: 10 circuit(s)
Analyse der Hamilton-Schaltungskompilierungsergebnisse
In diesem Abschnitt evaluieren wir die Leistung von drei Transpilationsmethoden – SABRE, dem AI-gestützten Transpiler und Rustiq – an Quantenschaltungen, die mit PauliEvolutionGate konstruiert wurden, die häufig in Hamilton-Simulationsaufgaben verwendet werden.
Rustiq schnitt im Durchschnitt am besten in Bezug auf die Schaltungstiefe ab und erreichte etwa 20% niedrigere Tiefe als SABRE. Dies ist zu erwarten, da Rustiq speziell für die Synthese von PauliEvolutionGate-Operationen mit optimierten, niedrig-tiefen Zerlegungsstrategien entwickelt wurde. Darüber hinaus zeigt das Tiefendiagramm, dass Rustiq am effektivsten skaliert, wenn die Schaltungen an Größe und Komplexität zunehmen, und eine deutlich geringere Tiefe als sowohl AI als auch SABRE bei größeren Schaltungen beibehält.
Der AI-Transpiler zeigte starke und konsistente Leistung für die Schaltungstiefe und übertraf SABRE konsistent über die meisten Schaltungen hinweg. Er verursachte jedoch die höchste Laufzeit, insbesondere bei größeren Schaltungen, was seine Praktikabilität in zeitkritischen Workloads einschränken kann. Seine Skalierbarkeit bei der Laufzeit bleibt eine Schlüsselbeschränkung, obwohl er solide Verbesserungen bei der Tiefe bietet.
SABRE erzielte zwar die höchste durchschnittliche Tiefe, aber die niedrigste durchschnittliche Gate-Anzahl, dicht gefolgt vom AI-Transpiler. Dies steht im Einklang mit dem Design der SABRE-Heuristik, die die Minimierung der Gate-Anzahl direkt priorisiert. Rustiq hatte trotz seiner Stärke bei der Senkung der Tiefe die höchste durchschnittliche Gate-Anzahl, was ein bemerkenswerter Kompromiss ist, den man in Anwendungen berücksichtigen sollte, bei denen Schaltungsgröße mehr zählt als Schaltungsdauer.
Zusammenfassung
Während der AI-Transpiler im Allgemeinen bessere Ergebnisse als SABRE liefert, insbesondere bei der Schaltungstiefe, sollte die Schlussfolgerung nicht einfach "immer den AI-Transpiler verwenden" sein. Es gibt wichtige Nuancen zu berücksichtigen:
-
AI-Transpiler ist typischerweise zuverlässig und liefert tiefenoptimierte Schaltungen, bringt aber Kompromisse bei der Laufzeit mit sich und hat auch andere Einschränkungen, einschließlich unterstützter Coupling-Maps und Synthese-Fähigkeiten. Diese sind in der Qiskit Transpiler Service-Dokumentation detailliert beschrieben.
-
In einigen Fällen, insbesondere bei sehr großen oder hardwarespezifischen Schaltungen, ist der AI-Transpiler möglicherweise nicht so effektiv. In diesen Fällen bleibt der Standard-SABRE-Transpiler äußerst zuverlässig und kann durch Anpassung seiner Parameter weiter optimiert werden (siehe das SABRE-Optimierungs-Tutorial).
-
Es ist auch wichtig, die Schaltungsstruktur bei der Wahl einer Methode zu berücksichtigen. Zum Beispiel ist
rustiqspeziell für Schaltungen mitPauliEvolutionGatekonzipiert und liefert oft die beste Leistung für Hamilton-Simulationsprobleme.
Empfehlung:
Es gibt keine Einheitslösung für die Transpilationsstrategie. Benutzer werden ermutigt, die Struktur ihrer Schaltung zu verstehen und mehrere Transpilationsmethoden zu testen – einschließlich AI, SABRE und spezialisierter Tools wie Rustiq – um die effizienteste Lösung für ihr spezifisches Problem und ihre Hardware-Einschränkungen zu finden.
Schritt 3: Ausführung mit Qiskit Primitives
Da sich dieses Tutorial auf Transpilation konzentriert, werden keine Experimente auf einem Quantengerät ausgeführt. Das Ziel ist es, die Optimierungen aus Schritt 2 zu nutzen, um eine transpilierte Schaltung mit reduzierter Tiefe und Gate-Anzahl zu erhalten.
Schritt 4: Nachbearbeitung und Rückgabe des Ergebnisses im gewünschten klassischen Format
Da es keine Ausführung für dieses Notebook gibt, gibt es keine Ergebnisse zur Nachbearbeitung.
Referenzen
[1] "LightSABRE: A Lightweight and Enhanced SABRE Algorithm". H. Zou, M. Treinish, K. Hartman, A. Ivrii, J. Lishman et al. https://arxiv.org/abs/2409.08368
[2] "Practical and efficient quantum circuit synthesis and transpiling with Reinforcement Learning". D. Kremer, V. Villar, H. Paik, I. Duran, I. Faro, J. Cruz-Benito et al. https://arxiv.org/abs/2405.13196
[3] "Pauli Network Circuit Synthesis with Reinforcement Learning". A. Dubal, D. Kremer, S. Martiel, V. Villar, D. Wang, J. Cruz-Benito et al. https://arxiv.org/abs/2503.14448
[4] "Faster and shorter synthesis of Hamiltonian simulation circuits". T. Goubault de Brugière, S. Martiel et al. https://arxiv.org/abs/2404.03280