Przejdź do głównej treści

Wprowadzenie do transpilatora Qiskit opartego na AI

Szacowane użycie: 5 minut na IBM Heron (UWAGA: To tylko szacunek. Twój czas wykonania może się różnić.)

Cele nauki

Po ukończeniu tego samouczka użytkownicy powinni rozumieć:

  • Jak używać transpilatora opartego na AI (generate_ai_pass_manager) jako zamiennika standardowego transpilatora
  • Jak transpilator oparty na AI wypada w porównaniu z domyślnym transpilerem pod względem głębokości dwuqubitowej, liczby bramek i czasu transpilacji
  • Jak używać układów lustrzanych do oceny jakości transpilacji poprzez wykonanie na sprzęcie

Wymagania wstępne

Sugerujemy, aby przed przystąpieniem do tego samouczka użytkownicy byli zaznajomieni z następującymi tematami:

Tło

Transpilator Qiskit oparty na AI wprowadza przebiegi transpilacji oparte na uczeniu maszynowym, które mogą produkować krótsze, bardziej efektywne sprzętowo układy niż tradycyjne metody heurystyczne, takie jak SABRE. Krótsze układy akumulują mniej szumów, co bezpośrednio poprawia jakość wyników na rzeczywistym sprzęcie kwantowym.

W tym samouczku porównujemy dwie strategie transpilacji:

StrategiaAPI
Domyślnagenerate_preset_pass_manager(optimization_level=3, ...)
AIgenerate_ai_pass_manager(optimization_level=1, ai_optimization_level=3, ...)

Mierzymy trzy metryki dla każdej strategii: głębokość bramek dwuqubitowych, całkowitą liczbę bramek i czas transpilacji.

Benchmarki transpilatora opartego na AI

W testach benchmarkingowych transpilator oparty na AI konsekwentnie produkował płytsze, wyższej jakości układy w porównaniu ze standardowym transpilerem Qiskit. W tych testach użyliśmy domyślnej strategii menedżera przebiegów Qiskit, skonfigurowanej za pomocą generate_preset_pass_manager. Choć ta domyślna strategia jest często skuteczna, może mieć trudności z większymi lub bardziej złożonymi układami. Natomiast przebiegi oparte na AI osiągnęły średnio 24% redukcję liczby bramek dwuqubitowych i 36% redukcję głębokości układu dla dużych układów (ponad 100 qubitów) podczas transpilacji do topologii heavy-hex sprzętu IBM Quantum®. Więcej informacji na temat tych benchmarków znajdziesz w tym blogu.

Benchmarki transpilatora opartego na AI

Ten samouczek bada kluczowe zalety przebiegów AI i to, jak wypadają one w porównaniu z tradycyjnymi metodami.

Wymagania

Przed rozpoczęciem tego samouczka upewnij się, że masz zainstalowane:

  • Qiskit SDK v2.0 lub nowszy, z obsługą wizualizacji
  • Qiskit Runtime (pip install qiskit-ibm-runtime) v0.22 lub nowszy
  • Qiskit IBM Transpiler z lokalnym trybem AI (pip install 'qiskit-ibm-transpiler[ai-local-mode]')
  • Qiskit Aer (pip install qiskit-aer)

Konfiguracja

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib qiskit qiskit-aer qiskit-ibm-runtime qiskit-ibm-transpiler
from qiskit import QuantumCircuit
from qiskit.circuit.random import random_circuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit_ibm_transpiler import generate_ai_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel, depolarizing_error
import matplotlib.pyplot as plt
from statistics import mean, stdev
import time
import logging

seed = 42

def transpile_with_metrics(pass_manager, circuit):
"""Transpile a circuit and return the result along with key metrics."""
start = time.time()
qc_out = pass_manager.run(circuit)
elapsed = time.time() - start

depth_2q = qc_out.depth(lambda x: x.operation.num_qubits == 2)
gate_count = qc_out.size()

