דלג לתוכן הראשי
פרויקט זה בשלב בטא. מצאת באג? פתח issue ב-GitHub. יש שאלה או רעיון? שאל ב-Discussions — נשמח לשמוע ממך!
מה איכות התרגום בדף זה?

איך לפרש את הוויזואליזציות של shaded lightcone

החבילה מספקת שתי דרכים להסתכל על shaded lightcone:

  • draw_shaded_lightcone מציב את החסמים מעל דיאגרמת המעגל. זה הכי טוב למעגלים על שרשרת חד-ממדית של Qubit, שבהם דיאגרמת המעגל והפריסה הפיזית מתאימות.

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

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

הגדרה​

השתמשו באותו מעגל Ising מסוג Trotter ובאותו אובזרבבל כמו במדריך ההתחלה המהירה.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_slc": "qiskit-addon-slc", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Pauli, PauliLindbladMap, QubitSparsePauliList
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
merge_bounds,
)
from qiskit_addon_slc.utils import generate_noise_model_paulis
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions

def trotter_ising_circuit(num_qubits, num_steps, rx_angle, rzz_angle):
"""Trotterized transverse-field Ising evolution on a 1D chain."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(rx_angle, range(num_qubits))
circuit.barrier()
for start in (0, 1): # even then odd bonds
for i in range(start, num_qubits - 1, 2):
circuit.rzz(rzz_angle, i, i + 1)
circuit.barrier()
return circuit

num_qubits = 10
circuit = trotter_ising_circuit(
num_qubits, num_steps=4, rx_angle=np.pi / 16, rzz_angle=-np.pi / 3
)
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])

boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)

forward_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
backward_bounds = compute_backward_bounds(boxed_circuit, noise_model_paulis)

rng = np.random.default_rng(42)
noise_rates = {
layer: PauliLindbladMap.from_components(
rng.random(len(terms)) * 5e-3,
QubitSparsePauliList.from_sparse_list(
terms.to_sparse_list(), terms.num_qubits
),
)
for layer, terms in noise_model_paulis.items()
}
merged_bounds = merge_bounds(
boxed_circuit, forward_bounds, backward_bounds, noise_rates
)
print(f"observable: Z on qubit {num_qubits // 2}")
Optimal spacetime partitioning not implemented! Just partitioning list of noisy boxes.
observable: Z on qubit 5

draw_shaded_lightcone​

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

from qiskit_addon_slc.visualization import draw_shaded_lightcone

draw_shaded_lightcone(
boxed_circuit, merged_bounds, noise_model_paulis, fold=-1, scale=0.5
)

Output of the previous code cell

הערות חשובות​

1. כל מספר הוא סכום על איברי השגיאה החולקים תומך. בלי מסנן, החסמים של כל איבר שגיאה הפועל על אותו Qubit, או על אותו זוג Qubit, מתווספים לערך אחד: כל שלושת סוגי ה-Pauli על Qubit, וכל התשעה על זוג. לכך יש שתי השלכות. ערך יכול לחרוג מ-2.0, אף על פי שהחסם של אף איבר בודד לא יכול (תיבה עם התווית 4.5 היא כמה איברים שמסתכמים, לא חסם שהופר). והאיור לא יכול לומר לכם אם ערך גדול בא מסוג Pauli אחד או מכמה סוגים דומים בגודלם; הסעיף הבא מראה איך להפריד ביניהם.

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

הפרדה בין סוגי ה-Pauli​

השתמשו ב-pauli_filter כדי לראות סוג אחד בכל פעם. מספר שלם בוחר משקל Pauli; מחרוזת בוחרת Pauli ספציפי, ומותאמת מול כל איבר רעש מצומצם לתומך הלא-זהותי שלו. כך ש-"X" בוחר כל שגיאת XX חד-Qubitית, בלי קשר לאיזה Qubit היא פועלת, ו-"XX" בוחר את אלה במשקל 2 (תווית ברוחב מלא כמו "XII" לא מתאימה לכלום).

from qiskit_addon_slc.visualization import accumulate_filtered_bounds

box_id = next(iter(merged_bounds))
print(f"single-qubit supports of box {box_id!r}:\n")
print(f"{'filter':>8} bounds per qubit")
for pauli_filter in (None, 1, "X", "Y", "Z"):
filtered = accumulate_filtered_bounds(
boxed_circuit, merged_bounds, noise_model_paulis, pauli_filter
)
per_qubit = {
support[0]: round(float(bound), 3)
for support, bound in sorted(filtered[box_id].items())
if len(support) == 1
}
print(f"{pauli_filter!s:>8} {per_qubit}")
single-qubit supports of box 'm0':

filter bounds per qubit
None {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
1 {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.312, 4: 1.355, 5: 5.111, 6: 1.506, 7: 0.124, 8: 0.019, 9: 0.0}
X {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.153, 4: 0.577, 5: 2.0, 6: 0.702, 7: 0.056, 8: 0.01, 9: 0.0}
Y {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.148, 4: 0.607, 5: 2.0, 6: 0.631, 7: 0.057, 8: 0.01, 9: 0.0}
Z {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.011, 4: 0.172, 5: 1.111, 6: 0.172, 7: 0.011, 8: 0.0, 9: 0.0}

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

העברת אותו מסנן ל-draw_shaded_lightcone רושמת אותו בכותרת האיור, כך שאי אפשר לטעות ולחשוב שאיור מסונן הוא לא מסונן:

draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter="X",
fold=-1,
scale=0.5,
)

Output of the previous code cell

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

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

animate_shaded_lightcone​

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

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

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

from qiskit import transpile
from qiskit.transpiler import CouplingMap
from qiskit_addon_slc.visualization import animate_shaded_lightcone

# A small square-lattice device stands in for a real backend here.
coupling_map = CouplingMap.from_grid(3, 4)

# Lay the chain onto a connected path of physical qubits, snaking through the grid, so the
# transpiler inserts no SWAPs: a SWAP-laden circuit is far more expensive to bound and harder to
# read.
initial_layout = [0, 1, 2, 3, 7, 6, 5, 4, 8, 9]
device_circuit = transpile(
circuit,
coupling_map=coupling_map,
initial_layout=initial_layout,
optimization_level=0,
)
boxed_device_circuit = boxing_pass.run(device_circuit)
device_noise_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_device_circuit),
coupling_map=coupling_map,
circuit=boxed_device_circuit,
)
# The same observable, on the physical qubit the middle of the chain was laid onto.
device_observable = Pauli("I" * device_circuit.num_qubits).compose(
"Z", [initial_layout[num_qubits // 2]]
)
device_bounds = compute_forward_bounds(
boxed_device_circuit, device_noise_paulis, device_observable
)

animate_shaded_lightcone(boxed_device_circuit, device_bounds, coupling_map)

Output of the previous code cell

קריאת האנימציה​

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

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

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

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

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

במה להשתמש​

draw_shaded_lightconeanimate_shaded_lightcone
גיאומטריהדיאגרמת המעגלמפת הצימוד של ה-QPU
מתאים במיוחד לשרשראות חד-ממדיותכל קישוריות
סוגי פאולימסוכמים, אלא אם מסנניםתמיד מפוצלים, כפרוסות עוגה
זמןכל השכבות בבת אחתשכבה אחת בכל פריים
פלטאיור של matplotlibאיור של plotly

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