טלפורטציה קוונטית וקידוד סופר-צפוף
Kifumi Numata (26 Apr 2024)
הורידו את קובץ ה-PDF של ההרצאה המקורית. שימו לב שחלק מקטעי הקוד עשויים להיות מיושנים, שכן מדובר בתמונות סטטיות.
זמן QPU משוער להפעלת הניסוי הזה הוא 10 שניות.
1. מבוא
כדי לפתור כל בעיה קוונטית בסדר גודל שימושי, נצטרך להעביר מידע ברחבי המחשב הקוונטי מ-Qubit אחד לאחר. קיימים פרוטוקולים מוכרים לכך, אך חלק מהיסודיים שבהם נוסחו בהקשר של שליחת מידע בין צדדים מרוחקים. לאורך השיעור הזה נשתמש לעיתים בשפה המתאימה להקשר זה, כמו "חברים מרוחקים שמשתפים מידע". אך יש לזכור שלפרוטוקולים האלה יש משמעות רחבה יותר בתחום המחשוב הקוונטי. בשיעור זה נבחן את פרוטוקולי התקשורת הקוונטית הבאים:
- טלפורטציה קוונטית שימוש במצב שזור משותף (המכונה לעיתים e-bit) לשליחת מצב קוונטי לא ידוע לחבר מרוחק, תוך צורך בתקשורת קלאסית משלימה.
- קידוד סופר-צפוף קוונטי כיצד לשלוח שני סיביות מידע על ידי שליחת Qubit יחיד לחבר מרוחק (שוב בשימוש ב-Qubit שזורים משותפים מראש).
לרקע נוסף הרלוונטי לנושאים אלה, אנו ממליצים על שיעור 4 ב"יסודות מידע קוונטי" בנושא שזירה בפעולה.
בתיאור לעיל, "מצב קוונטי לא ידוע" מתייחס פשוט למצב בצורה המתוארת בשיעור הקודם:
כאשר ו- הם מספרים מרוכבים כך ש-. זה מאפשר לנו לכתוב את המצב הקוונטי בצורה
מכיוון שאנחנו רוצים להיות מסוגלים להעביר את המידע בכל מצב קוונטי אקראי, יצירת מצב כזה היא הנקודה שממנה נתחיל את השיעור הזה.
2. מטריצות צפיפות
ניתן לכתוב גם את המצב הקוונטי כמטריצת הצפיפות שלו. צורה זו שימושית לציון תערובת הסתברותית של מצבים קוונטיים טהורים. במקרה של Qubit יחיד, ניתן לכתוב
שימו לב שמטריצת הצפיפות היא סכום לינארי של מטריצות פאולי, כפי שמוצג להלן,
או, באופן כללי,
כאשר .
וקטור בלוך הוא .
עכשיו, בואו ניצור מצב קוונטי שרירותי באמצעות מספרים אקראיים.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
import numpy as np
# create a random 1-qubit state from a random (theta, varphi) to define r vector
np.random.seed(1) # fixing seed for repeatibility
theta = np.random.uniform(0.0, 1.0) * np.pi # from 0 to pi
varphi = np.random.uniform(0.0, 2.0) * np.pi # from 0 to 2*pi
def get_r_vec(theta, varphi):
rx = np.sin(theta) * np.cos(varphi)
ry = np.sin(theta) * np.sin(varphi)
rz = np.cos(theta)
return (rx, ry, rz)
# get r vector
rx, ry, rz = get_r_vec(theta, varphi)
print("theta=" + str(theta), ",varphi=" + str(varphi))
print("(rx, ry, rz) = (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ")")
theta=1.3101132663588946 ,varphi=4.525932273597346
(rx, ry, rz) = (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022)
ניתן להציג את וקטור בלוך זה על כדור בלוך.
from qiskit.visualization import plot_bloch_vector
r = [rx, ry, rz]
plot_bloch_vector(r)
3. טומוגרפיה של מצב קוונטי
אם תמדדו את המצב הקוונטי רק בבסיס החישובי ( ו-), מידע הפאזה (מידע המספרים המרוכבים) יאבד. אך אם יש לנו עותקים רבים של על ידי חזרה על תהליך ההכנה (לא ניתן לשכפל מצבים, אך ניתן לחזור על תהליכי הכנה), נוכל להעריך את ערכי על ידי ביצוע טומוגרפיה של מצב קוונטי עבור מטריצת הצפיפות . בהתחשב בצורה:
מתקיים
במקרה של ,
הטרנספורמציה האחרונה במשוואה מיועדת ל-. לכן, ניתן לקבל את על ידי הסתברות של פחות הסתברות של .
הערכת ערך
כדי להעריך את , ניצור מצב קוונטי ונמדוד אותו. לאחר מכן נחזור על ההכנה והמדידה פעמים רבות. לבסוף נשתמש בסטטיסטיקה של המדידות להערכת ההסתברויות לעיל ובכך נעריך את .
ליצירת המצב הקוונטי האקראי, נשתמש ב-Gate האוניטרי הכללי עם הפרמטרים . (ראו U-gate למידע נוסף.)
from qiskit import QuantumCircuit
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
# measure in computational basis
qc.measure(0, 0)
qc.draw(output="mpl")
באמצעות AerSimulator, נמדוד בבסיס החישובי כדי להעריך את .
# see if the expected value of measuring in the computational basis
# approaches the limit of rz
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram
# Define backend
backend = AerSimulator()
nshots = 1000 # or 10000
# nshots = 10000
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 375, '0': 625}
rz_approx = (counts["0"] - counts["1"]) / nshots
print("rz = ", rz, " and approx of rz = ", rz_approx)
rz = 0.2577405946274022 and approx of rz = 0.25
באמצעות שיטת טומוגרפיית המצב הקוונטי, הערכנו את ערך . במקרה זה, מכיוון שבחרנו פרמטר למצב ה"אקראי", אנו יודעים את ערך ויכולים לבדוק את עבודתנו. אך מטבעה, עבודה בסדר גודל שימושי אינה תמיד כה פשוטה לבדיקה. נדון יותר על בדיקת תוצאות קוונטיות בהמשך הקורס. לעת עתה, פשוט שימו לב שההערכה שלנו הייתה סבירה למדי.
תרגיל 1: הערכת ערך
זכרו שמחשבי הקוונטום של IBM® מודדים לאורך ציר ה- (לעיתים נאמר "בבסיס ה-" או "בבסיס החישובי"). אולם, על ידי שימוש בסיבובים ל פני המדידה, ניתן למדוד גם את ההיטל של המצב הקוונטי על ציר ה-x. ליתר דיוק, אם נסובב את המערכת שלנו כך שדברים שהצביעו לאורך יצביעו עכשיו לאורך , נוכל לשמור על אותה חומרת מדידה לאורך , אך ללמוד על המצב שרגע לפני הצביע לאורך . כך מחשבים קוונטים רבים (וכל מחשבי הקוונטום של IBM) מבצעים מדידות לאורך צירים מרובים.
עם הבנה זו, נסו לכתוב קוד להערכת ערך תוך שימוש בטומוגרפיית מצב קוונטי.
פתרון:
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
qc.h(0)
qc.measure(0, 0)
qc.draw(output="mpl")
# Define backend
backend = AerSimulator()
nshots = 10000
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 5925, '0': 4075}
rx_approx = (counts["0"] - counts["1"]) / nshots
print("rx = ", rx, " and approx of rx = ", rx_approx)
rx = -0.1791150283307452 and approx of rx = -0.185
תרגיל 2: הערכת ערך
תוך שימוש באותם טיעונים לוגיים כמו קודם, ניתן לסובב את המערכת לפני המדידה כדי ללמוד על .
נסו לכתוב קוד בעצמכם להערכת ערך באמצעות טומוגרפיית מצב קוונטי. אפשר להתחיל מהדוגמה הקודמת, אך לבצע סיבובים שונים. (למידע נוסף על ה-Gate השונים בשימוש, כולל sdg, ראו בהפניה ל-API.)
פתרון:
# create a 1-qubit quantum state psi from theta, varphi parameters
qc = QuantumCircuit(1, 1)
qc.u(theta, varphi, 0.0, 0)
qc.sdg(0)
qc.h(0)
qc.measure(0, 0)
qc.draw(output="mpl")
# Define backend
backend = AerSimulator()
nshots = 10000
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'1': 9759, '0': 241}
ry_approx = (counts["0"] - counts["1"]) / nshots
print("ry = ", ry, " and approx of ry = ", ry_approx)
ry = -0.9494670044331133 and approx of ry = -0.9518
עכשיו הערכנו את כל רכיבי ויכולים לכתוב את הוקטור המלא.
print("Estimated vector is (", rx_approx, ",", ry_approx, ",", rz_approx, ").")
print("Original random vector was (" + str(rx) + ", " + str(ry) + ", " + str(rz) + ").")
Estimated vector is ( -0.185 , -0.9518 , 0.25 ).
Original random vector was (-0.1791150283307452, -0.9494670044331133, 0.2577405946274022).
קיבלתם הערכה של הוקטור האקראי המקורי בצורה מדויקת למדי באמצעות שיטת טומוגרפיית המצב הקוונטי הזו.
4. טלפורטציה קוונטית
בואו נשקול את המצב שבו דמות בשם אליס רוצה לשלוח מצב קוונטי לא ידוע לחברה בוב, שנמצא רחוק. נניח שהם יכולים לתקשר רק בתקשורת קלאסית (כמו אימייל או טלפון). אליס לא יכולה להעתיק את המצב הקוונטי (בגלל משפט אי-השכפול). אם היא חזרה על אותו תהליך הכנה פעמים רבות, היא יכלה לצבור סטטיסטיקות כפי שעשינו זה עתה. אבל מה אם יש רק מצב יחיד לא ידוע? מצב זה אולי צץ מתהליך פיזי שאתם רוצים לחקור. או שהוא יכול להיות חלק מחישוב קוונטי גדול יותר. במקרה כזה, כיצד יכולה אליס לשלוח את המצב לבוב? היא יכולה, אם היא ובוב חולקים משאב קוונטי יקר ערך: מצב שזור משותף, כמו מצב בל שהוצג בשיעור הקודם: לפעמים תראו גם התייחסות לזה כ"זוג EPR" או "e-bit" (יחידה בסיסית של שזירה). אם אליס חולקת מצב שזור כזה עם בוב, היא יכולה לטלפורט את המצב הקוונטי הלא ידוע לבוב על ידי ביצוע סדרת פעולות קוונטיות ושליחת שני סיביות של מידע קלאסי.
4.1 הפרוטוקול של טלפורטציה קוונטית
הנחה: לאליס יש מצב קוונטי לא ידוע לשליחה לבוב. אליס ובוב חולקים מצב שזור של 2 Qubit, או e-bit, כשלכל אחד מהם יש אחד מה-Qubit פיזית במיקומו.
הנה אנו מתארים את ההליך ללא הסבר. פרטים אלה ייושמו להלן.
- אליס שוזרת את עם החלק שלה מה-e-bit באמצעות שער CNOT.
- אליס מפעילה שער Hadamard על , ומודדת את שני ה-Qubit שלה בבסיס החישובי.
- אליס שולחת לבוב את תוצאות המדידה שלה (אחת מבין "00", "01", "10", או "11")
- בוב מבצע אופרטור תיקון בהתבסס על שני הסיביות של מידע אליס על החלק שלו מזוג ה-e-bit.
- אם "00", בוב לא עושה כלום
- אם "01", בוב מפעיל שער X
- אם "10", בוב מפעיל שער Z
- אם "11", בוב מפעיל שער iY = ZX
- החלק של בוב מה-e-bit הופך ל-.
זה גם מפורט יותר ביסודות המידע הקוונטי. אבל המצב יהיה ברור יותר כשנממש זאת ב-Qiskit.
4.2 Circuit קוונטי המדמה טלפורטציה קוונטית
כרגיל, נשתמש במסגרת דפוסי Qiskit. חלק זה יתמקד במיפוי בלבד.
שלב 1: מיפוי הבעיה ל-Circuit קוונטי ואופרטורים
כדי לתאר את התרחיש לעיל, אנו זקוקים ל-Circuit עם שלושה Qubit: שניים לזוג השזור שבין אליס לבוב, ואחד למצב הקוונטי הלא ידוע .
from qiskit import QuantumCircuit
import numpy as np
# create 3-qubits circuit
qc = QuantumCircuit(3, 3)
qc.draw(output="mpl")
בהתחלה, לאליס יש מצב קוונטי לא ידוע ניצור אותו באמצעות שער .
# Create the unknown quantum state using the u-gate. Alice has this.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation
qc.draw(output="mpl")
אנחנו יכולים לדמיין את המצב שיצרנו, אבל רק בגלל שאנו יודעים אילו פרמטרים שימשו בשער . אם מצב זה צץ מתהליך קוונטי מסובך, המצב לא יהיה ניתן לידיעה מבלי להריץ את התהליך פעמים רבות ולאסוף סטטיסטיקות כמו בטומוגרפיה.
# show the quantum state on bloch sphere
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
out_vector = Statevector(qc)
plot_bloch_multivector(out_vector)

לפני שפרוטוקול זה בכלל מתחיל, אנו מניחים שלאליס ולבוב יש זוג שזור משותף. אם אליס ובוב נמצאים באמת במקומות שונים, ייתכן שהם הגדירו את המצב המשותף לפני שמצב הלא ידוע נוצר. מכיוון שהדברים האלה קורים על Qubit שונים, סדרם כאן לא משנה, וסדר זה נוח לויזואליזציה.
# Alice and Bob are together in the same place and set up an entangled pair.
qc.h(1)
qc.cx(1, 2)
qc.barrier() # for visual separation.
# We can consider that Alice and Bob might move their qubits to different physical locations, now.
qc.draw(output="mpl")
בשלב הבא, אליס שוזרת את עם החלק שלה מה-e-bit המשותף, באמצעות שער ושער , ומודדת אותם בבסיס החישובי.
# Alice entangles the unknown state with her part of the e-bit, using the CNOT gate and H gate.
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Alice measures the two qubits.
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw(output="mpl")
אליס שולחת לבוב את תוצאות המדידה שלה (אחת מבין "00", "01", "10", או "11"), ובוב מבצע אופרטור תיקון בהתבסס על שני הסיביות של מידע אליס על החלק שלו מה-e-bit המשותף. אז, החלק של בוב הופך ל-.
# Alice sent the results to Bob. Bob applies correction
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()
qc.draw(output="mpl")
השלמת Circuit טלפורטציה קוונטית! בואו נראה את מצב הפלט של Circuit זה באמצעות סימולטור ה-statevector.
from qiskit_aer import StatevectorSimulator
backend = StatevectorSimulator()
out_vector = backend.run(qc, shots=1).result().get_statevector() # set shots = 1
plot_bloch_multivector(out_vector)

