פונק ציות עלות
במהלך שיעור זה, נלמד כיצד להעריך פונקציית עלות:
- ראשית, נלמד על פרימיטיבים של Qiskit Runtime
- נגדיר פונקציית עלות . זו פונקציה ספציפית לבעיה שמגדירה את מטרת הבעיה עבור המייעל למזעור (או למיקסום)
- הגדרת אסטרטגיית מדידה עם פרימיטיבים של Qiskit Runtime לאיזון בין מהירות לדיוק
פרימיטיבים
כל המערכות הפיזיות, בין אם קלאסיות ובין אם קוונטיות, יכולות להתקיים במצבים שונים. לדוגמה, מכונית על כביש יכולה להיות בעלת מסה, מיקום, מהירות או תאוצה מסוימים המאפיינים את מצבה. באופן דומה, מערכות קוונטיות יכולות גם הן להיות במצורות או מצבים שונים, אך הן שונות ממערכות קלאסיות באופן שבו אנו מתמודדים עם מדידות ואבולוציה של מצב. זה מוביל לתכונות ייחודיות כמו סופרפוזיציה ושזירה שהן בלעדיות למכניקת הקוונטים. ממש כמו שאנו יכולים לתאר את מצב המכונית באמצעות תכונות פיזיקליות כמו מהירות או תאוצה, אנו יכולים גם לתאר את מצב המערכת הקוונטית באמצעות אובזרוובלים, שהם אובייקטים מתמטיים.
במכניקת הקוונטים, מצבים מיוצגים על ידי וקטורי עמודה מרוכבים מנורמלים, או קטים (), ואובזרוובלים הם אופרטורים לינאריים הרמיטיים () הפועלים על הקטים. וקטור עצמי () של אובזרוובל מכונה מצב עצמי. מדידת אובזרוובל עבור אחד ממצביו העצמיים () תיתן לנו את הערך העצמי המתאים () כפלט.
אם אתם תוהים כיצד למדוד מערכת קוונטית ומה ניתן למדוד, Qiskit מציע שני פרימיטיבים שיכולים לעזור:
Sampler: בהינתן מצב קוונטי , פרימיטיב זה מחשב את ההסתברות של כל מצב בסיס חישובי אפשרי.Estimator: בהינתן אובזרוובל קוונטי ומצב , פרימיטיב זה מחשב את הערך הצפוי של .
הפרימיטיב Sampler
הפרימיטיב Sampler מחשב את ההסתברות לקבל כל מצב אפשרי מהבסיס החישובי, בהינתן מעגל קוונטי המכין את המצב . הוא מחשב
כאשר הוא מספר ה-Qubitים, ו- הוא הייצוג השלם של כל מחרוזת בינארית אפשרית (כלומר, מספרים שלמים בבסיס ).
ה-Sampler של Qiskit Runtime מריץ את המעגל מספר פעמים על מכשיר קוונטי, מבצע מדידות בכל ריצה, ומשחזר את התפלגות ההסתברות ממחרוזות הביטים שהתקבלו. ככל שיבצע יותר ריצות (או shots), התוצאות יהיו מדויקות יותר, אך הדבר דורש יותר זמן ומשאבים קוונטיים.
עם זאת, מכיוון שמספר הפלטים האפשריים גדל בצורה אקספוננציאלית עם מספר ה-Qubitים (כלומר, ), גם מספר ה-shots יצטרך לגדול בצורה אקספוננציאלית כדי לתפוס התפלגות הסתברות צפופה. לכן, Sampler יעיל רק עבור התפלגויות הסתברות דלילות; שבהן המצב היעד חייב להיות ניתן לביטוי כצירוף לינארי של מצבי בסיס חישובי, כאשר מספר האיברים גדל לכל היותר פולינומית עם מספר ה-Qubitים:
ניתן גם להגדיר את Sampler לשליפת הסתברויות מחלק מהמעגל, המייצג תת-קבוצה של המצבים האפשריים הכוללים.
הפרימיטיב Estimator
הפרימיטיב Estimator מחשב את הערך הצפוי של אובזרוובל עבור מצב קוונטי ; שבו הסתברויות האובזרוובל ניתנות לביטוי כ-, כאשר הם המצבים העצמיים של האובזרוובל . הערך הצפוי מוגדר אז כממוצע של כל התוצאות האפשריות (כלומר, הערכים העצמיים של האובזרוובל) של מדידת המצב , משוקלל לפי ההסתברויות המתאימות:
עם זאת, חישוב הערך הצפוי של אובזרוובל אינו תמיד אפשרי, שכן לעתים קרובות אנו לא יודעים את הבסיס העצמי שלו. ה-Estimator של Qiskit Runtime משתמש בתהליך אלגברי מורכב כדי להעריך את הערך הצפוי על מכשיר קוונטי אמיתי על ידי פירוק האובזרוובל לצירוף של אובזרוובלים אחרים שהבסיס העצמי שלהם ידוע לנו.
במילים פשוטות יותר, Estimator מפרק כל אובזרוובל שאינו יודע כיצד למדוד לאובזרוובלים פשוטים וניתנים למדידה הנקראים אופרטורי פאולי.
כל אופרטור ניתן לביטוי כצירוף של אופרטורי פאולי.
כך ש-
כאשר הוא מספר ה-Qubitים, עבור (כלומר, מספרים שלמים בבסיס ), ו-.
לאחר ביצוע פירוק זה, Estimator גוזר מעגל חדש עבור כל אובזרוובל (מהמעגל המקורי), כדי לאלכסן בפועל את אובזרוובל פאולי בבסיס החישובי ולמדוד אותו. אנו יכולים למדוד בקלות אובזרוובלי פאולי מכיוון שאנו יודעים את מראש, מה שאינו המקרה בדרך כלל עבור אובזרוובלים אחרים.
עבור כל , ה-Estimator מריץ את המעגל המתאים על מכשיר קוונטי מספר פעמים, מודד את מצב הפלט בבסיס החישובי, ומחשב את ההסתברות לקבל כל פלט אפשרי . לאחר מכן הוא מחפש את הערך העצמי של המתאים לכל פלט , מכפיל ב-, ומסכם את כל התוצאות כדי לקבל את הערך הצפוי של האובזרוובל עבור המצב הנתון .
מכיוון שחישוב הערך הצפוי של פאוליים אינו מעשי (כלומר, גדל אקספוננציאלית), Estimator יכול להיות יעיל רק כאשר כמות גדולה של שווה לאפס (כלומר, פירוק פאולי דליל במקום צפוף). באופן פורמלי אנו אומרים שכדי שחישוב זה יהיה ניתן לפתרון ביעילות, מספר האיברים השונים מאפס חייב לגדול לכל היותר פולינומית עם מספר ה-Qubitים :
הקורא עשוי להבחין בהנחה הגלומה שגם דגימת ההסתברות צריכה להיות יעילה כפי שהוסבר עבור Sampler, כלומר
דוגמה מודרכת לחישוב ערכים צפויים
נניח את המצב החד-קיוביטי , ואובזרוובל
עם הערך הצפוי התיאורטי הבא
מכיוון שאנו לא יודעים כיצד למדוד אובזרוובל זה, לא ניתן לחשב את ערכו הצפוי ישירות, ועלינו לבטא אותו מחדש כ-. ניתן להראות שזה מוביל לאותה תוצאה בשל העובדה ש-, ו-.
נראה כיצד לחשב את ו- ישירות. מכיוון ש- ו- אינם מתחלפים (כלומר, אין להם אותו בסיס עצמי), לא ניתן למדוד אותם בו-זמנית, ולכן אנחנו צריכים את המעגלים העזר:
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime rustworkx
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
# The following code will work for any other initial single-qubit state and observable
original_circuit = QuantumCircuit(1)
original_circuit.h(0)
H = SparsePauliOp(["X", "Z"], [2, -1])
aux_circuits = []
for pauli in H.paulis:
aux_circ = original_circuit.copy()
aux_circ.barrier()
if str(pauli) == "X":
aux_circ.h(0)
elif str(pauli) == "Y":
aux_circ.sdg(0)
aux_circ.h(0)
else:
aux_circ.id(0)
aux_circ.measure_all()
aux_circuits.append(aux_circ)
original_circuit.draw("mpl")
# Auxiliary circuit for X
aux_circuits[0].draw("mpl")
# Auxiliary circuit for Z
aux_circuits[1].draw("mpl")
כעת נוכל לבצע את החישוב ידנית באמצעות Sampler ולאמת את התוצאות עם Estimator:
from qiskit.primitives import StatevectorSampler, StatevectorEstimator
from qiskit.result import QuasiDistribution
import numpy as np
## SAMPLER
shots = 10000
sampler = StatevectorSampler()
job = sampler.run(aux_circuits, shots=shots)
# Run the sampler job and step through results
expvals = []
for index, pauli in enumerate(H.paulis):
data_pub = job.result()[index].data
bitstrings = data_pub.meas.get_bitstrings()
counts = data_pub.meas.get_counts()
quasi_dist = QuasiDistribution(
{outcome: freq / shots for outcome, freq in counts.items()}
)
# Use the probabilities and known eigenvalues of Pauli operators to estimate the expectation value.
val = 0
if str(pauli) == "X":
val += -1 * quasi_dist.get(1, 0)
val += 1 * quasi_dist.get(0, 0)
if str(pauli) == "Y":
val += -1 * quasi_dist.get(1, 0)
val += 1 * quasi_dist.get(0, 0)
if str(pauli) == "Z":
val += 1 * quasi_dist.get(0, 0)
val += -1 * quasi_dist.get(1, 0)
expvals.append(val)
# Print expectation values
print("Sampler results:")
for pauli, expval in zip(H.paulis, expvals):
print(f" >> Expected value of {str(pauli)}: {expval:.5f}")
total_expval = np.sum(H.coeffs * expvals).real
print(f" >> Total expected value: {total_expval:.5f}")
# Use estimator for comparison
observables = [
*H.paulis,
H,
] # Note: run for individual Paulis as well as full observable H
estimator = StatevectorEstimator()
job = estimator.run([(original_circuit, observables)])
estimator_expvals = job.result()[0].data.evs
# Print results
print("Estimator results:")
for obs, expval in zip(observables, estimator_expvals):
if obs is not H:
print(f" >> Expected value of {str(obs)}: {expval:.5f}")
else:
print(f" >> Total expected value: {expval:.5f}")
Sampler results:
>> Expected value of X: 1.00000
>> Expected value of Z: 0.00420
>> Total expected value: 1.99580
Estimator results:
>> Expected value of X: 1.00000
>> Expected value of Z: 0.00000
>> Total expected value: 2.00000
דיוק מתמטי (אופציונלי)
כאשר מבטאים את ביחס לבסיס המצבים העצמיים של , , נובע:
מכיוון שאיננו יודעים את הערכים העצמיים או המצבים העצמיים של האובזרוובל היעד , ראשית עלינו לשקול את האלכסון שלו. בהינתן ש- הוא הרמיטי, קיים טרנספורמציה אוניטרית כך ש- כאשר היא מטריצת הערכים העצמיים האלכסונית, כך ש- אם , ו-.
משמע שהערך הצפוי ניתן לכתיבה מחדש כ: