אלגוריתמים קוונטיים: אומדן פאזה
Kento Ueda (15 May 2024)
מחברת זו מספקת את המושגים הבסיסיים ואת היישום של טרנספורמציית פורייה הקוונטית (QFT) ואומדן הפאזה הקוונטי (QPE).
הורד את ה-PDF של ההרצאה המקורית. שים לב שחלק מקטעי הקוד עשויים להיות מיושנים כיוון שמדובר בתמונות סטטיות.
זמן QPU משוער להרצת הניסוי הוא 7 שניות.
1. מבוא
טרנספורמציית פורייה הקוונטית (QFT)
טרנספורמציית פורייה הקוונטית היא המקבילה הקוונטית של טרנספורמציית פורייה הדיסקרטית הקלאסית. זוהי טרנספורמציה לינארית המוחלת על מצבים קוונטיים, הממפה בסיסי חישוב לייצוגי הבסיס של פורייה שלהם. ה-QFT ממלא תפקיד מרכזי באלגוריתמים קוונטיים רבים, ומציע שיטה יעילה לחילוץ מידע תקופתיות ממצבים קוונטיים. ניתן לממש את ה-QFT עם פעולות באמצעות Gates קוונטיים כמו Hadamard gates ו-Control-Phase gates עבור qubits, מה שמאפשר האצה אקספוננציאלית על פני טרנספורמציית פורייה הקלאסית.
- יישומים: זהו חלק יסודי באלגוריתמים קוונטיים כמו אלגוריתם שור לפירוק מספרים גדולים ולוגריתם דיסקרטי.
אומדן פאזה קוונטי (QPE)
אומדן הפאזה הקוונטי הוא אלגוריתם קוונטי המשמש לאמידת הפאזה הקשורה לווקטור עצמי של אופרטור יוניטרי. אלגוריתם זה מספק גשר בין התכונות המתמטיות המופשטות של מצבים קוונטיים ויישומיהם החישוביים.
- יישומים: הוא יכול לפתור בעיות כמו מציאת ערכים עצמיים של מטריצות יוניטריות ודמיית מערכות קוונטיות.
יחד, QFT ו-QPE מהווים את עמוד השדרה החיוני של אלגוריתמים קוונטיים רבים הפותרים בעיות שאינן ניתנות לפתרון על ידי מחשבים קלאסיים. בסיום מחברת זו, תרכוש הבנה כיצד מיישמים טכניקות אלו.
2. יסודות טרנספורמציית פורייה הקוונטית (QFT)
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit.quantum_info import Statevector
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from numpy import pi
בהקבלה לטרנספורמציית פורייה הדיסקרטית, ה-QFT פועל על מצב קוונטי עבור qubits וממפה אותו למצב הקוונטי .
כאשר .
או בייצוג מטריצה יוניטרית:
2.1. אינטואיציה
טרנספורמציית פורייה הקוונטית (QFT) עושה מיפוי בין שני בסיסים: בסיס החישוב (Z) ובסיס פורייה. אבל מה משמעות בסיס פורייה בהקשר זה? סביר להניח שאתה זוכר שטרנספורמציית פורייה של פונקציה מתארת את הקונבולוציה של על פונקציה סינוסואידלית בתדר . במילים פשוטות: טרנספורמציית פורייה היא פונקציה המתארת כמה מכל תדר נצטרך כדי לבנות פונקציה מפונקציות סינוס (או קוסינוס). כדי לקבל תחושה טובה יותר למה ה-QFT אומר בהקשר זה, שקול את התמונות המדורגות למטה המציגות מספר המקודד בבינארי, באמצעות ארבעה qubits:
בבסיס החישוב, אנחנו מאחסנים מספרים בבינארי באמצעות המצבים ו-.
שים לב לתדירות שבה qubits שונים משתנים; ה-Qubit השמאלי ביותר מתהפך עם כל תוספת במספר, הבא עם כל 2 תוספות, השלישי עם כל 4 תוספות, וכן הלאה.
אם נחיל טרנספורמציית פורייה קוונטית על מצבים אלה, נבצע מיפוי
(לעיתים קרובות אנחנו מסמנים מצבים בבסיס פורייה באמצעות טילדה (~)).
בבסיס פורייה, אנחנו מאחסנים מספרים באמצעות סיבובים שונים סביב ציר ה-Z:
IFRAME
המספר שאנחנו רוצים לאחסן קובע את הזווית שבה כל qubit מסתובב סביב ציר ה-Z. במצב , כל ה-Qubits נמצאים במצב . כפי שנראה בדוגמה לעיל, כדי לקודד את המצב על 4 qubits, סובבנו את ה-Qubit השמאלי ביותר ב- סיבובים מלאים ( רדיאנים). ה-Qubit הבא מסתובב כפליים מזה ( רדיאנים, או סיבובים מלאים), זווית זו מוכפלת שוב עבור ה-Qubit שאחריו, וכן הלאה.
שוב, שים לב לתדירות שבה כל qubit משתנה. ה-Qubit השמאלי ביותר (qubit 0) במקרה זה בעל התדר הנמוך ביותר, והימני ביותר בעל הגבוה ביותר.
2.2 דוגמה: QFT של qubit אחד
נשקול את המקרה של .
ניתן לכתוב את המטריצה היוניטרית:
פעולה זו היא תוצאה של החלת שער ה-Hadamard ().
2.3 ייצוג מכפלה של QFT
נכליל טרנספורמציה עבור , הפועל על המצב .
2.4 דוגמה: בניית Circuit של QFT עם 3 qubits
מהתיאור לעיל, אולי לא ברור כיצד לבנות Circuit של QFT. לעת עתה, פשוט שים לב שאנחנו מצפים לשלושה qubits שיהיו להם פאזות המתפתחות בקצבים "שונים". ההבנה של כיצד זה מתורגם ל-Circuit נשארת כתרגיל לקורא. ישנם מספר דיאגרמות ודוגמאות ב-PDF של ההרצאה. משאבים נוספים כוללים שיעור זה מקורס יסודות האלגוריתמים הקוונטיים.
נדגים את QFT באמצעות סימולטורים בלבד, ולכן לא נשתמש במסגרת Qiskit patterns עד שנעבור לאומדן פאזה קוונטי.
# Prepare for 3 qubits circuit
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
qc = QuantumCircuit(qr, cr)
qc.h(2)
qc.cp(pi / 2, 1, 2) # Controlled-phase gate from qubit 1 to qubit 2
qc.cp(pi / 4, 0, 2) # Controlled-phase gate from qubit 0 to qubit 2
qc.draw(output="mpl")
qc.h(1)
qc.cp(pi / 2, 0, 1) # Controlled-phase gate from qubit 0 to qubit 1
qc.draw(output="mpl")
qc.h(0)
qc.draw(output="mpl")
qc.swap(0, 2)
qc.draw(output="mpl")
ננסה להחיל QFT על כדוגמה.
ראשית, נאשר את הסימון הבינארי של המספר 5 וניצור את ה-Circuit המקודד את המצב 5:
bin(5)
'0b101'
qc = QuantumCircuit(3)
qc.x(0)
qc.x(2)
qc.draw(output="mpl")
נבדוק את המצבים הקוונטיים באמצעות סימולטור Aer:
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

