איך החבילה הזו קשורה ל-ffsim
המושגים במדריך הזה זמינים רק ב-Python API.
ffsim והחבילה הזו מתחלקות בעבודה ולא חופפות, לאורך קו אחד:
| ffsim אחראית על | qiskit-fermions אחראית על |
|---|---|
אופרטורי האנזץ ברמה גבוהה (UCJOpSpinBalanced, UCCSDOpRestrictedReal ואחיהם), הבנויים מאמפליטודות coupled-cluster או מווקטור פרמטרים | המעגל הפרמיוני (FermionicCircuit) שהאופרטורים האלה הופכים אליו, והטרנספילציה שלו למעגל קיוביטים תחת כל קידוד מפרמיון לקיוביט |
| סימולציה מהירה במרחב קומפקטי של מספר חלקיקים קבוע | מסגרת ה-mapper ומבני הנתונים של האופרטורים שמהם המעגל בנוי |
ההשלכה המעשית פועלת לשני הכיוונים. המתמטיקה של האנזץ נמצאת ב-ffsim, ולכן UCJ ו-UCC מקבלים אופרטור ffsim ישירות כקלט. מנגד, שערי Qiskit של ffsim עצמה ספציפיים לטרנספורמציית Jordan-Wigner, ולכן הורדת אחד מאופרטורי האנזץ שלה דרך קידוד אחר היא מה שהבאתו לכאן קונה לכם.
סימולציה היא המקום שבו השתיים נפגשות, והמדריך הזה מסביר איך. ffsim היא ה-Backend לסימולציה של החבילה הזו, ומגיעים אליה דרך הפרוטוקולים שלה עצמה ולא דרך עטיפה: מדריך SKQD קורא ל-ffsim.apply_unitary(), ל-ffsim.linear_operator() ול-ffsim.sample_state_vector() ישירות על אובייקטי FermionicCircuitועל אובייקטי FermionOperatorללא שלב המרה.
התחברות לממשק הסימולציה של ffsim
ffsim היא סימולטור בעל ביצועים גבוהים למעגלים קוונטיים פרמיוניים, שמנצל שימור של מספר חלקיקים ושל ספין-Z כדי לייצג וקטורי מצב בצורה קומפקטית יותר מוקטור מצב גנרי של קיוביטים במימד . היא מגדירה פרוטוקולים שכל אובייקט יכול לממש כדי להשתתף במנגנון הסימולציה שלה (ראו qiskit_fermions.protocols עבור הפרוטוקולים של החבילה הזו עצמה, שעוקבים אחר אותו עיצוב):
-
ffsim.SupportsApplyUnitary, באמצעות המתודה_apply_unitary_(vec, norb, nelec, copy), שמפעילה את האובייקט כאוניטרי על וקטור מצב של מספר חלקיקים קבוע -
ffsim.SupportsLinearOperator, באמצעות המתודה_linear_operator_(norb, nelec), שמחזירה מבט של האובייקט כ-scipy.sparse.linalg.LinearOperatorעל אותו סקטור -
ffsim.SupportsTrace, באמצעות המתודה_trace_(norb, nelec), שמחזירה את העקבה של האובייקט על אותו סקטור.
החבילה הזו מממשת את הממשק הזה: כל שער פרמיוני ב-qiskit_fermions.circuit.library מספק _apply_unitary_, ו-FermionOperator מספק _linear_operator_ ו-_trace_. זה מה שהופך את האופרטורים והמעגלים של החבילה הזו לתואמים ל-ffsim, כך שהכלים שלה עובדים עליהם באופן טבעי, בלי שלב המרה. ffsim.apply_unitary() יכול לסמלץ FermionicCircuit מקצה לקצה, ffsim.linear_operator() יכול לאלכסן FermionOperator, וכלי דגימה כמו ffsim.sample_state_vector() (בשימוש במדריך SKQD כדי להפוך וקטור מצב מסומלץ לספירות מדידה) עובדים ללא שינוי.
מה ש-_linear_operator_ מחזיר הוא LinearOperator רגיל של SciPy, ולכן scipy.sparse.linalg.eigsh() וחבריה עובדים עליו גם כן.
>>> import ffsim
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> norb, nelec = 2, (1, 1)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(1)], 0.5),
... ([cre(1), ann(0)], 0.5),
... ])
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(Evolution(2 * norb, hamiltonian, time=1.0), circuit.modes)
>>>
>>> reference = ffsim.hartree_fock_state(norb, nelec)
>>> state = ffsim.apply_unitary(reference, circuit, norb=norb, nelec=nelec) # native ffsim call
החיבור דרך הפרוטוקולים של ffsim הוא מה שקונה את זה: האקוסיסטם המתפתח באופן פעיל שלה של כלי סימולציה ודגימה חל על המעגלים והאופרטורים של החבילה הזו ללא שינוי, ומשתמשים שכבר עובדים עם ffsim יכולים לשלב את השערים והאופרטורים של החבילה הזו בלי ללמוד ממשק סימולציה נוסף.
ffsim היא תלות אופציונלית
ffsim מוצהרת כתוספת אופציונלית (pip install "qiskit-fermions[ffsim]", או בעקיפין על ידי [all]), ומוגנת בזמן ריצה על ידי HAS_FFSIM (כפי שהוצג למעלה). התקנתה פותחת את הסימולציה: ffsim.SupportsLinearOperator ו-ffsim.SupportsTrace ממומשים על ידי המרת FermionOperator של החבילה הזו ל-ffsim.FermionOperator, ולכן בלי ffsim הם זורקים MissingOptionalLibraryError. כל מה שלא מסמלץ (בניית אופרטורים, מיפוים, וטרנספילציה של המעגלים שמתקבלים) לא צריך אותה בכלל.
סימולציה פרמיונית חיה בסקטור של מספר חלקיקים קבוע
גם _apply_unitary_ וגם _linear_operator_ מקבלים ארגומנט nelec ומייצגים את וקטור המצב מעל בסיס הדטרמיננטות של מספר חלקיקים קבוע עבור הסקטור (norb, nelec) הזה, בהתאם להגדרת מרחב ה-FCI של ffsim (ובעקיפין של PySCF), ולא מעל המרחב המלא במימד שסימולטור קיוביטים כללי היה משתמש בו. זה מרחב קטן בהרבה (גודלו הוא מכפלה של מקדמים בינומיים ולא חזקת שתיים), אבל הוא מגיע עם הגבלה נוקשה. רק אופרטורים ושערים ששומרים על מספר החלקיקים (ובמקרה בעל הספין, על מספר החלקיקים של כל מין ספין בנפרד) אפשר לייצג בו. לאופרטור שפעולתו הייתה מעבירה אמפליטודה למספר חלקיקים אחר אין לאן לשים אותה.
ffsim פותרת את זה בדחיית אופרטור כזה על הסף: המרה שלו לאופרטור לינארי זורקת ValueError שמציין איזה חוק שימור נכשל. זו ברירת המחדל הנכונה, כי הפעלת עבור המילטוניאן עם איבר שלא שומר על מספר החלקיקים הייתה הופכת מה שהיה אמור להיות אוניטרי למפה לא אוניטרית וחסרת משמעות פיזיקלית.
-
Evolutionמעביר את הדחייה הזו מהאופרטור שהוא מפתח. -
OrbitalRotationבודק שמטריצת הסיבוב (המוטמעת) שלו היא בלוק-אלכסונית לאורך החלוקה אלפא/בטא במקרה בעל הספין, ומעלהValueErrorאם היא מערבבת בין מגזרי ספין.
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> non_conserving = FermionOperator.from_terms([([cre(0), cre(1)], 1.0)]) # creates 2 particles
>>> gate = Evolution(2 * norb, non_conserving, time=1.0)
>>>
>>> try:
... gate._apply_unitary_(reference, norb, nelec, copy=True)
... except ValueError as exc:
... print("rejected:", exc)
rejected: The given FermionOperator could not be converted to a LinearOperator because it does not conserve particle number and the z component of spin. Conserves particle number: False Conserves spin z: False
לכן סימולציה שאינה שומרת על מספר החלקיקים אינה אפשרית במרחב הפרמיוני, מעצם הגדרתה של ייצוג המגזר הקבוע, וזה המחיר של מרחב FCI הקומפקטי שהופך את הסימולציה הפרמיונית לאפשרית מלכתחילה. אם האלגוריתם שלך זקוק לאופרטורים שמפרים את מספר החלקיקים (למשל ערוץ שגיאה ילידי-קיוביט, או אופרטור שנבנה עבור המילטוניאן ממופה שאינו שומר על מספרי החלקיקים איבר אחר איבר), עשה קודם transpile לקיוביטים וסמלץ את QuantumCircuit שמתקבל באמצעות סימולטור ברמת קיוביטים. כל מסלול transpilation מתאים לכך; המדריכים על מעגל פרמיוני ו-transpilation נכנסים ליותר פרטים, אבל generate_preset_jw_pass_manager() הוא ברירת מחדל סבירה.
מוסכמת בלוקי הספין למערכות בעלות ספין
nelec מוגדר כ-int | tuple[int, int], וסוג הערך שלו, ולא דגל נפרד, הוא שבוחר באחת מפריסות המודים הנתמכות:
-
int בוחר בפרשנות חסרת ספין.
norbהמודים מטופלים ישירות כאורביטלים חסרי ספין, ו-nelecהוא המספר הכולל של החלקיקים. -
זוג
(n_alpha, n_beta)בוחר בפרשנות בעלת ספין של2 * norbמודים לפי מוסכמת בלוקי ספין קבועה. המודים0 .. norbהם אורביטלי אלפא (ספין למעלה) והמודיםnorb .. 2 * norbהם אורביטלי בטא (ספין למטה). כל סוג ספין נשמר באופן בלתי תלוי; איבר של אלפא בלבד יכול להזיז אלקטרון בין מודי אלפא אבל לעולם לא אל מוד בטא, ולהפך.
ההכרעה הזו מתבצעת בכל נקודת כניסה של פרוטוקול ffsim בחבילה הזו (בנאי שערים, מימושי _apply_unitary_placed_, והידור המגזרים של גרעין ה-Rust הילידי), והיא המוסכמה שבה משתמשים לאורך המדריכים LUCJ ו-SKQD (למשל, InitializeModes.from_hartree_fock() ממלא את התפוסות של אלפא במודים 0 .. n_alpha ואת התפוסות של בטא במודים norb .. norb + n_beta). כדאי להשוות זאת למודול qiskit_fermions.operators ול-FermionicCircuit בכלל, שמשתמשים באינדקסי מודים כלליים ללא משמעות ספין מובנית (ראה את המדריך למעגל פרמיוני). משמעות בלוקי הספין נכפית רק כאשר nelec בעל ספין מועבר לקריאת סימולציה, ולא נאפית בתוך הייצוג של האופרטור או המעגל עצמו.
>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> norb, nelec = 3, (2, 1)
>>> init = InitializeModes.from_hartree_fock(norb, nelec)
>>> print([bool(occ) for occ in init.occupation]) # alpha modes 0,1; beta mode 3 (= norb + 0)
[True, True, False, True, False, False]
השלבים הבאים
-
עבור על המדריך SKQD כדי לראות כיצד
ffsim.apply_unitary()ו-ffsim.sample_state_vector()משמשים יחד לדגימת מעגלים שנבנו מהשערים של החבילה הזו, ולחישוב ערך ציפייה של המילטוניאן באמצעותffsim.linear_operator()(שבעצמו נשען על אותה שיטת פרוטוקול_linear_operator_שמתוארת כאן). -
עבור על המדריך LUCJ כדי לראות את החצי השני של הסיפור: לקיחת אופרטור ansatz של ffsim דרך צינור ה-transpilation של החבילה הזו ועד למפת צימוד של התקן.
-
קרא את המדריך למעגל פרמיוני כדי להכיר את אינדוקס המודים הכללי, ללא תלות בספין, שמשמש מחוץ לקריאות סימולציה.
-
קרא את המדריך ל-transpilation כדי ללמוד איך לצאת מהמרחב הפרמיוני
ולסמלץ על קיוביטים, מה שנדרש עבור אופרטורים שאינם שומרים על מספר החלקיקים.
-
עיין ב-
qiskit_fermions.protocolsלקטלוג המלא של הפרוטוקולים שהחבילה הזו מגדירה, כולל פרוטוקולי ההמרה (SupportsFermionOperator,SupportsMajoranaOperator) שאינם קשורים ל-ffsim. -
קרא את המדריכים של ffsim עצמה לזרימות העבודה שהיא אחראית עליהן, ובפרט בניית ansatz מסוג UCJ ו-אופטימיזציה שלו באופן וריאציוני. וקטורי הפרמטרים שהמדריכים האלה מפעילים הם מה ש-
UCJו-UCCמקבלים, דרך האופרטורים שהם בונים.