אפשר לראות שהמצב הקוונטי שנוצר על ידי שער ה- של Qubit 0 (ה-Qubit שהחזיק במקור את המצב הסודי) הועבר ל-Qubit 2 (ה-Qubit של בוב).
אפשר להריץ את התא לעיל כמה פעמים כדי לוודא. אולי תשימו לב ש-Qubit 0 ו-1 משנים מצבים, אבל Qubit 2 תמיד במצב .
4.3 הרצה ואישור התוצאה על ידי הפעלת ה-U ההפוך
לעיל, בדקנו ויזואלית שהמצב המטולפורט נראה נכון. דרך נוספת לבדוק אם המצב הקוונטי טולפורט כראוי, היא להפעיל את ההופכי של שער על ה-Qubit של בוב כדי שנוכל למדוד '0'. כלומר, מכיוון ש- הוא הזהות, אם ה-Qubit של בוב נמצא במצב שנוצר מ- אז הפעלת ההופכי אמורה לתת
# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse() # inverse of u(theta,varphi,0.0)
qc.measure(2, 2) # add measurement gate
qc.draw(output="mpl")
נריץ תחילה את ה-Circuit באמצעות AerSimulator, לפני שנעבור למחשב קוונטי אמיתי.
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram
# Define backend
backend = AerSimulator()
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc], shots=nshots)
result = job.result()
# Extract counts data
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'011': 2510, '010': 2417, '000': 2635, '001': 2438}
זכרו שבסימון little endian, Qubit 2 הוא ה-Qubit השמאלי ביותר (או התחתון ביותר, בתוויות העמודה). שימו לב שה-Qubit השמאלי והתחתון ביותר בתוויות העמודה הוא 0 עבור כל התוצאות האפשריות. זה מראה שיש לנו סיכוי של 100% למדוד את במצב . זוהי התוצאה הצפויה, ומציינת שפרוטוקול הטלפורטציה עבד כראוי.
4.4 טלפורטציה על מחשב קוונטי אמיתי
בשלב הבא, נבצע טלפורטציה על מחשב קוונטי אמיתי. באמצעות פונקציית ה-Circuit הדינמי, אנו יכולים לפעול אמצע-Circuit באמצעות תוצאות מדידה, ולממש בזמן אמת את הפעולות המותנות ב-Circuit הטלפורטציה. לפתרון בעיות עם מחשבים קוונטיים אמיתיים, נעקוב אחר ארבעת השלבים של דפוסי Qiskit.
- מיפוי הבעיה ל-Circuit קוונטי ואופרטורים
- אופטימיזציה עבור חומרת היעד
- הרצה על חומרת היעד
- עיבוד לאחר התוצאות
תרגיל 3: בניית Circuit הטלפורטציה
נסו לבנות את כל Circuit הטלפורטציה מאפס כדי לבדוק את הבנתכם. גללו מעלה אם צריכים תזכורת.
פתרון:
# Step 1: Map problem to quantum circuits and operators
# Create the circuit with 3-qubits and 1-bit
qc = QuantumCircuit(3, 3)
# Alice creates an unknown quantum state using the u-gate.
qc.u(theta, varphi, 0.0, 0)
qc.barrier() # for visual separation
# Eve creates EPR pair and sends q1 to Alice and q2 to Bob
##your code goes here##
qc.h(1)
qc.cx(1, 2)
qc.barrier()
# Alice entangles the unknown state with her EPR part, using the CNOT gate and H gate.
##your code goes here##
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Alice measures the two qubits.
##your code goes here##
qc.measure(0, 0)
qc.measure(1, 1)
# Alice sent the results to Bob. Now, Bob applies correction
##your code goes here##
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()
# Apply the inverse of u-gate to measure |0>
qc.u(theta, varphi, 0.0, 2).inverse()
qc.measure(2, 2)
qc.draw(output="mpl")
כתזכורת, הפעלת ההופכי של שער היא רק כדי שנוכל לאמת את ההתנהגות הצפויה. זה אינו חלק משליחת המצב לבוב, ולא היינו משתמשים בשער ההופכי אם המטרה היחידה הייתה להעביר מידע קוונטי.
שלב 2: אופטימיזציה עבור חומרת היעד
כדי להריץ על חומרה, ייבאו את QiskitRuntimeService וטענו את האישורים השמורים שלכם. בחרו את ה-Backend עם מספר המשימות הקטן ביותר בתור.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
service.backends()
[<IBMBackend('ibm_brisbane')>,
<IBMBackend('ibm_torino')>]
# You can also identify the least busy device
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is <IBMBackend('ibm_brisbane')>
# You can specify the device
# backend = service.backend('ibm_brisbane')
בואו נראה את מפת הצימוד של המכשיר שבחרתם.
from qiskit.visualization import plot_gate_map
plot_gate_map(backend)