לבסוף, נוסיף QFT ונצפה במצב הסופי של ה-Qubits שלנו:
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

אנחנו יכולים לראות שפונקציית ה-QFT שלנו עבדה נכון. Qubit 0 סובב ב- מסיבוב מלא, qubit 1 ב- סיבובים מלאים (שווה ערך ל- מסיבוב מלא), ו-Qubit 2 ב- סיבובים מלאים (שווה ערך ל- מסיבוב מלא).
2.5 תרגיל: QFT
(1) מממש QFT של 4 qubits.
##your code goes here##
(2) החל QFT על , סמלץ ושרטט את וקטור המצב באמצעות כדור בלוך.
##your code goes here##
פתרון התרגיל: QFT
(1)
qr = QuantumRegister(4)
cr = ClassicalRegister(4)
qc = QuantumCircuit(qr, cr)
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
(2)
bin(14)
'0b1110'
qc = QuantumCircuit(4)
qc.x(1)
qc.x(2)
qc.x(3)
qc.draw("mpl")
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

3. יסודות אומדן הפאזה הקוונטי (QPE)
בהינתן פעולה יוניטרית , אלגוריתם QPE מעריך את ב-. מכיוון ש- יוניטרי, לכל ערכי העצם שלו יש נורמה של 1.
3.1 הליך
1. הגדרה
נמצא בקבוצה אחת של רשמי qubit. קבוצה נוספת של qubit יוצרת את רשם הספירה, שבו נאחסן את הערך :
2. סופרפוזיציה
מחילים פעולת Gate הדאמרד -סיבית על רשם הספירה:
3. פעולות יוניטריות מבוקרות
צריך להכיר את ה- היוניטרי המבוקר, שמחיל את האופרטור היוניטרי על רשם היעד רק אם סיבית הבקרה המתאימה היא . מכיוון ש- הוא אופרטור יוניטרי עם וקטור עצם כך ש-, מתקיים:
3.2 דוגמה: QPE עם T-gate
בואו נשתמש ב-Gate מסוג כדוגמה ל-QPE ונעריך את הפאזה שלו.
אנחנו מצפים למצוא:
כאשר
אנחנו מאתחלים את של וקטור העצם של Gate מסוג על ידי החלת Gate מסוג :
qpe = QuantumCircuit(4, 3)
qpe.x(3)
qpe.draw(output="mpl")
לאחר מכן, מחילים Gate מסוג הדאמרד על qubit הספירה:
for qubit in range(3):
qpe.h(qubit)
qpe.draw(output="mpl")
מבצעים את הפעולות היוניטריות המבוקרות:
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.draw(output="mpl")
מחילים את טרנספורמציית פורייה הקוונטית ההפוכה כדי להמיר את מצב רשם הספירה, ולאחר מכן מודדים את רשם הספירה:
from qiskit.circuit.library import QFT
# Apply inverse QFT
qpe.append(QFT(3, inverse=True), [0, 1, 2])
qpe.draw(output="mpl")
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
ניתן לדמות באמצעות הסימולטור Aer:
aer_sim = AerSimulator()
shots = 2048
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
אנחנו רואים שמקבלים תוצאה אחת (001) בוודאות, שמתורגמת לערך העשרוני: 1. עכשיו צריך לחלק את התוצאה (1) ב- כדי לקבל את :
האלגוריתם של שור מאפשר לנו לפרק גורמים של מספר על ידי בניית Circuit עם לא ידוע ולאחר מכן להשיג את .
3.3 תרגיל
העריכו את תוך שימוש ב-3 qubit לספירה ו-Qubit אחד עבור וקטור עצם.
. מכיוון שאנחנו רוצים לממש , צריך להגדיר .
##your code goes here##
פתרון התרגיל:
# Create and set up circuit
qpe = QuantumCircuit(4, 3)
# Apply H-Gates to counting qubits:
for qubit in range(3):
qpe.h(qubit)
# Prepare our eigenstate |psi>:
qpe.x(3)
# Do the controlled-U operations:
angle = 2 * pi / 3
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(angle, counting_qubit, 3)
repetitions *= 2
# Do the inverse QFT:
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
aer_sim = AerSimulator()
shots = 4096
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
4. הרצה באמצעות ה-Sampler primitive של Qiskit Runtime
נבצע QPE באמצעות המכשיר הקוונטי האמיתי ונעקוב אחר 4 שלבים של תבניות Qiskit.
- מיפוי הבעיה לפורמט ילידי-קוונטי
- אופטימיזציה של ה-Circuit
- הרצת ה-Circuit היעד
- עיבוד לאחר של התוצאות
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Sampler
# Loading your IBM Quantum® account(s)
service = QiskitRuntimeService()
4.1 שלב 1: מיפוי הבעיה ל-Circuit ואופרטורים קוונטיים
qpe = QuantumCircuit(4, 3)
qpe.x(3)
for qubit in range(3):
qpe.h(qubit)
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
backend = service.least_busy(simulator=False, operational=True, min_num_qubits=4)
print(backend)
<IBMBackend('ibm_strasbourg')>
4.2 שלב 2: אופטימיזציה לחומרת היעד
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qpe)
qc_compiled.draw("mpl", idle_wires=False)

4.3 שלב 3: הרצה על חומרת היעד
real_sampler = Sampler(mode=backend)
job = real_sampler.run([qc_compiled], shots=1024)
job_id = job.job_id()
print("job id:", job_id)
job id: d13p4zb5z6q00087ag00
job = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
result_real = job.result()
print(result_real)
PrimitiveResult([SamplerPubResult(data=DataBin(c=BitArray(<shape=(), num_shots=1024, num_bits=3>)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2025-06-09 22:39:00', stop='2025-06-09 22:39:00', size=1024>)])}, 'version': 2})
4.4 שלב 4: עיבוד לאחר של התוצאות
from qiskit.visualization import plot_histogram
plot_histogram(result_real[0].data.c.get_counts())
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'