return qc_out, {
"depth_2q": depth_2q,
"gate_count": gate_count,
"time_s": round(elapsed, 3),
}

def remap_to_contiguous(tqc):
"""Remap a transpiled circuit to use contiguous qubit indices.

Transpiled circuits target specific physical qubits (e.g., qubit 45, 67)
on a large backend. This remaps them to 0, 1, 2, ... so Aer only
simulates the active qubits."""
active = sorted(
{tqc.find_bit(q).index for inst in tqc.data for q in inst.qubits}
)
qubit_map = {old: new for new, old in enumerate(active)}
new_qc = QuantumCircuit(len(active))
for inst in tqc.data:
old_indices = [tqc.find_bit(q).index for q in inst.qubits]
new_qc.append(inst.operation, [qubit_map[i] for i in old_indices])
return new_qc

def build_mirror_circuit(tqc, simulate=True):
"""Build a mirror circuit: U followed by U-dagger, with measurements.

The expected output is always |0...0>, so measuring the survival
probability reveals how much noise each transpilation strategy adds.

Args:
tqc: A transpiled circuit.
simulate: If True (default), remap to contiguous qubits so Aer
only simulates the active qubits. If False, keep the full
physical layout for hardware execution."""
if simulate:
tqc = remap_to_contiguous(tqc)
mirror = tqc.compose(tqc.inverse())
mirror.measure_all()
return mirror

def print_summary(results):
"""Print a summary of each metric as mean +/- stdev across all circuits,
along with the mean percentage improvement of AI over Default."""
metrics = [
("Depth 2Q", "Depth 2Q (Default)", "Depth 2Q (AI)"),
("Gate Count", "Gate Count (Default)", "Gate Count (AI)"),
("Time (s)", "Time (Default)", "Time (AI)"),
]
header = (
f"{'Metric':<12}{'Default (mean +/- std)':>24}"
f"{'AI (mean +/- std)':>22}{'AI % improvement':>22}"
)
print(header)
print("-" * len(header))
for label, col_def, col_ai in metrics:
defaults = [r[col_def] for r in results]
ais = [r[col_ai] for r in results]
pct = [(d - a) / d * 100 for d, a in zip(defaults, ais)]
default_str = f"{mean(defaults):.1f} +/- {stdev(defaults):.1f}"
ai_str = f"{mean(ais):.1f} +/- {stdev(ais):.1f}"
pct_str = f"{mean(pct):+.1f}% +/- {stdev(pct):.1f}%"
print(f"{label:<12}{default_str:>24}{ai_str:>22}{pct_str:>22}")

def plot_metrics_and_pct(results, title_prefix):
"""Plot metric comparisons and percentage improvement of AI over Default."""
qubits = [r["Qubits"] for r in results]
metrics = [
("Depth 2Q (Default)", "Depth 2Q (AI)", "Two-Qubit Depth"),
("Gate Count (Default)", "Gate Count (AI)", "Gate Count"),
("Time (Default)", "Time (AI)", "Transpilation Time"),
]

# Row 1: raw metric comparison
fig, axs = plt.subplots(1, 3, figsize=(21, 5))
fig.suptitle(
f"{title_prefix}: Metric Comparison",
fontsize=15,
fontweight="bold",
y=1.02,
)
for ax, (col_def, col_ai, label) in zip(axs, metrics):
ax.plot(qubits, [r[col_def] for r in results], "o-", label="Default")
ax.plot(qubits, [r[col_ai] for r in results], "s-", label="AI")
ax.set_title(label)
ax.set_xlabel("Number of Qubits")
ax.set_ylabel(label)
ax.legend()
plt.tight_layout()
plt.show()

# Row 2: percentage improvement
fig, axs = plt.subplots(1, 3, figsize=(21, 5))
fig.suptitle(
f"{title_prefix}: % Improvement of AI over Default",
fontsize=15,
fontweight="bold",
y=1.02,
)
for ax, (col_def, col_ai, label) in zip(axs, metrics):
pct = [(r[col_def] - r[col_ai]) / r[col_def] * 100 for r in results]
ax.axhline(
0, color="#1f77b4", linewidth=2, label="Default (baseline)"
)
ax.plot(qubits, pct, "s-", color="#ff7f0e", label="AI")
ax.fill_between(qubits, 0, pct, alpha=0.15, color="#ff7f0e")
ax.set_title(label)
ax.set_xlabel("Number of Qubits")
ax.set_ylabel("% Improvement")
ax.legend()
plt.tight_layout()
plt.show()

# Suppress verbose AI-powered transpiler logs
logging.getLogger(
"qiskit_ibm_transpiler.wrappers.ai_local_synthesis"
).setLevel(logging.WARNING)

Przykład symulatora na małą skalę

Krok 1: Odwzorowanie klasycznych danych wejściowych na problem kwantowy

Generujemy 20 losowych układów o głębokości 4, gdzie liczba qubitów wynosi od sześciu do 25. Układy te posłużą jako nasze przypadki testowe do porównania strategii transpilacji.

num_circuits_sim = 20
depth_sim = 4
qubit_range_sim = list(range(6, 26))

circuits_sim = [
# We have only two qubit gates, as those test how well the transpiler can optimize the circuit.
random_circuit(
num_qubits=n,
depth=depth_sim,
max_operands=2,
num_operand_distribution={2: 1},
seed=seed + i,
)
for i, n in enumerate(qubit_range_sim)
]

print(
f"Created {len(circuits_sim)} circuits with qubit counts: {qubit_range_sim}"
)
circuits_sim[0].draw(output="mpl", fold=-1)
Created 20 circuits with qubit counts: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Wynik poprzedniej komórki kodu

Krok 2: Optymalizacja problemu pod kątem wykonania na sprzęcie kwantowym

Budujemy domyślny menedżer przebiegów (SABRE) dla wybranego backendu. Obie strategie transpilacji celują w pełną mapę sprzężeń backendu. Lokalna symulacja pozostaje wykonalna, ponieważ krok symulacji używa funkcji remap_to_contiguous do przenumerowania każdego transpilowanego układu tylko na jego aktywne qubitów, dzięki czemu Aer symuluje jedynie te qubity zamiast całego urządzenia.

service = QiskitRuntimeService()
backend = service.least_busy(
min_num_qubits=100, operational=True, simulator=False
)

pm_default_sim = generate_preset_pass_manager(
optimization_level=3,
backend=backend,
seed_transpiler=seed,
)
results_sim = []

for i, qc in enumerate(circuits_sim):
n = qubit_range_sim[i]

qc_default, m_default = transpile_with_metrics(pm_default_sim, qc)

# Create a fresh AI pass manager each iteration to avoid stale layout state
pm_ai = generate_ai_pass_manager(
optimization_level=1,
ai_optimization_level=3,
backend=backend,
)
qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)

results_sim.append(
{
"Qubits": n,
"Depth 2Q (Default)": m_default["depth_2q"],
"Depth 2Q (AI)": m_ai["depth_2q"],
"Gate Count (Default)": m_default["gate_count"],
"Gate Count (AI)": m_ai["gate_count"],
"Time (Default)": m_default["time_s"],
"Time (AI)": m_ai["time_s"],
}
)

print_summary(results_sim)
Fetching 4 files: 0%| | 0/4 [00:00<?, ?it/s]
Metric Default (mean +/- std) AI (mean +/- std) AI % improvement
--------------------------------------------------------------------------------
Depth 2Q 33.0 +/- 12.9 26.4 +/- 8.0 +15.8% +/- 17.6%
Gate Count 522.0 +/- 266.0 560.5 +/- 279.1 -9.0% +/- 9.0%
Time (s) 0.0 +/- 0.0 0.2 +/- 0.1 -893.6% +/- 362.9%