למכשירים שונים עשויות להיות מפות צימוד שונות, ולכל מכשיר יש כמה Qubit ומצמדים שהם בעלי ביצועים טובים יותר מאחרים. לבסוף, למחשבים קוונטיים שונים עשויות להיות שערי ילידים שונים (שערים שהחומרה יכולה לבצע). Transpiling של ה-Circuit כותב מחדש את ה-Circuit הקוונטי המופשט באמצעות שערים שמחשב הקוונטי היעד יכול לבצע, ובוחר את המיפוי האופטימלי ל-Qubit פיזיים (בין היתר). Transpilation הוא נושא עשיר ומורכב. למידע נוסף על Transpilation, ראו את ה-API reference.
# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)
qc_compiled.draw("mpl", idle_wires=False, fold=-1)
שלב 3: הרצת ה-Circuit.
באמצעות ה-Sampler Runtime primitive, נריץ את ה-Circuit היעד.
# Step 3: Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nkhpn2txg008jt0d0
# Check the job status
job.status()
'DONE'
אפשר גם לבדוק את מצב המשימה מלוח המחוונים של IBM Quantum®.
# If the Notebook session got disconnected you can also check your job status by running the following code
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
job_real = service.job(job.job_id()) # Input your job-id between the quotations
job_real.status()
'DONE'
אם אתם רואים 'DONE' מוצג, תוכלו לקבל את התוצאה על ידי הרצת התא שלהלן.
# Execute after 'DONE' is displayed
result_real = job_real.result()
print(result_real[0].data.c.get_counts())
{'001': 992, '110': 430, '011': 579, '010': 605, '111': 402, '000': 925, '100': 57, '101': 106}
שלב 4: עיבוד לאחר התוצאות
# Step 4: Post-process the results
from qiskit.visualization import plot_histogram
plot_histogram(result_real[0].data.c.get_counts())
אפשר לפרש את התוצאות לעיל ישירות. או, באמצעות marginal_count, אפשר לייחס את תוצאות בוב ל-Qubit 2.
# trace out Bob's results on qubit 2
from qiskit.result import marginal_counts
bobs_qubit = 2
real_counts = result_real[0].data.c.get_counts()
bobs_counts = marginal_counts(real_counts, [bobs_qubit])
plot_histogram(bobs_counts)
כפי שאנו רואים כאן, יש כמה תוצאות שבהן מדדנו . אלה נובעות מרעש ושגיאות. בפרט, ל-Circuit דינמיים יש נטייה לשיעור שגיאות גבוה יותר בגלל המדידה הגוזלת זמן באמצע ה-Circuit.
4.5 נקודות מפתח בטלפורטציה קוונטית
אנחנו יכולים להעביר מצב קוונטי לחבר מרוחק על ידי שיתוף זוג Qubit שזורים (e-bit).
-
האם טלפורטציה קוונטית יכולה לשלוח את המצב הקוונטי מהר יותר מהאור? לא, כי אליס חייבת לומר לבוב את תוצאות המדידה בדרך קלאסית.
-
האם טלפורטציה קוונטית תשבור את "משפט אי-השכפול", האוסר על העתקת מצב קוונטי? לא, כי המצב הקוונטי המקורי שניתן לאליס על אחד מה-Qubit שלה אבד במדידה. הוא קרס ל- או .
5. קידוד צפוף קוונטי
כמעט אותה הגדרה יכולה לשמש למטרה שונה. נניח שאליס רוצה לשלוח לבוב שני סיביות של מידע קלאסי, אבל אין לה אפשרות לתקשר עם בוב בערוץ קלאסי. עם זאת, הם חולקים זוג שזור ומותר לה לשלוח את ה-Qubit שלה למיקומו של בוב. שימו לב להבדל מפרוטוקול הטלפורטציה הקוונטית. בטלפורטציה, תקשורת קלאסית הייתה זמינה לחברים, והמטרה הייתה לשלוח מצב קוונטי. כאן, תקשורת קלאסית אינה נגישה והם משתמשים בהעברת Qubit כדי לשתף שתי סיביות של מידע קלאסי.
5.1 הפרוטוקול של קידוד צפוף קוונטי
הנחה: לאליס יש שתי סיביות מידע, נניח . אליס ובוב חולקים זוג שזור (e-bit), אבל הם לא יכולים לתקשר בערוץ קלאסי.
- אליס מבצעת אחת מהפעולות הבאות על החלק שלה מה-e-bit.
- אם , היא לא עושה כלום
- אם , היא מפעילה את Gate Z
- אם , היא מפעילה את Gate X
- אם , היא מפעילה את Gate Z ואת Gate X.
- אליס שולחת את החלק שלה מה-e-bit למיקומו של בוב.
- בוב מפעיל CNOT Gate עם ה-Qubit של אליס כשליטה וה-Qubit שלו כיעד, לאחר מכן מפעיל Gate H על ה-Qubit של אליס, ומודד את שני ה-Qubits. המצבים ההתחלתיים האפשריים ותוצאות פעולות בוב הן:
שימו לב שסימן השלילי של הוא פאזה גלובלית, לכן הוא אינו מדיד.
5.2 Circuit קוונטי המדמה קידוד צפוף קוונטי
על בסיס הפרוטוקול של קידוד צפוף קוונטי, אפשר לבנות את ה-Circuit של הקידוד הצפוף כמפורט להלן. נסו לשנות את ההודעה, msg, שאליס רוצה להעביר לבוב.
from qiskit import QuantumCircuit
שלבי דפוס Qiskit מזוהים בתגובות הקוד.
# Step 1: Map problem to quantum circuits and operators
# Create 2-qubits circuit
qc = QuantumCircuit(2, 2)
# Eve creates EPR pair and send q0 to Alice and q1 to Bob
qc.h(0)
qc.cx(0, 1)
qc.barrier()
# set message which Alice wants to transform to Bob
msg = "11" # You can change the message
if msg == "00":
pass
elif msg == "10":
qc.x(0)
elif msg == "01":
qc.z(0)
elif msg == "11":
qc.z(0)
qc.x(0)
qc.barrier()
# Bob receives EPR qubit from Alice and performs unitary operations
qc.cx(0, 1)
qc.h(0)
qc.barrier()
# Bob measures q0 and q1
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw(output="mpl")
# We will execute on a simulator first
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
# Define backend
backend = AerSimulator()
shots = 1000
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job_sim = sampler.run([isa_qc], shots=shots)
result_sim = job_sim.result()
# Extract counts data
counts = result_sim[0].data.c.get_counts()
print(counts)
{'11': 1000}
# Visualize the results
from qiskit.visualization import plot_histogram
plot_histogram(counts)
אפשר לראות שבוב קיבל את ההודעה שאליס רצתה לשלוח לו.
בשלב הבא, נבדוק זאת עם מחשב קוונטי אמיתי.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)
print("The least busy device is ", backend)
The least busy device is <IBMBackend('ibm_brisbane')>
# Step 1 was already completed before the simulator job above.
# Step 2: Optimize for target hardware
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qc)
qc_compiled.draw("mpl", idle_wires=False)
# Step 3:Execute the target circuit
sampler = Sampler(backend)
job = sampler.run([qc_compiled])
job_id = job.job_id()
print("job id:", job_id)
job id: d13nnyq3grvg008j0zag
# Check the job status
job.status()
'DONE'
# If the Notebook session got disconnected you can also check your job status by running the following code
# from qiskit_ibm_runtime import QiskitRuntimeService
# service = QiskitRuntimeService()
job = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
# Execute after job has successfully run
real_result = job.result()
print(real_result[0].data.c.get_counts())
{'11': 3942, '01': 107, '10': 41, '00': 6}
# Step 4: post-process the results
from qiskit.visualization import plot_histogram
plot_histogram(real_result[0].data.c.get_counts())
התוצאה היא מה שציפינו לה. שימו לב שקידוד צפוף קוונטי על מחשב קוונטי אמיתי הראה פחות שגיאות מאשר במקרה של טלפורטציה קוונטית על מחשב קוונטי אמיתי. סיבה אפשרית לכך היא שטלפורטציה קוונטית משתמשת ב-Circuits דינמיים, וקידוד צפוף קוונטי לא. נלמד עוד על שגיאות ב-Circuits קוונטיים בשיעורים מאוחרים יותר.
6. סיכום
בסשן זה, מימשנו שני פרוטוקולים קוונטיים. למרות שהתרחישים עבור שניהם הכוללים חברים מרוחקים מוסרים במידת מה מחישוב קוונטי על QPU בודד, יש להם יישומים בחישוב קוונטי, ועוזרים לנו להבין טוב יותר את העברת המידע הקוונטי.
- טלפורטציה קוונטית: למרות שאי אפשר להעתיק מצבים קוונטיים, ניתן לטלפורט מצבים קוונטיים לא ידועים על ידי שיתוף שזירה.
- קידוד צפוף קוונטי: זוג שזור משותף, והעברת Qubit אחד, מאפשרים תקשורת של שתי סיביות של מידע קלאסי.
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'