Metody kompilacji dla obwodów symulacji Hamiltoniana
Szacowane zużycie QPU: w tym samouczku nie przeprowadzono żadnego wykonania, ponieważ skupia się on na procesie transpilacji.
Tło
Kompilacja obwodów kwantowych jest kluczowym krokiem w procesie obliczeń kwantowych. Polega ona na przekształceniu wysokopoziomowego algorytmu kwantowego w fizyczny obwód kwantowy spełniający ograniczenia docelowego sprzętu kwantowego. Skuteczna kompilacja może znacząco wpłynąć na wydajność algorytmów kwantowych poprzez redukcję głębokości obwodu, liczby bramek oraz czasu wykonania. Ten samouczek omawia trzy różne podejścia do kompilacji obwodów kwantowych w Qiskit, demonstrując ich mocne strony i zastosowania na praktycznych przykładach.
Celem tego samouczka jest nauczenie użytkowników, jak stosować i oceniać trzy metody kompilacji w Qiskit: transpiler SABRE, transpiler oparty na AI oraz wtyczkę Rustiq. Użytkownicy dowiedzą się, jak efektywnie korzystać z każdej metody i jak porównywać ich wydajność na różnych obwodach kwantowych. Po ukończeniu tego samouczka będziesz potrafić wybierać i dostosowywać strategie kompilacji w zależności od konkretnych celów optymalizacyjnych, takich jak redukcja głębokości obwodu, minimalizacja liczby bramek lub poprawa czasu działania.
Czego się nauczysz
- Jak używać transpilera Qiskit z algorytmem SABRE do optymalizacji układu i trasowania.
- Jak wykorzystać transpiler AI do zaawansowanej, zautomatyzowanej optymalizacji obwodów.
- Jak zastosować wtyczkę Rustiq dla obwodów wymagających precyzyjnej syntezy operacji, szczególnie w zadaniach symulacji Hamiltoniana.
Ten samouczek korzysta z trzech przykładowych obwodów zgodnych z przepływem pracy Qiskit patterns, aby zilustrować wydajność każdej metody kompilacji. Po ukończeniu tego samouczka będziesz wyposażony w narzędzia do wyboru odpowiedniej strategii kompilacji w zależności od swoich wymagań i ograniczeń.
Przegląd metod kompilacji
1. Transpiler Qiskit z algorytmem SABRE
Transpiler Qiskit używa algorytmu SABRE (SWAP-based BidiREctional heuristic search) do optymalizacji układu i trasowania obwodu. SABRE skupia się na minimalizacji bramek SWAP i ich wpływu na głębokość obwodu, przy jednoczesnym przestrzeganiu ograniczeń łączności sprzętu. Ta metoda jest bardzo wszechstronna i nadaje się do ogólnego zastosowania w optymalizacji obwodów, zapewniając balans między wydajnością a czasem obliczeń. Aby skorzystać z najnowszych ulepszeń algorytmu SABRE, opisanych w [1], możesz zwiększyć liczbę prób (na przykład layout_trials=400, swap_trials=400). Na potrzeby tego samouczka użyjemy domyślnych wartości liczby prób, aby porównać wyniki z domyślnym transpilerem Qiskit. Zalety i eksploracja parametrów algorytmu SABRE są omówione w osobnym samouczku dogłębnym.
2. Transpiler AI
Transpiler oparty na AI w Qiskit wykorzystuje uczenie maszynowe do przewidywania optymalnych strategii transpilacji, analizując wzorce w strukturze obwodu i ograniczeniach sprzętu, aby wybrać najlepszą sekwencję optymalizacji dla danego wejścia. Ta metoda jest szczególnie skuteczna w przypadku wielkoskalowych obwodów kwantowych, oferując wysoki stopień automatyzacji i zdolność adaptacji do różnorodnych typów problemów. Oprócz ogólnej optymalizacji obwodów, transpiler AI może być używany z przejściem AIPauliNetworkSynthesis, które jest ukierunkowane na obwody sieci Pauliego — bloki złożone z bramek H, S, SX, CX, RX, RY i RZ — i stosuje podejście syntezy opartej na uczeniu przez wzmacnianie. Więcej informacji na temat transpilera AI i jego strategii syntezy znajdziesz w [2] i [3].
3. Wtyczka Rustiq
Wtyczka Rustiq wprowadza zaawansowane techniki syntezy specjalnie dla operacji PauliEvolutionGate, które reprezentują rotacje Pauliego powszechnie stosowane w dynamice Trotteryzowanej. Ta wtyczka jest cenna dla obwodów implementujących symulację Hamiltoniana, takich jak te używane w problemach chemii i fizyki kwantowej, gdzie dokładne rotacje Pauliego są niezbędne do efektywnej symulacji Hamiltonianów problemowych. Rustiq oferuje precyzyjną syntezę obwodów o małej głębokości dla tych wyspecjalizowanych operacji. Więcej szczegółów na temat implementacji i wydajności Rustiq znajdziesz w [4].
Poprzez dogłębne zbadanie tych metod kompilacji, ten samouczek dostarcza użytkownikom narzędzi do poprawy wydajności ich obwodów kwantowych, torując drogę do bardziej efektywnych i praktycznych obliczeń kwantowych.
Wymagania
Przed rozpoczęciem tego samouczka upewnij się, że masz zainstalowane następujące pakiety:
- Qiskit SDK v1.3 lub nowszy, z obsługą wizualizacji
- Qiskit Runtime v0.28 lub nowszy (
pip install qiskit-ibm-runtime) - Qiskit IBM Transpiler (
pip install qiskit-ibm-transpiler) - Lokalny tryb AI Transpiler Qiskit IBM (
pip install qiskit_ibm_ai_local_transpiler) - Biblioteka grafów Networkx (
pip install networkx)
Konfiguracja
# 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
Część 1: Obwód Efficient SU2
Krok 1: Odwzorowanie klasycznych danych wejściowych na problem kwantowy
W tej sekcji badamy obwód efficient_su2 — sprzętowo-wydajny ansatz powszechnie stosowany w wariacyjnych algorytmach kwantowych (takich jak VQE) i zadaniach kwantowego uczenia maszynowego. Obwód składa się z naprzemiennych warstw jednoQubitowych rotacji i bramek splątujących ułożonych w okrężny wzorzec, zaprojektowanych do efektywnej eksploracji przestrzeni stanów kwantowych przy zachowaniu zarządzalnej głębokości.
Rozpoczniemy od skonstruowania jednego obwodu efficient_su2, aby zademonstrować, jak porównywać różne metody kompilacji. Po Części 1 rozszerzymy analizę na większy zestaw obwodów, umożliwiając kompleksowy benchmark do oceny wydajności różnych technik kompilacji.
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")
Krok 2: Optymalizacja problemu pod kątem wykonania na sprzęcie kwantowym
Ten krok jest głównym celem samouczka. Dążymy tutaj do optymalizacji obwodów kwantowych pod kątem efektywnego wykonania na rzeczywistym sprzęcie kwantowym. Naszym głównym celem jest redukcja głębokości obwodu i liczby bramek, które są kluczowymi czynnikami poprawy wierności wykonania i łagodzenia szumów sprzętowych.
- Transpiler SABRE: Używa domyślnego transpilera Qiskit z algorytmem układu i trasowania SABRE.
- Transpiler AI (tryb lokalny): Standardowy transpiler oparty na AI używający lokalnego wnioskowania i domyślnej strategii syntezy.
- Wtyczka Rustiq: Wtyczka transpilatora zaprojektowana do kompilacji o małej głębokości, dostosowana do zadań symulacji Hamiltoniana.
Celem tego kroku jest porównanie wyników tych metod pod względem głębokości i liczby bramek przetranspilowanego obwodu. Kolejną ważną miarą, którą bierzemy pod uwagę, jest czas transpilacji. Analizując te metryki, możemy ocenić względne mocne strony każdej metody i określić, która z nich tworzy najbardziej wydajny obwód do wykonania na wybranym sprzęcie.
Uwaga: W przypadku początkowego przykładu obwodu SU2 będziemy porównywać wyłącznie transpiler SABRE z domyślnym transpilerem AI. Jednak w kolejnym benchmarku używającym obwodów Hamlib porównamy wszystkie trzy metody transpilacji.
# 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')>
Transpiler Qiskit z algorytmem SABRE:
pm_sabre = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
Transpiler AI:
# Standard AI transpiler pass manager, using the local mode
pm_ai = generate_ai_pass_manager(
backend=backend, optimization_level=3, ai_optimization_level=3
)
Wtyczka Rustiq:
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,
)
Transpilacja i zbieranie metryk
Aby porównać wydajność metod kompilacji, definiujemy funkcję, która transpiluje obwód wejściowy i zbiera odpowiednie metryki w spójny sposób. Obejmuje to całkowitą głębokość obwodu, ogólną liczbę bramek oraz czas transpilacji.
Oprócz tych standardowych metryk rejestrujemy również głębokość dwuQubitową, która jest szczególnie ważną miarą przy ocenie wykonania na sprzęcie kwantowym. W odróżnieniu od całkowitej głębokości, która uwzględnia wszystkie bramki, głębokość dwuQubitowa dokładniej odzwierciedla rzeczywisty czas wykonania obwodu na sprzęcie. Dzieje się tak, ponieważ bramki dwuQubitowe dominują zazwyczaj w budżecie czasu i błędów w większości urządzeń kwantowych. Dlatego minimalizacja głębokości dwuQubitowej ma kluczowe znaczenie dla poprawy wierności i redukcji efektów dekoherencji podczas wykonania.
Użyjemy tej funkcji do analizy wydajności różnych metod kompilacji na wielu obwodach.
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.
Wyświetlenie przetranspilowanych wyników dla jednego z obwodów.
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