Tabela podsumowująca pokazuje średnią i odchylenie standardowe każdej metryki dla wszystkich 20 układów, wraz ze średnim procentowym ulepszeniem transpilatora opartego na AI w stosunku do domyślnego. Wartości dodatnie wskazują, że transpilator oparty na AI uzyskał lepsze wyniki; wartości ujemne wskazują, że lepszy był domyślny.

Dla tego przykładu na małą skalę transpilator oparty na AI osiąga średnio około 16% mniejszą głębokość dwuqubitową, ale kosztem około 9% wyższej liczby bramek. Podkreśla to kluczowy kompromis przy wyborze między dwiema strategiami: transpilator oparty na AI priorytetyzuje redukcję głębokości (mniej sekwencyjnych warstw bramek dwuqubitowych), podczas gdy domyślny transpilator (SABRE) priorytetyzuje minimalizację całkowitej liczby bramek (mniej wstawianych bramek SWAP). W zależności od aplikacji jedna metryka może mieć większe znaczenie niż druga.

plot_metrics_and_pct(results_sim, "Small-Scale Random Circuits")

Wynik poprzedniej komórki kodu

Wynik poprzedniej komórki kodu

Głębokość dwuqubitowa: Transpilator oparty na AI ogólnie produkuje układy o mniejszej głębokości dwuqubitowej. Głębokość jest jedną z podstawowych metryk, do optymalizacji której wytrenowany jest model routingu AI, a poprawa jest widoczna dla większości rozmiarów układów, choć SABRE może go dorównać lub pobić w przypadku poszczególnych układów.

Liczba bramek: Wyniki są podobne w tej skali, a SABRE utrzymuje niewielką przewagę ogólnie. Heurystyka routingu SABRE jest zaprojektowana tak, aby minimalizować liczbę wstawianych bramek SWAP, co bezpośrednio redukuje liczbę bramek. Przy małych rozmiarach układów różnica jest skromna.

Czas transpilacji: Czas działania SABRE jest niemal stały niezależnie od liczby qubitów, więc rozmiar układu ma niewielki wpływ na czas transpilacji w tej skali. Podstawowa logika routingu SABRE jest wysoce zoptymalizowana (w dużej mierze zaimplementowana w Rust). Transpilator oparty na AI działa zauważalnie dłużej i skaluje się wraz z rozmiarem układu, choć czasy bezwzględne pozostają rozsądne dla interaktywnego użycia.

Krok 3: Wykonanie za pomocą prymitywów Qiskit

Aby ocenić wpływ transpilacji na wierność układu, zbuduj układy lustrzane z przypadku 10-qubitowego i uruchom je na symulatorze Aer z prostym modelem szumów. Oczekiwanym wynikiem układu lustrzanego jest zawsze bitmapa złożona z samych zer, więc prawdopodobieństwo zmierzenia 0n|0\rangle^{\otimes n} pokazuje, jak dobrze każda strategia transpilacji zachowuje wierność.

# Use the 10-qubit circuit (index where qubits == 10)
idx_10q = qubit_range_sim.index(10)

qc_10q = circuits_sim[idx_10q]
qc_default_10q, _ = transpile_with_metrics(pm_default_sim, qc_10q)

pm_ai = generate_ai_pass_manager(
optimization_level=1,
ai_optimization_level=3,
backend=backend,
)
qc_ai_10q, _ = transpile_with_metrics(pm_ai, qc_10q)

tqc_methods = {
"Default": qc_default_10q,
"AI": qc_ai_10q,
}

