טרנספורם פורייה הקוונטי
למודול Qiskit in Classrooms הזה, על הסטודנטים להכין סביבת Python עובדת עם החבילות הבאות מותקנות:
qiskitv2.1.0 ומעלהqiskit-ibm-runtimev0.40.1 ומעלהqiskit-aerv0.17.0 ומעלהqiskit.visualizationnumpypylatexenc
להגדרה והתקנה של החבילות לעיל, ראה את המדריך התקנת Qiskit. כדי להריץ עבודות על מחשבים קוונטיים אמיתיים, הסטודנטים יצטרכו להגדיר חשבון ב-IBM Quantum® לפי השלבים במדריך הגדרת חשבון IBM Cloud שלך.
מודול זה נבדק והשתמש ב-13 שניות של זמן QPU. זהו אומדן בתום לב; השימוש בפועל שלך עשוי להשתנות.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
מבוא
טרנספורם פורייה הוא כלי נפוץ עם יישומים במתמטיקה, פיזיקה, עיבוד אותות, דחיסת נתונים ותחומים אחרים אין-ספור. גרסה קוונטית של טרנספורם פורייה, שנקראת בצדק טרנספורם פורייה הקוונטי, מהווה את הבסיס לכמה מהאלגוריתמים הקוונטיים החשובים ביותר.
היום, אחרי תזכורת על טרנספורם פורייה הקלאסי, נדבר על איך אנחנו מממשים את טרנספורם פורייה הקוונטי על מחשב קוונטי. לאחר מכן, נדון באחד מהיישומים של טרנספורם פורייה הקוונטי לאלגוריתם שנקרא אלגוריתם אומדן הפאזה. אומדן פאזה קוונטי הוא שגרת עזר באלגוריתם הפירוק לגורמים המפורסם של שור, שלעתים מכונה "אבן הכתר" של המחשוב הקוונטי. מודול זה בונה לעבר מודול אחר שכולו על אלגוריתם שור, אבל הוא גם מיועד להיות עצמאי. טרנספורם פורייה הקוונטי הוא אלגוריתם מרתק ושימושי בפני עצמו!
טרנספורם פורייה הקלאסי
לפני שנקפוץ לטרנספורם פורייה הקוונטי, בואו נזכיר לעצמנו את הגרסה הקלאסית. טרנספורם פורייה הוא שיטה לטרנספורמציה מבסיס אחד שנקרא "בסיס" לאחר. אפשר לחשוב על שני בסיסים כנקודות מבט שונות על אותה בעיה — שניהם דרכים תקפות לביטוי פונקציה, אבל אחת מהן עשויה להיות יותר מאירת עיניים, תלוי בבעיה שבידיך. כמה דוגמאות לזוגות של בסיסים שמחוברים על ידי טרנספורם פורייה הם מיקום ותנע, וזמן ותדירות.
בואו נראה דוגמה של איך טרנספורם פורייה יכול לעזור לנו לגלות איזה תו כלי נגינה מנגן על פי צורת גל האודיו שלו. בדרך כלל, אנחנו רואים את צורות הגל מיוצגות בבסיס הזמן — כלומר, האמפליטודה של הגל מבוטאת כפונקציה של הזמן.

אנחנו יכולים לטרנספורם פורייה את צורת הגל הזאת כדי לעבור מבסיס הזמן לבסיס התדירות:

בבסיס התדירות, אנחנו יכולים לראות בקלות פסגה ברורה בכ-260 הרץ. זה דו אמצעי!
עכשיו, אולי יכולת לקבוע שמנגנים דו אמצעי בלי שימוש בטרנספורם פורייה, אבל מה אם מנגנים כמה תווים בבת אחת? אז צורת הגל הופכ ת מסובכת יותר כשאנחנו מציגים אותה בבסיס הזמן:

אבל ספקטרום התדירות מזהה בבירור שלוש פסגות:

זה היה אקורד דו מז'ור, עם התווים דו, מי ו-סול.
סוג זה של ניתוח פורייה יכול לעזור לנו לחלץ את רכיבי התדירות של כל אות מסובך.
טרנספורם פורייה דיסקרטי
טרנספורם פורייה שימושי למגוון יישומי עיבוד אותות. אבל ברוב היישומים בעולם האמיתי (כולל דוגמת המוזיקה שהשתמשנו לעיל), אנחנו רוצים לטרנספורם קבוצה דיסקרטית של נקודות נתונים — לא פונקציה רציפה. במקרה הזה, אנחנו משתמשים בטרנספורם פורייה הדיסקרטי. טרנספורם פורייה הדיסקרטי (DFT) פועל על וקטור וממפה אותו לוקטור לפי הנוסחה:
כאשר אנחנו לוקחים . (שים לב שיש מוסכמות אחרות שיש להן סימן מינוס בחזקה, אז היזהר כשאתה רואה את ה-DFT בחיים האמיתיים.) נזכור ש- היא פונקציה מחזורית, עם מחזור . לכן, על ידי כפל בפונקציה זו, טרנספורם פורייה הוא בעצם דרך לפרק את הפונקציה (הדיסקרטית) לצירוף לינארי של הפונקציות המחזוריות המרכיבות אותה, כל אחת עם מחזור .
טרנספורם פורייה הקוונטי
אז עכשיו, ראינו איך טרנספורם פורייה משמש לייצוג פונקציה כצירוף לינארי של קבוצה חדשה של "פונקציות בסיס". טרנספורמציות בסיס מתבצעות גם באופן קבוע על מצבי Qubit. לדוגמה, המצב של Qubit בודד יכול להיות מבוטא בבסיס החישובי , עם מצבי הבסיס ו-, או בבסיס כ- עם מצבי בסיס ו-. שניהם תקפים באותה מידה, אבל אחד עשוי להיות יותר טבעי מהשני, תלוי בסוג הבעיה שאתה מנסה לפתור.
מצבי Qubit יכולים גם להיות מבוטאים בבסיס פורייה, שבו מצב מבוטא במונחים של צירוף לינארי של מצבי בסיס פורייה , במקום מצבי הבסיס החישובי הרגילים . לשם כך, צריך להחיל טרנספורם פורייה קוונטי (QFT):
כאשר כמו לעיל, ו- הוא מספר מצבי הבסיס במערכת הקוונטית שלך. שים לב שמכיוון שאנחנו עובדים עם Qubit עכשיו, Qubit נותנים לנו מצבי בסיס, ולכן . כאן, מצבי הבסיס כתובים כמספר יחיד כאשר נע מ- עד , אבל בדרך כלל תראה את מצבי הבסיס מבוטאים כ-, , , ..., , כאשר כל ספרה בינארית מייצגת את מצב ה-Qubit 0 עד , מימין לשמאל. יש דרך פשוטה להמיר את המצבים הבינאריים האלה למספר יחיד: פשוט התייחס אליהם כמספרים בינאריים! לכן, , , , , וכן הלאה, עד .
בניית אינטואיציה למצבי בסיס פורייה
אז, סקרנו מה מצבי הבסיס החישובי הם וכיצד הם מסודרים: הם הקבוצה של מצבים שבהם כל Qubit הוא או , ואנחנו מסדרים אותם מהמצב שבו כל ה-Qubit הם , , עד המצב שבו הם כולם , .
אבל איך אנחנו יכולים להבין את מצבי הבסיס של פורייה? כל מצבי בסיס פורייה הם סופרפוזיציות שוות של כל מצבי הבסיס החישובי, אבל כל מצב שונה מהאחר בתקופתיות בפאזה של הרכיבים. כדי להבין את זה ביתר קונקרטיות, בואו נסתכל על ארבעת מצבי בסיס פורייה של מערכת דו-Qubit. מצב פורייה הנמוך ביותר הוא זה שהפאזה שלו לא משתנה כלל:
אנחנו יכולים לדמיין את המצב הזה על ידי הצגת האמפליטודה המרוכבת של כל אחד מהאיברים. הקו האדום מנחה את העין להראות לך איך הפאזה של אמפליטודה זו עוטפת את המישור המרוכב כפונקציה של מצב הבסיס החישובי. עבור , הפאזה נשארת קבועה:

מצב בסיס פורייה הבא הוא זה שהפאזות של רכיביו עוטפות מ- עד בדיוק פעם אחת:
ואנחנו יכולים לראות את העטיפה הזאת בגרף האמפליטודה המרוכבת לעומת מצב הבסיס החישובי:

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

לבסוף, רכיב פורייה הגבוה ביותר הוא זה עם הפאזה המשתנה הכי מהר. בדוגמה שלנו עם שני Qubit, זה זה שהפאזות שלו עוטפות מ-0 עד שלוש פעמים:

בכלל, עבור מצב של Qubit, יהיו מצבי בסיס פורייה, שהתדירות בשינוי הפאזה שלהם נעה מקבועה, עבור , עד משתנה מהיר עבור , שמשלים עטיפות סביב על פני הסופרפוזיציה של המצבים. אז, כשאנחנו לוקחים QFT של מצב קוונטי, אנחנו בעצם עושים את אותו ניתוח בסיסי שעשינו עבור צורת הגל המוסיקלית בהקדמה. אנחנו קובעים את רכיבי תדירות פורייה שתורמים ליצירת המצב הקוונטי שמעניין אותנו.
נסה כמה QFT לדוגמה
בואו ננסה להמשיך לבנות את האינטואיציה שלנו לטרנספורם פורייה הקוונטי על ידי הכנת מצב בבסיס החישובי, ואז לראות מה קורה כשאנחנו מחילים את ה-QFT עליו. לעת עתה, נתייחס ל-QFT כקופסה שחורה שאנחנו מחילים באמצעות QFTGate מספריית המעגלים של Qiskit. בהמשך, נציץ מתחת למכסה המנוע כדי לראות איך הוא מיושם.
אנחנו מתחילים בטעינת החבילות הנחוצות ובחירת מכשיר להרצת ה-Circuit שלנו:
import numpy as np
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.circuit.library import QFTGate
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
service = QiskitRuntimeService()
# Use the least busy backend
# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)
backend = service.backend("ibm_pinguino2")
print(backend.name)
ibm_pinguino2
אם אין לך זמן זמין בחשבון שלך או שאתה רוצה להשתמש בסימולטור מכל סיבה שהיא, תוכל להריץ את התא למטה כדי להגדיר סימולטור שיחקה את המכשיר הקוונטי שבחרנו לעיל:
# Load the backend sampler
from qiskit.primitives import BackendSamplerV2
# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
noise_model = NoiseModel.from_backend(backend)
# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)
# Alternatively, load a fake backend with generic properties and define a simulator.
from qiskit.providers.fake_provider import GenericBackendV2
backend_gen = GenericBackendV2(num_qubits=18)
sampler_gen = BackendSamplerV2(backend=backend_gen)
מצב בסיס חישובי בודד
ראשית, בואו ננסה לטרנספורם מצב בסיס חישובי בודד. נתחיל בהכנת מצב חישובי אקראי:
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# flip state of random qubits to put in a random single computational basis state
for i in range(1, qubits):
if np.random.randint(0, 2):
qc.x(i)
# make a copy of the above circuit. (to be used when we apply the QFT in next part)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
עכשיו, בואו נטרנספורם פורייה את המצב הזה עם QFTGate:
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc_qft)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
כפי שאפשר לראות, אנחנו מודדים את האוכלוסיות של כל מצב להיות פחות או יותר שוות, בניכוי רעש ניסויי וסטטיסטי. אז, אם לוקחים את ה-QFT של מצב בסיס חישובי בודד, התוצאה היא סופרפוזיציה שווה של כל המצבים. אם אתה מכיר טרנספורמים של פורייה, זה כנראה לא מפתיע אותך. עיקרון בסיסי אחד שיכול לעזור לנו לבנות קשר אינטואיטיבי בין פונקציה לטרנספורם פורייה שלה הוא שרוחב פונקציה הפוך פרופורציונלי לרוחב טרנספורם פורייה שלה. אז, משהו שמאוד מקומי בזמן, לדוגמה, כמו פולס קצר מאוד, יצטרך מגוון רחב של תדירויות ליצור את הפולס הזה. האות הזה יהיה מאוד רחב במרחב פורייה.
עובדה זו קשורה בעצם לאי-ודאות קוונטית! עקרון אי-הוודאות של היזנברג מנוסח בדרך כלל כ-. אז אם אי-הוודאות ב- () קטנה, אי-הוודאות בתנע () חייבת להיות גדולה, ולהיפך. מסתבר שטרנספורמציה מבסיס המיקום לבסיס התנע מתבצעת דרך טרנספורם פורייה.
הערה: זכור, אנחנו מודדים אוכלוסיות בכל אחד ממצבי הבסיס, אז אנחנו מאבדים מידע על הפאזות היחסיות בין החלקים השונים של הסופרפוזיציה. לכן, בעוד ש-QFT של כל מצב בסיס חישובי בודד יניב את אותו פיזור שווה באוכלוסייה על פני כל מצבי הבסיס, הפאזות לא יהיו בהכרח זהות.
שני מצבי בסיס חישובי
עכשיו, בואו נראה מה קורה כשאנחנו מכינים סופרפוזיציה של מצבי בסיס חישובי. מה לדעתך יראה טרנספורם פורייה במקרה הזה?
בואו נבחר את הסופרפוזיציה:
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# To make this state, we just need to apply a Hadamard to the last qubit
qc.h(qubits - 1)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# First, let's go through steps 2-4 for the first circuit, qc
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
עכשיו, בואו נטרנספורם פורייה את המצב הזה עם QFTGate:
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc_qft)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-process
plot_histogram(counts)
זה אולי קצת יותר מפתיע. נראה שה-QFT של המצב הוא סופרפוזיציה של כל מצבי הבסיס הזוגיים. אבל אם נחשוב בחזרה לדמות שלנו של כל מצב בסיס , ואיך הפאזה של כל רכיב עוטפת סביב פעמים, אז הסיבה שאנחנו מקבלים את התוצאה הזאת עשויה להתבהר.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לגלות את הפתרון.
בעזרת הרמז למעלה, הסבר למה התוצאה שקיבלנו עבור ה-QFT של צפויה.
תשובה:
למצב המקורי יש פאזה יחסית של 0 (או כפולה שלמה של ) בין שני חלקי הסופרפוזיציה. אז אנחנו יודעים שלמצב הזה יש רכיבי פורייה שהפאזות שלהם גם תואמות באותה צורה: אלה שיש להם היסט פאזה 0 בין האיבר |0000> לאיבר |1000>. כל מצב בסיס פורייה מורכב מאיברים שהפאזה שלהם מצטברת בקצב של , כלומר, כשמסדרים בדרך הרגילה, לכל איבר בסופרפוזיציה יש פאזה של גדולה יותר מהאיבר שקדם לו. אז, בנקודת האמצע , אנחנו רוצים שהפאזה תהיה כפולה שלמה של . זה קורה כאשר הוא זוגי.
איזו סופרפוזיציה של מצבים חישוביים תתאים ל-QFT עם פסגות על כל מספר בינארי אי-זוגי?
תשובה:
אם לקחת את ה-QFT של המצב , אז תראה פסגות על כל מצב בעל מספר בינארי אי-זוגי.
פירוק אלגוריתם ה-QFT
עכשיו שצברנו יותר אינטואיציה לגבי הקשר בין מצבי Qubit בבסיס החישובי ובבסיס פורייה, בואו נצלול לתוך אלגוריתם ה-QFT עצמו. במילים אחרות, אילו Gates אנחנו בעצם מיישמים על המחשב הקוונטי כדי להשיג את הטרנספורמציה הזו?
בואו נתחיל בקטן, עם Qubit יחיד. כלומר, יהיו לנו שני מצבי בסיס. QFT הופך מצבי בסיס חישוביים ו- למצבי בסיס פורייה ו-:
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לגלות את הפתרון.
השתמש במשוואה עבור ה-QFT מהסעיף הקודם כדי לאמת את שני מצבי הבסיס של פורייה ל מעלה.
תשובה:
הנוסחה הכללית של QFT היא:
עבור Qubit יחיד (), , ו-. אז, יש לנו