קידוד נתונים
מבוא וסימונים
כדי להשתמש באלגוריתם קוונטי, יש להכניס נתונים קלאסיים לתוך Circuit קוונטי. לכך מתייחסים בדרך כלל כקידוד נתונים, אך גם כטעינת נתונים. נזכיר משיעורים קודמים את מושג המיפוי של תכונות — מיפוי של תכונות נתונים ממרחב אחד למשנהו. העברה של נתונים קלאסיים למחשב קוונטי היא סוג של מיפוי, שאפשר לקרוא לו מיפוי תכונות. בפועל, מיפויי התכונות המובנים ב-Qiskit (כמו z_Feature Map ו-ZZ Feature Map) יכללו בדרך כלל שכבות סיבוב ושכבות שזירה המרחיבות את המצב לממדים רבים במרחב הילברט. תהליך הקידוד הזה הוא חלק קריטי באלגוריתמי למידת מכונה קוונטיים ומשפיע ישירות על היכולות החישוביות שלהם.
חלק מטכניקות הקידוד שלהלן ניתנות לסימולציה קלאסית יעילה; קל במיוחד לראות זאת בשיטות קידוד המניבות מצבי מכפלה (כלומר, אינן שוזרות Qubitים). וכדאי לזכור שסביר שהיתרון הקוונטי יימצא דווקא כאשר המורכבות הקוונטית של מערך הנתונים מתאימה היטב לשיטת הקידוד. לכן סביר מאוד שבסופו של דבר תכתוב Circuit קידוד משלך. כאן אנו מציגים מגוון רחב של אסטרטגיות קידוד אפשריות כדי שתוכל להשוות ביניהן ולראות מה אפשרי. אפשר לומר כמה דברים כלליים על יעילות טכניקות הקידוד. לדוגמה, efficient_su2 (ראה להלן) עם סכמת שזירה מלאה סביר הרבה יותר שיתפוס תכונות קוונטיות של נתונים מאשר שיטות המניבות מצבי מכפלה (כמו z_feature_map). אך אין זה אומר ש-efficient_su2 מספיק, או מתאים מספיק למערך הנתונים שלך, כדי להניב האצה קוונטית. הדבר מצריך בחינה מדוקדקת של מבנה הנתונים שמנסים למדל או לסווג. יש גם פשרה עם עומק ה-Circuit, שכן מיפויי תכונות רבים שמשזרים את כל ה-Qubitים ב-Circuit מניבים Circuitים עמוקים מאוד, עמוקים מדי לקבלת תוצאות שמישות על המחשבים הקוונטיים של היום.
סימונים
מערך נתונים הוא קבוצה של וקטורי נתונים: , כאשר כל וקטור הוא בעל ממדים, כלומר . ניתן להרחיב זאת לתכונות נתונים מרוכבות. בשיעור זה, נשתמש לעיתים בסימונים אלה עבור הקבוצה המלאה ועבור אלמנטים ספציפיים שלה כמו . אך בעיקר נתייחס לטעינה של וקטור יחיד ממערך הנתונים שלנו בכל פעם, ולרוב נתייחס פשוט לוקטור יחיד בן תכונות בתור .
בנוסף, נהוג להשתמש בסמל כדי לציין את מיפוי התכונות של וקטור הנתונים . בתכנות קוונטי ספציפית, נהוג לציין מיפויים בעזרת , סימון המדגיש את האופי האוניטרי של פעולות אלו. ניתן להשתמש באותו סמל לשניהם כיאות; שניהם הם מיפויי תכונות. לאורך קורס זה, אנו נוטים להשתמש ב:
- כאשר אנו דנים במיפויי תכונות בלמידת מכונה באופן כללי, ו
- כאשר אנו דנים במימושי Circuit של מיפויי תכונות.
נורמליזציה ואובדן מידע
בלמידת מכונה קלאסית, תכונות של נתוני אימון מנורמלות או מוצרות לרוב מחדש, מה שמשפר לעיתים קרובות את ביצועי המודל. דרך נפוצה אחת לעשות זאת היא נורמליזציית מינימום-מקסימום או סטנדרטיזציה. בנורמליזציית מינימום-מקסימום, עמודות תכונות של מטריצת הנתונים (נאמר, תכונה ) מנורמלות:
כאשר מינימום ומקסימום מתייחסים למינימום ולמקסימום של תכונה על פני וקטורי הנתונים במערך . כל ערכי התכונות נופלים אז בקטע היחידה: לכל , .
נורמליזציה היא גם מושג יסודי במכניקת הקוונטים ובתכנות קוונטי, אך היא שונה במקצת מנורמליזציית מינימום-מקסימום. נורמליזציה במכניקת הקוונטים מחייבת שהאורך (בהקשר של תכנות קוונטי, הנורמה-2) של וקטור המצב שווה לאחד: , המבטיח שסכום ההסתברויות של המדידה שווה ל-1. המצב מנורמל על ידי חלוקה בנורמה-2; כלומר, על ידי סיכול מחדש
בתכנות קוונטי ובמכניקת הקוונטים, זוהי לא נורמליזציה שאנשים מטילים על הנתונים, אלא תכונה יסודית של מצבים קוונטיים. בהתאם לסכמת הקידוד שלך, אילוץ זה עשוי להשפיע על האופן שבו הנתונים שלך מוצרים מחדש. לדוגמה, בקידוד אמפליטודה (ראה להלן), וקטור הנתונים מנורמל כנדרש על ידי מכניקת הקוונטים, וזה משפיע על המידות של הנתונים המקודדים. בקידוד פאזה, מומלץ לסכם מחדש את ערכי התכונות כ- כדי שלא יהיה אובדן מידע עקב אפקט המודולו- של הקידוד לזווית פאזה של Qubit[1,2].
שיטות קידוד
בכמה הסעיפים הבאים, נתייחס למערך נתונים קלאסי לדוגמה קטן המורכב מ- וקטורי נתונים, כל אחד בעל תכונות:
בסימונים שהוצגו לעיל, נוכל לומר שהתכונה ה- של וקטור הנתונים ה- בקבוצה שלנו היא , לדוגמה.
קידוד בסיס
קידוד בסיס מקודד מחרוזת -ביטים קלאסית למצב בסיס חישובי של מערכת -Qubit. נניח לדוגמה . ניתן לייצג זאת כמחרוזת -ביטים , ועל ידי מערכת -Qubit כמצב קוונטי . באופן כללי יותר, עבור מחרוזת -ביטים: , מצב ה--Qubit המתאים הוא כאשר עבור . שים לב שזה עבור תכונה בודדת.
קידוד בסיס בתכנות קוונטי מייצג כל סיבית קלאסית כ-Qubit נפרד, ממפה את הייצוג הבינארי של הנתונים ישירות למצבים קוונטיים בבסיס החישובי. כאשר צריך לקודד תכונות מרובות, כל תכונה מומרת תחילה לצורתה הבינארית ולאחר מכן מוקצית לקבוצה נפרדת של Qubitים — קבוצה אחת לכל תכונה — כאשר כל Qubit משקף סיבית בייצוג הבינארי של אותה תכונה.
כדוגמה, בוא נקודד את הוקטור (5, 7, 0).
נניח שכל התכונות מאוחסנות בארבעה ביטים (יותר ממה שצריך, אבל מספיק לייצוג כל מספר שלם בעל ספרה אחת בבסיס 10):
5 → binary 0101
7 → binary 0111
0 → binary 0000
מחרוזות ביטים אלה מוקצות לשלוש קבוצות של ארבעה Qubitים כל אחת, ולכן מצב הבסיס הכולל של 12 Qubit הוא:
כאן, ארבעת ה-Qubitים הראשונים מייצגים את התכונה הראשונה, ארבעת ה-Qubitים הבאים את התכונה השנייה, וארבעת ה-Qubitים האחרונים את התכונה השלישית. הקוד להלן ממיר את וקטור הנתונים (5,7,0) למצב קוונטי, ומוכלל לעשות זאת עבור תכונות אחרות בעלות ספרה אחת.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit
from qiskit import QuantumCircuit
# Data point to encode
x = 5 # binary: 0101
y = 7 # binary: 0111
z = 0 # binary: 0000
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, "04b")] # [0,1,0,1]
y_bits = [int(b) for b in format(y, "04b")] # [0,1,1,1]
z_bits = [int(b) for b in format(z, "04b")] # [0,0,0,0]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,1,0,1,1,1,0,0,0,0]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw("mpl")

בדוק את הבנתך
קרא את השאלה למטה, חשוב על תשובתך, ולאחר מכן לחץ על המשולש לחשיפת הפתרון.
כתוב קוד לקידוד הוקטור הראשון במערך הנתונים לדוגמה שלנו :
באמצעות קידוד בסיס.
תשובה:
import math
from qiskit import QuantumCircuit
# Data point to encode
x = 4 # binary: 0100
y = 8 # binary: 1000
z = 5 # binary: 0101
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, '04b')] # [0,1,0,0]
y_bits = [int(b) for b in format(y, '04b')] # [1,0,0,0]
z_bits = [int(b) for b in format(z, '04b')] # [0,1,0,1]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,0,1,0,0,0,0,1,0,1]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw('mpl')
קידוד אמפליטודה
קידוד אמפליטודה מקודד נתונים לתוך האמ פליטודות של מצב קוונטי. הוא מייצג וקטור נתונים קלאסי -ממדי מנורמל, , כאמפליטודות של מצב קוונטי בן Qubitים, :
כאשר הוא אותו ממד של וקטורי הנתונים כמקודם, הוא האיבר ה- של ו- הוא מצב הבסיס החישובי ה-. כאן, הוא קבוע נורמליזציה שיש לקבוע מהנתונים המקודדים. זוהי תנאי הנורמליזציה המוטל על ידי מכניקת הקוונטים:
באופן כללי, זהו תנאי שונה מנורמליזציית מינימום/מקסימום המשמשת לכל תכונה על פני כל וקטורי הנתונים. האופן המדויק שבו מתמודדים עם זה יהיה תלוי בבעיה שלך. אך אין דרך לעקוף את תנאי הנורמליזציה הקוונטי-מכני שלעיל.
בקידוד אמפליטודה, כל תכונה בוקטור נתונים מאוחסנת כאמפליטודה של מצב קוונטי שונה. מאחר שמערכת של Qubitים מספקת אמפליטודות, קידוד אמפליטודה של תכונות דורש Qubitים.
כדוגמה, בוא נקודד את הוקטור הראשון במערך הנתונים לדוגמה שלנו , באמצעות קידוד אמפליטודה. נורמליזציה של הוקטור המתקבל נותנת לנו:
והמצב הקוונטי של 2 Qubitים המתקבל יהיה:
בדוגמה לעיל, מספר התכונות בוקטור אינו חזקה של 2. כאשר אינו חזקה של 2, פשוט בוחרים ערך למספר ה-Qubitים כך ש- וממלאים את וקטור האמפליטודה בקבועים לא אינפורמטיביים (כאן, אפס).
כמו בקידוד בסיס, לאחר שחישבנו איזה מצב יקודד את מערך הנתונים שלנו, ב-Qiskit אנו יכולים להשתמש בפונקציה initialize להכנתו:
import math
desired_state = [
1 / math.sqrt(105) * 4,
1 / math.sqrt(105) * 8,
1 / math.sqrt(105) * 5,
1 / math.sqrt(105) * 0,
]
qc = QuantumCircuit(2)
qc.initialize(desired_state, [0, 1])
qc.decompose(reps=5).draw(output="mpl")
יתרון של קידוד אמפליטודה הוא הדרישה הנ"ל ל- Qubitים בלבד לקידוד. עם זאת, האלגוריתמים הבאים חייבים לפעול על האמפליטודות של מצב קוונטי, ושיטות להכנה ומדידה של מצבים קוונטיים אינן נוטות להיות יעילות.
בדוק את הבנתך
קרא את השאלות למטה, חשוב על תשו בותיך, ולאחר מכן לחץ על המשולשים לחשיפת הפתרונות.
רשום את המצב המנורמל לקידוד הוקטור הבא (המורכב משני וקטורים ממערך הנתונים לדוגמה שלנו):
באמצעות קידוד אמפליטודה.
תשובה:
כדי לקודד 6 מספרים, נצטרך לפחות 6 מצבים זמינים שעל אמפליטודותיהם נוכל לקודד. זה ידרוש 3 Qubitים. באמצעות גורם נורמליזציה לא ידוע , נוכל לכתוב זאת כ:
שים לב ש
אז לבסוף,
עבור אותו וקטור נתונים כתוב קוד ליצירת Circuit הטוען תכונות נתונים אלה באמצעות קידוד אמפליטודה.
תשובה:
desired_state = [
9 / math.sqrt(270),
8 / math.sqrt(270),
6 / math.sqrt(270),
2 / math.sqrt(270),
9 / math.sqrt(270),
2 / math.sqrt(270),
0,
0,
]
print(desired_state)
qc = QuantumCircuit(3)
qc.initialize(desired_state, [0, 1, 2])
qc.decompose(reps=8).draw(output="mpl")
[0.5477225575051662, 0.48686449556014766, 0.36514837167011077, 0.12171612389003691, 0.5477225575051662, 0.12171612389003691, 0, 0]
ייתכן שתצטרך להתמודד עם וקטורי נתונים גדולים מאוד. שקול את הוקטור
כתוב קוד לאוטומציה של הנורמליזציה, וצור Circuit קוונטי לקידוד אמפליטודה.
תשובה:
יש תשובות אפשריות רבות. הנה קוד שמדפיס כמה שלבים בדרך:
import numpy as np
from math import sqrt
init_list = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5]
qubits = round(np.log(len(init_list)) / np.log(2) + 0.4999999999)
need_length = 2**qubits
pad = need_length - len(init_list)
for i in range(0, pad):
init_list.append(0)
init_array = np.array(init_list) # Unnormalized data vector
length = sqrt(
sum(init_array[i] ** 2 for i in range(0, len(init_array)))
) # Vector length
norm_array = init_array / length # Normalized array
print("Normalized array:")
print(norm_array)
print()
qubit_numbers = []
for i in range(0, qubits):
qubit_numbers.append(i)
print(qubit_numbers)
qc = QuantumCircuit(qubits)
qc.initialize(norm_array, qubit_numbers)
qc.decompose(reps=7).draw(output="mpl")
Normalized array: [0.17342199 0.34684399 0.21677749 0.39019949 0.34684399 0.26013299 0.086711 0.39019949 0.086711 0.21677749 0.30348849 0. 0.1300665 0.30348849 0.21677749 0. ]
[0, 1, 2, 3]

האם אתה רואה יתרונות לקידוד אמפליטודה על פני קידוד בסיס? אם כן, הסבר.
תשובה:
ייתכנו מספר תשובות. תשובה אחת היא שבהינתן הסדר הקבוע של מצבי הבסיס, קידוד האמפליטודה הזה שומר על סדר המספרים המקודדים. לעיתים קרובות הוא גם יהיה מקודד בצפיפות רבה יותר.
יתרון של קידוד אמפליטודה הוא שנדרשים רק Qubitים עבור וקטור נתונים -ממדי (-תכונות) . עם זאת, קידוד אמפליטודה הוא בדרך כלל הליך לא יעיל הדורש הכנת מצב שרירותי, שהיא אקספוננציאלית במספר שערי CNOT. אחרת, לסיכום הכנת המצב יש מורכבות זמן ריצה פולינומית של במספר הממדים, כאשר ו- הוא מספר ה-Qubitים. קידוד אמפליטודה "מספק חיסכון אקספוננציאלי במרחב במחיר של עלייה אקספוננציאלית בזמן"[3]; עם זאת, הגדלת זמן הריצה ל- ניתנת להשגה במקרים מסוימים[4]. לצורך האצה קוונטית מקצה לקצה, יש לקחת בחשבו ן את מורכבות זמן הריצה של טעינת הנתונים.
קידוד זווית
קידוד זווית הוא בעל עניין רב במודלי QML רבים המשתמשים במפות תכונות פאולי כמו מכונות וקטור תמיכה קוונטיות (QSVM) ומעגלים קוונטיים וריאציוניים (VQC), בין היתר. קידוד זווית קשור קשר הדוק לקידוד פאזה ולקידוד זווית צפוף המוצגים להלן. כאן נשתמש ב"קידוד זווית" כדי להתייחס לסיבוב ב-, כלומר סיבוב מציר ה- שמתבצע למשל על ידי שער או שער [1,3]. למעשה, ניתן לקדד נתונים בכל סיבוב או שילוב של סיבובים. אך נפוץ בספרות, ולכן אנו מדגישים אותו כאן.
כשמוחלים על Qubit יחיד, קידוד הזווית מעניק סיבוב בציר ה-Y שפרופורציונלי לערך הנתון. נביט בקידוד של תכונה בודדת (ה-) מוקטור הנתונים ה- בסט נתונים, :
לחלופין, ניתן לבצע קידוד זווית באמצעות שערי , אם כי למצב המקודד יהיה פאזה יחסית מרוכבת בהשוואה ל-.
קידוד זווית שונה משתי השיטות הקודמות שנדונו בכמה דרכים. בקידוד זווית:
- כל ערך תכונה ממופה ל-Qubit מתאים, , ומשאיר את ה-Qubit במצב מכפלה.
- ערך מספרי אחד מקודד בכל פעם, ולא קבוצת תכונות שלמה מנקודת נתונים.
- נדרשים Qubit עבור תכונות נתונים, כאשר . לרוב מתקיימת שוויון כאן. נראה כיצד אפשרי בסעיפים הבאים.
- ה-Circuit המתקבל הוא בעומק קבוע (בדרך כלל העומק הוא 1 לפני ה-Transpiler).
ה-Circuit הקוונטי בעומק קבוע הופך אותו לנוח במיוחד לחומרת קוונטים נוכחית. תכונה נוספת של קידוד הנתונים שלנו באמצעות (ובפרט, בחירתנו להשתמש בקידוד זווית ציר-Y) היא שהוא יוצר מצבים קוונטיים בעלי ערכים ממשיים שיכולים להיות שימושיים עבור יישומים מסוימים. לסיבוב ציר-Y, נתונים ממופים עם שער סיבוב ציר-Y בזווית ממשית (Qiskit RYGate). כמו בקידוד פאזה (ראה להלן), אנו ממליצים לשנות קנה מידה לנתונים כך ש-, כדי למנוע אובדן מידע ותופעות לא רצויות אחרות.
קוד Qiskit הבא מסובב Qubit יחיד ממצב ראשוני כדי לקדד ערך נתון .
from qiskit.quantum_info import Statevector
from math import pi
qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)
states = state1, state2
נגדיר פונקציה להצגה חזותית של הפעולה על וקטור המצב. פרטי הגדרת הפונקציה אינם חשובים, אך היכולת להמחיש את וקטורי המצב ושינוייהם היא חשובה.
import numpy as np
from qiskit.visualization.bloch import Bloch
from qiskit.visualization.state_visualization import _bloch_multivector_data
def plot_Nstates(states, axis, plot_trace_points=True):
"""This function plots N states to 1 Bloch sphere"""
bloch_vecs = [_bloch_multivector_data(s)[0] for s in states]
if axis is None:
bloch_plot = Bloch()
else:
bloch_plot = Bloch(axes=axis)
bloch_plot.add_vectors(bloch_vecs)
if len(states) > 1:
def rgba_map(x, num):
g = (0.95 - 0.05) / (num - 1)
i = 0.95 - g * num
y = g * x + i
return (0.0, y, 0.0, 0.7)
num = len(states)
bloch_plot.vector_color = [rgba_map(x, num) for x in range(1, num + 1)]
bloch_plot.vector_width = 3
bloch_plot.vector_style = "simple"
if plot_trace_points:
def trace_points(bloch_vec1, bloch_vec2):
# bloch_vec = (x,y,z)
n_points = 15
thetas = np.arccos([bloch_vec1[2], bloch_vec2[2]])
phis = np.arctan2(
[bloch_vec1[1], bloch_vec2[1]], [bloch_vec1[0], bloch_vec2[0]]
)
if phis[1] < 0:
phis[1] = phis[1] + 2 * pi
angles0 = np.linspace(phis[0], phis[1], n_points)
angles1 = np.linspace(thetas[0], thetas[1], n_points)
xp = np.cos(angles0) * np.sin(angles1)
yp = np.sin(angles0) * np.sin(angles1)
zp = np.cos(angles1)
pnts = [xp, yp, zp]
bloch_plot.add_points(pnts)
bloch_plot.point_color = "k"
bloch_plot.point_size = [4] * len(bloch_plot.points)
bloch_plot.point_marker = ["o"]
for i in range(len(bloch_vecs) - 1):
trace_points(bloch_vecs[i], bloch_vecs[i + 1])
bloch_plot.sphere_alpha = 0.05
bloch_plot.frame_alpha = 0.15
bloch_plot.figsize = [4, 4]
bloch_plot.render()
plot_Nstates(states, axis=None, plot_trace_points=True)
זו הייתה רק תכונה בודדת של וקטור נתונים יחיד. כשמקודדים תכונות לזוויות הסיבוב של Qubit, נניח עבור וקטור הנתונים ה- מצב המכפלה המקודד ייראה כך:
נציין שזה שקול ל-
בדוק את הבנתך
קרא את השאלות הבאות, חשוב על תשובותיך, ולאחר מכן לחץ על המשולשים לחשיפת הפתרונות.
קדד את וקטור הנתונים באמצעות קידוד זווית, כפי שתואר לעיל.
תשובה:
qc = QuantumCircuit(3)
qc.ry(0, 0)
qc.ry(2 * math.pi / 4, 1)
qc.ry(2 * math.pi / 2, 2)
qc.draw(output="mpl")
בשימוש בקידוד זווית כפי שתואר לעיל, כמה Qubit נדרשים לקידוד 5 תכונות?
תשובה: 5
קידוד פאזה
קידוד פאזה דומה מאוד לקידוד הזווית שתואר לעיל. זווית הפאזה של Qubit היא זווית ממשית סביב ציר ה- מציר ה-+. נתונים ממופים עם סיבוב פאזה, , כאשר (ראה Qiskit PhaseGate למידע נוסף). מומלץ לשנות קנה מידה לנתונים כך ש-. זה מונע אובדן מידע ותופעות לא רצויות אחרות[1,2].
Qubit מאותחל לרוב במצב , שהוא eigenvector של אופרטור סיבוב הפאזה, כלומר מצב ה-Qubit צריך קודם להיות מסובב כדי שקידוד הפאזה יוכל להיות מיושם. לכן הגיוני לאתחל את המצב עם שער הדמארד: . קידוד פאזה על Qubit יחיד פירושו הענקת פאזה יחסית פרופורציונלית לערך הנתון:
פרוצדורת קידוד הפאזה ממפה כל ערך תכונה לפאזה של Qubit מתאים, . בסך הכל, לקידוד פאזה יש עומק Circuit של 2, כולל שכבת הדמארד, מה שהופך אותו לסכמת קידוד יעילה. מצב רב-Qubit המקודד בפאזה ( Qubit עבור תכונות) הוא מצב מכפלה:
קוד Qiskit הבא מכין תחילה את המצב הראשוני של Qubit יחיד על ידי סיבובו עם שער הדמארד, ולאחר מכן מסובב אותו שוב באמצעות שער פאזה כדי לקדד תכונת נתון .
qc = QuantumCircuit(1)
qc.h(0) # Hadamard gate rotates state down to Bloch equator
state1 = Statevector.from_instruction(qc)
qc.p(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)
states = state1, state2
qc.draw("mpl", scale=1)
נוכל להמחיש את הסיבוב ב- באמצעות פונקציית plot_Nstates שהגדרנו.
plot_Nstates(states, axis=None, plot_trace_points=True)
תרשים כדור הבלוך מראה את סיבוב ציר ה-Z כאשר . החץ הירוק הבהיר מראה את המצב הסופי.
קידוד פאזה משמש במפות תכונות קוונטיות רבות, בפרט מפות תכונות ו-, ומפות תכונות פאולי כלליות, בין היתר.
בדוק את הבנתך
קרא את השאלות הבאות, חשוב על תשובותיך, ולאחר מכן לחץ על המשולשים לחשיפת הפתרונות.
כמה Qubit נדרשים כדי להשתמש בקידוד פאזה כפי שתואר לעיל לאחסון 8 תכונות?
תשובה: 8
כתוב קוד לטעינת הוקטור באמצעות קידוד פאזה.
תשובה:
ייתכנו תשובות רבות. הנה דוגמה אחת:
phase_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0]
qc = QuantumCircuit(len(phase_data))
for i in range(0, len(phase_data)):
qc.h(i)
qc.rz(phase_data[i] * 2 * math.pi / float(max(phase_data)), i)
qc.draw(output="mpl")
קידוד זווית צפוף
קידוד זווית צפוף (DAE) הוא שילוב של קידוד זווית וקידוד פאזה. DAE מאפשר לקדד שני ערכי תכונות ב-Qubit יחיד: אחד עם זווית סיבוב ציר-Y, והשני עם זווית סיבוב ציר-: . הוא מקדד שתי תכונות כדלקמן:
קידוד שתי תכונות נתונים ל-Qubit אחד מביא לצמצום של פי במספר ה-Qubit הנדרשים לקידוד. בהרחבה לתכונות נוספות, ניתן לקדד את וקטור הנתונים כ:
ניתן להכליל את DAE לפונקציות שרירותיות של שתי התכונות במקום הפונקציות הסינוסואידיות שבשימוש כאן. זה נקרא קידוד Qubit כללי[7].
כדוגמה ל-DAE, הקוד שלהלן מקדד ומדמה את הקידוד של התכונות ו-.
qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(3 * pi / 8, 0)
state2 = Statevector.from_instruction(qc)
qc.rz(7 * pi / 4, 0)
state3 = Statevector.from_instruction(qc)
states = state1, state2, state3
plot_Nstates(states, axis=None, plot_trace_points=True)
בדוק את הבנתך
קרא את השאלות הבאות, חשוב על תשובותיך, ולאחר מכן לחץ על המשולשים לחשיפת הפתרונות.
בהתאם לטיפול לעיל, כמה Qubit נדרשים לקידוד 6 תכונות באמצעות קידוד צפוף?
תשובה: 3
כתוב קוד לטעינת הוקטור באמצעות קידוד זווית צפוף.
תשובה:
שים לב שהרחבנו את הרשימה ב-"0" כדי להימנע מבעיית פרמטר בלתי מנוצל יחיד בסכמת הקידוד שלנו.
dense_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5, 0]
qc = QuantumCircuit(int(len(dense_data) / 2))
entry = 0
for i in range(0, int(len(dense_data) / 2)):
qc.ry(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.rz(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.draw(output="mpl")
קידוד עם מפות פיצ'רים מובנות
קידוד בנקודות שרירותיות
קידוד זוויתי, קידוד פאזה וקידוד צפוף הכינו מצבי מכפלה עם פיצ'ר מקודד על כל Qubit (או שני פיצ'רים לכל Qubit). זה שונה מקידוד בסיס וקידוד אמפליטודה, שבהם מנצלים מצבים שזורים. אין התאמה 1:1 בין פיצ'ר נתונים ל-Qubit. בקידוד אמפליטודה, למשל, ייתכן שפיצ'ר אחד הוא האמפליטודה של המצב ופיצ'ר אחר הוא האמפליטודה של . בדרך כלל, שיטות שמקודדות במצבי מכפלה מניבות Circuit-ים רדודים יותר ויכולות לאחסן 1 או 2 פיצ'רים על כל Qubit. שיטות שמשתמשות בשזירה ומשייכות פיצ'ר למצב ולא ל-Qubit מובילות ל-Circuit-ים עמוקים יותר, ויכולות לאחסן יותר פיצ'רים לכל Qubit בממוצע.
אך הקידוד לא חייב להיות כולו במצבי מכפלה או כולו במצבים שזורים כמו בקידוד אמפליטודה. למעשה, ערכות קידוד רבות המובנות ב-Qiskit מאפשרות קידוד גם לפני וגם אחרי שכבת שזירה, בניגוד להתחלה בלבד. זה ידוע בשם "העלאה מחדש של נתונים" (data reuploading). לעבודות קשורות, ראו הפניות [5] ו-[6].
בחלק זה נשתמש ונמחיש כמה מערכות הקידוד המובנות. כל השיטות בחלק זה מקודדות פיצ'רים כסיבובים על Gate-ים עם פרמטרים על Qubit-ים, כאשר . שימו לב שמקסום טעינת נתונים לכמות Qubit-ים נתונה אינו השיקול היחיד. במקרים רבים, עומק ה-Circuit עשוי להיות שיקול חשוב אפילו יותר ממספר ה-Qubit-ים.
Efficient SU2
דוגמה נפוצה ושימושית לקידוד עם שזירה היא ה-Circuit efficient_su2 של Qiskit. מדהים לציין שה-Circuit הזה יכול, למשל, לקודד 8 פיצ'רים על 2 Qubit-ים בלבד. בואו נראה זאת, ואז ננסה להבין כיצד זה אפשרי.
from qiskit.circuit.library import efficient_su2
circuit = efficient_su2(num_qubits=2, reps=1, insert_barriers=True)
circuit.decompose().draw(output="mpl")
כשנכתוב את המצב שלנו, נשתמש בקונבנציית Qiskit שלפיה Qubit-ים בעלי המשקל הנמוך ביותר מסודרים בצד ימין, כמו או מצבים אלו יכולים להיות מורכבים מאוד מהר מאוד, ודוגמה נדירה זו עשויה להסביר מדוע מצבים כאלה לעתים נדירות נכתב ים במפורש.
המערכת שלנו מתחילה במצב עד המחסום הראשון (נקודה שנסמן כ-), המצבים שלנו הם:
זה בדיוק קידוד צפוף, שכבר ראינו. עכשיו אחרי שער ה-CNOT, במחסום השני (), המצב שלנו הוא