Tabela wyników:
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
Wykres wyników
Ponieważ zdefiniowaliśmy funkcję do spójnego zbierania metryk, zdefiniujemy też funkcję do ich wizualizacji. Tutaj przedstawimy na wykresie głębokość dwuQubitową, liczbę bramek i czas działania dla każdej metody kompilacji na poszczególnych obwodach.
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"
)

Analiza wyników kompilacji obwodów SU2
W tym eksperymencie porównujemy dwie metody transpilacji — transpiler SABRE Qiskit i transpiler oparty na AI — na zestawie obwodów efficient_su2. Ponieważ te obwody nie zawierają żadnych operacji PauliEvolutionGate, wtyczka Rustiq nie jest uwzględniona w tym porównaniu.
Średnio transpiler AI osiąga lepsze wyniki pod względem głębokości obwodu, z poprawą przekraczającą 10% w całym zakresie obwodów SU2. W przypadku liczby bramek (rozmiar obwodu) i czasu transpilacji obie metody dają ogólnie podobne wyniki.
Jednak analiza poszczególnych punktów danych ujawnia głębszy wgląd:
- Dla większości rozmiarów Qubitowych zarówno SABRE, jak i AI dają niemal identyczne wyniki, co sugeruje, że w wielu przypadkach obie metody zbiegają się do podobnie wydajnych rozwiązań.
- Dla pewnych rozmiarów obwodów, konkretnie dla 30, 50, 70 i 90 Qubitów, transpiler AI znajduje znacznie płytsze obwody niż SABRE. Wskazuje to, że podejście AI oparte na uczeniu jest w stanie odkrywać bardziej optymalne układy lub ścieżki trasowania w przypadkach, gdy heurystyka SABRE zawodzi.
To zachowanie podkreśla ważny wniosek:
Choć SABRE i AI często dają porównywalne wyniki, transpiler AI może od czasu do czasu odkryć znacznie lepsze rozwiązania, szczególnie pod względem głębokości, co może prowadzić do znacząco poprawionej wydajności na sprzęcie.
Część 2: Circuit symulacji Hamiltonianu
Krok 1: Badanie Circuitów z PauliEvolutionGate
W tej sekcji badamy Circuit kwantowe skonstruowane przy użyciu PauliEvolutionGate, który umożliwia efektywną symulację hamiltonianów. Przeanalizujemy, jak różne metody kompilacji optymalizują te Circuity dla różnych hamiltonianów.
Hamiltoniany użyte w benchmarku
Hamiltoniany użyte w tym benchmarku opisują parowe interakcje między Qubitami, obejmując wyrazy takie jak , i . Hamiltoniany te są powszechnie stosowane w chemii kwantowej, fizyce materii skondensowanej i nauce o materiałach, gdzie modelują układy oddziałujących cząstek.
Dla odniesienia możesz zapoznać się z szerszym zestawem hamiltonianów w tym artykule: Efficient Hamiltonian Simulation on Noisy Quantum Devices.
Źródło benchmarku: Hamlib i Benchpress
Circuity używane w tym benchmarku pochodzą z repozytorium benchmarku Hamlib, które zawiera realistyczne zadania symulacji hamiltonianów.
Te same Circuity były wcześniej benchmarkowane za pomocą Benchpress, otwartego frameworka do oceny wydajności transpilacji kwantowej. Korzystając z tego znormalizowanego zestawu Circuitów, możemy bezpośrednio porównać skuteczność różnych strategii kompilacji na reprezentatywnych problemach symulacji.
Symulacja hamiltonianów jest podstawowym zadaniem w obliczeniach kwantowych, z zastosowaniami w symulacjach molekularnych, problemach optymalizacyjnych i kwantowej fizyce wielu ciał. Zrozumienie, jak różne metody kompilacji optymalizują te Circuity, może pomóc w poprawie praktycznego wykonania takich Circuitów na urządzeniach kwantowych bliskiej generacji.
# 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
Krok 2: Optymalizacja problemu pod kątem wykonania na sprzęcie kwantowym
Podobnie jak w poprzednim przykładzie, użyjemy tego samego Backendu, aby zapewnić spójność porównań. Ponieważ menedżery przejść (pm_sabre, pm_ai i pm_rustiq) zostały już zainicjowane, możemy przejść bezpośrednio do transpilacji Circuitów hamiltonianów każdą metodą.
Ten krok koncentruje się wyłącznie na przeprowadzeniu transpilacji i rejestrowaniu wynikowych metryk Circuitów, w tym głębokości, liczby Gateów i czasu transpilacji. Analizując te wyniki, staramy się określić efektywność każdej metody transpilacji dla tego typu Circuitów. Transpiluj i rejestruj metryki:
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.
Tabela wyników (pomijamy wizualizację, ponieważ wynikowe Circuity są bardzo duże):
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]
Wizualizacja wydajności w zależności od indeksu Circuitu:
plot_transpilation_metrics(
results_ham, "Transpilation Metrics for Hamiltonian Circuits"
)

Wizualizacja procentu Circuitów, dla których każda metoda wypadła najlepiej.
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)
Analiza wyników kompilacji Circuitów hamiltonianowych
W tej sekcji oceniamy wydajność trzech metod transpilacji — SABRE, Transpilatora AI i Rustiq — na Circuitach kwantowych zbudowanych z PauliEvolutionGate, które są powszechnie stosowane w zadaniach symulacji hamiltonianów.
Rustiq osiągnął średnio najlepsze wyniki pod względem głębokości Circuitu**, uzyskując około 20% mniejszą głębokość niż SABRE. Jest to zgodne z oczekiwaniami, ponieważ Rustiq jest specjalnie zaprojektowany do syntezy operacji PauliEvolutionGate ze zoptymalizowanymi strategiami dekompozycji o niskiej głębokości. Co więcej, wykres głębokości pokazuje, że wraz ze wzrostem rozmiaru i złożoności Circuitów, Rustiq skaluje się najefektywniej, utrzymując znacząco niższą głębokość niż zarówno AI, jak i SABRE dla większych Circuitów.
Transpilator AI wykazał silną i spójną wydajność pod względem głębokości Circuitu, konsekwentnie przewyższając SABRE w większości Circuitów. Jednak wiązał się z najwyższym czasem działania, zwłaszcza dla większych Circuitów, co może ograniczać jego praktyczność w zadaniach wrażliwych na czas. Jego skalowalność pod względem czasu działania pozostaje kluczowym ograniczeniem, mimo że oferuje solidne ulepszenia w zakresie głębokości.
SABRE, choć generujący najwyższą średnią głębokość, osiągnął najniższą średnią liczbę Gateów, z wynikiem bliskim Transpilatora AI. Jest to zgodne z projektem heurystyki SABRE, która priorytetowo minimalizuje liczbę Gateów. Rustiq, mimo swojej siły w redukcji głębokości, miał najwyższą średnią liczbę Gateów, co jest istotnym kompromisem do rozważenia w zastosowaniach, gdzie rozmiar Circuitu jest ważniejszy niż czas jego trwania.
Podsumowanie
Choć Transpilator AI generalnie daje lepsze wyniki niż SABRE, szczególnie pod względem głębokości Circuitu, wniosek nie powinien być po prostu „zawsze używaj Transpilatora AI". Należy wziąć pod uwagę ważne niuanse:
-
Transpilator AI jest zazwyczaj niezawodny i zapewnia Circuity zoptymalizowane pod kątem głębokości, ale wiąże się z kompromisami w czasie działania, a także ma inne ograniczenia, w tym obsługiwane mapy sprzężeń i możliwości syntezy. Szczegóły znajdziesz w dokumentacji Qiskit Transpiler Service.
-
W niektórych przypadkach, szczególnie w przypadku bardzo dużych lub specyficznych sprzętowo Circuitów, Transpilator AI może nie być tak skuteczny. W takich przypadkach domyślny Transpilator SABRE pozostaje niezwykle niezawodny i można go dalej optymalizować, dostosowując jego parametry (patrz samouczek optymalizacji SABRE).
-
Ważne jest również uwzględnienie struktury Circuitu przy wyborze metody. Na przykład
rustiqjest dedykowany dla Circuitów zawierającychPauliEvolutionGatei często daje najlepsze wyniki dla problemów symulacji hamiltonianów.
Zalecenie:
Nie istnieje jedna uniwersalna strategia transpilacji. Zachęcamy do zrozumienia struktury swojego Circuitu i przetestowania wielu metod transpilacji — w tym AI, SABRE i wyspecjalizowanych narzędzi takich jak Rustiq — aby znaleźć najbardziej efektywne rozwiązanie dla konkretnego problemu i ograniczeń sprzętowych.
Krok 3: Wykonanie z użyciem prymitywów Qiskit
Ponieważ ten samouczek koncentruje się na transpilacji, żadne eksperymenty nie są wykonywane na urządzeniu kwantowym. Celem jest wykorzystanie optymalizacji z Kroku 2, aby uzyskać przetranspilowany Circuit o zredukowanej głębokości i liczbie Gateów.
Krok 4: Przetwarzanie końcowe i zwracanie wyniku w pożądanym formacie klasycznym
Ponieważ w tym notebooku nie ma wykonania, nie ma wyników do przetworzenia końcowego.
Odniesienia
[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