דלג לתוכן הראשי

Variational Quantum Eigensolver (VQE)

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

  • qiskit
  • qiskit_ibm_runtime
  • qiskit-aer
  • qiskit.visualization
  • numpy
  • pylatexenc

להגדרה והתקנה של חבילות אלה, ראו את המדריך התקנת Qiskit. להרצת משימות על מחשבי קוונטום אמיתיים, הסטודנטים יצטרכו להגדיר חשבון IBM Cloud, לפי השלבים במדריך הגדרת חשבון IBM Cloud שלך.

מודול זה נבדק ועשה שימוש של כ-8 דקות בזמן QPU. זה אומדן, והשימוש בפועל שלך עשוי להשתנות.

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime scipy
# 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'

מבוא

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

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

בחלקים הבאים נחקור תהליך יצירת המולקולה, תוך התמקדות במולקולת H2H_2. נשתמש במחשב קוונטום אמיתי, בשילוב עם טכניקות אופטימיזציה קלאסיות, כדי למצוא את האנרגיה של תהליך פשוט אך בסיסי זה. ניסוי זה יספק הדגמה מעשית של כיצד ניתן ליישם חישוב קוונטי לפתרון בעיות בכימיה חישובית, ויספק תובנות לגבי תפקידה של אנרגיית האלקטרונים.

VQE - אלגוריתם קוונטי ורiaציוני לבעיות ערכים עצמיים

טכניקות קירוב בכימיה - עיקרון הורiaציה וסט הבסיס

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

iddtψ=H^ψi\hbar \frac{d}{dt}|\psi\rangle = \hat{H}|\psi\rangle

כאן, H^\hat{H} הוא אופרטור ההמילטוניאן, המייצג את האנרגיה הכוללת של המערכת, ו-ψ|\psi\rangle היא פונקציית הגל המכילה את כל המידע על המצב הקוונטי של המערכת. (הערה: ddt\frac{d}{dt} הוא הנגזרת הכוללת לפי זמן, ואנו לא כוללים כאן במפורש את ערך האנרגיה העצמית EE.)

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

H^ψ=Eψ\hat{H}|\psi\rangle = E|\psi\rangle

בצורה זו, EE מייצג את ערך האנרגיה העצמי המתאים למצב הקוונטי ψ|\psi\rangle. ההמילטוניאן כולל תרומות אנרגיה שונות, כגון האנרגיה הקינטית של אלקטרונים וגרעינים, הכוחות המושכים בין אלקטרונים לגרעינים, והכוחות הדוחים בין אלקטרונים.

פתרון משוואת ערך האנרגיה העצמי מאפשר לנו לחשב את רמות האנרגיה הקוונטיות של מערכות אטומיות ומולקולריות. אולם, עבור מולקולות, פתרון מדויק הוא קשה מכיוון שפונקציית הגל Ψ\Psi, המתארת את הפיזור המרחבי של האלקטרונים, היא מורכבת ורב-ממדית.

כתוצאה מכך, מדענים משתמשים בטכניקות קירוב כדי לקבל פתרונות מעשיים ומדויקים. בעבודה זו, נתמקד בשתי שיטות מרכזיות:

  1. עיקרון הוריאציה

    שיטה זו מקרבת את פונקציית הגל ומכוונת אותה כדי להתקרב ככל האפשר לאנרגיית המטרה, בדרך כלל אנרגיית מצב היסוד של המערכת. הרעיון המרכזי מאחורי עיקרון הוריאציה הוא פשוט:

    • אם אנו מנחשים פונקציית גל Ψtrial\Psi_\text{trial} ("פונקציית ניסיון"), האנרגיה המחושבת ממנה תהיה תמיד שווה או גבוהה מאנרגיית מצב היסוד (E0E_0) של המערכת. Eapprox=ΨtrialH^ΨtrialΨtrialΨtrialE0E_\text{approx} = \frac{\langle \Psi_\text{trial}|\hat{H}|\Psi_\text{trial}\rangle}{\langle \Psi_\text{trial}|\Psi_\text{trial}\rangle} \geq E_0
    • על ידי כוונון פרמטרים θ\theta בפונקציית הניסיון, Ψtrial(θ)|\Psi_\text{trial}(\theta)\rangle, נוכל לקבל קירוב טוב יותר ויותר לאנרגיית מצב היסוד.
    • הדיוק שלה תלוי מאוד בבחירת פונקציית הניסיון Ψtrial\Psi_\text{trial}. פונקציית ניסיון שנבחרה רע עלולה להוביל לאומדן אנרגיה הרחוק מדיוק.
  2. קירוב סט הבסיס

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

    פונקציות הבסיס מונעות לעיתים קרובות מהפתרונות האנליטיים של מערכות פשוטות כמו אטום המימן, ולובשות צורות כמו פונקציות גאוסיאניות או מסוג סלייטר, אם כי הן עדיין קירובים. במקום לעבוד עם האורביטלים המולקולריים המלאים "המדויקים" תיאורטית אך בלתי ניתנים לטיפול, אנו מבטאים אותם כשילוב לינארי (סכום עם מקדמים) של פונקציות הבסיס הללו. שיטה זו ידועה כגישת קומבינציה לינארית של אורביטלים אטומיים (LCAO) כאשר פונקציות הבסיס דומות לאורביטלים אטומיים. על ידי אופטימיזציה של המקדמים בשילוב לינארי זה, נוכל למצוא את פונקציית הגל והאנרגיה המקורבות הטובות ביותר בתוך מגבלות סט הבסיס הנבחר.

    • ככל שנכלול יותר פונקציות בסט הבסיס, כך הקירוב טוב יותר, אך זה בא במחיר של מאמץ חישובי גבוה יותר.
    • סט בסיס קטן מספק אומדן גס, בעוד שסט בסיס גדול נותן תוצאות מדויקות יותר על חשבון דרישת משאבי חישוב רבים יותר.

לסיכום, כדי להפוך חישובים לאפשריים ולהפחית את העלות החישובית, אנו משתמשים בעיקרון הוריאציה על ידי קירוב פונקציית הגל, מה שמפחית את המורכבות החישובית ומאפשר אופטימיזציה איטרטיבית למזעור אנרגיה. בינתיים, גישת סט הבסיס מפשטת חישובים על ידי ייצוג אורביטלים אטומיים כשילוב של פונקציות מוגדרות מראש, במקום לפתור פונקציית גל רציפה ישירות.

בדוק את ההבנה שלך

שקול את פונקציית הגל לניסיון Ψtrial(α,x)=Aeαx2\Psi_\text{trial}(\alpha,x) = Ae^{- \alpha x^2} כאשר AA הוא קבוע נרמול ו-α\alpha הוא פרמטר ניתן לכוונון.

(a) נרמל את פונקציית הגל לניסיון על ידי קביעת AA כך ש-

Ψtrial2dx=1\int_{-\infty}^{\infty} |\Psi_\text{trial}|^2 dx = 1.

(b) חשב את ערך הציפייה של ההמילטוניאן H^\hat{H} הנתון על ידי:

H^=22md2dx2+V(x) \hat{H} = -\frac{\hbar^2}{2m} \frac{d^2}{dx^2} + V(x) כאשר V(x)=12mω2x2V(x) = \frac{1}{2}m\omega^2x^2, המתאים לפוטנציאל אוסילטור הרמוני פשוט.

(c) השתמש בעיקרון הוריאציה כדי למצוא את α\alpha האופטימלי על ידי מזעור Eapprox(α)E_\text{approx}(\alpha)

תשובה:

(a) לנרמול פונקציית הגל הנתונה לניסיון:

Ψtrial2dx=A2e2αx2dx=1\int_{-\infty}^{\infty} |\Psi_\text{trial}|^2 dx = \int_{-\infty}^{\infty} A^2 e^{-2 \alpha x^2} dx = 1

השתמש באינטגרל הגאוסי:

eax2dx=πa, for a>0 \int_{-\infty}^{\infty} e^{-a x^2} dx = \sqrt{\frac{\pi}{a}} \text{, for } a>0

הגדר a=2αa = 2\alpha ואז קבל: A2πa=1A^2\sqrt{\frac{\pi}{a}} = 1 A=(2απ)1/4\therefore A = (\frac{2\alpha}{\pi})^{1/4}

(b) ההמילטוניאן עבור אוסילטור הרמוני הוא:

H^=22md2dx2+12mω2x2\hat{H} = -\frac{\hbar^2}{2m} \frac{d^2}{dx^2} + \frac{1}{2} m \omega^2 x^2

  • ערך ציפייה של האנרגיה הקינטית

T=22mΨtriald2dx2Ψtrialdx\langle T \rangle = -\frac{\hbar^2}{2m} \int_{-\infty}^{\infty} \Psi_\text{trial}^* \frac{d^2}{dx^2} \Psi_\text{trial} dx

לקיחת הנגזרת השנייה:

ddxΨtrial=2αxAeαx2\frac{d}{dx} \Psi_\text{trial} = -2\alpha x A e^{-\alpha x^2}d2dx2Ψtrial=Aeαx2(4α2x22α)\frac{d^2}{dx^2} \Psi_\text{trial} = A e^{-\alpha x^2} (4\alpha^2 x^2 - 2\alpha)

לפיכך:

T=22mA2e2αx2(4α2x22α)dxT = -\frac{\hbar^2}{2m} \int_{-\infty}^{\infty} A^2 e^{-2\alpha x^2} (4\alpha^2 x^2 - 2\alpha) dx

שימוש בתוצאות אינטגרל גאוסי סטנדרטיות:

T=2α2m\langle T \rangle = \frac{\hbar^2 \alpha}{2m}
  • ערך ציפייה של האנרגיה הפוטנציאלית
V=12mω2x2Ψtrial2dx\langle V \rangle = \frac{1}{2} m \omega^2 \int_{-\infty}^{\infty} x^2 |\Psi_\text{trial}|^2 dx

שימוש ב:

x2eax2dx=π2a3/2\int_{-\infty}^{\infty} x^2 e^{-a x^2} dx = \frac{\sqrt{\pi}}{2a^{3/2}}

נקבל:

V=mω24α\langle V \rangle = \frac{m \omega^2}{4\alpha}
  • ערך ציפייה של האנרגיה הכוללת
Eapprox(α)=2α2m+mω24α\therefore E_\text{approx}(\alpha) = \frac{\hbar^2 \alpha}{2m} + \frac{m \omega^2}{4\alpha}

(c) אופטימיזציה של α\alpha לאנרגיה מינימלית

נגזור:

ddα(2α2m+mω24α)=0\frac{d}{d\alpha} \left( \frac{\hbar^2 \alpha}{2m} + \frac{m \omega^2}{4\alpha} \right) = 0

פתרון:

22mmω24α2=0\frac{\hbar^2}{2m} - \frac{m \omega^2}{4\alpha^2} = 0αopt=mω2\alpha_\text{opt} = \frac{m\omega}{2\hbar}

הצבת αopt\alpha_\text{opt} ב-EapproxE_\text{approx}:

Eapprox=ω2\therefore E_\text{approx} = \frac{\hbar \omega}{2}

שמתאים לאנרגיית מצב היסוד המדויקת של האוסילטור הרמוני הקוונטי.

VQE (Variational Quantum Eigensolver)

ה-Variational Quantum Eigensolver (VQE) היא השיטה הראשית שבה נשתמש לחקר תהליך H+H=H2H+H = H_2, וכאן נבחן מה זה VQE וכיצד הוא עובד. אבל קודם נעצור ונסתכל על דבר אחד חשוב מאוד דרך שאלת הבדיקה.

בדוק את ההבנה שלך

אם כבר יש לנו כל כך הרבה אסטרטגיות לבעיות כימיות, אז למה אנחנו צריכים מחשב קוונטום? ומה המטרה של שימוש בשני מחשבים קוונטיים וקלאסיים ביחד?

תשובה:

למחשוב קוונטי יש סיכוי לחולל מהפכה בכימיה על ידי התמודדות עם בעיות שמחשבים קלאסיים מתקשים בהן בשל הסקלאציה האקספוננציאלית של מצבים קוונטיים. ריצ'רד פיינמן ציין בפרסום את ההבחנה שכדי לדמות את הטבע, גם החישובים חייבים להיות קוונטיים [מקור 1].

למשל, דימוי קפאין עם סט הבסיס הפשוט ביותר (STO-3G) ידרוש 104810^{48} ביטים, הרבה יותר מהמספר הכולל של כוכבים ביקום הנראה (102410^{24}) [מקור 2]. מחשב קוונטי יכול לתאר את האורביטלים האלקטרוניים של קפאין עם 160 Qubits.

מחשבים קוונטיים מעבדים באופן טבעי אינטראקציות קוונטיות באמצעות סופרפוזיציה ושזירה, המספקות דרך מבטיחה לאפשר סימולציות מולקולריות מדויקות. יתר על כן, אנו יכולים לשלב את היתרונות של מחשבים קוונטיים (סימולציית אלקטרונים) ומחשבים קלאסיים (עיבוד מקדים/לאחר של נתונים, ניהול תהליך האלגוריתם, אופטימיזציה, וכן הלאה). אלה צפויים לשפר את גילוי חומרים, עיצוב תרופות וחיזוי תגובות, ולהפחית ניסויי ניסוי-וטעייה יקרים. [מקור 3][מקור 4]

אם אתה רוצה לדעת למה צריך מחשבים קוונטיים לבעיות כימיות ולמה להשתמש גם במשאבי מחשוב קוונטיים וגם קלאסיים, בדוק את המאמרים הבאים:

עכשיו בוא נחזור ל-VQE.

VQE משלב את כוחם של מחשבים קוונטיים עם מחשבים קלאסיים, ובאופן בסיסי משתמש בעקרונות וריאציוניים כדי לקבל את אנרגיית מצב היסוד של המערכת. כדי להבין VQE, קודם פרקו אותו לשלושה חלקים:

VQE workflow

(קוונטי) אובייקט הניתן למדידה: ההמילטוניאן המולקולרי (אנרגיית מולקולה)

ב-VQE, ההמילטוניאן המולקולרי/אטומי הוא אובייקט הניתן למדידה, כלומר ניתן למדוד את ערכו דרך ניסוי. המטרה שלנו היא למצוא את האנרגיה הנמוכה ביותר האפשרית (אנרגיית מצב היסוד) של המולקולה. לשם כך, אנו משתמשים במצב קוונטי לניסיון, שנוצר על ידי Circuit קוונטי מפרמטרים (ansatz). אנו מודדים את האובייקט הניתן למדידה ומבצעים אופטימיזציה על המצב הקוונטי עד שנגיע לאנרגיה הנמוכה ביותר האפשרית.

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

לאחר שנקבל המילטוניאן מולקולרי באמצעות סט הבסיס והאסטרטגיות המתאימות לעיל, עלינו להפוך המילטוניאן זה לאחד המתאים למחשבים קוונטיים. מיפוי בעיות לאופרטורי פאולי יכול להיות מסובך למדי. זה נכון במיוחד בכימיה קוונטית, שעובדת עם חלקיקים בלתי ניתנים להבחנה (אלקטרונים), מכיוון ש-Qubits הם ניתנים להבחנה. לא נכנס לפרטי המיפויים כאן, אך אנו מפנים אותך למשאבים הבאים. דיון כללי על מיפוי בעיה לאופרטורים קוונטיים ניתן למצוא ב-Quantum computing in practice. דיון מפורט יותר על מיפוי בעיות כימיה לאופרטורים קוונטיים ניתן למצוא ב-Quantum chemistry with VQE.

עבור מודול זה, נספק לך את ההמילטוניאנים המתאימים (של Qubit אחד) עבור HH ו-H2H_2 כדי שנוכל להתמקד בשימוש במחשב הקוונטי. המילטוניאנים אלה של Qubit אחד מוכנים על ידי שימוש בסט הבסיס STO-6G ו-מיפוי ג'ורדן-ויגנר, שהוא המיפוי הישיר ביותר עם הפרשנות הפיזיקלית הפשוטה ביותר, מכיוון שהוא ממפה את התפוסה של אורביטל ספין אחד לתפוסה של Qubit אחד. כמו כן, השתמשנו ב-טכניקת צמצום Qubit באמצעות סימטריה של ההמילטוניאן, המשתמשת בדפוסים כיצד תפוסות ספין מתנהגות כדי לצמצם את מספר ה-Qubits. עבור מולקולת H2H_2, אנו מניחים שהמרחק בין שני אטומי המימן הוא 0.735 A˚\mathring A.

(קוונטי) Ansatz: פונקציית הגל לניסיון (כיצד לבנות מצב קוונטי ראשוני עם Circuit קוונטי)

עבור VQE, ה-ansatz (רבים: ansätze) מורכב משני מרכיבים מרכזיים. הראשון הוא הכנת מצב ראשוני, שמגדירה את מצב ה-Qubit על ידי החלת Gates קוונטיים ללא פרמטר וריאציוני. המרכיב השני הוא ה-Circuit הקוונטי המפרמטרי, Circuit קוונטי מיוחד עם פרמטרים ניתנים לכוונון, בדומה לחוגות ברדיו. פרמטרים אלה ישמשו את האופטימייזר הקלאסי — החלק האחרון — כדי לעזור לנו להגיע למצב היסוד הטוב ביותר האפשרי.

בחלק עיקרון הוריאציה, למדנו שאיכות המצב לניסיון משפיעה על איכות תוצאות האלגוריתם הוריאציוני. זה אומר שבחירת ansatz טוב חשובה ב-VQE. שוב, זהו נושא עשיר ומורכב. לא נכסה את סוגי ה-ansatz השונים או את מקורותיהם כאן. אם אתה מעוניין ללמוד עוד על Circuits קוונטיים מפרמטרים ו-ansatz, תוכל לחקור את השיעור Ansatz ו-variational form מקורס תכנון אלגוריתם וריאציוני, המספק הסברים ודוגמאות מפורטים של ansätze.

מכיוון שנשתמש בהמילטוניאן של Qubit אחד במודול זה, אנחנו צריכים Circuit קוונטי מפרמטרי של Qubit אחד כ-ansatz. נראה שלושה סוגים של ansätze של Qubit אחד בחלק הבא. נשווה אותם ונדון בשיקולים מרכזיים בבחירת ansatz.

(קלאסי) אופטימייזר: כוונון עדין של ה-Circuit הקוונטי