print(
f"Default: depth {qc_default_10q.depth()}, gates {qc_default_10q.size()}"
)
print(f"AI: depth {qc_ai_10q.depth()}, gates {qc_ai_10q.size()}")
Default: depth 84, gates 280
AI: depth 91, gates 343
# Build a simple depolarizing noise model
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(
depolarizing_error(0.001, 1),
["sx", "x", "rz"], # ~0.1% per 1Q gate
)
noise_model.add_all_qubit_quantum_error(
depolarizing_error(0.01, 2),
["cx", "ecr"], # ~1% per 2Q gate
)

aer_sim = AerSimulator(noise_model=noise_model)

shots = 10000
survival_probs = {}

for method, tqc in tqc_methods.items():
mirror = build_mirror_circuit(tqc, simulate=True)

sampler = SamplerV2(mode=aer_sim)
job = sampler.run([mirror], shots=shots)
counts = job.result()[0].data.meas.get_counts()

all_zeros = "0" * mirror.num_qubits
survival = counts.get(all_zeros, 0) / shots
survival_probs[method] = survival
print(
f"{method:8s} P(|00...0>) = {survival:.4f} ({counts.get(all_zeros, 0)}/{shots})"
)
Default P(|00...0>) = 0.8460 (8460/10000)
AI P(|00...0>) = 0.8121 (8121/10000)

Uruchomiliśmy oba układy lustrzane przez symulator Aer z prostym modelem szumów depolaryzacyjnych. Prawdopodobieństwo przetrwania, zdefiniowane jako ułamek pomiarów, które zwracają bitmapę złożoną z samych zer, mierzy, ile szumów wprowadza każda strategia transpilacji.

Krok 4: Postprzetwarzanie i zwrócenie wyniku w pożądanym formacie klasycznym

Wyciągamy prawdopodobieństwo zmierzenia bitmapy złożonej z samych zer z obu uruchomień. Wyższe prawdopodobieństwo przetrwania wskazuje na lepszą wierność, co oznacza, że transpilacja wprowadziła mniej szumów. Wykres poniżej pokazuje dopełnienie, 1 - P(|0...0>), tak że niższy słupek wskazuje lepszą wierność i małe różnice w błędzie są łatwiejsze do dostrzeżenia.

# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.
# A lower bar means the transpilation introduced less noise.
error_probs = {method: 1 - p for method, p in survival_probs.items()}

fig, ax = plt.subplots(figsize=(6, 4))
ax.bar(
error_probs.keys(),
error_probs.values(),
color=["steelblue", "coral"],
)
ax.set_ylabel("1 - P(|0...0>)")
ax.set_title("Mirror Circuit Error (10-qubit, Aer Simulator)")
ax.set_ylim(0, 1)
plt.tight_layout()
plt.show()

Wynik poprzedniej komórki kodu

W tym przypadku domyślny transpilator wyprodukował zarówno płytszy, jak i mniejszy układ dla tego konkretnego przypadku 10-qubitowego, więc jego wyższa wierność jest oczekiwana. Wyniki dla poszczególnych układów się różnią: jak pokazuje tabela podsumowująca powyżej, zaleta transpilatora opartego na AI polega na średnio mniejszej głębokości dwuqubitowej, a nie na każdym indywidualnym układzie. Która strategia daje wyższą wierność, zależy od wielkości różnicy w każdej metryce, charakterystyki szumów sprzętu i struktury układu. Przy jednorodnym modelu szumów depolaryzacyjnych całkowita liczba bramek często ma bardziej bezpośredni wpływ na skumulowany błąd niż głębokość sama w sobie.

Przykład sprzętowy na dużą skalę

Kroki 1–4

Tutaj wszystkie te szczegóły są łączone w przejrzysty przepływ pracy na większą skalę, który jest następnie uruchamiany na rzeczywistym sprzęcie kwantowym.

Poniższy kod generuje 25 losowych układów o głębokości 8, gdzie liczba qubitów wynosi od 26 do 50. Układy te są następnie transpilowane obiema strategiami i zbierane są te same metryki. Następnie budujemy układy lustrzane z przypadku 26-qubitowego i przesyłamy je do rzeczywistego backendu.

