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

הגדרת רמת אופטימיזציה של ה-Transpiler

גרסאות חבילות

הקוד בדף זה פותח באמצעות הדרישות הבאות. אנו ממליצים להשתמש בגרסאות אלו או בגרסאות חדשות יותר.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

מכשירים קוונטיים אמיתיים כפופים לרעש ושגיאות Gate, ולכן אופטימיזציה של המעגלים כדי להפחית את עומקם ומספר ה-Gate שלהם יכולה לשפר משמעותית את התוצאות המתקבלות מהרצת אותם מעגלים. לפונקציה generate_preset_pass_manager יש ארגומנט מיקום חובה אחד, optimization_level, השולט בכמה מאמץ ה-Transpiler משקיע באופטימיזציה של מעגלים. ארגומנט זה יכול להיות מספר שלם המקבל אחד מהערכים 0, 1, 2 או 3. רמות אופטימיזציה גבוהות יותר מייצרות מעגלים מאופטמים יותר על חשבון זמני קומפילציה ארוכים יותר. הטבלה הבאה מסבירה את האופטימיזציות המבוצעות עם כל הגדרה.

רמת אופטימיזציהתיאור
0

ללא אופטימיזציה: בדרך כלל משמש לאפיון חומרה

  • תרגום בסיסי
  • Layout/Routing: TrivialLayout, שבו נבחרים אותם מספרי Qubit פיזיים כמספרים וירטואליים ומוכנסים SWAPs כדי לגרום לזה לעבוד (באמצעות SabreSwap)
1

אופטימיזציה קלה:

  • Layout/Routing: Layout נסיון ראשון עם TrivialLayout. אם נדרשים SWAPs נוספים, נמצא layout עם מספר מינימלי של SWAPs באמצעות SabreSwap, ואז משתמש ב-VF2LayoutPostLayout כדי לנסות לבחור את ה-Qubit הטובים ביותר בגרף.
  • InverseCancellation
  • אופטימיזציית Gate חד-קיוביטית
2

אופטימיזציה בינונית:

  • Layout/Routing: רמת אופטימיזציה 1 (ללא trivial) + הוריסטי מאופטמל עם עומק חיפוש גדול יותר וניסיונות של פונקציית אופטימיזציה. מכיוון ש-TrivialLayout אינו בשימוש, אין ניסיון להשתמש באותם מספרי Qubit פיזיים וירטואליים.
  • CommutativeCancellation
3

אופטימיזציה גבוהה:

  • רמת אופטימיזציה 2 + הוריסטי מאופטמל על layout/routing עם מאמץ/ניסיונות נוספים
  • סינתזה מחדש של בלוקי Gate דו-קיוביטיים באמצעות פירוק KAK של Cartan.
  • מעברים המפרים unitarity:
    • OptimizeSwapBeforeMeasure: מזיז את המדידות כדי להימנע מ-SWAPs
    • RemoveDiagonalGatesBeforeMeasure: מסיר Gateים לפני מדידות שלא ישפיעו על המדידות

רמת אופטימיזציה בפעולה

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

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary

UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)

qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")

Output of the previous code cell

נשתמש ב-backend המדומה FakeSherbrooke בדוגמאות שלנו. ראשית, נבצע transpile באמצעות רמת אופטימיזציה 0.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

למעגל שעבר transpile יש שישה Gate ECR דו-קיוביטיים.

חזור על הפעולה עבור רמת אופטימיזציה 1:

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

למעגל שעבר transpile עדיין יש שישה Gate ECR, אך מספר ה-Gateים החד-קיוביטיים הצטמצם.

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

pass_manager = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

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

חזור שוב, עם רמת אופטימיזציה 3:

pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)

Output of the previous code cell

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

pass_manager = generate_preset_pass_manager(
optimization_level=3,
approximation_degree=0.99,
backend=backend,
seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)

Output of the previous code cell

למעגל זה יש רק שני Gate ECR, אך הוא מעגל משוער. כדי להבין כיצד ההשפעה שלו שונה מהמעגל המדויק, נוכל לחשב את ה-fidelity בין האופרטור האוניטרי שמעגל זה מממש, לבין האוניטרי המדויק. לפני ביצוע החישוב, נצמצם תחילה את המעגל שעבר transpile, המכיל 127 קיוביטים, למעגל המכיל רק את הקיוביטים הפעילים, שמספרם שניים.

import numpy as np

def trace_to_fidelity_2q(trace: float) -> float:
return (4.0 + trace * trace.conjugate()) / 20.0

# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)

# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j

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

צעדים הבאים

המלצות