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

מבוא מעשי לקריטריוני DiVincenzo עם Qiskit 2

מבוא

הפיזיקאי David DiVincenzo תיאר חמישה דרישות מרכזיות לכל מימוש פיזי של מחשב קוונטי, ועוד שני קריטריונים נוספים לתקשורת קוונטית. במחברת זו נחווה כל קריטריון של DiVincenzo דרך הדגמות מעשיות ב-Qiskit. במקום להעמיק בתיאוריה, כל חלק מסביר בקצרה קריטריון אחד ואז מספק תרגילי קוד באמצעות Qiskit 2. תוכלו להריץ Circuit-ים על סימולטורים ומכשירי IBM Quantum אמיתיים כדי לחקור כל עיקרון בצורה ידנית.

חמשת הקריטריונים של DiVincenzo לחישוב קוונטי:

  1. מערכת פיזית ניתנת לסקאלינג עם Qubit-ים מאופיינים היטב.
  2. יכולת לאתחל Qubit-ים למצב ייחוס פשוט (למשל |00…0〉).
  3. זמני דקוהרנס ארוכים (קוהרנס ה-Qubit ארוך בהרבה מזמן פעולת ה-Gate).
  4. סט אוניברסלי של Gate-ים קוונטיים (מסוגל לבצע פעולות אוניטריות שרירותיות).
  5. יכולת מדידה ספציפית ל-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-ים הוא 12(0...0+1...1)\frac{1}{\sqrt{2}}(|0...0\rangle + |1...1\rangle). בסימולציה אידיאלית, מדידת 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}

Quantum circuit diagram

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}

Code output

תוצאה צפויה (מקרה אידיאלי): ה-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 כדי להכין את המצב 10|10\rangle. כלומר, Qubit 0 צריך להיות במצב 0|0\rangle ו-Qubit 1 במצב 1|1\rangle. השתמשו בשער ובהוראה המתאימים לכך.

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 במצב +=(0+1)/2|+\rangle = (|0\rangle+|1\rangle)/\sqrt{2}, שהוא מצב סופרפוזיציה, ושני Qubits במצב Bell (00+11)/2(|00\rangle+|11\rangle)/\sqrt{2}:

import numpy as np

# Initialize a single qubit in |+> state and measure in Z-basis
qc_plus = QuantumCircuit(1, 1)
state_plus = [1/np.sqrt(2), 1/np.sqrt(2)] # amplitude for |0> and |1>
qc_plus.initialize(state_plus, 0)
qc_plus.measure(0, 0)

# Initialize two qubits in a Bell state manually
qc_bell = QuantumCircuit(2, 2)
bell_state = [1/np.sqrt(2), 0, 0, 1/np.sqrt(2)] # amplitudes for |00>,|01>,|10>,|11>
qc_bell.initialize(bell_state, [0, 1])
qc_bell.measure([0, 1], [0, 1])

# Transpile and run the initialization circuits
isa_qc_plus = pm.run(qc_plus)
job_plus = sampler.run([isa_qc_plus], shots=1024)
result_plus = job_plus.result()
counts_plus = result_plus[0].data.c.get_counts()

print("Outcome of |+> state measured in Z-basis:", counts_plus)

isa_qc_bell = pm.run(qc_bell)
job_bell = sampler.run([isa_qc_bell], shots=1024)
result_bell = job_bell.result()
counts_bell = result_bell[0].data.c.get_counts()

print("Outcome of Bell state measured in Z-basis:", counts_bell)
Outcome of |+> state measured in Z-basis: {'1': 499, '0': 525}
Outcome of Bell state measured in Z-basis: {'00': 508, '11': 516}

תוצאות צפויות: מצב ה-|+〉 של Qubit בודד, כאשר נמדד, ייתן 0 ו-1 עם הסתברות של כ-50% כל אחד. מדידת מצב Bell אמורה לתת כ-50% 00 וכ-50% 11. אם רואים את אלה, זה מאשר שהאתחול לאותם מצבים הצליח.

אתחול באמצע Circuit: ה-reset של Qiskit ניתן לשימוש באמצע Circuit כדי לאתחל מחדש Qubit ל-|0〉 תוך כדי. לדוגמה, בקודי תיקון שגיאות או באלגוריתמים איטרטיביים, לעיתים קרובות מודדים Qubit ואז מאפסים אותו לשימוש חוזר. פעולת ה-reset היא דטרמיניסטית; היא מוחקת כל מצב קיים ומקררת את ה-Qubit למצב הבסיס.

דוגמה על מכשיר: על חומרה כמו ibmq_brisbane (127 Qubits) או כל מכשיר IBM, כל ה-Qubits מתחילים ב-|0〉 כברירת מחדל כאשר מריצים עבודה. אם נצטרך מצב התחלה שונה, נצטרך להפעיל שערים בהתחלה (כמו שעשינו עם X כדי לקבל |1〉). אתחול מחדש רציף (לצורך תיקון שגיאות קוונטי) הוא נושא מחקר פעיל מכיוון שביצוע מהיר שלו הוא אתגר. למרבה המזל, לשימוש בסיסי, היכולת להתחיל מחדש ב-|0…0〉 זמינה, והדגמנו איך להשיג מצבי התחלה רצויים אחרים גם כן.

3. קריטריון 3 – זמן קוהרנטיות ארוך (דקוהרנטיות מול זמן שער)

קריטריון 3: "זמני דקוהרנטיות רלוונטיים ארוכים, ארוכים הרבה יותר מזמן פעולת השער." זה מתייחס לצורך של Qubits לשמור על מצבם הקוונטי זמן מספיק לביצוע הפעולות הדרושות. לכל Qubit יש זמן T₁ (זמן רגיעת אנרגיה, עד כמה מהר |1〉 דועך ל-|0〉) וזמן T₂ (זמן דפייזינג, עד כמה מהר קוהרנטיות הפאזה היחסית אובדת). כדי שמחשב קוונטי יעבוד, סולמות הזמן האלה צריכים לעלות בהרבה על משך פעולות השער.

מטרת ההדגמה: לחקור קוהרנטיות Qubit ב-Qiskit על ידי הצגה כיצד דקוהרנטיות משפיעה על תוצאות Circuit ככל שאורך הביצוע גדל. נשתמש ב-Backend מדומה עם זמני T1/T2 ידועים לסימולציה של אפקט זה.

כדי להדגים את ההשפעה של קוהרנטיות סופית, נסמלץ ניסוי דעיכת T1. נכין Qubit במצב |1〉, נחכה זמן מסוים באמצעות הוראת delay, ואז נמדוד. אנחנו מצפים שהסתברות למדוד |1〉 תפחת ככל שהעיכוב גדל.

# This part is done for you. We are creating a list of circuits,
# each with a different delay time.

time_delays_ns = [0, 50000, 100000, 150000, 200000, 250000, 300000] # delay durations in ns

decay_expts = []
for delay in time_delays_ns:
qc = QuantumCircuit(1, 1)
qc.x(0) # initialize qubit to |1>
if delay > 0:
qc.delay(delay, 0, unit='ns') # wait 'delay' nanoseconds
qc.measure(0, 0)
decay_expts.append(qc)

decay_expts[1].draw('mpl') # Visualize one of the circuits

Quantum circuit diagram

תרגיל 3: סימולציה של ניסוי דעיכת T1

עכשיו, השתמשו בסימולטור רועש המבוסס על FakeVigo (שיש לו זמני T1 של כ-50-100 µs) כדי להריץ את ה-Circuits האלה. הסימולטור יחיל אוטומטית את שגיאות T1/T2 במהלך הוראות ה-delay. בצעו Transpile על ה-Circuits לאותו Backend והריצו אותם.

from qiskit_ibm_runtime.fake_provider import FakeVigoV2 as FakeVigo
from qiskit_aer import AerSimulator

# --- YOUR CODE HERE ---

# 1. Create a noisy simulator from the FakeVigo backend
###sim_vigo = ...

# 2. Transpile the list of circuits for this simulator
###pm = ...

###isa_decay_expts = ...

# 3. Use the Sampler to run all the transpiled circuits in a single job
###sampler = ...

###job = ...

###result = ...

# --- END YOUR CODE ---

# This part is done for you to analyze and print the results.
for idx, (delay, qc) in enumerate(zip(time_delays_ns, isa_decay_expts)):
counts = result[idx].data.c.get_counts()
p1 = counts.get('1', 0) / 1000 # Assuming 1000 shots
print(f"Delay {delay} ns: P(qubit=1) = {p1:.3f}")

4. קריטריון 4 – קבוצה אוניברסלית של שערים קוונטיים

קריטריון 4: "קבוצה 'אוניברסלית' של שערים קוונטיים." כלומר, החומרה שלנו חייבת לאפשר לנו לבצע כל חישוב קוונטי על ידי הרכבת קבוצה סופית של שערים בסיסיים. בחישוב קלאסי, NAND הוא אוניברסלי; בקוונטי, ישנן אפשרויות רבות של קבוצות שערים אוניברסליות (כמו {H, T, CNOT} או השערים הנייטיביים של מכונה נתונה). מכשירי IBM, לדוגמה, כוללים קבוצת פעולות נייטיביות כמו סיבובים חד-Qubit שרירותיים ו-CNOTs בין Qubits מסוימים, שביחד הן אוניברסליות. תפקידה של Qiskit הוא לרוב לקמפל שערים ברמה גבוהה לתוך שערי הבסיס האלה.

מטרת ההדגמה: להמחיש אוניברסליות שערים על ידי הצגה כיצד Qiskit מפרקת שערים. ניקח שער לא-נייטיבי (כמו שער Toffoli בן 3 Qubits, CCX) ונראה כיצד הוא מתפרק לשערי הבסיס של המכשיר. זה מדגים שקבוצת השערים הסופקת היא אכן אוניברסלית – היא יכולה לייצר את הפעולה המורכבת יותר.

ראשית, נראה מהם שערי הבסיס עבור Backend טיפוסי של IBM. נשאל את תצורת מכשיר (או גרסתו המדומה). לדוגמה, שערי הבסיס של ibmq_brisbane: אמורים לראות את ההסתברות P(qubit=1) יורדת ככל שזמן העיכוב גדל, בעקבות עקומת דעיכה אקספוננציאלית האופיינית לרגיעת T1. זה מדגים ישירות כיצד זמן קוהרנטיות סופי מוביל לשגיאות חישוב אם ה-Circuit רץ יותר מדי זמן.

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

from qiskit_ibm_runtime.fake_provider import FakeBrisbane
fake_brisbane = FakeBrisbane()
print("Basis gates for ibmq_brisbane:", fake_brisbane.configuration().basis_gates)
Basis gates for ibmq_brisbane: ['ecr', 'id', 'rz', 'sx', 'x']

זה עשוי לפלוט משהו כמו ['id', 'rz', 'sx', 'x', 'ecr']. אלו הן הפעולות הפרימיטיביות שהחומרה תומכת בהן נייטיבית (Identity/ללא-פעולה, סיבוב RZ, שער sqrt(X), שער X, ו-controlled-X). כל שער אחר חייב להיות מורכב מאלה. קבוצה זו ידועה כאוניברסלית לחישוב קוונטי (בעיקרון, סיבובים חד-Qubit בתוספת שער שזירה דו-Qubit מהווים קבוצה אוניברסלית).

עכשיו, ניקח שער Toffoli (CCX) כמקרה בוחן. CCX הופך Qubit יעד רק אם שני Qubits שליטה הם 1. זה לא שער נייטיבי על חומרת IBM. Qiskit מספקת הוראת ccx, אך מאחורי הקלעים היא תפרק אותה.

תרגיל 4: פירוק שער Toffoli

השלימו את הקוד למטה כדי לבנות Circuit עם שער Toffoli (CCX) ואז להשתמש ב-Qiskit כדי לפרק אותו לשערי הבסיס הנייטיביים של Backend FakeBrisbane.

from qiskit import QuantumCircuit
from qiskit_ibm_runtime.fake_provider import FakeBrisbane

# The fake_brisbane backend from the previous cell is reused here.

# --- YOUR CODE HERE ---

# 1. Create a circuit that can accommodate a Toffoli gate
###qc_toffoli = ...

# Apply a CCX gate with controls on qubits 0, 1 and target on qubit 2

# 2. Transpile the circuit to the fake Brisbane backend
###pm = ...

###isa_qc_toffoli = ...

# --- END YOUR CODE ---

print("Toffoli circuit before decomposition:")
print(qc_toffoli)

print("\nToffoli circuit after transpiling to Brisbane basis:")
# The .draw() method will now show the decomposed circuit
print(isa_qc_toffoli.draw(fold=120))

בפלט של ה-Transpile, אמורים לראות את ה-CCX מוחלף ברצף של שערים בסיסיים יותר כמו rz, sx, ו-ecr. זה מוכיח שהשערים הנייטיביים מספיקים לביטוי ה-Toffoli.

אוניברסליות בפועל: התרגיל שלמעלה מראה ששער מורכב בן 3 Qubits נבנה משערים פשוטים יותר. באופן כללי, כל unitary רב-Qubit יכול להיות מורכב משערים בני 1 ו-2 Qubits. ה-Transpiler הוא רכיב קריטי בכל מחסנית תוכנה קוונטית, מכיוון שהוא גושר על הפער בין האלגוריתמים המופשטים שאנחנו רוצים להריץ לבין הפעולות הפיזיות שמכשיר קוונטי ספציפי יכול לבצע בפועל.

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

5. קריטריון 5 – מדידת Qubit

קריטריון 5: "יכולת מדידה ספציפית ל-Qubit." מצבו של כל Qubit חייב להיות מדיד (בדרך כלל בבסיס החישובי, |0〉 או |1〉). במילים אחרות, לאחר הרצת Circuit קוונטי, אנחנו צריכים לקרוא כל Qubit כביט קלאסי 0/1. קריטריון זה עוסק בהחזקת גלאים אמינים לכל Qubit ובאפשרות לבחור אילו Qubits למדוד.

מטרת ההדגמה: להראות כיצד לבצע מדידות ב-Qiskit על סימולטורים ומכשירים אמיתיים, ולהדגיש את ההבדלים (כמו רעש מדידה). נמדוד Qubits במצבים שונים ונבחן את התוצאות. נדגים גם כיצד שגיאות readout עשויות להופיע על ידי השוואת תוצאות סימולטור מול חומרה.

ראשית, דוגמת מדידה פשוטה:

qc_measure = QuantumCircuit(2, 2)
qc_measure.x(0) # qubit 0 -> |1>, qubit 1 stays |0>
qc_measure.measure([0, 1], [0, 1])
qc_measure.draw('mpl')

Quantum circuit diagram

sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_measure = pm.run(qc_measure)
job = sampler.run([isa_qc_measure], shots=1000)
result = job.result()
counts = result[0].data.c.get_counts()

print("Simulator measurement counts:", counts)
Simulator measurement counts: {'01': 1000}

אנחנו מצפים ל-1000 ספירות של 01 על הסימולטור. עכשיו, נראה שגיאת מדידה בפעולה על ידי סימולציה שלה. נוכל להוסיף שגיאת readout לסימולטור Aer שלנו. Qiskit Aer מאפשרת לנו להגדיר ReadoutError ולצרף אותו ל-Qubits במודל הרעש.

תרגיל 5: סימולציה של שגיאת Readout

השלימו את הקוד להגדרת מודל שגיאת readout פשוט שבו לכל Qubit יש סיכוי של 2% להימדד בצורה שגויה (0 נקרא כ-1, או 1 נקרא כ-0). לאחר מכן, הריצו את Circuit המדידה עם מודל הרעש הזה.

from qiskit_aer.noise import NoiseModel, ReadoutError

# --- YOUR CODE HERE ---

# 1. Define a 2% readout error for each single qubit.
# The format is a list of lists of probabilities: [[P(0|0), P(1|0)], [P(0|1), P(1|1)]]
# P(A|B) is the probability of measuring A given the state was |B>.
###ro_error = ...

# 2. Create a new noise model
###noise_model_ro = ...

# 3. Add the readout error to all qubits in the noise model
... # Hint: Use the add_all_qubit_readout_error method

# --- END YOUR CODE ---

sim_backend.set_options(noise_model=noise_model_ro)
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_measure = pm.run(qc_measure)

# Run the measurement circuit with readout noise
sampler = Sampler(mode=sim_backend)

job = sampler.run([isa_qc_measure], shots=1024)
result = job.result()
counts = result[0].data.c.get_counts()

print("Simulation with 2% readout error:", counts)

הפלט המסומלץ הזה יציג ספירות שגויות (כמו 11, 00, 10) בדומה למה שחומרה אמיתית עשויה לייצר, ויוכיח את ההשפעה של מדידה לא מושלמת.

דוגמה על מכשיר: על מכשיר אמיתי כמו ibmq_brisbane, ניתן להריץ את אותו Circuit ועלולים לראות ספירות דומות, לא אפסיות, עבור תוצאות שגויות. נתוני כיול המכשיר מפרטים שגיאת readout לכל Qubit. היכולת לכוון ולקרוא Qubits ספציפיים היא קריטית, והבנת מאפייני השגיאה שלהם היא מפתח לקבלת תוצאות משמעותיות. הרצה על מכשיר אמיתי הודגמה בתרגיל 1b: הרצה על מחשב IBM Quantum אמיתי.

קריטריונים לתקשורת קוונטית (Flying Qubits)

DiVincenzo גם ציין שני קריטריונים ספציפיים לתקשורת קוונטית, חשובים לבניית מחשב קוונטי מחובר ברשת:

  1. יכולת לבצע המרה הדדית בין Qubits נייחים ל-Flying Qubits. (לדוגמה, מיפוי Qubit במעבד לפוטון שיכול לנסוע.)
  2. יכולת להעביר Flying Qubits בין מיקומים בנאמנות. (לדוגמה, שליחת Qubit פוטוני דרך סיב אופטי ללא אובדן מידע קוונטי.)

אלה חורגים משימוש סטנדרטי ב-Qiskit מכיוון ש-Qiskit עוסקת בעיקר ב-Qubits נייחים על שבב. עם זאת, ניתן להמחיש את הרעיון של קריטריונים אלה עם דוגמה פשוטה: טלפורטציה קוונטית. הטלפורטציה מראה המרת מצב Qubit נייח למידע הנישא על ידי זוג שזור (החלק ה"מעופף") ותקשורת קלאסית, המשמשת לאחר מכן לשחזור המצב על Qubit נייח אחר במקום אחר.

המודול Quantum Teleportation של Qiskit in Classrooms מאת ד"ר Katie McCormick ינחה אתכם דרך אחד הפרוטוקולים המרתקים ביותר במידע קוונטי: טלפורטציה קוונטית, שבה מצב קוונטי (Qubit) נשלח מ-Alice ל-Bob באמצעות שזירה ושני ביטים קלאסיים בלבד. תלמדו את נוהל הטלפורטציה המלא שלב-אחר-שלב — כיצד להכין את זוג Bell השזור, לבצע מדידת בסיס Bell בצד של Alice, לשדר תוצאות קלאסיות, וליישם את השער הקוונטי הנכון על Qubit של Bob כדי לשחזר את המצב המקורי בצורה מושלמת. בדרך, תחקרו מדוע טלפורטציה של מידע Qubit אינה מפירה את משפט ה-no-cloning ואינה חורגת ממהירות האור. דרך תרגילים מעשיים באמצעות חומרת IBM Quantum או סימולטורים, תקבלו הבנה פרקטית של מדידה, שזירה ושליטה forward-feed בפעולה.

על ידי שליטה בטלפורטציה קוונטית, תבינו כיצד לקודד, להעביר ולשחזר מידע קוונטי בין צמתים שונים — מה שמניח את היסודות לרשתות קוונטיות, מערכות repeater, תוכניות תקשורת מאובטחות ומחשוב קוונטי מודולרי וניתן להרחבה. כיצד זה קשור לקריטריונים 6 ו-7: ברשת קוונטית אמיתית, זוג השזירה המשותף היה נוצר על ידי חלוקת "Flying Qubits" (כמו פוטונים) בין מיקומי Alice ו-Bob (קריטריון 7: העברה נאמנה). פרוטוקול הטלפורטציה עצמו משמש אז כדרך למיפוי מצב ה-Qubit הנייח של Alice על חצי השזור שלה, ומעביר אותו ביעילות ל-Bob (קריטריון 6: המרה הדדית). Qiskit מאפשרת לנו לסמלץ את לוגיקת הפרוטוקול בצורה מושלמת, ומספקת מודל מושגי לאופן שבו קריטריונים אלה מתממשים בארכיטקטורות תקשורת.

סיכום ומסקנות

עיצבנו סדרת תרגילים ממוקדי-קוד להמחשת קריטריוני DiVincenzo באמצעות Qiskit. דרך דוגמאות hands-on אלה, חקרתם כיצד פלטפורמת מחשוב קוונטי אמיתית עומדת בכל דרישה:

  • מדרגיות: בניית Circuits על Qubits רבים יותר והבנת סקלת הרעש.
  • אתחול: שימוש ב-resets והכנת מצב לתחילת חישובים בצורה אמינה במצבים ידועים.
  • שערים אוניברסליים: Transpile של פעולות מורכבות לשערי הבסיס של מכונה, מה שמוכיח שניתן לבצע כל חישוב.
  • מדידה: קריאת Qubits והתמודדות עם שגיאות readout ריאליסטיות.
  • קוהרנטיות: ראיית ההשפעה של T₁, T₂ סופיים על נאמנות אלגוריתמים והצורך שפעולות יהיו מהירות ביחס לדקוהרנטיות.

לשלמות, נגענו גם בהיבטי תקשורת קוונטית דרך המודול Quantum Teleportation של Qiskit in Classrooms, שמקשר את שני הקריטריונים האחרונים (Flying Qubits).

לסיום, שווה לציין כיצד קריטריונים אלה מתחברים יחד במחשב קוונטי אמיתי כמו זה של IBM. מכשיר כמו ibmq_brisbane כולל 127 Qubits על-מוליכים (קריטריון 1), כל אחד מתחיל ב-|0〉 (קריטריון 2), עם קבוצת שערים מכוילת ומהדרים לאוניברסליות (קריטריון 4), רזוננטורי readout מיקרוגלים לכל Qubit (קריטריון 5), וזמני קוהרנטיות של מאות מיקרו-שניות לעומת פעולות בסדר גודל של ננו-שניות (קריטריון 3). לצורך ניסויי רישות קוונטית, IBM ואחרים חוקרים המרת מיקרוגל-לאופטי לצורך Flying Qubits, ושזירה של Qubits מרוחקים (קריטריונים 6 ו-7); אלו תחומי מחקר פעילים.

על ידי השלמת התרגילים במחברת זו, לא רק ראיתם את הגדרות קריטריוני DiVincenzo, אלא נגעתם בהם דרך קוד; בניית אינטואיציה לגבי מה כל דרישה אומרת עבור חומרה ואלגוריתמים קוונטיים אמיתיים. אתם מוזמנים להרחיב ניסויים אלה, ובהצלחה בחישוב הקוונטי!