תחילת העבודה עם Qiskit בכיתה
למודול Qiskit in Classrooms הזה, הסטודנטים צריכים סביבת Python פעילה עם החבילות הבאות מותקנות:
qiskitv2.1.0 ומעלהqiskit-ibm-runtimev0.40.1 ומעלהqiskit-aerv0.17.0 ומעלהqiskit.visualizationnumpypylatexenc
להגדרה והתקנה של החבילות הנ"ל, ראו את המדריך התקנת Qiskit. כדי להריץ עבודות על מחשבים קוונטיים אמיתיים, הסטודנטים יצטרכו להגדיר חשבון ב-IBM Quantum® על ידי ביצוע השלבים במדריך הגדרת חשבון IBM Cloud® שלך.
המודול הזה נבדק והשתמש ב-2 שניות של זמן QPU על מעבד Heron v2. זה הערכה בלבד. השימוש בפועל עשוי להשתנות.
# Added by doQumentation — required packages for this notebook
!pip install -q 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'
מבוא
במודולים של Qiskit in the Classroom, תהיה לך הזדמנות להשתמש במחשב קוונטי כדי לחקור מושגים שונים בתחומים הסמוכים למחשוב קוונטי כמו מכניקת קוונטים, מדעי המחשב, כימיה ועוד. המודול הזה משמש כתנאי מקדים לשאר המודולים — הוא מציג את יסודות המחשוב הקוונטי ואיך להשתמש ב-Qiskit להרצת Circuit קוונטי.
ראשית נספק לך סקירה קצרה על אופן הפעולה של מחשב קלאסי, ואז נראה לך איך המושגים האלה מותאמים לפרדיגמת המחשוב הקוונטי. לבסוף, נראה לך איך לחבר את המושגים האלה יחד כדי לבנות ולהריץ את ה-Circuit הקוונטי הראשון שלך.
מחשבים קלאסיים
כנראה שאתה מכיר את הבסיס של אופן הפעולה של מחשבים קלאסיים, אבל כאן נדגיש כמה מהתכונות המרכזיות כדי שנוכל לאחר מכן להשוות בין מחשבים קלאסיים לקוונטיים.
יחידות המידע הבסיסיות: ביטים
מחשבים קלאסיים מעבדים מידע קלאסי, ויחידת המידע הקלאסית הבסיסית היא ה-bit. bit בודד יכול לאחסן את התשובה לשאלת "כן/לא" אחת. בדרך כלל אנחנו מייצגים את שני המצבים הבינאריים של bit כ-"0" ו-"1".
סקירה של מספרים בינאריים
שילוב ביטים מאפשר לך לאחסן מידע רב יותר. לדוגמה, אם אתה רוצה לאחסן מספר מ-0 עד 15, תוכל לעשות זאת עם ארבעה ביטים בדרך הבאה:
| 0 = 0000 | 4 = 0100 | 8 = 1000 | 12 = 1100 |
| 1 = 0001 | 5 = 0101 | 9 = 1001 | 13 = 1101 |
| 2 = 0010 | 6 = 0110 | 10 = 1010 | 14 = 1110 |
| 3 = 0011 | 7 = 0111 | 11 = 1011 | 15 = 1111 |
בכלל, כדי להמיר ממספר בינארי של ביטים למספר מוכר בבסיס 10, מכפילים את הbit הפחות משמעותי (הימני ביותר) ב-, את הbit הבא משמאל ב-, אחר כך את הבא ב-, וכן הלאה, עד שמגיעים לbit הכי משמעותי (השמאלי ביותר), שאותו מכפילים ב-.
כלומר, ביטים יכולים להיות באחד מ- מצבים שונים אפשריים.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לחשוף את הפתרון.
כמה ביטים תצטרך כדי לייצג את המספר 86? כתוב את ה-bitstring שמקודד את המספר הזה בבינארי.
תשובה:
זכור, ביטים מאפשרים לך לייצג את המספרים עד , לכן שישה ביטים יגיעו לנו עד . זה לא מספיק. נוסיף עוד bit אחד כדי להגיע עד . עכשיו נפרק את 86 לחזקות של 2:
פעולות בסיסיות: Gate-ים
עכשיו, מחשב צריך להיות מסוגל לעשות משהו עם הביטים כדי, ובכן, לחשב. Gate-ים בינאריים הם הפעולות שמהוות את אבני הבניין הבסיסיות של כל האלגוריתמים והקודים המורכבים יותר.
Gate של bit בודד:
NOT
כשיש לך רק bit אחד, יש רק דרך אחת לשנות את מצבו: להפוך את המצב מ-0 ל-1 או מ-1 ל-0. אנחנו קוראים לזה Gate "NOT". ניתן לייצג את האפקט של Gate זה — ושל שאר ה-Gate-ים שנדון בהם למטה — בטבלת אמת, עם עמודות עבור מצבי הכניסה והפלט של ה-Qubit-ים. טבלת האמת של Gate NOT היא:
| קלט | פלט |
|---|---|
| 0 | 1 |
| 1 | 0 |
Gate-ים מרובי ביטים:
AND
AND הוא Gate של שני ביטים שלוקח שני ביטי קלט ומוציא bit בודד. הוא מוציא 1 אם שני ביטי הקלט הם 1, ו-0 אחרת:
| קלט | פלט |
|---|---|
| 00 | 0 |
| 01 | 0 |
| 10 | 0 |
| 11 | 1 |
OR
OR הוא עוד Gate של שני ביטים עם bit פלט בודד. הוא מוציא 1 אם אחד מהביטים הוא 1:
| קלט | פלט |
|---|---|
| 00 | 0 |
| 01 | 1 |
| 10 | 1 |
| 11 | 1 |
XOR
XOR מייצג "OR בלעדי" והוא כמו Gate OR, אבל מוציא 1 אם רק אחד מביטי הקלט הוא 1. הוא מוציא 0 אם שניהם 1 או שניהם 0:
| קלט | פלט |
|---|---|
| 00 | 0 |
| 01 | 1 |
| 10 | 1 |
| 11 | 0 |
מדידות:
בדרך כלל, כשלומדים על מחשוב קלאסי, לא מקדישים הרבה תשומת לב לתהליך קריאת מצב הביטים. הסיבה לכך היא שהנושא לא מורכב מבחינה קונצפטואלית. אפשר למדוד את הביטים בכל עת לפני, במהלך, או אחרי חישוב, וזה לא משפיע על התוצאה. זה לא המצב במחשוב קוונטי, כפי שנדון למטה.
Circuit-ים:
על ידי שילוב ה-Gate-ים למעלה, ניתן לבצע כל סוג של פעולה שרוצים על מחשב. ניקח דוגמה פשוטה: באמצעות Gate-ים AND ו-XOR, ניתן לבנות את ה-Circuit של חצי-מחבר, אשר מחשב את סכום שני ביטים. זה מיוצג בדיאגרמת Circuit לוגי, שבה הקווים מייצגים את הביטים וה-Gate-ים שפועלים על הביטים מוצגים כסמלים על הקווים המתאימים:
אז, שני הביטים מועתקים ומוזנים דרך Gate AND וגם Gate XOR. התוצאה של Gate XOR היא "bit הסכום" (S), שנשאר במקום האחדות של המספר הבינארי, ותוצאת Gate AND היא "bit הנשא" (C), שהוא הערך של הספרה המשמעותית הבאה במספר הבינארי. הנה טבלת האמת:
| סכום () | נשא () | ||
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לחשוף את הפתרון.
אמת שטבלת האמת הנ"ל נותנת את הפתרון הנכון עבור Circuit מחבר. כלומר, עבור כל אחת מארבע האפשרויות של A ו-B, אמת ש-.
תשובה:
מחשבים קוונטיים
ביטים qubit-ים
בדיוק כמו שביטים הם יחידות המידע הבסיסיות של מידע קלאסי, ביטים קוונטיים, או "Qubit-ים," הם יחידות המידע הבסיסיות של מידע קוונטי. כמו ה-bit הקלאסי, מצב ה-Qubit יכול להיות 0 או 1, שאנו מסמנים בדרך כלל כ- ו-. אבל בשונה מ-bit קלאסי, bit קוונטי יכול גם להיות ב-סופרפוזיציה של מצב ומצב בו-זמנית. בכלל, qubit יכול להיות בכל מצב מהצורה:
כאשר ו- הם משרעות מרוכבות עם .
הפאזה הקוונטית
מכיוון ש- ו- מרוכבים, ניתן לכתוב כל אחד מהם כ- כאשר נקרא ה-פאזה. אם מכפילים את כל המצב באותו גורם פאזה כללי, שום דבר לא משתנה פיזית — זו נקראת פאזה גלובלית, ואין לה השלכות שניתן לצפות.
מסיבה זו, המנהג הוא "לפקטור החוצה" את , ולקבל:
כאשר הוא הפאזה ה-יחסית של המצב הקוונטי, שכן יש לה השלכות שניתן לצפות.
הפאזה הזו ממלאת תפקיד חשוב מאוד במחשוב קוונטי, ותחקור את השלכותיה השונות במודולי Qiskit in the Classroom הבאים.
qubit-ים מרובים
בעוד שמצב ביטים מרובים ניתן לבטא פשוט כמחרוזת של 0-ים ו-1-ים, מצב ה-Qubit-ים המרובים מסתבך קצת יותר בגלל עקרונות ה-סופרפוזיציה וה-שזירה.
זכור ש- ביטים יכולים להיות באחד מ- מצבים אפשריים החל ממספרים בינאריים 000...000 עד 111...111. אבל עכשיו, בגלל עקרון הסופרפוזיציה, qubit-ים יכולים להיות בסופרפוזיציה של כל המצבים האלה בו-זמנית!
ניתן לבטא זאת כ:
כאשר, כמו במקרה הקלאסי, המצב מתאים למצב שבו כל qubit נמצא בשילוב הנכון של 0-ים ו-1-ים כדי לתת את המספר הבינארי . אלה ידועים כ"מצבי הבסיס החישובי" של המערכת הקוונטית. לדוגמה, מצב של שלושה qubit-ים ניתן לכתוב כסופרפוזיציה של שמונה מצבי הבסיס החישובי שלו:
כל qubit במערכת מסומן עם אינדקס עד . המנהג הוא לקרוא את מצבי ה-Qubit-ים מימין לשמאל, כך שמצב ה-Qubit הוא המצב הימני ביותר ומצב ה-Qubit הוא השמאלי ביותר. זה ידוע כסימון "little-endian", וזה עלול להיראות לא אינטואיטיבי בהתחלה, מכיוון שאנו רגילים לקרוא משמאל לימין.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לחשוף את הפתרון.
במבט ראשון, אולי נראה לא אינטואיטיבי לסדר את ה-Qubit-ים מימין לשמאל כמו בסימון little-endian, אבל זה למעשה דבר מאוד לוגי לעשות! הסבר למה. (זכור את הדיון שלנו למעלה על המרת בינארי לבסיס 10.)
תשובה:
אם אנחנו מסדרים qubit-ים מימין לשמאל, כך ש-Qubit 0 הוא הכי רחוק ימינה ו-Qubit N-1 הוא הכי רחוק שמאלה, הגיוני לשייך את qubit ל-bit הפחות משמעותי, שמוכפל ב- ואת qubit ל-bit הכי משמעותי, שמוכפל ב-.
שזירה
כפי שציינו קודם, תכונה מרכזית נוספת של qubit-ים היא שהם יכולים להיות שזורים זה עם זה. ניקח דוגמה של מצב שני qubit-ים, כאשר ו-:
אז, מצב ה-Qubit 0 יכול להיות או עם הסתברות שווה, וכך גם מצב ה-Qubit 1. אבל ההסתברויות האלה כבר לא בלתי תלויות זו בזו. אם נמצא שמצב ה-Qubit 0 הוא , אז אנחנו יודעים ש-Qubit 1 יהיה גם ב-. זה נכון לא משנה כמה רחוקים הם זה מזה, וזו הסיבה שפעולת מדידת מצב שזור מכונה לפעמים "פעולה מפחידה מרחוק."
שזירה יכולה גם ללבוש צורות אחרות. לדוגמה, המצב
מייצר תוצאות הפוכות בכל פעם: אם qubit אחד נמדד , השני מובטח להיות ב-.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לחשוף את הפתרון.
האם המצב שזור? למה כן או למה לא?
תשובה:
הוא לא שזור. אמנם התוצאות תמיד זהות כשמודדים את שני ה-Qubit-ים, אבל זה רק מפני שכל qubit תמיד קבוע במצב . תוצאת מדידת qubit אחד לא באמת תלויה בשני — שניהם פשוט תמיד .
בכלל, אם ניתן לתאר את מצב כל qubit בנפרד ואז להכפיל אותם יחד כך:
אז זה ידוע כ"מצב מכפלה" ו-אינו שזור.
סימון וקטורי
לעיתים קרובות עוזר להשתמש בוקטורים ומטריצות כדי לראות כיצד המצב הקוונטי משתנה תחת פעולות שונות. בייצוג זה, המצבים הקוונטיים שלנו יהיו וקטורים, וה-Gate-ים הקוונטיים שלנו (שיידונו בפרק הבא) יהיו מטריצות שמשנות את הוקטורים.
עבור qubit בודד, צורות הוקטור של המצבים נבחרות להיות: בדרך זו, מצב שרירותי ניתן לכתוב כ:
עבור מצב כללי של qubit-ים, נצטרך וקטור ממימד , עם מצבי בסיס מסודרים כצפוי, בסדר עולה של ערך בינארי:
עם בחירת סימון הוקטורי הזה בראש, נוכל להציג את ה-Gate-ים הקוונטיים הדרושים לנו, את השפעתם על מצבים קוונטיים ואת צורותיהם המטריציאליות.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על התשובה, ואז לחץ על המשולש כדי לחשוף את הפתרון.
יש ארבעה מצבי בסיס חישובי עבור מערכת של שני qubit-ים. כתוב כל אחד מהם בסימון ket ובסימון וקטורי.
תשובה:
Gate-ים Gate-ים קוונטיים
בדיוק כמו ש-Gate-ים קלאסיים כמו NOT, AND, OR ו-XOR ניתנים לשילוב לבניית Circuit-ים קלאסיים שרירותיים, Gate-ים קוונטיים ממלאים את אותו תפקיד במחשוב קוונטי. מכיוון של-Qubit-ים יש תכונות מכניקת קוונטים נוספות, Gate-ים קוונטיים עשירים יותר בהתאמה. למרות שעדיין ניתן לתאר את פעולתם על מצבי הבסיס ו- עם טבלת אמת, זה לא מצלם את התמונה המלאה. עבור Gate-ים קוונטיים, לעיתים קרובות טבעי יותר להשתמש בייצוג מטריציאלי, מכיוון שהם גם פועלים על סופרפוזיציות של מצבי בסיס.
להלן נציג את ה-Gate-ים הקוונטיים הנפוצים ביותר ואיך הם משנים את ה-Qubit-ים שהם מקיימים עמם אינטראקציה. כשניתן, נחבר אותם בחזרה ל-Gate-ים קלאסיים מוכרים.
Gate-ים של qubit בודד
Gate : זה המקבילה הקוונטית של פעולת NOT. טבלת האמת שלו נראית בדיוק כמו Gate NOT הקלאסי:
| קלט | פלט |
|---|---|
והייצוג המטריציאלי:
ב-Qiskit, יצירת Circuit עם Gate נראית כך:
from qiskit import QuantumCircuit
qc = QuantumCircuit(1)
qc.x(0)
qc.draw("mpl")
בדיאגרמת Circuit הפשוטה הזו, ה-Qubit מיוצג על ידי קו, הקו האופקי השחור, וה-Gate מופיע כקופסה על אותו קו.
Gate Hadamard: יוצר מצב סופרפוזיציה. טבלת אמת:
| קלט | פלט |
|---|---|
ייצוג מטריציאלי:
Circuit עם Gate Hadamard נוצר כך:
from qiskit import QuantumCircuit
qc = QuantumCircuit(1)
qc.h(0)
qc.draw("mpl")
Gate : מוסיף הזזת פאזה של למצב :
| קלט | פלט |
|---|---|
ב-Qiskit, יצירת Circuit עם Gate נראית כך:
qc = QuantumCircuit(1)
qc.z(0)
qc.draw("mpl")
Gate : מוסיף הזזת פאזה של למצב :
| קלט | פלט |
|---|---|
ב-Qiskit, יצירת Circuit עם Gate נראית כך:
qc = QuantumCircuit(1)
qc.t(0)
qc.draw("mpl")
שערים רב-Qubit
שערים של שני qubit יכולים להידמות לשערים קלאסיים של שני ביטים, אבל עם הסתייגות אחת חשובה: כל שערים קוונטיים חייבים להיות הפיכים. במונחים של אלגברה לינארית, המשמעות היא שהם מיוצגים על ידי מטריצות אוניטריות. לכן, שני qubit כניסה תמיד ממופים לשני qubit יציאה, והפעולה יכולה, באופן עקרוני, להיות מבוטלת. זה עומד בניגוד לשערים הקלאסיים שראינו לעיל כמו AND או OR, שמאבדים מידע ואינם הפיכים — בהינתן פלט, לא ניתן לקבוע את הכניסה בצורה ייחודית.
שער CNOT (Controlled-NOT): שני qubit הכניסה נקראים qubit ה"שליטה" וה"מטרה". Qubit השליטה נשאר ללא שינוי, אבל מצבו קובע מה קורה ל-Qubit המטרה. אם qubit השליטה נמצא במצב , אז שער מופעל על המטרה; אם מצב qubit השליטה הוא , אז לא נעשה שינוי. בסימון שלהלן, נניח ש-Qubit (ה-Qubit הימני ביותר) הוא השליטה, וה-Qubit (ה-Qubit השמאלי ביותר) הוא המטרה. להלן, הסימון הוא
| כניסה | יציאה |
|---|---|
אז, המטריצה המייצגת פעולה זו היא:
qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw("mpl")
זהו דיאגרמת Circuit הראשונה שאנחנו רואים עם שני qubit, המיוצגים על ידי שני החוטים. שער CNOT ממומש בין שני ה-Qubit, כאשר הוא השליטה ו- הוא המטרה.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על תשובתך, ואז לחץ על המשולש כדי לגלות את הפתרון.
לרוב השערים יש אותה צורת מטריצה ב-Qiskit כמו בכל מקום אחר. אבל שער CNOT פועל על שני qubit, ולכן פתאום הוספות הסדר של qubit הופכות לבעיה. טקסטים שמסדרים qubit יראו צורת מטריצה שונה לשערי CNOT שלהם. אמת על ידי כפל מטריצות מפורש שמטריצת CNOT לעיל פועלת נכון על המצב
תשובה:
שער SWAP: שער זה מחליף את המצבים של שני qubit. טבלת אמת:
| כניסה | יציאה |
|---|---|
אז, המטריצה המייצגת פעולה זו היא:
qc = QuantumCircuit(2)
qc.swap(0, 1)
qc.draw("mpl")
שער SWAP יכול בעצם להיבנות משלושה CNOT. כדי לראות איך, נוכל להשתמש ב-decompose() של ה-Gate עם Qiskit:
qc = QuantumCircuit(2)
qc.swap(0, 1)
qc.decompose().draw("mpl")
כאן אנחנו רואים לראשונה כיצד מספר שערים מוצגים בדיאגרמת Circuit. אנחנו קוראים אותה משמאל לימין, כך שהשער השמאלי ביותר מופעל ראשון.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על תשובתך, ואז לחץ על המשולש כדי לגלות את הפתרון.
אמת שהשילוב של CNOT לעיל מביא לשער SWAP. תוכל לעשות זאת עם כפל מטריצות או כל שיטה אחרת.
תשובה:
עם כפל מטריצות:
שימוש בטבלת אמת כדי לראות כיצד המצבים משתנות עם כל CNOT. בעמודה האחרונה, המצבים אמורות להיות שוות לעמודת "יציאה" בטבלת אמת ה-SWAP:
| כניסה | CNOT(A,B) | CNOT(B,A) | CNOT(A,B) |
|---|---|---|---|
שער Toffoli (או "controlled-controlled-NOT" (CCNOT)): זהו שער של שלושה qubit. השם "controlled-controlled-NOT" כבר עשוי לספר לך איך הוא עובד: יש שני qubit שליטה ו-Qubit מטרה אחד, ומצב ה-Qubit המטרה מתהפך רק אם שני qubit השליטה נמצאים במצב . אנחנו שומרים על הוסכמה שהשתמשנו בה עם ה-CNOT:
אז טבלת האמת היא:
| כניסה | יציאה |
|---|---|
והמטריצה המייצגת פעולה זו היא:
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.draw("mpl")
גם שער Toffoli יכול להיפרק ל-CNOT, יחד עם כמה שערים אחרים. עם זאת, הוא מורכב הרבה יותר מפירוק שער SWAP, ולכן הוא ייותר כתרגיל רשות בסוף המודול לחקור ולאמת פירוק זה.
מדידות
מדידות ממלאות תפקיד מיוחד בחישוב קוונטי — תפקיד שאין לו אנלוג בחישוב קלאסי. בעוד שבחישוב קלאסי ניתן לבדוק את הביטים שלך בכל נקודה שתבחר במהלך אלגוריתם, בחישוב קוונטי אתה חייב להיות מאוד סלקטיבי לגבי מתי להסתכל על ה-Qubit שלך כי מדידה קורסת את מצבם ומשמידה את הסופרפוזיציה שנותנת ל-Qubit את המורכבות החישובית שלהם.
בפרט, בהינתן מצב קוונטי של ביטים , מדידה תקרוס את המצב לאחד מפונקציות הבסיס עם הסתברות השווה ל-.
אבל האפקט ההרסני הזה של מדידה אינו תמיד מכשול. הוא למעשה משאב מפתח באלגוריתמים ופרוטוקולים מסוימים, כמו קוונטום טלפורטציה והפצת מפתח קוונטית.
ב-Qiskit, כאשר מדידה נעשית, היא נשלחת לרשם קלאסי שבו היא מאוחסנת כביט קלאסי. יצירת Circuit עם מדידה נראית כך:
qc = QuantumCircuit(
1, 1
) # the second number is the number of classical bits in the circuit
qc.measure(0, 0)
qc.draw("mpl")
Circuit
עכשיו שאנחנו יודעים איך qubit, שערים ומדידות עובדים, בוא נבנה ונריץ Circuit קוונטי משלנו! לשם כך, נצטרך להציג לכם תהליך עבודה שימושי הנקרא Qiskit patterns.
מסגרת Qiskit patterns
מסגרת Qiskit patterns היא נוהל כללי לגישה ופתרון בעיות עם מחשב קוונטי. היא מורכבת מארבעה שלבים:
- מיפוי הבעיה שלנו ל-Circuit קוונטיים ואופרטורים
- אופטימיזציה של ה-Circuit לחומרה המטרה
- הרצה על חומרה מטרה
- עיבוד לאחר מכן של התוצאות שלנו
כדי להמחיש שלבים אלה, נממש גרסה קוונטית של Circuit חצי-מוסיף שנדון לעיל.
1. מיפוי
Circuit המוסיף הקלאסי משתמש בשערי XOR ו-AND כדי לחשב את ביטי הסכום והנשיאה, בהתאמה. נוכל להתאים שערים אלה להקשר הקוונטי כדי לייצר חצי-מוסיף קוונטי. ראשית, בזכרנו ששערים קוונטיים הם הפיכים, לא נוכל פשוט לדרוס את הכניסות. במקום זאת, אנחנו מציגים שני qubit עזר המאותחלים ל- כדי לאחסן את פלטי הסכום והנשיאה. אז, המצב הקוונטי המלא שלנו יהיה מורכב מ-Qubit ו-, ו-Qubit הסכום והנשיאה, שנסמן ו-:
עכשיו, אנחנו צריכים שערים קוונטיים שמשיגים מה שעשו שערי XOR ו-AND ב-Circuit הקלאסי.
סכום:
עבור ה-XOR, אנחנו מפעילים שני CNOT, כל אחד עם qubit שליטה ו- ו-Qubit מטרה לשניהם. אם ו- שונים, אז אחד משערי CNOT יהפוך את למצב . אם ו- שניהם , אז שום דבר לא קורה ל- והוא נשאר במצב . אם ו- שניהם , אז מצב יתהפך פעמיים, ויחזור למצב .
נשיאה:
עבור ביט הנשיאה, אנחנו צריכים משהו שעובד כמו שער AND הקלאסי.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על תשובתך, ואז לחץ על המשולש כדי לגלות את הפתרון.
הסתכל אחורה על השערים שדיברנו עליהם כדי לראות אם תוכל לנחש איזה שער קוונטי נשתמש במקום שער AND הקלאסי:
תשובה:
זה שער Toffoli! זכור, שער Toffoli, או controlled-controlled-NOT, הופך את מצב המטרה אם ורק אם qubit שליטה 0 AND qubit שליטה 1 שניהם . לכן, אם ה-Qubit המטרה מתחיל במצב , אז יש לו אותה פעולה כמו שער AND.
אז, עכשיו יש לנו את כל המרכיבים הדרושים לנו לבנות את ה-Circuit הקוונטי:
# qubits: a, b, sum, carry
qc = QuantumCircuit(4)
# Choose values for A and B:
a = 0
b = 0
# Prepare A and B qubits according to selected values:
if a:
qc.x(0)
if b:
qc.x(1)
# XOR (sum) into qubit 2
qc.cx(0, 2)
qc.cx(1, 2)
# AND (carry) into qubit 3
qc.ccx(0, 1, 3) # a AND b
# measure
qc.measure_all()
qc.draw("mpl")
לעיל הוא דיאגרמת ה-Circuit עבור Circuit חצי-המוסיף הקוונטי. כפי שהוזכר קודם, החוטים מייצגים qubit עד מסודרים מלמעלה למטה, ורשם הביטים הקלאסי הוא החוט הכפול בתחתית. ואז, קוראים משמאל לימין, אנחנו רואים כיצד השערים מופעלים על כל qubit על ידי ראיית היכן מופיעים הקופסאות על החוטים המתאימים. לבסוף, המדידות מוצגות בסוף. המדידות קורסות את מצבים ה-Qubit לערכי או מוגדרים, והתוצאות נשלחות לרשם קלאסי.
עדינות אחת: למרות שדיאגרמת ה-Circuit מצוירת משמאל לימין, כאשר כותבים את ביטוי המטריצה המתאים אנחנו חייבים לקרוא אותו מימין לשמאל. זאת משום שבכפל מטריצות, האופרטור הקרוב ביותר לווקטור המצב (שהוא הכי ימני) פועל ראשון. לכן, לדוגמה, ה-Circuit לעיל (ללא התחשבות במדידות) ייכתב כ:
2. אופטימיזציה:
לאחר מכן, עלינו לאפטם את ה-Circuit כדי להריץ אותו על חומרת הקוונטום. אופטימיזציה זו מושגת באמצעות ה-Transpiler, שמתרגם את ה-Circuit המופשט שמוצג לעיל להוראות שהמחשב הקוונטי יבין. הוא מקצה את ה-Qubit הלוגיים לעיל ל-Qubit פיזיים ממשיים על המעבד וכותב מחדש את השערים במונחים של הסט הנייטיבי שלו של שערים שאופטמו להרצה על המחשב הקוונטי. לבסוף, ה-Transpiler גם מממש משהו הנקרא "דיכוי ומיתון שגיאות" כדי לנסות למזם את השפעת השגיאות על התוצאה. זה לא כל כך חשוב ל-Circuit הפשוט שלנו, אבל אם תמשיך במסע החישוב הקוונטי שלך להריץ Circuit מורכבים יותר, תראה בקרוב את הערך של דיכוי ומיתון שגיאות. אם תרצה ללמוד עוד על כך, ראה את הקורס של Olivia Lane, Quantum Computing in Practice.
ראשית, אנחנו טוענים את החבילות הנדרשות לתקשורת עם מחשבי קוונטום IBM® ובוחרים Backend להריץ עליו. נוכל לבחור את ה-Backend הפחות עמוס, או לבחור Backend ספציפי שאנחנו יודעים את תכונותיו.
ישנו קוד למטה לשמירת הפרטים שלך בשימוש ראשון. הקפד למחוק מידע זה מהמחברת לאחר שמירתו בסביבתך, כדי שהפרטים שלך לא ישותפו בטעות כשאתה משתף את המחברת. ראה הגדר את חשבון ה-IBM Cloud שלך ואתחל את השירות בסביבה לא מהימנה לקבלת הנחיות נוספות.
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Qiskit Runtime service
# 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_fez
עכשיו, אנחנו משתמשים ב-Transpiler כדי לאפטם את ה-Circuit. נוכל לבחור את רמת האופטימיזציה מ-0 (ללא אופטימיזציה) עד 3 (אופטימיזציה גבוהה ביותר). כדי לראות מה כל רמה כוללת, כנס למדריך הגדר את רמת אופטימיזציה Transpiler. ה-Circuit שנוצר יראה שונה באופן משמעותי מה-Circuit הלוגי שעשינו בשלב המיפוי שלנו.
# Transpile the circuit and optimize for running on the quantum computer selected
# 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)
qc_isa.draw("mpl")
"Sampler" הוא פרימיטיב שנועד לדגום מצבים אפשריות הנובעות מ-Circuit קוונטי, ולאסוף סטטיסטיקות על אילו מצבים עשויות להימדד ועם איזו הסתברות. אנחנו מייבאים את Qiskit Runtime Sampler כאן:
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
sampler = Sampler(mode=backend)
אם מיציתם את הזמן המוקצב שלכם על מחשבי קוונטום ממשיים או אם אתם ללא חיבור לאינטרנט, ייתכן שתעדיפו להשתמש בסימולטור. לשם כך, הריצו את התא שלהלן ובטלו את ההערה על השורה המשויכת בשלב "הרצה".
# 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.
# backend_gen = GenericBackendV2(num_qubits=18)
# sampler_gen = BackendSamplerV2(backend=backend_gen)
3. הרצה
לאחר הכנת ה-Circuit, נוכל עכשיו להריץ אותו על המחשב הקוונטי!
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()
4. עיבוד לאחר מכן
עכשיו אנחנו מוכנים לצפות בתוצאות שלנו! נציג היסטוגרם של 100 הדגימות של ה-Circuit.
from qiskit.visualization import plot_histogram
print("counts = ", counts)
plot_histogram(counts)
counts = {'0000': 90, '0100': 4, '1100': 3, '0010': 3}
ההיסטוגרם לעיל מציג את תוצאות המדידה של כל ארבעת ה-Qubit בסוף ה-Circuit. מחשב קוונטי אידיאלי ללא רעש היה מודד את ה-Qubit שיש להם אותם ערכים בכל פעם, אבל במציאות, הרעש יגרום לחלק מהריצות לייצר שגיאות.
בדוק את ההבנה שלך
קרא את השאלה/ות למטה, חשוב על תשובתך, ואז לחץ על המשולש כדי לגלות את הפתרון.
השתמש ב-bitstring עם הספירות הרבות ביותר כערכים שלך עבור , , ו-, אמת שה-Circuit של המוסיף הקוונטי עבד.
תשובה:
אנחנו צריכים לאמת ש-. זכור ש-bitstring מסודרת בשיטת little-endian, אז היא נקראת CSBA.
מההיסטוגרם לעיל, אנחנו רואים ש-bitstring 0000 היא הדומיננטית.
חזור ושנה את הערכים של ו- ל- ו- ועבור שוב על שלבי Qiskit patterns כדי להריץ מחדש את ה-Circuit. אמת שה-Circuit של המוסיף עבד שוב.
תשובה:
אמור לקבל היסטוגרם שבו ה-bitstring הדומיננטית היא 1011:
אחת התכונות הנוספות של חצי-המוסיף הקוונטי על פני חצי-המוסיף הקלאסי היא שהוא יכול לרוץ עם כניסות קוונטיות. כלומר, הוא יכול "לחבר" Qubit ו- גם אם הם נמצאים במצבים סופרפוזיציה. בסעיף שאלות האתגר למטה, תתבקש להכין את ה-Qubit בסופרפוזיציות ולראות מה קורה!
סיכום
מודול זה תוכנן לתת לך הבנה יסודית מוצקה של העקרונות הבסיסיים מאחורי החישוב הקוונטי על ידי השוואתו לחישוב קלאסי. בדקנו את ה-Circuit חצי-המוסיף הקלאסי ואז הראינו לך כיצד להתאים את ה-Circuit לרוץ עם qubit על מחשב קוונטי. עכשיו אתה מוכן לחקור את מודולי Qiskit in the Classroom האחרים!
מושגים קריטיים:
- בניגוד לביטים קלאסיים שיכולים לקבל רק ערכים של 0 ו-1, qubit יכולים גם להיות במצבים סופרפוזיציה של גם 0 וגם 1.
- ניתן לשים מספר qubit בסופרפוזיציה על פני ה-bitstrings המותרים קלאסית הנקראים מצבים בסיס חישוביות.
- ניתן לשזור מספר qubit כך שמצב האחד תלוי במצב השני.
- המוסכמה של Qiskit היא להשתמש בסימון little-endian, שמציב את ה-Qubit הפחות משמעותי, , בעמדה הימנית ביותר ואת ה-Qubit המשמעותי ביותר, , בשמאל.
- שערים קוונטיים הם פעולות הפיכות המיוצגות על ידי מטריצות אוניטריות הפועלות על וקטורי המצב הקוונטי. בסימון זה, המטריצה הקרובה ביותר לוקטור (הכי ימנית) פועלת ראשונה.
- מדידות קורסות מצב סופרפוזיציה קוונטי לאחד ממצביו המותרות קלאסית, עם הסתברות השווה לריבוע האמפליטודה של מצב הבסיס החישובי המתאים בסופרפוזיציה.
- Circuit קוונטיים מיוצגים לעתים קרובות בשימוש דיאגרמות Circuit קוונטיים, שבהן qubit מוצגים כחוטים אופקיים, ושערים קוונטיים מופיעים לאורך חוטים אלה משמאל לימין.
- כדי להריץ Circuit קוונטי, אנחנו משתמשים בארבעה שלבים בתהליך העבודה Qiskit patterns: מפה, אפטם, הרץ, עבד לאחר מכן.
שאלות
שאלות נכון/לא נכון
-
ביט בודד במחשב קלאסי יכול להחזיק רק את הערך 0 או 1.
-
שזירה פירושה שמצב qubit אחד אינו תלוי במצב של qubit אחר.
-
שערים קוונטיים הם בדרך כלל פעולות בלתי הפיכות.
-
מוסכמת Qiskit מציבה את ה-Qubit הפחות משמעותי, , בעמדה השמאלית ביותר.
-
מדידת מצב קוונטי תמיד נותנת את אותה תוצאה אם חוזרים עליה פעמים רבות.
-
שער Hadamard יוצר סופרפוזיציה ב-Qubit בודד.
-
Circuit קוונטיים עשויים לכלול פעולות מדידה הקורסות את מצב הסופרפוזיציה לאחד מהמצבות המותרות קלאסית.
-
מספר המצבים הקלאסיות האפשריות עבור ביטים הוא .
-
הסתברויות התוצאה עבור מדידות קוונטיות ניתנות על ידי אמפליטודות בריבוע של מצבים הבסיס הניתנות למדידה קלאסית.
שאלות תשובה קצרה
-
מהם כמה הבדלים עיקריים בין ביט ל-Qubit?
-
מה קורה למצב קוונטי כאשר הוא נמדד?
-
מדוע אנחנו משתמשים בסימון little-endian ב-Qiskit?
-
מהם ארבעת השלבים בתהליך העבודה Qiskit patterns?
שאלות אתגר:
- במודול, השתמשנו במוסיף רק כדי לחבר מצבים מותרות קלאסית עבור ו-. אבל נוכל גם להכין את ו- בסופרפוזיציות! שנה את הקוד כדי להכין כל qubit בסופרפוזיציה שווה של 0 ו-1, ואז הרץ את ה-Circuit החדש וקבל היסטוגרם חדש. מה אתה רואה? הסבר מה קורה.