ברגע שהמחשב הקוונטי מודד את האנרגיה של האובייקט הניתן למדידה מה-ansatz, הפרמטרים של ה-ansatz וערך האנרגיה נשלחים לאופטימייזר הקלאסי לכוונון. תהליך אופטימיזציה זה מבוצע על מחשב קלאסי, בדרך כלל באמצעות חבילות מדע כלליות כמו SciPy.

האופטימייזר הקלאסי מתייחס לאנרגיה הנמדדת כפונקציית עלות. בבעיות אופטימיזציה, פונקציית עלות (הנקראת לעיתים גם פונקציית מטרה) היא פונקציה מתמטית המודדת כמה "טוב" פתרון מסוים. המטרה של האופטימייזר היא למצוא את קבוצת הפרמטרים שממזערת פונקציית עלות זו. בהקשר של מציאת אנרגיית מצב היסוד של מולקולה, האנרגיה עצמה משמשת כפונקציית העלות — אנו רוצים למצוא את הפרמטרים עבור ה-Circuit הקוונטי שלנו ("הפתרון" שלנו) המניבים את האנרגיה הנמוכה ביותר האפשרית. האופטימייזר הקלאסי משתמש בערך האנרגיה הנמדדת זה (העלות) וקובע את קבוצת הפרמטרים הממוטבים הבאה עבור ה-ansatz הקוונטי. פרמטרים מעודכנים אלה נשלחים לאחר מכן בחזרה ל-Circuit הקוונטי, והתהליך חוזר על עצמו. עם כל איטרציה, האופטימייזר הקלאסי מכוונן את הפרמטרים כדי לנסות ולהפחית את האנרגיה (למזער את פונקציית העלות) עד שיתמלא קריטריון התכנסות מוגדר מראש, ובאופן אידיאלי מבטיח שתימצא האנרגיה הנמוכה ביותר האפשרית (המתאימה למצב היסוד של המולקולה לאותו מרחק קשר וסט בסיס).

ישנן אסטרטגיות אופטימיזציה רבות הניתנות על ידי חבילות מדע כמו SciPy. תוכל למצוא עוד בשיעור לולאות אופטימיזציה של קורס תכנון אלגוריתם וריאציוני. כאן נשתמש ב-COBYLA (Constrained Optimization BY Linear Approximations), אלגוריתם אופטימיזציה מתאים לנופי אנרגיה מורכבים. בפרט, COBYLA לא מנסה לחשב גרדיאנט של הפונקציה הנחקרת; זה נקרא אופטימייזר ללא גרדיאנט. דמיין שאתה מנסה למצוא את הפסגה הגבוהה ביותר ברכס הרים בעיניים עצומות. מכיוון שאינך יכול לראות את כל הנוף, אתה נוקט בצעדים קטנים לכיוונים שונים, תוך בדיקה אם אתה עולה או יורד. COBYLA עובד בצורה דומה — הוא נע דרך מרחב הפרמטרים, בוחן ערכים שונים, ומשפר בהדרגה את התוצאה עד שהוא מוצא את הטוב ביותר.

עכשיו אתה מוכן לבצע חישוב VQE. לשם כך, נסה את שאלת הבדיקה למטה, המסכמת את התהליך הכולל.

בדוק את ההבנה שלך

מלא את החסרים במונחים הנכונים כדי להשלים את סיכום תהליך ה-VQE.

VQE הוא אלגוריתם קוונטי וריאציוני, המשלב את כוחם של (1) ________ ומחשוב קלאסי, המשמש למציאת (2) __________ של מולקולה. התהליך מתחיל בהגדרת (3) __________, המייצג את האנרגיה הכוללת של המערכת ומשמש כאובייקט הניתן למדידה במדידות קוונטיות. לאחר מכן, אנו מכינים (4) __________, Circuit קוונטי עם פרמטרים ניתנים לכוונון המייצג את פונקציית הגל לניסיון של המולקולה. פרמטרים אלה מותאמים אופטימלית באמצעות (5) __________, אלגוריתם קלאסי המכוונן פרמטרים באיטרטיביות כדי למזער את האנרגיה הנמדדת. בדיון לעיל השתמשנו ב-(6) __________, אשר מחדד את פרמטרי ה-ansatz מבלי שהוא זקוק לחישובי נגזרות. התהליך נמשך עד שאנו מגיעים ל-(7) __________, כלומר מצאנו את האנרגיה הנמוכה ביותר האפשרית של המולקולה.

בנק מילים:

  • classical optimizer
  • ground state energy
  • hardware-efficient
  • ansatz
  • molecular Hamiltonian
  • COBYLA
  • quantum computing
  • convergence

תשובה:

1 → quantum computing

2 → ground state energy

3 → molecular Hamiltonian

4 → ansatz

5 → classical optimizer

6 → COBYLA

7 → convergence

חישוב אנרגיית המצב הבסיסי של אטום מימן עם VQE

עכשיו, בוא נשתמש במה שלמדנו כדי לחשב את אנרגיית המצב הבסיסי של אטום מימן. לאורך המודול, נשתמש במסגרת עבודה לחישוב קוונטי הנקראת "Qiskit patterns", שמחלקת תהליכי עבודה לשלבים הבאים:

  • שלב 1: מיפוי קלטים קלאסיים לבעיה קוונטית
  • שלב 2: אופטימיזציה של הבעיה להרצה קוונטית
  • שלב 3: הרצה באמצעות פרימיטיבים של Qiskit Runtime
  • שלב 4: עיבוד לאחר מכן וניתוח קלאסי

Qiskit pattern

בדרך כלל נלך בצעדים האלה.

בוא נתחיל בטעינת כמה חבילות נחוצות, כולל פרימיטיבים של Qiskit Runtime. כמו כן נבחר את המחשב הקוונטי הפחות עמוס שזמין לנו.

יש קוד למטה לשמירת האישורים שלך בשימוש הראשון. הקפד למחוק את המידע הזה מהמחברת לאחר שמירתו לסביבתך, כדי שהאישורים שלך לא ישותפו בטעות כשתשתף את המחברת. ראה הגדר את חשבון IBM Cloud שלך ו-אתחל את השירות בסביבה לא מהימנה לקבלת הנחיות נוספות.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')

# Load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_brisbane

התא שלמטה יאפשר לך לעבור בין שימוש בסימולטור או בחומרה אמיתית לאורך המחברת. אנחנו ממליצים להריץ אותו עכשיו:

# 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

# Alternatively, load a fake backend with generic properties and define a simulator.

noise_model = NoiseModel.from_backend(backend)

# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)

שלב 1: מיפוי הבעיה ל-Circuit קוונטיים ואופרטורים

אנחנו מתחילים את חישוב ה-VQE שלנו בהגדרת ההמילטוניאן עבור מולקולת המימן (H2H_2) במרחק קשר ספציפי. ההמילטוניאן הזה מייצג את האנרגיה הכוללת של המערכת במונחים של אופרטורי Qubit, לאחר שהופק ומופה ממערכת המולקולה באמצעות נוהל סטנדרטי: 1) שימוש בבסיס STO-6G (אוסף ספציפי של פונקציות מתמטיות המשמשות לקירוב אורביטלים אלקטרוניים), 2) יישום מיפוי ג'ורדן-ויגנר (טכניקה לתרגום אופרטורים פרמיוניים המתארים אלקטרונים לאופרטורי Qubit), ו-3) ביצוע הפחתת Qubit באמצעות סימטריות של ההמילטוניאן לפישוט הבעיה.

כפי שהסברנו קודם, אנרגיות המצב הבסיסי המחושבות תלויות מאוד בבחירת הבסיס ובגיאומטריה המולקולרית (כמו מרחק הקשר). עבור תצורה ספציפית זו ולאחר ביצוע הטרנספורמציות הללו, ההמילטוניאן של Qubit המתקבל הוא פשוט:

H^=0.2355I+0.2355Z\hat{H} = -0.2355 I + 0.2355 Z

כאן, II מייצג את אופרטור הזהות ו-ZZ מייצג את אופרטור פאולי-Z, הפועל על Qubit יחיד. המקדמים נגזרים מהאינטגרלים המחושבים באמצעות בסיס STO-6G במרחק הקשר המסוים הזה עם טרנספורמציה נכונה.

עם ההמילטוניאן הזה מוגדר, אנחנו יכולים להשתמש ב-VQE כדי לחשב את אנרגיית המצב הבסיסי שלו. כדאי להשוות את אנרגיית המצב הבסיסי המחושבת שלנו לערכים צפויים. עבור אטום מימן (H) בודד ומבודד, אנרגיית המצב הבסיסי היא בדיוק -0.5 Hartree (בהיעדר אפקטים רלטיביסטיים). בוא נחשב את אנרגיית המצב הבסיסי המדויקת של ההמילטוניאן הספציפי של ה-Qubit שלנו כפי שהוגדר לעיל ונשווה אותה לערכים ידועים רלוונטיים.

from qiskit.quantum_info import SparsePauliOp
import numpy as np

# Qubit Hamiltonian of the hydrogen atom generated by using STO-3G basis set and parity mapping
Hamiltonian = SparsePauliOp.from_list([("I", -0.2355), ("Z", 0.2355)])

# exact ground state energy of Hamiltonian

A = np.array(Hamiltonian)
eigenvalues, eigenvectors = np.linalg.eig(A)
print(
"The exact ground state energy of the Hamiltonian is ",
min(eigenvalues).real,
"hartree",
)
h = min(eigenvalues.real)
The exact ground state energy of the Hamiltonian is  -0.471 hartree

לאחר מכן, אנחנו צריכים Circuit קוונטי עם פרמטרים, ansatz, להכנת פונקציית גל ניסיונית Ψtrial\Psi_\text{trial} עבור המצב הבסיסי. המטרה היא למצוא את הפרמטרים θ\theta שממזערים את ערך הציפיה של האנרגיה ψ(θ)H^ψ(θ)\langle\psi(\theta)|\hat{H}|\psi(\theta)\rangle. בחירת ה-ansatz היא קריטית מכיוון שהיא קובעת את קבוצת המצבים הקוונטיים האפשריים ש-Circuit שלנו יכול להכין. "ansatz טוב" הוא כזה שגמיש מספיק לייצוג מצב קרוב מאוד למצב הבסיסי האמיתי של ההמילטוניאן שאנחנו חוקרים, אך לא כל כך מורכב שהוא דורש יותר מדי פרמטרים או Circuit עמוק מדי עבור מחשבים קוונטיים נוכחיים.

כאן, ננסה שלושה ansätze חד-Qubit שונים כדי לראות איזה מהם מספק "כיסוי" טוב יותר של המצבים הקוונטיים האפשריים ש-Qubit יחיד יכול להיות בהם. ה"כיסוי" מתייחס לטווח המצבים הקוונטיים ש-Circuit ה-ansatz יכול לייצר על ידי שינוי הפרמטרים שלו.

נשתמש בשלושה ansätze המבוססים על שילובים שונים של Gate סיבוב חד-Qubit:

  • ansatz עם Gate סיבוב חד-ציר אחד: ansatz זה משתמש בסיבובים סביב ציר יחיד בלבד (Rx(θ)R_x(\theta)). על כדור בלוך, זה מתאים לתנועה לאורך מעגל ספציפי בלבד. זהו הגמיש פחות ומכסה קבוצה מוגבלת של מצבים.
  • שני ansätze עם Gate סיבוב דו-ציר: ansätze אלה משלבים סיבובים סביב שני צירים שונים (Rx(θ1)Rz(θ2)R_x(\theta_1) R_z(\theta_2) ו-Rx(θ1)Rz(θ2)Rx(θ3)R_x(\theta_1) R_z(\theta_2) R_x(\theta_3)). זה מאפשר לנו להגיע לחלק גדול יותר של כדור בלוך, בהשוואה לסיבוב חד-ציר.

על ידי השוואת תוצאות VQE שהתקבלו עם שלושת ה-ansätze הללו, נוכל לראות כיצד הגמישות וכיסוי מרחב המצבים של ה-ansatz משפיעים על יכולתנו למצוא את אנרגיית המצב הבסיסי האמיתית של ההמילטוניאן הפשוט שלנו. ansatz גמיש יותר בעל פוטנציאל למצוא קירוב טוב יותר, אך עשוי להיות קשה יותר למייעל הקלאסי.

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import Statevector, DensityMatrix, Pauli

theta = Parameter("θ")
phi = Parameter("φ")
lam = Parameter("λ")

ansatz1 = QuantumCircuit(1)
ansatz1.rx(theta, 0)

ansatz2 = QuantumCircuit(1)
ansatz2.rx(theta, 0)
ansatz2.rz(phi, 0)

ansatz3 = QuantumCircuit(1)
ansatz3.rx(theta, 0)
ansatz3.rz(phi, 0)
ansatz3.rx(lam, 0)
<qiskit.circuit.instructionset.InstructionSet at 0x1059def80>

עכשיו, בוא נייצר 5000 מספרים אקראיים לכל פרמטר ונשרטט את ההתפלגות של מצבים קוונטיים אקראיים, שנוצרו על ידי שלושת ה-ansätze עם הפרמטרים האקראיים הללו. אפשר לחשוב על הפרמטרים האלה כמו סיבובים סביב צירים שונים על פני כדור. כדי לראות את התפלגות המצב הקוונטי, נשתמש בכדור בלוך, כדור תלת-ממדי המציג את מצב Qubit יחיד. כל נקודה על הכדור מייצגת מצב אפשרי של ה-Qubit, כאשר הקטבים הצפוני והדרומי הם כמו ה"0" וה"1" הקלאסיים, אך ה-Qubit יכול גם להיות בכל מקום באמצע, ולהציג תכונות קוונטיות מיוחדות כמו סופרפוזיציה. ראשית, הכן את הפונקציות הנחוצות לשרטוט כדור בלוך התלת-ממדי והכן 5000 פרמטרים אקראיים.

import matplotlib.pyplot as plt

def plot_bloch(bloch_vectors):
# Extract X, Y, Z coordinates for 3D projection
X_coords = bloch_vectors[:, 0]
Z_coords = bloch_vectors[:, 2]

# Compute Y coordinates from X and Z to approximate the full Bloch sphere projection
Y_coords = bloch_vectors[:, 1]

# Create 3D plot
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection="3d")
ax.scatter(X_coords, Y_coords, Z_coords, color="blue", alpha=0.6)

# Labels and title
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Parameterized 1-Qubit Circuit on 3D Bloch Sphere")

# Set axis limits and make them equal
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])

# Ensure equal aspect ratio for all axes
ax.set_box_aspect([1, 1, 1]) # Equal scaling for x, y, z axes

# Show grid
ax.grid(True)

plt.show()

num_samples = 5000 # Number of random states
theta_vals = np.random.uniform(0, 2 * np.pi, num_samples)
phi_vals = np.random.uniform(0, 2 * np.pi, num_samples)
lam_vals = np.random.uniform(0, 2 * np.pi, num_samples)

בוא נראה איך ה-ansatz הראשון שלנו עובד.

# List to store Bloch Sphere XZ coordinates
bloch_vectors = []

# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create a circuit and bind parameters
qc = ansatz1
bound_qc = qc.assign_parameters({theta: theta_vals[i]}) # , lam: lam_vals[i]})
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)

X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components

# Convert to a numpy array for plotting
bloch_vectors = np.array(bloch_vectors)

plot_bloch(bloch_vectors)

Output of the previous code cell

אנחנו יכולים לראות שה-ansatz הראשון שלנו מחזיר מצבים קוונטיים המפוזרים בצורת טבעת על כדור בלוך. זה הגיוני, כי נתנו ל-ansatz פרמטר סיבוב יחיד בלבד. הוא לכן יכול לייצר רק מצבים המסובבים סביב ציר אחד. התחלה מהנקודה (0,0,1)(0,0,1) וסיבוב סביב ציר אחד תניב תמיד טבעת. אחר כך בוא נבדוק את ה-ansatz השני שלנו, שיש לו שני Gate סיבוב ניצבים - Rx ו-Rz.

bloch_vectors = []

# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create circuit and bind parameters
qc = ansatz2
bound_qc = qc.assign_parameters(
{theta: theta_vals[i], phi: phi_vals[i]}
) # , lam: lam_vals[i]})
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)

X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components

# Convert to numpy array for plotting
bloch_vectors = np.array(bloch_vectors)

plot_bloch(bloch_vectors)

Output of the previous code cell

כאן, אנחנו יכולים לראות שה-ansatz השני שלנו מכסה חלק גדול יותר של כדור בלוך - אך שים לב שהנקודות מרוכזות יותר סביב הקטבים ומפוזרות יותר סביב קו המשווה. עכשיו הגיע הזמן לבדוק את ה-ansatz האחרון שלנו.

bloch_vectors = []

# Generate quantum states and extract Bloch vectors
for i in range(num_samples):
# Create circuit and bind parameters
qc = ansatz3
bound_qc = qc.assign_parameters(
{theta: theta_vals[i], phi: phi_vals[i], lam: lam_vals[i]}
)
state = Statevector.from_instruction(bound_qc)
rho = DensityMatrix(state)

X = rho.expectation_value(Pauli("X")).real
Y = rho.expectation_value(Pauli("Y")).real
Z = rho.expectation_value(Pauli("Z")).real
bloch_vectors.append([X, Y, Z]) # Store X, Z components

# Convert to numpy array for plotting
bloch_vectors = np.array(bloch_vectors)

plot_bloch(bloch_vectors)

Output of the previous code cell

כאן אפשר לראות מצבים קוונטיים מפוזרים באופן אחיד יותר שנוצרו על ידי ה-ansatz האחרון שלנו.

כפי שצוין, הדבר הכי טוב לעשות הוא לרכוש ידע על המצב הבסיסי שאתה מחפש ולהשתמש ב-ansatz שמתאים היטב לבדיקת מצבים קרובים למצב הבסיסי הזה. לדוגמה, אם ידענו שהמצב הבסיסי שלנו נמצא ליד קוטב, אולי היינו בוחרים ב-ansatz 2. לפשטות, נישאר עם ansatz 3, שבודק באופן אחיד את כדור בלוך כולו.

עכשיו שבחרנו את ה-ansatz שלנו, בוא נשרטט את ה-Circuit.

# Pre-defined ansatz circuit and operator class for Hamiltonian

ansatz = ansatz3

num_params = ansatz.num_parameters
print("This circuit has ", num_params, "parameters")

ansatz.draw("mpl", style="iqp")
This circuit has  3 parameters

Output of the previous code cell

