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

מעבר פאזה של Nishimori

הערכת שימוש: 3 דקות על מעבד Heron r2 (הערה: זוהי הערכה בלבד. זמן הריצה שלך עשוי להשתנות.)

רקע

מדריך זה מדגים כיצד להגשים מעבר פאזה של Nishimori על מעבד קוונטי של IBM®. ניסוי זה תואר במקור במאמר Realizing the Nishimori transition across the error threshold for constant-depth quantum circuits.

מעבר הפאזה של Nishimori מתייחס למעבר בין פאזות מסודרות בטווח קצר לטווח ארוך במודל Ising עם קשרים אקראיים. במחשב קוונטי, הפאזה המסודרת בטווח ארוך באה לידי ביטוי במצב בו קיוביטים משולבים קוונטית על פני כל המכשיר. מצב משולב קוונטית זה מוכן באמצעות פרוטוקול generation of entanglement by measurement (GEM). באמצעות מדידות אמצע-מעגל, פרוטוקול GEM מסוגל לשלב קוונטית קיוביטים על פני כל המכשיר באמצעות מעגלים בעומק קבוע בלבד. מדריך זה משתמש במימוש של פרוטוקול GEM מחבילת התוכנה GEM Suite.

דרישות

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

  • Qiskit SDK v1.0 ומעלה, עם תמיכה ב-visualization
  • Qiskit Runtime v0.22 ומעלה ( pip install qiskit-ibm-runtime )
  • GEM Suite ( pip install gem-suite )

הכנה

# Added by doQumentation — required packages for this notebook
!pip install -q gem-suite matplotlib qiskit qiskit-ibm-runtime
import matplotlib.pyplot as plt

from collections import defaultdict

from qiskit_ibm_runtime import QiskitRuntimeService

from qiskit.transpiler import generate_preset_pass_manager

from gem_suite import PlaquetteLattice
from gem_suite.experiments import GemExperiment

שלב 1: מיפוי קלטים קלאסיים לבעיה קוונטית

פרוטוקול GEM פועל על מעבד קוונטי עם קישוריות קיוביטים המתוארת על ידי סריג. מעבדים קוונטיים של IBM כיום משתמשים ב-heavy hex lattice. הקיוביטים של המעבד מקובצים ל-פלאקטות (plaquettes) על בסיס תא היחידה של הסריג בו הם שוכנים. מכיוון שקיוביט עשוי להופיע ביותר מתא יחידה אחד, הפלאקטות אינן זרות. בסריג heavy hex, פלאקט מכיל 12 קיוביטים. הפלאקטות עצמן גם יוצרות סריג, שבו שתי פלאקטות מחוברות אם הן חולקות קיוביטים כלשהם. בסריג heavy hex, פלאקטות שכנות חולקות 3 קיוביטים.

בחבילת התוכנה GEM Suite, המחלקה הבסיסית למימוש פרוטוקול GEM היא PlaquetteLattice, המייצגת את סריג הפלאקטות (שונה מסריג heavy hex). ניתן לאתחל PlaquetteLattice ממפת צימוד קיוביטים. כרגע, רק מפות צימוד heavy hex נתמכות.

תא הקוד הבא מאתחל סריג פלאקטות ממפת הצימוד של מעבד קוונטי של IBM. סריג הפלאקטות לא תמיד מקיף את כל החומרה. לדוגמה, ל-ibm_torino יש 133 קיוביטים בסך הכל, אך סריג הפלאקטות הגדול ביותר שמתאים למכשיר משתמש רק ב-125 מהם, ומכיל סך של 18 פלאקטות. דבר דומה ניתן לראות גם במכשירי IBM Quantum® עם ספירות קיוביטים שונות.

# QiskitRuntimeService.save_account(channel="ibm_quantum", token="<YOUR_API_KEYN>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)

print(f"Number of qubits in backend: {backend.num_qubits}")
print(
f"Number of qubits in plaquette lattice: {len(list(plaquette_lattice.qubits()))}"
)
print(f"Number of plaquettes: {len(list(plaquette_lattice.plaquettes()))}")
Number of qubits in backend: 133
Number of qubits in plaquette lattice: 125
Number of plaquettes: 18

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

plaquette_lattice.draw_plaquettes()

Output of the previous code cell

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

# Get a list of the plaquettes
plaquettes = list(plaquette_lattice.plaquettes())
# Display information about plaquette 0
plaquettes[0]
PyPlaquette(index=0, qubits=[0, 1, 2, 3, 4, 15, 16, 19, 20, 21, 22, 23], neighbors=[3, 1])

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

plaquette_lattice.draw_qubits()

Output of the previous code cell

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

  • כל קיוביט הוא מוצל (אפור) או לא מוצל. הקיוביטים המוצללים הם קיוביטי "אתר" (site) המייצגים את האתרים של מודל Ising, והקיוביטים הלא מוצללים הם קיוביטי "קשר" (bond) המשמשים לתיווך אינטראקציות בין קיוביטי האתר.
  • כל קיוביט אתר מסומן כ-(A) או (B), המציין אחד משני תפקידים שקיוביט אתר יכול למלא בפרוטוקול GEM (התפקידים מוסברים מאוחר יותר).
  • כל קצה צבוע באחד משישה צבעים, ובכך מחלק את הקצוות לשש קבוצות. חלוקה זו קובעת כיצד ניתן לבצע שערים דו-קיוביטיים במקביל, כמו גם תבניות תזמון שונות שסביר שיגרמו לכמויות שונות של שגיאה על מעבד קוונטי רועש. מכיוון שקצוות בקבוצה זרים, ניתן להחיל שכבת שערים דו-קיוביטיים על אותם קצוות בו-זמנית. למעשה, ניתן לחלק את ששת הצבעים לשלוש קבוצות של שני צבעים כך שהאיחוד של כל קבוצה של שני צבעים עדיין זר. לכן, יש צורך רק בשלוש שכבות של שערים דו-קיוביטיים כדי להפעיל כל קצה. ישנן 12 דרכים לחלק את ששת הצבעים כך, וכל חלוקה כזו מניבה לוח זמנים שונה של 3 שכבות שערים.

כעת לאחר שיצרתם סריג פלאקטות, השלב הבא הוא לאתחל אובייקט GemExperiment, תוך העברת סריג הפלאקטות וה-backend שבו אתם מתכננים להריץ את הניסוי. המחלקה GemExperiment מנהלת את המימוש בפועל של פרוטוקול GEM, כולל יצירת מעגלים, הגשת עבודות וניתוח הנתונים. תא הקוד הבא מאתחל את מחלקה הניסוי תוך הגבלת סריג הפלאקטות לשתיים בלבד מהפלאקטות (21 קיוביטים), מצמצם את גודל הניסוי כדי להבטיח שהרעש בחומרה לא יעלה על האות.

gem_exp = GemExperiment(plaquette_lattice.filter([9, 12]), backend=backend)

# visualize the plaquette lattice after filtering
plaquette_lattice.filter([9, 12]).draw_qubits()

Output of the previous code cell

מעגל פרוטוקול GEM נבנה באמצעות השלבים הבאים:

  1. הכנת מצב all-+|+\rangle על ידי החלת שער Hadamard על כל קיוביט.
  2. החלת שער RZZR_{ZZ} בין כל זוג קיוביטים מחוברים. ניתן להשיג זאת באמצעות 3 שכבות של שערים. כל שער RZZR_{ZZ} פועל על קיוביט אתר וקיוביט קשר. אם קיוביט האתר מסומן (B), אז הזווית קבועה ל-π2\frac{\pi}{2}. אם קיוביט האתר מסומן (A), אז הזווית מורשית להשתנות, מייצרת מעגלים שונים. כברירת מחדל, טווח הזוויות מוגדר ל-21 נקודות מרווחות שווה בין 00 ל-π2\frac{\pi}{2}, כולל.
  3. מדידת כל קיוביט קשר בבסיס Pauli XX. מכיוון שקיוביטים נמדדים בבסיס Pauli ZZ, ניתן לבצע זאת על ידי החלת שער Hadamard לפני מדידת הקיוביט.

שימו לב שהמאמר המצוטט בהקדמה למדריך זה משתמש באמנה שונה לזווית RZZR_{ZZ}, השונה מהאמנה המשמשת במדריך זה בפקטור של 2.

בשלב 3, רק קיוביטי הקשר נמדדים. כדי להבין באיזה מצב נשארים קיוביטי האתר, מועיל לשקול את המקרה שבו זווית RZZR_{ZZ} המוחלת על קיוביטי אתר (A) בשלב 2 שווה ל-π2\frac{\pi}{2}. במקרה זה, קיוביטי האתר נשארים במצב משולב קוונטית מאוד הדומה למצב GHZ,

GHZ=0000+1111.\lvert \text{GHZ} \rangle = \lvert 00 \cdots 00 \rangle + \lvert 11 \cdots 11 \rangle.

בשל האקראיות בתוצאות המדידה, המצב בפועל של קיוביטי האתר עשוי להיות מצב שונה עם סדר ארוך טווח, לדוגמה, 00110+11001\lvert 00110 \rangle + \lvert 11001 \rangle. עם זאת, ניתן לשחזר את מצב GHZ על ידי החלת פעולת פענוח המבוססת על תוצאות המדידה. כאשר זווית RZZR_{ZZ} מכוונת כלפי מטה מ-π2\frac{\pi}{2}, ניתן עדיין לשחזר את הסדר ארוך הטווח עד לזווית קריטית, שבהיעדר רעש, היא בקירוב 0.3π0.3 \pi. מתחת לזווית זו, המצב המתקבל כבר אינו מציג שזירה ארוכת טווח. מעבר זה בין נוכחות והיעדר סדר ארוך טווח הוא מעבר הפאזה של Nishimori.

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

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

בנוסף להיותו תלוי בזווית RZZR_{ZZ} בשלב 2, שכברירת מחדל סוקרת 21 ערכים, מעגל פרוטוקול GEM תלוי גם בתבנית התזמון המשמשת ליישום 3 השכבות של שערי RZZR_{ZZ}. כפי שנדון קודם לכן, ישנן 12 תבניות תזמון כאלה. לכן, המספר הכולל של מעגלים בניסוי הוא 21×12=25221 \times 12 = 252.

ניתן ליצור את המעגלים של הניסוי באמצעות המתודה circuits של המחלקה GemExperiment.

circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
Total number of circuits: 252

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

# Restrict experiment to the first scheduling pattern
gem_exp.set_experiment_options(schedule_idx=0)

# There are less circuits now
circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")

# Print the RZZ angles swept over
print(f"RZZ angles:\n{gem_exp.parameters()}")
Total number of circuits: 21
RZZ angles:
[0. 0.07853982 0.15707963 0.23561945 0.31415927 0.39269908
0.4712389 0.54977871 0.62831853 0.70685835 0.78539816 0.86393798
0.9424778 1.02101761 1.09955743 1.17809725 1.25663706 1.33517688
1.41371669 1.49225651 1.57079633]

תא הקוד הבא מצייר דיאגרמה של המעגל באינדקס 5. כדי לצמצם את גודל הדיאגרמה, שערי המדידה בסוף המעגל מוסרים.

# Get the circuit at index 5
circuit = circuits[5]
# Remove the final measurements to ease visualization
circuit.remove_final_measurements()
# Draw the circuit
circuit.draw("mpl", fold=-1, scale=0.5)

Output of the previous code cell

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

Transpiling של מעגלים קוונטיים להרצה על חומרה בדרך כלל כרוך במספר שלבים. בדרך כלל, השלבים הכרוכים בעומס חישובי רב ביותר הם בחירת פריסת הקיוביטים, ניתוב השערים הדו-קיוביטיים כדי להתאים לקישוריות הקיוביטים של החומרה, ואופטימיזציה של המעגל כדי למזער את ספירת השערים והעומק שלו. בפרוטוקול GEM, שלבי הפריסה והניתוב אינם נחוצים מכיוון שהקישוריות של החומרה כבר משולבת בעיצוב הפרוטוקול. למעגלים כבר יש פריסת קיוביטים, והשערים הדו-קיוביטיים כבר ממופים על חיבורים מקוריים. יותר מכך, כדי לשמר את המבנה של המעגל בזמן ששינוי זווית RZZR_{ZZ}, יש לבצע רק אופטימיזציה מאוד בסיסית של המעגל.

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

