מבוא מעשי לקריטריוני DiVincenzo עם Qiskit 2
מבוא
הפיזיקאי David DiVincenzo תיאר חמישה דרישות מרכזיות לכל מימוש פיזי של מחשב קוונטי, ועוד שני קריטריונים נוספים לתקשורת קוונטית. במחברת זו נחווה כל קריטריון של DiVincenzo דרך הדגמות מעשיות ב-Qiskit. במקום להעמיק בתיאוריה, כל חלק מסביר בקצרה קריטריון אחד ואז מספק תרגילי קוד באמצעות Qiskit 2. תוכלו להריץ Circuit-ים על סימולטורים ומכשירי IBM Quantum אמיתיים כדי לחקור כל עיקרון בצורה ידנית.
חמשת הקריטריונים של DiVincenzo לחישוב קוונטי:
- מערכת פיזית ניתנת לסקאלינג עם Qubit-ים מאופיינים היטב.
- יכולת לאתחל Qubit-ים למצב ייחוס פשוט (למשל |00…0〉).
- זמני דקוהרנס ארוכים (קוהרנס ה-Qubit ארוך בהרבה מזמן פעולת ה-Gate).
- סט אוניברסלי של Gate-ים קוונטיים (מסוגל לבצע פעולות אוניטריות שרירותיות).
- יכולת מדידה ספציפית ל-Qubit (קריאת מצב כל Qubit).
(DiVincenzo גם תיאר שני קריטריונים לתקשורת קוונטית: היכולת לבצע המרה בין Qubit-ים נייחים ו"מעופפים", ולהעביר Qubit-ים מעופפים בנאמנות בין מיקומים. אנחנו כוללים אותם בפעילות מומלצת בסוף המחברת.)
כל אחד מהחלקים הבאים מתאים לקריטריון אחד. נשתמש ב-Qiskit כדי להמחיש את המושג עם קוד וניסויים אינטראקטיביים שתוכלו לנסות. לדוגמה, נראה כיצד הגדלת מספר ה-Qubit-ים ועומק ה-Circuit משפיעים על התוצאות (קריטריון 1), כיצד לאפס ולהכין מצבי Qubit (קריטריון 2), כיצד למדוד Qubit-ים בסימולטורים לעומת מכשירים אמיתיים (קריטריון 4), כיצד Qiskit מרכיב Gate-ים אוניברסליים (קריטריון 3), וכיצד קוהרנס סופי (T₁, T₂) משפיע על חישובים (קריטריון 5). בסופו של דבר, תצברו אינטואיציה עמוקה יותר למה כל קריטריון של DiVincenzo אומר בפועל וכיצד Qiskit מאפשר להתנסות בהם.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy
# Install necessary packages
!pip install qiskit[visualization] qiskit-ibm-runtime qiskit-aer qiskit_ibm_runtime
1. קריטריון 1 – Qubit-ים ניתנים לסקאלינג ומאופיינים היטב
קריטריון 1: "מערכת פיזית ניתנת לסקאלינג עם Qubit-ים מאופיינים היטב." כלומר, אנחנו צריכים פלטפורמת חומרה קוונטית שבה אפשר להגדיל את מספר ה-Qubit-ים ועדיין לשלוט בהם בצורה אמינה. המאפיינים של כל Qubit (רמות אנרגיה, שיעורי שגיאות, קישוריות וכו') צריכים להיות מובנים היטב. בעיקרון, אנחנו רוצים לבנות Circuit-ים גדולים יותר מבלי שהמערכת תתמוטט. בפועל, ככל שמספר ה-Qubit-ים או עומק ה-Circuit גדל, שגיאות ודקוהרנס מצטברים, כך שהדגמת ניתנות לסקאלינג אומרת גם הבנת ההשפעה של הגדלת הגודל על הביצועים.
מטרת ההדגמה: להשתמש ב-Qiskit כדי להראות את השפעת הגדלת Circuit (במספר Qubit-ים או עומק Gate) על נאמנות הפלט. נסמלץ תרחיש אידיאלי לעומת תרחיש רועש כדי לראות כיצד מערכת גדולה יותר או Circuit עמוק יותר נכנעים לדקוהרנס ושגיאות.
ראשית, בואו נבנה מצב שזור קטן (מצב GHZ) על 3 Qubit-ים, ואז גדול יותר על 5 Qubit-ים, כמבחן סקאלינג פשוט. מצב GHZ של n Qubit-ים הוא . בסימולציה אידיאלית, מדידת GHZ של n Qubit-ים מניבה רק שני תוצאות (כולם 0 או כ ולם 1) עם הסתברות שווה. נשווה את הפלט האידיאלי לפלט הרועש ככל שנגדיל את n או עומק ה-Circuit.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import SamplerV2 as Sampler
# 3-qubit GHZ circuit
qc3 = QuantumCircuit(3, 3)
qc3.h(0)
qc3.cx(0, 1)
qc3.cx(1, 2)
qc3.measure([0, 1, 2], [0, 1, 2])
# 5-qubit GHZ circuit (scaling up the number of qubits)
qc5 = QuantumCircuit(5, 5)
qc5.h(0)
qc5.cx(0, range(1, 5)) # entangle qubit 0 with all others
qc5.measure(range(5), range(5))
# Transpile for a simulator backend
sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc3 = pm.run(qc3)
isa_qc5 = pm.run(qc5)
# Run ideal simulations (no noise)
sampler = Sampler(mode=sim_backend)
job3 = sampler.run([isa_qc3], shots=1024)
result3 = job3.result()
counts3 = result3[0].data.c.get_counts()
job5 = sampler.run([isa_qc5], shots=1024)
result5 = job5.result()
counts5 = result5[0].data.c.get_counts()
print("3-qubit GHZ counts (ideal):", counts3)
plot_histogram(counts3, legend=['3-qubit ideal'], figsize=(6,4))
3-qubit GHZ counts (ideal): {'000': 531, '111': 493}

print("5-qubit GHZ counts (ideal):", counts5)
plot_histogram(counts5, legend=['5-qubit ideal'], figsize=(6,4))
5-qubit GHZ counts (ideal): {'11111': 535, '00000': 489}

תוצאה צפויה (מקרה אידיאלי): ה-GHZ בן 3 Qubit-ים מניב באופן אידיאלי כ-50% 000 וכ-50% 111 בספירות. ה-GHZ בן 5 Qubit-ים מניב כ-50% 00000 וכ-50% 11111. אין מחרוזות סיביות נוספות כי המצב הוא באופן אידיאלי קוהרנטי לחלוטין ושזור. אמורים להופיע שני עמודות גבוהות בהיסטוגרמה עבור כל Circuit המתאימות לתוצאות כל-אפסים וכל-אחדות.
עכשיו, בואו נראה מה קורה בסביבה רועשת. נשתמש ביכולות מודל הרעש של Qiskit Aer כדי לחקות שגיאות של מכשיר אמיתי. לדוגמה, אפשר לקחת את מאפייני Backend של IBM כדי ליצור מודל רעש שכולל שגיאות Gate, זמני Gate סופיים, רגיעת Qubit (T₁), דיפאזינג (T₂) ושגיאות קריאה. כאן, נשתמש בBackend מזויף המייצג את מכשיר IBM Quantum Brisbane ליצירת מודל רעש, ונריץ מחדש את Circuit-י ה-GHZ דרכו.
תרגיל 1א: סימולציה עם רעש
השלם את הקוד למטה כדי לסמלץ את Circuit-י ה-GHZ על סימולטור רועש המבוסס על Backend של FakeBrisbane. זה יראה לך כיצד הביצועים מידרדרים ככל שהמערכת מתרחבת בסביבת רעש מציאותית.
from qiskit_ibm_runtime.fake_provider import FakeBrisbane
# We will reuse the ideal circuits qc3 and qc5 and their results from the previous cell.
# --- YOUR CODE HERE ---
# 1. Create a fake backend for IBM Quantum Brisbane
###brisbane_backend = ...
# 2. Create a noisy AerSimulator from the fake backend's properties
###noisy_sim = ...
# 3. Transpile the circuits for the noisy simulator (this adapts them to the device's specific gates and connectivity)
###pm = ...
###isa_qc3_noisy = ...
###isa_qc5_noisy = ...
# 4. Run the noisy simulations using the Sampler and get the counts
###sampler = ...
###job3 = ...
###result3_noisy = ...
###counts3_noisy = ...
###job5 = ...
###result5_noisy = ...
###counts5_noisy = ...
# --- END YOUR CODE ---
# This part is done for you to print and plot the results:
print("3-qubit GHZ counts (noisy):", counts3_noisy)
plot_histogram(counts3_noisy, legend=['3-qubit noisy'], figsize=(6,4))
print("5-qubit GHZ counts (noisy):", counts5_noisy)
plot_histogram(counts5_noisy, legend=['5-qubit noisy'], figsize=(6,4))
תרגיל 1ב: הרצה על מחשב IBM Quantum אמיתי
הקוד למטה מריץ את Circuit-י ה-GHZ על מחשב IBM Quantum אמיתי. זה יראה לך כיצד הביצועים מידרדרים על מכשיר אמיתי.
# your_api_key = "deleteThisAndPasteYourAPIKeyHere"
# your_crn = "deleteThisAndPasteYourCRNHere"
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token=your_api_key,
# instance=your_crn,
# name="fallfest-2025",
# )
# Check that the account has been saved properly
# service = QiskitRuntimeService(name="fallfest-2025")
# print(service.saved_accounts())
# We will reuse the ideal circuits qc3 and qc5 and their results from the previous cell.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService(name="fallfest-2025")
real_backend = service.least_busy(operational=True, simulator=False)
print("Running on " + real_backend.name)
pm = generate_preset_pass_manager(backend=real_backend, optimization_level=1)
isa_qc3r = pm.run(qc3)
isa_qc5r = pm.run(qc5)
sampler = Sampler(mode=real_backend)
job3r = sampler.run([isa_qc3r], shots=1024)
result3r = job3r.result()
counts3r = result3r[0].data.c.get_counts()
job5r = sampler.run([isa_qc5r], shots=1024)
result5r = job5r.result()
counts5r = result5r[0].data.c.get_counts()
print("3-qubit GHZ counts (real):", counts3r)
plot_histogram(counts3r, legend=['3-qubit real'], figsize=(6,4))
print("5-qubit GHZ counts (real):", counts5r)
plot_histogram(counts5r, legend=['5-qubit real'], figsize=(6,4))
תוצאה צפויה (רועש לעומת אידיאלי): עם רעש, בין אם מסומלץ או על מכשיר אמיתי, מצב ה-GHZ פחות מושלם. יופיעו תוצאות נוספות מעבר לכל-0 וכל-1. עבור 3 Qubit-ים, במקום 100% ב-000/111, חלק מההסתברות דולף למחרוזות סיביות אחרות (למשל 001, 010 וכו') בגלל שגיאות Gate או דקוהרנס שהופך חלק מה-Qubit-ים. עבור 5 Qubit-ים, ההשפעה בולטת עוד יותר; ה-Circuit הגדול יותר (יותר Qubit-ים ו-Gate-י CNOT) צובר יותר שגיאות, כך שפסגות הכל-0 וכל-1 נמוכות יותר, ומופיעות תוצאות רבות אחרות. מגמה זו ממחישה את אתגר הניתנות לסקאלינג: ככל שאנחנו מתרחבים, שמירה על נאמנות גבוהה הופכת קשה יותר ללא תיקון שגיאות.
תובנה: מחשב קוונטי ניתן לסקאלינג צריך לשמר קורלציות קוונטיות ככל שהמערכת גדלה. הדוגמאות שלנו מראות כיצד הגדלת מספר Qubit-ים/עומק Gate גורמת לירידה בנאמנות התוצאות כשיש רעש. הקריטריונים הנותרים יתמודדו עם שמירה על Qubit-ים מתנהגים היטב (שגיאות נמוכות, ניתנים לאיתחול וכו') ככל שאנחנו מתרחבים.
2. קריטריון 2 – אתחול Qubit
קריטריון 2: "היכולת לאתחל את מצב ה-Qubits למצב פיצ'יאלי פשוט, כמו |000…〉." כל ה-Qubits צריכים להתחיל בצורה אמינה במצב התחלתי ידוע (בדרך כלל מצב הבסיס |0〉 לכל Qubit). האתחול הוא קריטי כדי שהאלגוריתמים יתחילו מדף נקי. בפועל, במכשירי IBM Quantum כל Qubit מאופס אוטומטית ל-|0〉 בתחילת כל הרצת Circuit. Qiskit גם מספקת הוראות לאיפוס Qubits או הכנת מצבים מותאמים אישית במהלך חישוב.
מטרת ההדגמה: נראה איך לאתחל Qubits ב-Qiskit, גם בהתחלה וגם באמצע Circuit. נדגים שימוש בהוראת reset ובשיטות הכנת מצב.
תרגיל 2: הכנת מצב ספציפי
בבלוק הקוד למטה, השלימו את ה-QuantumCircuit כדי להכין את המצב . כלומר, Qubit 0 צריך להיות במצב ו-Qubit 1 במצב . השתמשו בשער ובהוראה המתאימים לכך.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
# Create a circuit to initialize qubits to |10> and verify by measurement
qc_init = QuantumCircuit(2, 2)
# --- YOUR CODE HERE ---
# 1. Set qubit 1 to the |1> state
# 2. Explicitly reset qubit 0 to the |0> state
# --- END YOUR CODE ---
qc_init.measure([0, 1], [0, 1])
qc_init.draw('mpl')
# Run the circuit and check the outcome
sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_init = pm.run(qc_init)
sampler = Sampler(mode=sim_backend)
job = sampler.run([isa_qc_init], shots=1024)
result = job.result()
counts = result[0].data.c.get_counts()
print("Outcome of |10> state measured in Z-basis:", counts)
plot_histogram(counts)
אמורים לראות 10 (בינארי עבור qubit1=1, qubit0=0) עם הסתברות של 100% מהסימולציה, כלומר Qubit 1 הוכן בהצלחה במצב |1〉 ו-Qubit 0 במצב |0〉.
עכשיו, לצורך הכנת מצב כללי יותר, Qiskit מאפשרת אתחול למצבים שרירותיים באמצעות שיטת initialize. לדוגמה, נכין Qubit במצב , שהוא מצב סופרפוזיציה, ושני Qubits במצב Bell