שלב 2: אופטימיזציה עבור חומרת היעד

כשמריצים חישוב על מחשב קוונטי אמיתי, אנחנו לא רק אכפת לנו מהלוגיקה של ה-Circuit הקוונטי. אנחנו גם אכפת לנו מדברים כמו אילו פעולות יכולות להתבצע על ידי אותו מחשב קוונטי ספציפי, ואיפה על המחשב הקוונטי נמצאים ה-Qubitים שאנחנו משתמשים בהם. האם הם ממש ליד זה? האם הם רחוקים זה מזה? לכן, הצעד הבא הוא לשכתב את ה-Circuit שלנו באמצעות Gate שטבעיים למחשב הקוונטי שנשתמש בו, תוך התחשבות בפריסת ה-Qubitים. ניתן לעשות זאת על ידי transpilation - לאחר תהליך זה, אפשר לראות את ה-ansatz הפשוט שלנו הומר לקבוצה שונה של Gate, וה-Qubitים המופשטים שלנו ימופו ל-Qubitים פיזיים על מחשב קוונטי אמיתי.

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

config = backend.configuration()

print("Backend: {config.backend_name}")
print("Native gates: ", config.supported_instructions, ",")

target = backend.target

pm = generate_preset_pass_manager(target=target, optimization_level=3)

ansatz_isa = pm.run(ansatz)

ansatz_isa.draw(output="mpl", idle_wires=False, style="iqp")
Backend: {config.backend_name}
Native gates: ['ecr', 'id', 'delay', 'measure', 'reset', 'rz', 'sx', 'x'] ,

Output of the previous code cell

אפשר לראות שה-Gate rx, rz של ה-ansatz שלנו הומרו לסדרה של Gate rz, sx, שהם ה-Gate הטבעיים של ה-Backend שלנו. כמו כן, אפשר לראות ש-q0 שלנו ממופה עכשיו ל-Qubit הפיזי החמישי. אנחנו גם צריכים למפות את ההמילטוניאן שלנו בהתאם לשינויים הללו, כפי שמוצג בקוד הבא:

Hamiltonian_isa = Hamiltonian.apply_layout(layout=ansatz_isa.layout)

שלב 3: הרצה על חומרה אמיתית

עכשיו הגיע הזמן להריץ את ה-VQE שלנו על QPU אמיתי. לשם כך, קודם כל אנחנו צריכים פונקציית עלות לתהליך האופטימיזציה, שמחשבת את ערך הציפייה של ה-Hamiltonian עם מצב קוונטי שנוצר על ידי ה-ansatz. אל תדאגו! אתם לא צריכים לקודד הכל בעצמכם. הכנו פונקציה לכך, וכל מה שאתם צריכים לעשות הוא להריץ את התא למטה.

def cost_func(params, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator

Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (EstimatorV2): Estimator primitive instance
cost_history_dict: Dictionary for storing intermediate results

Returns:
float: Energy estimate
"""
pub = (ansatz, [hamiltonian], [params])
result = estimator.run(pubs=[pub]).result()
energy = result[0].data.evs[0]

cost_history_dict["iters"] += 1
cost_history_dict["prev_vector"] = params
cost_history_dict["cost_history"].append(energy)
print(f"Iters. done: {cost_history_dict['iters']} [Current cost: {energy}]")

return energy

לבסוף, אנחנו מכינים פרמטרים ראשוניים עבור ה-ansatz ותהליך האופטימיזציה שלו. אפשר פשוט להשתמש באפסים או בערכים אקראיים. בחרנו פרמטרים ראשוניים למטה, אבל אתם מוזמנים להוסיף או להסיר הערות בתא כדי לדגום פרמטרים באופן אקראי ואחיד מ-0 עד 2π2\pi.

# x0 = np.random.uniform(0, 2*pi, 3)
x0 = [1, 1, 0]
# QPU Est. 2min for ibm_brisbane

from scipy.optimize import minimize
from qiskit_ibm_runtime import Batch

batch = Batch(backend=backend)

cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}
estimator = Estimator(mode=batch)
estimator.options.default_shots = 10000

res = minimize(
cost_func,
x0,
args=(ansatz_isa, Hamiltonian_isa, estimator),
method="cobyla",
options={"maxiter": 10, "tol": 0.01},
)

batch.close()
Iters. done: 1 [Current cost: -0.3361517318448143]
Iters. done: 2 [Current cost: -0.4682546422099432]
Iters. done: 3 [Current cost: -0.38985802144149584]
Iters. done: 4 [Current cost: -0.38319217316749354]
Iters. done: 5 [Current cost: -0.4628720756579032]
Iters. done: 6 [Current cost: -0.4683301936226905]
Iters. done: 7 [Current cost: -0.45480498699294747]
Iters. done: 8 [Current cost: -0.4690533242050814]
Iters. done: 9 [Current cost: -0.465867415110354]
Iters. done: 10 [Current cost: -0.4606882723137227]
h_vqe = res.fun
print("The reference ground state energy is ", min(eigenvalues))
print("The computed ground state energy is ", h_vqe)
The reference ground state energy is  (-0.471+0j)
The computed ground state energy is -0.4690533242050814

כל הכבוד! סיימתם בהצלחה את הניסוי הראשון שלכם בכימיה קוונטית. אנחנו רואים הפרש בין אנרגיית מצב הבסיס המדויקת של ה-Hamiltonian לבין שלנו, אבל מאחר שהשתמשנו בטכניקת מיתון שגיאות ברירת מחדל (שמתקנת שגיאות קריאה), ההפרש קטן. זהו התחלה מצוינת!

הערה: אפשר לקבל תוצאה טובה יותר על ידי הגדרת רמת מיתון שגיאות באמצעות resilience_level. ערך ברירת המחדל הוא 1, ואם מגדירים ערך גבוה יותר, ייעשה שימוש בזמן QPU רב יותר אך ייתכן שיוחזרו תוצאות טובות יותר.

שלב 4: עיבוד לאחר מעשה

הגיע הזמן להסתכל על איך עבד האופטימיזטור הקלאסי שלנו. הרץ את התא למטה וראה את דפוס ההתכנסות.

fig, ax = plt.subplots()
x = np.linspace(0, 10, 10)

# Define the constant function
y_constant = np.full_like(x, h)
ax.plot(
range(cost_history_dict["iters"]), cost_history_dict["cost_history"], label="VQE"
)
ax.set_xlabel("Iterations")
ax.set_ylabel("Cost (Hartree)")
ax.plot(y_constant, label="Target")
plt.legend()
plt.draw()

Output of the previous code cell

התחלנו עם ערך ראשוני טוב למדי, כך שקיבלנו ערך סופי טוב בסה"כ ב-10 צעדים. אפשר לראות פסגות גדולות וקטנות, וזו התכונה האופיינית של אופטימיזטור COBYLA — הוא חוקר את המרחב כאילו אינו יכול לראות את הנוף ומתאים את גדלי הצעד עם כל מדידה.

בדוק את ההבנה שלך

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

תשובה:

הדבר הראשון לשקול הוא שינוי בסט הבסיסים המשמש לחישוב ה-Hamiltonian של המולקולות. כפי שהוזכר קודם, אנרגיית מצב הבסיס של אטום H היא ‎-0.5 Hartree, כידוע, ובסיס STO-6G שבחרנו אינו מספיק כדי לגזור ערך זה בדייקנות.

בחירת סוג בסיס מורכב יותר מגדילה את מספר ה-Qubits שבהם משתמש ה-Hamiltonian; לכן, אנחנו צריכים לבחור ansatz מורכב ומתאים יותר לבעיות כימיה.

הבא לאופטימיזציה הוא ניהול הרעש ב-QPU. טכניקות מיתון שגיאות מתקדמות יותר מניבות תוצאות טובות יותר אך עשויות לקחת יותר זמן לשימוש. כמו כן, כדאי לשקול כיצד shot_number משפיע על התוצאות.

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

חישוב אנרגיית מצב הבסיס של מולקולת המימן עם VQE

עכשיו שהסתכלנו על התהליך הכולל של VQE באמצעות אטומי HH, נחשב את אנרגיית מצב הבסיס של מולקולת H2H_2 בצורה מהירה יותר.

שלב 1: מיפוי הבעיה ל-Circuits ואופרטורים

כאן אנחנו גם מספקים לכם Hamiltonian חד-Qubit שמשתמש בבסיס STO-6G ובהמרת Jordan-Wigner, עם הפחתת Qubit באמצעות סימטריה של ה-Hamiltonian. שימו לב שהשתמשנו במרחק אטומי בין שני אטומי מימן של 0.735 A˚\mathring A.

שלא כמו בחישוב של אטום מימן יחיד (HH), כדי לחשב את מצב הבסיס של מולקולת מימן (H2H_2), אנחנו חייבים לשקול גם את הכוח הדוחה הפועל בין הגרעינים של שני אטומי המימן, בנוסף לאנרגיה הקשורה לאורביטלים האלקטרוניים. בשלב זה, נתן ערך זה כקבוע, ובפועל נחשב ערך זה בשאלת הביניים. H^=1.04886I+0.79674Z+0.18122X\hat{H} = -1.04886 I + -0.79674 Z + 0.18122 X

h2_hamiltonian = SparsePauliOp.from_list(
[("I", -1.04886087), ("Z", -0.7967368), ("X", 0.18121804)]
)

# exact ground state energy of hamiltonian
nuclear_repulsion = 0.71997
A = np.array(h2_hamiltonian)
eigenvalues, eigenvectors = np.linalg.eig(A)
print("Electronic ground state energy (Hartree): ", min(eigenvalues).real)
print("Nuclear repulsion energy (Hartree): ", nuclear_repulsion)
print(
"Total ground state energy (Hartree): ", min(eigenvalues).real + nuclear_repulsion
)
h2 = min(eigenvalues).real + nuclear_repulsion
Electronic ground state energy (Hartree):  -1.8659468547627318
Nuclear repulsion energy (Hartree): 0.71997
Total ground state energy (Hartree): -1.1459768547627318

שלב 2: אופטימיזציה עבור חומרת היעד

מאחר שמספר ה-Qubits שבהם משתמשים ה-VQE וה-Hamiltonian הקודמים זהה ל-Backend שישמש להרצה, נשתמש ב-ansatz הקיים ובצורתו האופטימית.

h2_hamiltonian_isa = h2_hamiltonian.apply_layout(layout=ansatz_isa.layout)

שלב 3: הרצה על חומרה אמיתית

עכשיו הגיע הזמן לבצע את החישובים על QPU אמיתי. כמעט הכל זהה, אך נשתמש בנקודת התחלה מתאימה להתאמה ל-Hamiltonian. כמו כן, בחלק האיטרטיבי, חלק מהגדרות ה-Estimator, המשמש לחישוב ציפיות ה-Hamiltonian עבור ה-ansatz ב-QPU, יוגדרו מעט שונה מהחישובים הקודמים. נדון בשינוי זה עוד בשאלת הביניים.

x0 = [2, 0, 0]
# QPU time 4min for ibm_brisbane
batch = Batch(backend=backend)

cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}
estimator = Estimator(mode=batch)
estimator.options.default_shots = 10000

res = minimize(
cost_func,
x0,
args=(ansatz_isa, h2_hamiltonian_isa, estimator),
method="cobyla",
options={"maxiter": 15},
)

batch.close()
Iters. done: 1 [Current cost: -0.710621837568328]
Iters. done: 2 [Current cost: -0.2603208441168329]
Iters. done: 3 [Current cost: -0.25548711201326424]
Iters. done: 4 [Current cost: -0.581129450619904]
Iters. done: 5 [Current cost: -1.722920997605439]
Iters. done: 6 [Current cost: -1.6633324849371915]
Iters. done: 7 [Current cost: -1.8066989598929164]
Iters. done: 8 [Current cost: -1.8051093803839542]
Iters. done: 9 [Current cost: -1.802692217571555]
Iters. done: 10 [Current cost: -1.8233585485263144]
Iters. done: 11 [Current cost: -1.6904116652617205]
Iters. done: 12 [Current cost: -1.8245120321245392]
Iters. done: 13 [Current cost: -1.6837021361383608]
Iters. done: 14 [Current cost: -1.8166632606115467]
Iters. done: 15 [Current cost: -1.863446212658907]
h2_vqe = res.fun + nuclear_repulsion
print(
"The reference ground state energy is ", min(eigenvalues).real + nuclear_repulsion
)
print("The computed ground state energy is ", h2_vqe)
The reference ground state energy is  -1.1459768547627318
The computed ground state energy is -1.143476212658907

למרות ש-VQE מספק תיאורטית גבול עליון לאנרגיית מצב הבסיס האמיתית, מימושים מעשיים על חומרה קוונטית אמיתית או על סימולציה רועשת, כמו גם הפשטות שנעשות בהכנת ה-Hamiltonian (כמו סטי בסיסים או הפחתת Qubit), עלולות להכניס שגיאות שלפעמים מביאות לאנרגיה מדודה הנמוכה מעט מהערך התיאורטי המדויק או ממסמך ייחוס מספרי ספציפי. למרות שיש כמה שגיאות, התוצאות נראות מספקות, במיוחד לאור מספר הצעדים הקטן. עכשיו, בואו נסיים את חישוב ה-VQE הזה על ידי הסתכלות על איך עבד האופטימיזטור.

שלב 4: עיבוד לאחר מעשה

fig, ax = plt.subplots()
x = np.linspace(0, 5, 15)

# Define the constant function
y_constant = np.full_like(x, min(eigenvalues))
ax.plot(
range(cost_history_dict["iters"]), cost_history_dict["cost_history"], label="VQE"
)
ax.set_xlabel("Iterations")
ax.set_ylabel("Cost (Hartree)")
ax.plot(y_constant, label="Target")
plt.legend()
plt.draw()

Output of the previous code cell

בדוק את ההבנה שלך

בואו נחשב את אנרגיית הדחייה הגרעינית של מולקולת H2H_2, שכללנו כערך קבוע (0.71997 Hartree).

H2 molecule

אנא השתמש בחוק קולון ובמערכת יחידות אטומיות כדי לוודא שאתה מקבל את הערך ב-Hartree.

תשובה:

מאחר ששני גרעיני המימן טעונים חיובית, הם דוחים זה את זה בגלל הכוח האלקטרוסטטי. דחייה זו מתוארת על ידי חוק קולון:

Erepulsive=e24πϵ0RE_{repulsive} = \frac{e^2}{4\pi\epsilon_0R},

כאשר ee הוא מטען הפרוטון, ϵ0\epsilon_0 הוא מאפשרות הוואקום, ו-RR הוא המרחק בין שני הגרעינים, נמדד במטרים או ברדיוסי Bohr ביחידות ג'ול (J).

כדי לחשב אנרגיה זו ב-Hartrees, אנחנו צריכים להמיר את המשוואה לעיל למערכת יחידות אטומיות (AU). ב-AU, e2=1e^2 = 1, 4πϵ0=14\pi\epsilon_0=1 ורדיוס Bohr (a0a_0) הוא 1 והופך לסקלת האורך הבסיסית ב-AU. עם פישוטים אלו, חוק קולון מצטמצם ל:

Erepulsion=1RE_{repulsion} = \frac{1}{R},

כאשר RR חייב להיות נמדד ברדיוסי Bohr (a0a_0).

כדי להמיר את הפרדת הגרעינים הנתונה ב-A˚\r{A} ל-a0a_0, אנחנו צריכים יחס המרה זה:

1A˚=1.88973a01\r{A} = 1.88973 a_0

לכן 0.735A˚0.735\r{A} הופך ל-0.7351.88973=1.38895a00.735 * 1.88973 = 1.38895 a_0.

לפיכך, אנרגיית הדחייה הגרעינית של H2H_2 הנתון היא

Erepulsion=1R=11.38895=0.71997HartreeE_{repulsion} = \frac{1}{R} = \frac{1}{1.38895} = 0.71997 Hartree

חישוב אנרגיית הריאקציה של H+H=H2H + H = H_2

עכשיו בואו נשתמש במה שהשגנו! השתמשת ב-VQE, פותר ערכים עצמיים קוונטי ורציאציוני, כדי לחשב את אנרגיית המצב הבסיסי של אטום HH ושל מולקולת H2H_2. מה שנותר הוא להשתמש בערכים שחישבנו כדי לקבל את אנרגיית הריאקציה של התהליך H+H=H2H+H=H_2.

אנרגיית ריאקציה היא שינוי האנרגיה שקורה כאשר חומרים מגיבים ויוצרים חומרים חדשים. תדמייני שאת בונה משהו: לפעמים צריך להשקיע אנרגיה (כמו לערום קוביות), ולפעמים אנרגיה משתחררת (כמו כדור שמתגלגל במורד הגבעה). בכימיה, תגובות הן או בולעות אנרגיה (אנדותרמיות) או משחררות אנרגיה (אקסותרמיות).

ניתן לחשב את אנרגיית הריאקציה של התהליך H+H=H2H+H = H_2 לפי הנוסחה הבאה:

Ereaction=EH2(EH+EH)E_{reaction} = E_{H_2} - (E_H + E_H)

על ידי הרצת התא למטה, בואו נראה את זה בצורה ויזואלית. כאן נשתמש בערך המצב הבסיסי המדויק של כל האמילטוניאן, ונשווה את אנרגיית הריאקציה של הפתרון המדויק ושל תוצאות VQE.

# Theoretical values
E_H_theo = h.real
E_H2_theo = h2

# Experimental values
E_H_exp = h_vqe
E_H2_exp = h2_vqe

# Calculate reaction energies
E_reaction_theo = E_H2_theo - (2 * E_H_theo)
E_reaction_exp = E_H2_exp - (2 * E_H_exp)

# Set up the plot
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_xlim(0, 3)
ax.set_ylim(-1.16, -0.93) # Adjust y-axis range to highlight differences
ax.set_xticks([])
ax.set_ylabel("Energy (Hartree)")
ax.set_title("H + H → H₂ Reaction Energy Diagram")

# Plot theoretical energy levels
ax.hlines(
y=2 * E_H_theo, xmin=0.5, xmax=1.3, linewidth=2, color="r", label="2H (Exact)"
)
ax.hlines(y=E_H2_theo, xmin=1.3, xmax=2, linewidth=2, color="b", label="H₂ (Exact)")

# Plot experimental energy levels
ax.hlines(
y=2 * E_H_exp,
xmin=0.5,
xmax=1.5,
linewidth=2,
color="r",
linestyle="dashed",
label="2H (VQE)",
)
ax.hlines(
y=E_H2_exp,
xmin=1.5,
xmax=2.5,
linewidth=2,
color="b",
linestyle="dashed",
label="H₂ (VQE)",
)

# Add labels
ax.text(
1,
2 * E_H_theo,
f"2H: {2*E_H_theo:.4f}",
verticalalignment="top",
horizontalalignment="left",
)
ax.text(
2,
E_H2_theo,
f"H₂: {E_H2_theo:.4f}",
verticalalignment="top",
horizontalalignment="left",
)
ax.text(
1,
2 * E_H_exp,
f"2H_VQE: {2*E_H_exp:.4f}",
verticalalignment="bottom",
horizontalalignment="right",
)
ax.text(
2,
E_H2_exp,
f"H₂_VQE: {E_H2_exp:.4f}",
verticalalignment="bottom",
horizontalalignment="right",
)

# Add arrows for reaction energy with ΔE label in the middle
mid_y_theo = (2 * E_H_theo + E_H2_theo) / 2
mid_y_exp = (2 * E_H_exp + E_H2_exp) / 2
ax.annotate(
"",
xy=(1.3, E_H2_theo),
xytext=(1.3, 2 * E_H_theo),
arrowprops=dict(arrowstyle="<->", color="g"),
)
ax.text(
1.35, mid_y_theo, f"ΔE: {E_reaction_theo:.4f}", color="g", verticalalignment="top"
)

ax.annotate(
"",
xy=(1.5, E_H2_exp),
xytext=(1.5, 2 * E_H_exp),
arrowprops=dict(arrowstyle="<->", color="g", linestyle="dashed"),
)
ax.text(
1.55,
mid_y_exp,
f"ΔE_VQE: {E_reaction_exp:.4f}",
color="g",
verticalalignment="center",
)

# Add legend
ax.legend()

plt.show()

Output of the previous code cell

כפי שמוצג באיור, למרות שיש כמה שגיאות, אנרגיית המצב הבסיסי המדויקת של האמילטוניאנים ואנרגיית הריאקציה שחושבה בעזרת תוצאות VQE דומות, קרובות ל-0.2- Hartree.

ראוי לציין כאן שאנרגיית הריאקציה של תהליך זה היא שלילית, מה שאומר שאנרגיה משתחררת במהלך התהליך, והמולקולה שנוצרת בעלת אנרגיה נמוכה יותר משני אטומים בודדים. 6. סיכום

בואו נסכם את מה שלמדנו עד כה.

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

לאחר מכן חקרנו את VQE, אלגוריתם נפוץ לחישוב אנרגיית המצב הבסיסי של מערכת קוונטית. הרצנו קוד לחישוב אנרגיות המצב הבסיסי של מימן אטומי (HH) ושל מולקולת המימן (H2H_2). בפרט, למדנו שיש צורך לקבל את האמילטוניאן המולקולרי המתאים למערכת ולהמיר אותו לצורה שניתן להריץ על מחשב קוונטי. ראינו גם שה-ansatz, Circuit קוונטי עם פרמטרים, נדרש להכנת מצבי גלים קוונטיים ניסיוניים בתוך VQE, ודנו בחשיבות בחירת מבנה Circuit ה-ansatz המתאים. למדנו גם שVQE מסתמך על תהליך אופטימיזציה איטרטיבי תוך שימוש במחשב קלאסי, המנחה את ה-Circuit הקוונטי למצוא את מצב האנרגיה הנמוכה ביותר, וראינו כיצד התהליך מתכנס.

לבסוף, השתמשנו באנרגיות המצב הבסיסי המחושבות של HH ו-H2H_2 שהתקבלו דרך VQE כדי לחשב את אנרגיית הריאקציה עבור התהליך H+HH2H + H \rightarrow H_2.

VQE הוא אלגוריתם קוונטי עוצמתי לטווח הקרוב, אך חשוב להיות מודעים למגבלותיו. הביצועים של VQE תלויים מאוד בבחירת ה-ansatz — מציאת ansatz שניתן להכין ביעילות ויכול לייצג במדויק את המצב הבסיסי האמיתי הופכת מאתגרת יותר עבור מולקולות גדולות ומורכבות יותר. יתר על כן, חומרה קוונטית נוכחית רגישה לרעש, מה שיכול להשפיע על דיוק תוצאות VQE, במיוחד עבור Circuits עמוקים יותר או מספרים גדולים יותר של Qubits. למרות האתגרים האלה, VQE משמש כאלגוריתם בסיסי, ומחקר מתמשך חוקר שיטות ורציאציוניות מתוחכמות יותר וטכניקות הפחתת שגיאות כדי לדחוף את גבולות האפשרי בכימיה קוונטית על מחשבים קוונטיים לטווח הקרוב. למשל, אלגוריתמים כמו Sample-based Quantum Diagonalization (SQD) מפותחים כיום, שמנצלים דגימות שהתקבלו מ-Circuits קוונטיים בשילוב עם אלכסוניזציה קלאסית בתת-מרחב כדי לשפר את הערכת האנרגיה ולטפל בחלק מהמגבלות שVQE מתמודד איתן, במיוחד בנוגע ליעילות המדידה ועמידות ברעש.

סקירה ושאלות

מושגים מרכזיים:

  • אלגוריתם קוונטי ורציאציוני הוא פרדיגמת חישוב שבה מחשב קלאסי ומחשב קוונטי עובדים יחד לפתרון בעיה.
  • ב-VQE, אנחנו מתחילים עם האמילטוניאן של המערכת שלנו וממפים אותו ל-Qubits להרצה על המחשב הקוונטי. אנחנו בוחרים Circuit קוונטי עם פרמטרים, ansatz, ועושים מדידות חוזרות, משנים את הפרמטרים של ה-ansatz, עד שמגיעים לערך האנרגיה הנמוך ביותר. החיפוש במרחב הפרמטרים נעשה בעזרת אופטימייזר קלאסי. כדי להשיג תוצאות טובות, יש לבחור ansatz טוב ואופטימייזר מתאים.
  • אנרגיית ריאקציה היא שינוי האנרגיה הכולל בתגובה כימית, הנקבע על ידי ההפרש בין אנרגיית המגיבים לאנרגיית התוצרים.

נכון/לא נכון

  1. עקרון הווריאציה קובע שערך הציפייה של האנרגיה עבור כל פונקציית גל ניסיונית הוא תמיד גדול מאנרגיית המצב הבסיסי האמיתי או שווה לה.
  2. ערכת בסיס היא אוסף של פונקציות המשמשות לקירוב פונקציות גל קוונטיות.
  3. VQE הוא אלגוריתם קוונטי המשמש לפתרון מדויק של משוואת שרדינגר עבור האמילטוניאן נתון.
  4. ב-VQE, Circuit קוונטי עם פרמטרים (ansatz) משמש להכנת פונקציות גל ניסיוניות.
  5. בחירת האופטימייזר ב-VQE (למשל, COBYLA, SPSA, או ADAM) אינה משפיעה על איכות התוצאה.
  6. ה-Estimator של Qiskit משמש לחישוב ישיר של ערכי ציפייה של אמילטוניאנים ב-VQE.

שאלות רב-ברירה:

  1. מה המטרה של האמילטוניאן ב-VQE?
  • א) ליצור מצבים קוונטיים אקראיים
  • ב) לקבוע את האנרגיה של מצבים קוונטיים
  • ג) לאופטמז Circuit קוונטי
  • ד) ליצור שזירה
  1. מה המטרה העיקרית של אלגוריתם VQE?
  • א) למצוא את אנרגיית המצב הבסיסי של האמילטוניאן
  • ב) ליצור שזירה בין Qubits
  • ג) לבצע את חיפוש גרובר
  • ד) לשבור את הצפנת RSA
  1. כמה מצבים קוונטיים נוצרים ב-notebook זה להשוואת ה-ansatz?
  • א) 100
  • ב) 1000
  • ג) 5000
  • ד) 10,000
  1. מדוע נדרש אופטימייזר קלאסי ב-VQE?
  • א) לביצוע מדידות קוונטיות
  • ב) לעדכן פרמטרי ansatz כדי למזער אנרגיה
  • ג) לשזור Qubits
  • ד) ליצור אקראיות קוונטית
  1. מדוע ה-ansatz מתוכנן להיות עם פרמטרים?
  • א) כדי לאפשר הכנת מצב קוונטי
  • ב) כדי לאפשר חיפוש במרחב רחב של מצבים קוונטיים
  • ג) כדי לצמצם את מורכבות ה-Circuit
  • ד) כדי למדוד ערכים עצמיים ישירות
  1. מה ההצהרה הנכונה ביותר לגבי בחירת ansatz טוב?
  • א) ansatz חייב לייצר מצבים מפוזרים באופן שווה על כדור בלוך, אחרת הוא ייכשל.
  • ב) ansatz צריך להיות מותאם למערכת שלך כדי לוודא שהוא יכול לייצר מצבים קרובים למצב הבסיסי.
  • ג) ansatz צריך לייצר מצבים אקראיים באמצעות הפרמטרים הורציאציוניים שלו.
  • ד) ansatz טוב יותר תמיד כולל יותר פרמטרים ורציאציוניים.

(אופציונלי) נספח: עומס האופטימייזר לפי מורכבות ה-ansatz

VQE מתמודד עם כמה אתגרים ידועים[ref 6], והבאים קשורים למה שלמדנו למעלה.

  1. אתגרי בחירת ansatz

קיים אתגר מובנה בבחירת ה-ansatz הורציאציוני הנכון. ansätze בהשראת כימיה (כמו UCCSD) מספקים דיוק פיזי אך דורשים Circuits עמוקים, בעוד ansätze יעילים לחומרה הם Circuits רדודים יותר אך עשויים לחסור פרשנות פיזית. כמו כן, ansätze רבים מציגים פרמטרים ורציאציוניים מיותרים שתורמים מעט לשיפור הדיוק אך מגדילים משמעותית את קושי האופטימיזציה.

  1. קשיי אופטימיזציה

נוף האופטימיזציה של VQE יכול לכלול אזורים שבהם גרדיאנטים פוחתים באופן אקספוננציאלי (רמות שטוחות — barren plateaus), מה שמקשה על אופטימייזרים קלאסיים לעדכן את הפרמטרים הורציאציוניים ביעילות. לשם כך, חוקרים ניסו להשתמש בסוגים שונים של אופטימייזרים — מבוססי גרדיאנט וחופשיים מגרדיאנט — אך שניהם מתמודדים עם אתגרים. אופטימייזרים מבוססי גרדיאנט סובלים מרמות שטוחות, בעוד שיטות חופשיות מגרדיאנט דורשות מספר רב של הערכות פונקציה.

  1. עומס האופטימייזר

אתגר ידוע נוסף הוא עומס האופטימייזר, שקשור לגודל הבעיה. ה-Circuits הקוונטיים הנדרשים ל-VQE גדלים בעומק ובמורכבות ככל שגודל הבעיה גדל; זה בדרך כלל גם מגדיל את מספר הפרמטרים לאופטימיזציה. תהליך האופטימיזציה הופך בלתי-ניתן לביצוע ככל שמספר הפרמטרים גדל, מה שמוביל להתכנסות איטית ולקשיים במציאת הפתרון האופטימלי.

כאן נבחן את האתגרים האלה על ידי שימוש ב-VQE עבור מולקולת H2H_2, עם שני סוגים שונים של ansätze.

(הערה: זה עשוי לקחת יותר זמן QPU, אז אל תהסס להשתמש בסימולטור אם אין לך מספיק זמן.)

from qiskit.circuit import ParameterVector

num_iter = 4
alpha = ParameterVector("alpha", 3)
beta = ParameterVector("beta", 3 * num_iter)

# step1: Map problem to quantum circuits and operators
hamiltonian = SparsePauliOp.from_list(
[("I", -1.04886087), ("Z", -0.7967368), ("X", 0.18121804)]
)

ansatz_1 = ansatz3
ansatz_2 = QuantumCircuit(1)
for i in range(num_iter):
ansatz_2.rx(beta[i * 3 + 0], 0)
ansatz_2.rz(beta[i * 3 + 1], 0)
ansatz_2.rx(beta[i * 3 + 2], 0)
ansatz_1.draw("mpl")

Output of the previous code cell

ansatz_2.draw("mpl")

Output of the previous code cell

# Step 2: Optimize for target hardware

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)

ansatz_isa_1 = pm.run(ansatz_1)
ansatz_isa_2 = pm.run(ansatz_2)
hamiltonian_isa_1 = hamiltonian.apply_layout(layout=ansatz_isa_1.layout)
hamiltonian_isa_2 = hamiltonian.apply_layout(layout=ansatz_isa_2.layout)

עכשיו בואו נריץ VQE עם נקודת התחלה של כולם אחד, עם מקסימום 20 צעדים, ונשווה את ההתכנסות של שני הריצות.

# QPU time 3m 40s for ibm_brisbane
# Step 3: Execute on target hardware

from scipy.optimize import minimize

x0 = np.ones(ansatz_1.num_parameters)

batch = Batch(backend=backend)

cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}
estimator = Estimator(mode=batch)
estimator.options.default_shots = 2048

res = minimize(
cost_func,
x0,
args=(ansatz_isa_1, hamiltonian_isa_1, estimator),
method="cobyla",
options={"maxiter": 20},
)

batch.close()
Iters. done: 1 [Current cost: -0.8782202668652658]
Iters. done: 2 [Current cost: -0.43473160695469165]
Iters. done: 3 [Current cost: -0.4076372093159749]
Iters. done: 4 [Current cost: -1.3587839859772106]
Iters. done: 5 [Current cost: -1.774529906754082]
Iters. done: 6 [Current cost: -1.541934983115727]
Iters. done: 7 [Current cost: -1.2732403113465345]
Iters. done: 8 [Current cost: -1.820842221085785]
Iters. done: 9 [Current cost: -1.8065762857059005]
Iters. done: 10 [Current cost: -1.8126394095981146]
Iters. done: 11 [Current cost: -1.8205831886180421]
Iters. done: 12 [Current cost: -1.8086715778994924]
Iters. done: 13 [Current cost: -1.8307676638629322]
Iters. done: 14 [Current cost: -1.8177328827556327]
Iters. done: 15 [Current cost: -1.8179426218088064]
Iters. done: 16 [Current cost: -1.8109239667991088]
Iters. done: 17 [Current cost: -1.824271872489647]
Iters. done: 18 [Current cost: -1.813167587671394]
Iters. done: 19 [Current cost: -1.824647343397313]
Iters. done: 20 [Current cost: -1.8219785311686143]
# Save Cost_history as a new list
ansatz_1_history = cost_history_dict["cost_history"]
# QPU time 3m 40s for ibm_brisbane

x0 = np.ones(ansatz_2.num_parameters)

batch = Batch(backend=backend)

cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}
estimator = Estimator(mode=batch)
estimator.options.default_shots = 2048

res = minimize(
cost_func,
x0,
args=(ansatz_isa_2, hamiltonian_isa_2, estimator),
method="cobyla",
options={"maxiter": 20},
)

batch.close()
Iters. done: 1 [Current cost: -0.738191173881188]
Iters. done: 2 [Current cost: -0.42636037194506304]
Iters. done: 3 [Current cost: -1.3503788613797374]
Iters. done: 4 [Current cost: -0.9109204349776897]
Iters. done: 5 [Current cost: -0.9060873157510835]
Iters. done: 6 [Current cost: -0.7735065414083984]
Iters. done: 7 [Current cost: -1.586889197437709]
Iters. done: 8 [Current cost: -1.659215191584943]
Iters. done: 9 [Current cost: -1.245445981794618]
Iters. done: 10 [Current cost: -1.1608385766138023]
Iters. done: 11 [Current cost: -1.1551733876027737]
Iters. done: 12 [Current cost: -1.8143337768286332]
Iters. done: 13 [Current cost: -1.2510951563756598]
Iters. done: 14 [Current cost: -1.6918311531865413]
Iters. done: 15 [Current cost: -1.8163783305531838]
Iters. done: 16 [Current cost: -1.8434877732947152]
Iters. done: 17 [Current cost: -1.8461898233304472]
Iters. done: 18 [Current cost: -1.0346471214915485]
Iters. done: 19 [Current cost: -1.8322518854150687]
Iters. done: 20 [Current cost: -1.717144678705999]
ansatz_2_history = cost_history_dict["cost_history"]
fig, ax = plt.subplots()

# Define the constant function)
ax.plot(
range(cost_history_dict["iters"]),
ansatz_1_history,
label="Ansatz with 3 parameters",
)
ax.plot(
range(cost_history_dict["iters"]),
ansatz_2_history,
label="Ansatz with 12 parameters",
)
ax.set_xlabel("Iterations")
ax.set_ylabel("Cost (Hartree)")
plt.legend()
plt.draw()

Output of the previous code cell

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

במקום להסתמך על Circuits פשוטים של Qubit בודד ו-ansatz ישיר, מורכבות האופטימיזציה גדלה כאשר נדרשים Circuits קוונטיים גדולים יותר ו-ansätze בנויים במבנה מורכב יותר. זה מדגיש אתגר ידוע ב-VQEs: עומס האופטימייזר.

חוקרים ממשיכים לפתח מתודולוגיות מתקדמות שונות שיכולות להשתמש במחשבים קוונטיים לבעיות כימיה. ניתן לגשת למגוון חומרי לימוד ב-IBM Quantum Learning.

מקורות

  • [ref 1 ] Richard P. Feynman, Simulating Physics with Computers, International Journal of Theoretical Physics, 1982.
  • [ref 2] Marov, M.Y. (2015). The Structure of the Universe. In: The Fundamentals of Modern Astrophysics. Springer, New York, NY.
  • [ref 3] How to solve difficult chemical engineering problems with quantum computing, IBM Research Blog, 2023.
  • [ref 4] Y. Cao, J. Romero and A. Aspuru-Guzik, "Potential of quantum computing for drug discovery," in IBM Journal of Research and Development, vol. 62, no. 6, pp. 6:1-6:20, 1 Nov.-Dec. 2018
  • [ref 5] Present State of Molecular Structure Calculation, REv. Mod. Phys. 32, 170, 1960
  • [ref 6] Fedorov, D.A., Peng, B., Govind, N. et al. VQE method: a short survey and recent developments. Mater Theory 6, 2 (2022)