# -------------------------Step 1-------------------------
num_circuits_hw = 25
depth_hw = 8
qubit_range_hw = list(range(26, 51))

circuits_hw = [
# We have only two qubit gates, as those test how well the transpiler can optimize the circuit.
random_circuit(
num_qubits=n,
depth=depth_hw,
max_operands=2,
num_operand_distribution={2: 1},
seed=seed + i,
)
for i, n in enumerate(qubit_range_hw)
]

print(
f"Created {len(circuits_hw)} circuits with qubit counts: {qubit_range_hw}"
)
Created 25 circuits with qubit counts: [26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
# -------------------------Step 2-------------------------
pm_default = generate_preset_pass_manager(
optimization_level=3,
backend=backend,
seed_transpiler=seed,
)

results_hw = []

for i, qc in enumerate(circuits_hw):
n = qubit_range_hw[i]

qc_default, m_default = transpile_with_metrics(pm_default, qc)

# Create a fresh AI pass manager each iteration to avoid stale layout state
pm_ai = generate_ai_pass_manager(
optimization_level=1,
ai_optimization_level=3,
backend=backend,
)
qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)

results_hw.append(
{
"Qubits": n,
"Depth 2Q (Default)": m_default["depth_2q"],
"Depth 2Q (AI)": m_ai["depth_2q"],
"Gate Count (Default)": m_default["gate_count"],
"Gate Count (AI)": m_ai["gate_count"],
"Time (Default)": m_default["time_s"],
"Time (AI)": m_ai["time_s"],
}
)

print_summary(results_hw)
Metric Default (mean +/- std) AI (mean +/- std) AI % improvement
--------------------------------------------------------------------------------
Depth 2Q 217.4 +/- 50.4 191.0 +/- 35.6 +10.9% +/- 10.7%
Gate Count 4513.3 +/- 1394.3 5227.1 +/- 1536.4 -16.4% +/- 5.8%
Time (s) 0.1 +/- 0.0 3.5 +/- 1.5 -3588.2% +/- 643.6%
plot_metrics_and_pct(results_hw, "Large-Scale Random Circuits")

Wynik poprzedniej komórki kodu

Wynik poprzedniej komórki kodu

# -------------------------Step 3-------------------------
# Build mirror circuits from the 26-qubit case
idx_26q = qubit_range_hw.index(26)

qc_26q = circuits_hw[idx_26q]
qc_default_26q, _ = transpile_with_metrics(pm_default, qc_26q)

pm_ai = generate_ai_pass_manager(
optimization_level=1,
ai_optimization_level=3,
backend=backend,
)
qc_ai_26q, _ = transpile_with_metrics(pm_ai, qc_26q)

mirror_default_hw = build_mirror_circuit(qc_default_26q, simulate=False)
mirror_ai_hw = build_mirror_circuit(qc_ai_26q, simulate=False)

# Re-transpile to basis gates (the inverse can introduce gates like sxdg)
pm_basis = generate_preset_pass_manager(
optimization_level=0,
backend=backend,
)
mirror_default_hw = pm_basis.run(mirror_default_hw)
mirror_ai_hw = pm_basis.run(mirror_ai_hw)

print(
f"Mirror circuit (Default): depth {mirror_default_hw.depth()}, gates {mirror_default_hw.size()}"
)
print(
f"Mirror circuit (AI): depth {mirror_ai_hw.depth()}, gates {mirror_ai_hw.size()}"
)

# Submit to real hardware
sampler_hw = SamplerV2(mode=backend)
sampler_hw.options.environment.job_tags = ["TUT_AITI"]

shots_hw = 500000
job_hw = sampler_hw.run([mirror_default_hw, mirror_ai_hw], shots=shots_hw)
print(f"Job submitted: {job_hw.job_id()}")
Mirror circuit (Default): depth 1577, gates 9672
Mirror circuit (AI): depth 1235, gates 11092
Job submitted: d8gt7vm6983c73dqbg0g
# -------------------------Step 4-------------------------
result_hw = job_hw.result()

survival_probs_hw = {}
for i, method in enumerate(["Default", "AI"]):
counts = result_hw[i].data.meas.get_counts()
mirror = [mirror_default_hw, mirror_ai_hw][i]
all_zeros = "0" * mirror.num_qubits
survival = counts.get(all_zeros, 0) / shots_hw
survival_probs_hw[method] = survival
print(
f"{method:8s} P(|00...0>) = {survival:.4f} ({counts.get(all_zeros, 0)}/{shots_hw})"
)

# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.
# A lower bar means the transpilation introduced less noise.
error_probs_hw = {method: 1 - p for method, p in survival_probs_hw.items()}

fig, ax = plt.subplots(figsize=(6, 4))
ax.bar(
error_probs_hw.keys(),
error_probs_hw.values(),
color=["steelblue", "coral"],
)
ax.set_ylabel("1 - P(|0...0>)")
ax.set_title(f"Mirror Circuit Error (26-qubit, {backend.name})")
ax.set_ylim(0, 1)
plt.tight_layout()
plt.show()
Default P(|00...0>) = 0.0005 (239/500000)
AI P(|00...0>) = 0.0050 (2516/500000)

Wynik poprzedniej komórki kodu

Analiza wyników

Wyniki na dużą skalę potwierdzają tendencje zaobserwowane w przykładzie na małą skalę, teraz przy bardziej wymagającej skali.

Głębokość dwuqubitowa: Transpilator oparty na AI nadal zapewnia zauważalnie mniejszą głębokość dwuqubitową w całym zakresie rozmiarów układów. Optymalizacja głębokości jest jednym z głównych celów, do których wytrenowany jest model routingu AI, a zaleta jest bardziej wyraźna przy większej liczbie qubitów, gdzie problem routingu staje się trudniejszy dla metod heurystycznych.

Liczba bramek: Domyślny transpilator (SABRE) konsekwentnie produkuje układy z mniejszą liczbą bramek we wszystkich rozmiarach układów w tym zakresie. Heurystyka SABRE jest specjalnie zaprojektowana tak, aby minimalizować liczbę bramek, a w tej skali zaleta jest wyraźna i jednolita.

Czas transpilacji: Różnica w czasie transpilacji zwiększa się przy większych skalach. SABRE pozostaje niemal stały, podczas gdy czas działania transpilatora opartego na AI rośnie bardziej stromo. Mimo to czas działania transpilatora opartego na AI pozostaje praktyczny dla większości przepływów pracy.

Wierność układu lustrzanego: Obie metody produkują prawdopodobieństwa przetrwania zdecydowanie poniżej 1% w tej skali, co pozostawia mało użytecznego sygnału. Przy całkowitej liczbie bramek około 10 000 i głębokościach dwuqubitowych przekraczających 1 000, szum depolaryzacyjny nagromadzony w układzie lustrzanym przytłacza większość sygnału. Podkreśla to kluczowe ograniczenie podejścia układów lustrzanych: choć jest ono proste i nie wymaga symulacji klasycznej, nie skaluje się dobrze do dużych lub głębokich układów, gdzie obie metody są zbliżone do poziomu szumów, a mały pozostały sygnał jest zdominowany przez nagromadzony błąd.

Choć wyniki te podkreślają skuteczność transpilatora opartego na AI, ważne jest, aby zauważyć jego ograniczenia. Metoda syntezy AI jest obecnie dostępna tylko dla określonych map sprzężeń, co może ograniczać jej szersze zastosowanie. Należy wziąć to pod uwagę przy ocenie jej użycia w różnych scenariuszach.

Następne kroki

Zalecenia

Jeśli ta praca wydała ci się interesująca, może cię zainteresować następujący materiał: