דלג לתוכן הראשי

מבוא ל-Transpiler מבוסס AI של Qiskit

אומדן שימוש: 5 דקות על IBM Heron (הערה: זהו אומדן בלבד. זמן הריצה בפועל עשוי להשתנות.)

תוצאות למידה

לאחר השלמת מדריך זה, המשתמשים אמורים להבין:

  • כיצד להשתמש ב-Transpiler מבוסס AI‏ (generate_ai_pass_manager) כתחליף ישיר ל-Transpiler הסטנדרטי
  • כיצד ה-Transpiler מבוסס AI משתווה ל-Transpiler ברירת המחדל מבחינת עומק דו-Qubit, ספירת Gate וזמן transpilation
  • כיצד להשתמש במעגלי מראה להערכת איכות ה-transpilation באמצעות הרצה על חומרה

דרישות מקדימות

אנחנו מציעים שהמשתמשים יכירו את הנושאים הבאים לפני שמתחילים את המדריך:

רקע

Transpiler ה-AI של Qiskit מציג פסי transpilation מבוססי למידת מכונה שיכולים לייצר מעגלים קצרים יותר ויעילים יותר לחומרה מאשר שיטות היוריסטיות מסורתיות כמו SABRE. מעגלים קצרים יותר מצברים פחות רעש, מה שמשפר ישירות את איכות התוצאות על חומרה קוונטית אמיתית.

במדריך זה אנחנו משווים שתי אסטרטגיות transpilation:

אסטרטגיהAPI
ברירת מחדלgenerate_preset_pass_manager(optimization_level=3, ...)
AIgenerate_ai_pass_manager(optimization_level=1, ai_optimization_level=3, ...)

אנחנו מודדים שלושה מדדים עבור כל אסטרטגיה: עומק Gate דו-Qubit, ספירת Gate כוללת, וזמן ריצת transpilation.

מדדי ה-Transpiler מבוסס AI

במבחני ביצועים, ה-Transpiler מבוסס AI ייצר באופן עקבי מעגלים רדודים יותר ובאיכות גבוהה יותר בהשוואה ל-Transpiler הסטנדרטי של Qiskit. למבחנים אלה השתמשנו באסטרטגיית pass manager ברירת המחדל של Qiskit, שהוגדרה עם generate_preset_pass_manager. אמנם אסטרטגיית ברירת המחדל יעילה לעיתים קרובות, אך היא עלולה להתקשות עם מעגלים גדולים או מורכבים יותר. לעומת זאת, פסים מבוססי AI השיגו הפחתה ממוצעת של 24% בספירת Gate דו-Qubit והפחתה של 36% בעומק המעגל עבור מעגלים גדולים (100+ Qubit) בעת transpilation לטופולוגיית heavy-hex של חומרת IBM Quantum®. למידע נוסף על מדדים אלה, ראה בבלוג.

מדדי Transpiler מבוסס AI

מדריך זה חוקר את היתרונות המרכזיים של פסי AI וכיצד הם משתווים לשיטות מסורתיות.

דרישות

לפני תחילת מדריך זה, וודא שהדברים הבאים מותקנים:

  • Qiskit SDK v2.0 ומעלה, עם תמיכה בvisualization
  • Qiskit Runtime‏ (pip install qiskit-ibm-runtime) v0.22 ומעלה
  • Qiskit IBM Transpiler עם מצב AI מקומי (pip install 'qiskit-ibm-transpiler[ai-local-mode]')
  • Qiskit Aer‏ (pip install qiskit-aer)

הגדרה

# 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)

דוגמה בסימולטור בקנה מידה קטן

שלב 1: מיפוי קלטים קלאסיים לבעיה קוונטית

אנחנו מייצרים 20 מעגלים אקראיים בעומק 4, כשמספר ה-Qubit נע בין שש ל-25. מעגלים אלו ישמשו כמקרי הבדיקה שלנו להשוואת אסטרטגיות transpilation.

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]

פלט של תא הקוד הקודם

שלב 2: אופטימיזציה של הבעיה להרצה על חומרה קוונטית

אנחנו בונים את ה-pass manager ברירת המחדל (SABRE) עבור ה-Backend הנבחר. שתי אסטרטגיות ה-transpilation מכוונות למפת הזיווג המלאה של ה-Backend. הסימולציה המקומית בהמשך נשארת ניתנת לביצוע מכיוון ששלב הסימולציה משתמש ב-remap_to_contiguous כדי לסמן מחדש כל מעגל transpiled רק על ה-Qubit הפעילים שלו, כך ש-Aer מסמלץ רק את ה-Qubit הללו ולא את המכשיר כולו.

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%

טבלת הסיכום מציגה את הממוצע וסטיית התקן של כל מדד על פני כל 20 המעגלים, יחד עם אחוז השיפור הממוצע של ה-Transpiler מבוסס AI לעומת ברירת המחדל. ערכים חיוביים מציינים שה-Transpiler מבוסס AI הניב תוצאות טובות יותר; ערכים שליליים מציינים שברירת המחדל הייתה טובה יותר.

בדוגמה בקנה מידה קטן זו, ה-Transpiler מבוסס AI משיג עומק דו-Qubit נמוך בכ-16% בממוצע, אך במחיר של ספירת Gate גבוהה בכ-9%. זה מדגיש פשרה מרכזית בבחירה בין שתי האסטרטגיות: ה-Transpiler מבוסס AI מעדיף הפחתת עומק (פחות שכבות רצופות של Gate דו-Qubit), בעוד ה-Transpiler ברירת המחדל (SABRE) מעדיף מזעור ספירת Gate הכוללת (פחות הכנסות SWAP). בהתאם ליישום שלך, מדד אחד עשוי להיות חשוב יותר מהאחר.

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

פלט של תא הקוד הקודם

פלט של תא הקוד הקודם

עומק דו-Qubit: ה-Transpiler מבוסס AI בדרך כלל מייצר מעגלים עם עומק דו-Qubit נמוך יותר. עומק הוא אחד המדדים המרכזיים שמודל ה-routing של AI מאומן לאופטם, והשיפור נראה לעין ברוב גדלי המעגל, אם כי SABRE מצליח להתאים אותו או לעלות עליו במעגלים בודדים.

ספירת Gate: התוצאות קרובות מאוד בקנה מידה זה, כשל-SABRE יש יתרון קל בסך הכל. היוריסטיקת ה-routing של SABRE נועדה למזעור מספר Gate SWAP שהוכנסו, מה שמפחית ישירות את ספירת ה-Gate. בגדלי מעגל קטנים, ההפרש צנוע.

זמן transpilation: זמן הריצה של SABRE כמעט קבוע ללא קשר למספר ה-Qubit, כך שגודל המעגל כמעט ואינו משפיע על זמן ה-transpilation שלו בקנה מידה זה. לוגיקת ה-routing המרכזית של SABRE ממוטבת ביסודיות (מיושמת ברובה ב-Rust). ה-Transpiler מבוסס AI לוקח זמן ניכר יותר ומתמדר עם גודל המעגל, אם כי הזמנים המוחלטים נשארים סבירים לשימוש אינטראקטיבי.

שלב 3: הרצה באמצעות Qiskit primitives

כדי להעריך את השפעת ה-transpilation על נאמנות המעגל, נבנה מעגלי מראה מהמקרה של 10 Qubit ונריץ אותם על סימולטור Aer עם מודל רעש פשוט. הפלט הצפוי של מעגל מראה הוא תמיד מחרוזת הביט של כל-אפסים, כך שהסתברות המדידה של 0n|0\rangle^{\otimes n} מדגימה עד כמה כל אסטרטגיית transpilation שומרת על נאמנות.

# 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)

הרצנו את שני מעגלי המראה דרך סימולטור Aer עם מודל רעש depolarizing פשוט. הסתברות ההישרדות, המוגדרת כשבר הירויות שמחזירות את מחרוזת כל-האפסים, מכמתת כמה רעש כל אסטרטגיית transpilation מכניסה.

שלב 4: עיבוד לאחר והחזרת תוצאה בפורמט קלאסי רצוי

אנחנו מחלצים את ההסתברות למדוד את מחרוזת כל-האפסים משתי ההרצות. הסתברות הישרדות גבוהה יותר מצביעה על נאמנות טובה יותר, כלומר ה-transpilation הכניס פחות רעש. הגרף להלן מציג את המשלים, ‏1 - P(|0...0>)‎, כך שעמודה נמוכה יותר מציינת נאמנות טובה יותר ושינויים קטנים בשגיאה קל יותר לראות.

# 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()

פלט של תא הקוד הקודם

במקרה זה, ה-Transpiler ברירת המחדל ייצר גם מעגל רדוד יותר וגם קטן יותר עבור המופע הספציפי הזה של 10 Qubit, כך שהנאמנות הגבוהה יותר שלו צפויה. תוצאות לפי מעגל משתנות: כפי שמראה טבלת הסיכום לעיל, היתרון של ה-Transpiler מבוסס AI הוא בעומק דו-Qubit נמוך יותר בממוצע, לא בכל מעגל בנפרד. איזו אסטרטגיה מניבה נאמנות גבוהה יותר תלויה בגודל ההפרש בכל מדד, מאפייני הרעש של החומרה ומבנה המעגל. תחת מודל רעש depolarizing אחיד, ספירת Gate הכוללת משפיעה לרוב באופן ישיר יותר על שגיאה מצברת מאשר עומק לבדו.

דוגמה על חומרה בקנה מידה גדול

שלבים 1-4

כאן כל הפרטים הללו מאוחדים לתהליך עבודה ברור בקנה מידה גדול יותר, שרץ לאחר מכן על חומרה קוונטית אמיתית.

הקוד להלן מייצר 25 מעגלים אקראיים בעומק 8, כשמספר ה-Qubit נע בין 26 ל-50. לאחר מכן מבוצע transpile למעגלים אלו עם שתי האסטרטגיות ונאספים אותם מדדים. לאחר מכן אנחנו בונים מעגלי מראה מהמקרה של 26 Qubit ושולחים אותם ל-Backend האמיתי.

# -------------------------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")

פלט של תא הקוד הקודם

פלט של תא הקוד הקודם

# -------------------------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)

פלט של תא הקוד הקודם

ניתוח התוצאות

התוצאות בקנה מידה גדול מחזקות את המגמות שנצפו בדוגמה בקנה מידה קטן, כעת בקנה מידה תובעני יותר.

עומק דו-Qubit: ה-Transpiler מבוסס AI ממשיך לספק עומק דו-Qubit נמוך ניכר לאורך כל טווח גדלי המעגל. אופטימיזציית עומק היא אחת המטרות המרכזיות שמודל ה-routing של AI מאומן עליהן, והיתרון בולט יותר במספרי Qubit גבוהים יותר שבהם בעיית ה-routing קשה יותר לשיטות היוריסטיות.

ספירת Gate: ה-Transpiler ברירת המחדל (SABRE) מייצר באופן עקבי מעגלים עם פחות Gate בכל גדלי המעגל בטווח זה. ההיוריסטיקה של SABRE מתוכננת במיוחד למזעור ספירת Gate, ובקנה מידה זה היתרון ברור ואחיד.

זמן transpilation: הפער בזמן transpilation מתרחב בקנה מידה גדול יותר. SABRE נשאר כמעט קבוע, בעוד זמן הריצה של ה-Transpiler מבוסס AI גדל ביתר תלילות. למרות זאת, זמן הריצה של ה-Transpiler מבוסס AI נשאר מעשי לרוב תהליכי העבודה.

נאמנות מעגל מראה: שתי השיטות מניבות הסתברויות הישרדות נמוכות בהרבה מ-1% בקנה מידה זה, כך שנותר מעט אות שימושי. עם ספירות Gate כוללות של כ-10,000 ועומקי דו-Qubit העולים על 1,000, הרעש המפוזר לאורך מעגל המראה מציף את רוב האות. זה מדגיש מגבלה מרכזית של גישת מעגל המראה: אמנם היא פשוטה ואינה דורשת סימולציה קלאסית, אך היא אינה מתרחבת היטב למעגלים גדולים או עמוקים, שבהם שתי השיטות מתקרבות לתחתית הרעש והאות הקטן שנותר נשלט על ידי שגיאה מצברת.

אמנם תוצאות אלו מדגישות את יעילות ה-Transpiler מבוסס AI, חשוב לציין את מגבלותיו. שיטת ה-AI synthesis זמינה כרגע רק עבור מפות coupling מסוימות, מה שעשוי להגביל את יישומיות הרחבה שלה. יש לקחת מגבלה זו בחשבון בעת הערכת השימוש בה בתרחישים שונים.

שלבים הבאים

המלצות

אם מצאת עבודה זו מעניינת, ייתכן שתתעניין בחומרים הבאים: