הרצת מעגלים דינמיים
מעגלים דינמיים הם כלים חזקים שבהם אפשר למדוד Qubits באמצע הרצת מעגל קוונטי ולאחר מכן לבצע פעולות לוגיקה קלאסית בתוך המעגל, על בסיס תוצאת מדידות אלה באמצע המעגל. תהליך זה מכונה גם classical feedforward. בעוד שאלה ימים מוקדמים להבין כיצד להפיק את המרב ממעגלים דינמיים, קהילת המחקר הקוונטי כבר זיהתה מספר מקרי שימוש, כגון הבאים:
-
הכנת מצב קוונטי יעילה, כגון מצב GHZ, מצב W (למידע נוסף על מצב W, ראו גם "State preparation by shallow circuits using feed forward"), ומחלקה רחבה של מצבי מכפלת מטריצה
-
אנטנגלמנט לטווח ארוך יעיל בין Qubits על אותו שבב באמצעות מעגלים רדודים
השיפורים שמביאים מעגלים דינמיים, עם זאת, כרוכים בפשרות. מדידות באמצע מעגל ופעולות קלאסיות בדרך כלל כוללות זמן ביצוע ארוך יותר מאשר שערים דו-Qubit, ועלייה זו בזמן עשויה לבטל את היתרונות של עומק מעגל מופחת. לכן, הפחתת אורך מדידת אמצע מעגל היא תחום מיקוד לשיפור כאשר IBM Quantum® משחרר את הגרסה החדשה של מעגלים דינמיים. לגבי הגבלות נוספות בשימוש במעגלים דינמיים, ראו את טבלת תאימות התכונות של Estimator או Sampler.
מפרט OpenQASM 3 מגדיר מספר מבני זרימת בקרה, אך IBM Quantum Compute Service כרגע תומך רק בפקודת ה-if המותנית. ב-Qiskit SDK, זה מתאים למתודת if_test על QuantumCircuit. מתודה זו מחזירה context manager ובדרך כלל משמשת בהצהרת with. מדריך זה מסביר כיצד להשתמש בהצהרה מותנית זו.
דוגמאות הקוד במדריך זה משתמשות בהוראת המדידה הרגילה למדידות אמצע מעגל. עם זאת, מומלץ להשתמש בהוראת MidCircuitMeasure במקום זאת, אם ה-Backend תומך בה. ראו את חלק מדידות אמצע מעגל לפרטים.
גרסאות חבילות
הקוד בדף זה פותח תוך שימוש בדרישות הבאות. אנחנו ממליצים להשתמש בגרסאות אלה או חדשות יותר.
qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
מצא Backends שתומכים במעגלים דינמיים
כדי למצוא את כל ה-Backends שהחשבון שלך יכול לגשת אליהם ותומכים במעגלים דינמיים, הרץ קוד כמו הבא. דוגמה זו מניחה שהשמרת את אישורי הכניסה שלך. אפשר גם לציין אישורים במפורש בעת אתחול חשבון IBM Quantum Compute Service. זה יאפשר לך לצפות ב-Backends הזמינים על מופע או סוג תוכנית ספציפיים, לדוגמה.
- ה-Backends הזמינים לחשבון תלויים במופע שצוין באישורים.
- הגרסה החדשה של מעגלים דינמיים זמינה כעת לכל המשתמשים על כל ה-Backends. ראו ההכרזה לפרטים נוספים.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings
warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_phoenix')>, <IBMBackend('ibm_pittsburgh')>]
מדידות אמצע מעגל
לפני qiskit-ibm-runtime v0.43.0, measure היה הוראת המדידה היחידה ב-Qiskit. עם זאת, למדידות אמצע מעגל יש דרישות כוונון שונות ממדידות סופניות (מדידות שמתרחשות בסוף מעגל). לדוגמה, צריך לשקול את משך ההוראה בכוונון מדידת אמצע מעגל כי הוראות ארוכות יותר גורמות למעגלים רועשים יותר. לא צריך לשקול את משך ההוראה עבור מדידות סופניות מכיוון שאין הוראות אחרי מדידות סופניות.
הוראת ה-MidCircuitMeasure ממפה להוראת ה-measure_2 המדווחת ב-supported_instructions של ה-Backend. עם זאת, measure_2 אינה נתמכת על כל ה-Backends. השתמש ב-service.backends(filters=lambda b: "measure_2" in b.supported_instructions) כדי למצוא Backends שתומכים בה. מדידות חדשות עשויות להתווסף בעתיד, אך אין ערובה לכך.
מתודת MidCircuitMeasure
ב-qiskit-ibm-runtime v0.43.0, הוצגה הוראת ה-MidCircuitMeasure. כשמה מעיד, זו הוראת מדידה חדשה שמותאמת לאמצע מעגל על QPUs של IBM®. בעוד שניתן להשתמש ב-QuantumCircuit.measure למדידת אמצע מעגל, בגלל עיצובה, MidCircuitMeasure בדרך כלל בחירה טובה יותר. לדוגמה, היא מוסיפה פחות תקורה למעגל שלך מאשר בשימוש ב-QuantumCircuit.measure.
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
-
חייב להיות לפחות רגיסטר קלאסי אחד כדי להשתמש במדידות.
-
ה-primitive של Sampler דורש מדידות מעגל. ניתן להוסיף מדידות מעגל עם ה-primitive של Estimator, אך המערכת מתעלמת מהן.
Store
עם גרסה 0.47.0 ומעלה של qiskit-ibm-runtime, אפשר להשתמש בהוראת store כדי לשמור את תוצאת ביטוי קלאסי, אם הביטוי הזה ישמש שוב ושוב. הפעולות מבוצעות במקביל באופן אוטומטי, מה שהופך את הקוד שלך ליעיל הרבה יותר בזמן ריצה.
למידע נוסף, ראו את מדריך Classical feedforward וזרימת בקרה.
כשמשתמשים ב-store כדי לשמור ערך לרגיסטר קלאסי על Backend אמיתי, הערך הזה נשמר בזיכרון רק במהלך הביצוע ואינו מועתק או מוחזר בתוצאת העבודה.
לדוגמה, בקוד הבא, ל-temp יש את אותו ערך כמו creg במהלך הביצוע, וה-if_test עובד כצפוי. אבל לאחר סיום העבודה, ה-temp BitArray שמוחזר בתוצאת העבודה אינו מכיל את ערך ה-creg. כלומר, job.result()[0].data.temp הוא 0.
creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...
דוגמה מלאה
הקוד הבא יוצר ומריץ מעגל דינמי על חומרת IBM®.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
# Legacy server-side primitive before qiskit-ibm-runtime v0.50.0
# from qiskit_ibm_runtime import Sampler
# Client-side primitive introduced in qiskit-ibm-runtime v0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = Sampler(backend)
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: dbjeaj0nceqs73ajs65g (DONE)
מגבלות Quantum Compute
שימו לב לאילוצים הבאים בעת הרצת מעגלים דינמיים ב-Quantum Compute.
-
בגלל הזיכרון הפיזי המוגבל על אלקטרוניקת הבקרה, יש גם מגבלה על מספר הצהרות ה-
ifוגודל האופרנדים שלהן. מגבלה זו היא פונקציה של מספר ה-broadcasts ומספר הסיביות המשודרות בעבודה (לא במעגל).בעיבוד תנאי
if, נתוני מדידה צריכים להיות מועברים ללוגיקת הבקרה כדי לבצע את ההערכה הזו. broadcast הוא העברה של נתונים קלאסיים ייחודיים, ו-broadcasted bits הוא מספר הסיביות הקלאסיות שמועברות. שקול את הבא:c0 = ClassicalRegister(3)c1 = ClassicalRegister(5)...with circuit.if_test((c0, 1)) ...with circuit.if_test((c0, 3)) ...with circuit.if_test((c1[2], 1)) ...בדוגמת הקוד הקודמת, שני אובייקטי ה-
if_testהראשונים עלc0נחשבים ל-broadcast אחד מכיוון שתוכן ה-c0לא השתנה, ולכן אין צורך לשדר אותו מחדש. ה-if_testעלc1הוא broadcast שני. הראשון משדר את כל שלוש הסיביות ב-c0והשני משדר רק סיבית אחת, ובסך הכל ארבע סיביות משודרות.כרגע, אם משדרים 60 סיביות בכל פעם, אז לעבודה יכולים להיות בערך 300 broadcasts. עם זאת, אם משדרים רק סיבית אחת בכל פעם, לעבודה יכולים להיות 2400 broadcasts.
-
האופרנד שנעשה בו שימוש בהצהרת
if_testחייב להיות 32 סיביות או פחות. לכן, אם משוויםClassicalRegisterשלם, גודל ה-ClassicalRegisterהזה חייב להיות 32 סיביות או פחות. אם משווים רק סיבית בודדת מ-ClassicalRegister, עם זאת, ה-ClassicalRegisterהזה יכול להיות בכל גודל (מכיוון שהאופרנד הוא רק סיבית אחת).לדוגמה, בלוק הקוד "לא חוקי" לא עובד כי
crגדול מ-32 סיביות. ניתן, עם זאת, להשתמש ברגיסטר קלאסי רחב מ-32 סיביות אם בודקים רק סיבית אחת, כפי שמוצג בבלוק הקוד "חוקי".- לא חוקי
- חוקי
cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr, 15)):...cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr[5], 1)):... -
תנאים מקוננים אינם מותרים. לדוגמה, בלוק הקוד הבא לא יעבוד מכיוון שיש לו
if_testבתוךif_testאחר:- לא חוקי
- חוקי
c1 = ClassicalRegister(1, "c1")c2 = ClassicalRegister(2, "c2")...with circ.if_test((c1, 1)):with circ.if_test(c2, 1)):...cr = ClassicalRegister(2)...with circuit.if_test((cr, 0b11)):... -
resetאו מדידות בתוך תנאים אינם נתמכים. -
פעולות אריתמטיות אינן נתמכות.
-
ראו את טבלת תכונות OpenQASM 3 כדי לקבוע אילו תכונות OpenQASM 3 נתמכות עם Qiskit וQuantum Compute.
-
כאשר OpenQASM 3 (במקום
QuantumCircuit) משמש כפורמט קלט להעברת מעגלים ל-primitives של IBM Quantum, רק הוראות שניתן לטעון ל-Qiskit נתמכות. פעולות קלאסיות, לדוגמה, אינן נתמכות מכיוון שלא ניתן לטעון אותן ל-Qiskit. ראו ייבוא תוכנית OpenQASM 3 ל-Qiskit למידע נוסף. -
הוראות
for,whileו-switchאינן נתמכות.
שימוש במעגלים דינמיים עם Estimator
מכיוון ש-Estimator אינו תומך במעגלים דינמיים, ניתן להשתמש ב-Sampler ולבנות מעגלי מדידה משלך במקום.
כדי לשחזר את התנהגות Estimator, עקוב אחר תהליך זה:
- קבץ את איברי כל ה-observables לחלוקה. ניתן לעשות זאת באמצעות ה-API של
PauliList, לדוגמה.הערהניתן להשתמש במאפיין ה-primitive של
BitArrayלחישוב ערכי הציפייה של ה-observables שסופקו. - הרץ מעגל שינוי בסיס אחד לכל חלוקה (איזה שינוי בסיס שצריך לבצע לכל חלוקה). ראו את מודול
measurement_basesשל תוסף כלי השירות למדידה למידע נוסף. לפרטים נוספים, ראו את התיעוד לחבילת כלי השירות של Qiskit addon. - חבר בחזרה את התוצאות לכל חלוקה.
הגבלות
עיין בכל טבלת תאימות תכונות כדי להבין הגבלות בשימוש במעגלים דינמיים. שים לב שתאימות תכונות אינה תלויה ב-primitive.
השלבים הבאים
- כדאי ללמוד כיצד ליישם dynamical decoupling מדויק באמצעות stretch.
- כדאי לעיין במדריך classical feedforward וזרימת בקרה.
- כדאי להשתמש בהצגה חזותית של תזמון המעגל לדיבוג ואופטימיזציה של המעגלים הדינמיים שלכם.
- לא כל הפונקציות תואמות למעגלים דינמיים. כדאי לבדוק את חלק תאימות התכונות עבור Sampler לפרטים.