# Demonstrate setting transpile options
gem_exp.set_transpile_options(
optimization_level=1 # This is the default optimization level
)
pass_manager = generate_preset_pass_manager(
backend=backend,
initial_layout=list(gem_exp.physical_qubits),
**dict(gem_exp.transpile_options),
)
transpiled = pass_manager.run(circuit)
transpiled.draw("mpl", idle_wires=False, fold=-1, scale=0.5)

Output of the previous code cell

שלב 3: הרצה באמצעות Qiskit primitives

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

exp_data = gem_exp.run(shots=10_000)

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

exp_data.block_for_results()
ExperimentData(GemExperiment, d0d5880a-34c1-4aab-a7b6-c4f58516bc03, job_ids=['cwg12ptmptp00082khhg'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])

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

בזווית RZZR_{ZZ} של π2\frac{\pi}{2}, המצב המפוענח יהיה מצב GHZ בהיעדר רעש. ניתן לדמיין את הסדר ארוך הטווח של מצב GHZ על ידי שרטוט המגנטיזציה של מחרוזות הביטים הנמדדות. המגנטיזציה MM מוגדרת כסכום של אופרטורי Pauli ZZ חד-קיוביטיים,

M=j=1NZj,M = \sum_{j=1}^N Z_j,

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

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

תא הקוד הבא מצייר את המגנטיזציה של מחרוזות הביטים הגולמיות ומחרוזות הביטים המפוענחות בזווית RZZR_{ZZ} של π2\frac{\pi}{2}.

def magnetization_distribution(
counts_dict: dict[str, int],
) -> dict[str, float]:
"""Compute magnetization distribution from counts dictionary."""
# Construct dictionary from magnetization to count
mag_dist = defaultdict(float)
for bitstring, count in counts_dict.items():
mag = bitstring.count("0") - bitstring.count("1")
mag_dist[mag] += count
# Normalize
shots = sum(counts_dict.values())
for mag in mag_dist:
mag_dist[mag] /= shots
return mag_dist

# Get counts dictionaries with and without decoding
data = exp_data.data()
# Get the last data point, which is at the angle for the GHZ state
raw_counts = data[-1]["counts"]
# Without decoding
site_indices = [
i for i, q in enumerate(gem_exp.plaquettes.qubits()) if q.role == "Site"
]
site_raw_counts = defaultdict(int)
for key, val in raw_counts.items():
site_str = "".join(key[-1 - i] for i in site_indices)
site_raw_counts[site_str] += val
# With decoding
_, site_decoded_counts = gem_exp.plaquettes.decode_outcomes(
raw_counts, return_counts=True
)

# Compute magnetization distribution
raw_magnetization = magnetization_distribution(site_raw_counts)
decoded_magnetization = magnetization_distribution(site_decoded_counts)

# Plot
plt.bar(*zip(*raw_magnetization.items()), label="raw")
plt.bar(*zip(*decoded_magnetization.items()), label="decoded", width=0.3)
plt.legend()
plt.xlabel("Magnetization")
plt.ylabel("Frequency")
plt.title("Magnetization distribution with and without decoding")
Text(0.5, 1.0, 'Magnetization distribution with and without decoding')

Output of the previous code cell

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

f=1N2(M2M2).f = \frac{1}{N^2} \left(\langle M^2 \rangle - \langle M \rangle ^2\right).

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

exp_data.figure("two_point_correlation")

Output of the previous code cell

כדי לקבוע את הנקודה הקריטית של מעבר הפאזה של Nishimori, ניתן להסתכל על השונות המנורמלת של M2/NM^2 / N, המוגדרת כ-

g=1N3(M4M22),g = \frac{1}{N^3} \left(\langle M^4 \rangle - \langle M^2 \rangle^2\right),

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

exp_data.figure("normalized_variance")

Output of the previous code cell

הגדלת הניסוי

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

gem_exp = GemExperiment(
plaquette_lattice.filter(range(3, 9)), backend=backend
)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

gem_exp = GemExperiment(plaquette_lattice, backend=backend)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

סיכום

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

סקר מדריך

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

קישור לסקר