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

Transpiler

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

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

from qiskit.circuit import Parameter, QuantumCircuit

circuit = QuantumCircuit(4, 7)
circuit.h(1)
circuit.h(2)
circuit.cz(1, 2)
circuit.h(1)
circuit.cx(1, 0)
circuit.cx(2, 3)
circuit.measure(range(1, 4), range(3))
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
for qubit in range(4):
circuit.rz(Parameter(f"th_{qubit}"), qubit)
circuit.rx(Parameter(f"phi_{qubit}"), qubit)
circuit.rz(Parameter(f"lam_{qubit}"), qubit)
circuit.measure(range(4), range(3, 7))

circuit.draw("mpl", scale=0.8)

../_images/cf27e1ef03e51b2360c90165a4efeaa793da36083bb674774ca06c8181ef63dd.png

קיבוץ פעולות ל-boxes​

אפשר להגדיר את הארגומנט enable_gates ל-True או ל-False כדי לציין אם יש לקבץ את שערי שני ה-qubits ל-boxes. באופן דומה, enable_measures מציין אם יש לקבץ מדידות או לא. קטע הקוד הבא מראה דוגמה שבה מקובצים גם שערים וגם מדידות.

from samplomatic.transpiler import generate_boxing_pass_manager

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
)
transpiled_circuit = boxing_pass_manager.run(circuit)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/b323dde8a5412e42359aef1831af92ed3702d2251547c663208dc084a2995276.png

כפי שאפשר לראות באיור, ה-pass manager יוצר boxes משני סוגים: כאלה שמכילים שכבה בודדת של שערי שני qubits, וכאלה שמכילים שכבה בודדת של מדידות. ההפרדה הזו משקפת שיטות מקובלות בפרוטוקולים ללמידת רעש והפחתתו, שבדרך כלל מכוונים לשכבות של פעולות הומוגניות. שערי שני ה-qubits והמדידות ממוקמים ב-box השמאלי ביותר שיכול להכיל אותם, וכל שער qubit בודד ממוקם באותו box עם שער שני ה-qubits או המדידה שאחריהם הוא בא.

הקוד הבא מראה דוגמה שבה enable_gates מוגדר ל-False. כפי שאפשר לראות, שערי שני ה-qubits אינם מקובצים ל-boxes, וגם לא שערי ה-qubit הבודד שקודמים להם.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=False,
enable_measures=True,
)
transpiled_circuit = boxing_pass_manager.run(circuit)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/3fc8e660b0c7eff1f5aa2e571d064f91b3eb2738c5990727e026a8ffe1101a1c.png

בחירה איך להעיר את ה-boxes​

כל ה-boxes של שערי שני ה-qubits ושל מדידות במעגל המוחזר מחזיקים הערות left-dressed. בפרט, כל ה-boxes שמכילים שערי שני qubits מסומנים בהערת Twirl. עבור boxes של מדידות, המשתמשים יכולים לבחור בין Twirl, BasisTranform (כאשר mode מוגדר ל-"measure"), או שניהם. הקוד הבא יוצר מעגל שבו כל ה-boxes עוברים twirl, וה-boxes של המדידות מסומנים בנוסף ב-BasisTranform.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
measure_annotations="all",
)
transpiled_circuit = boxing_pass_manager.run(circuit)

הכנת המעגל להזרקת רעש​

הארגומנט inject_noise_targets מאפשר לציין אילו boxes יקבלו הערת InjectNoise. למשל, הקוד הבא יוצר מעגל שבו ל-boxes של שערי שני ה-qubits יש הערת InjectNoise אבל ל-boxes של המדידות אין.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
inject_noise_targets="gates",
)
transpiled_circuit = boxing_pass_manager.run(circuit)

אם מעגל מכיל שני boxes או יותר ששקולים עד כדי שערי qubit בודד, כולם מסומנים בהערת InjectNoise עם אותו ref. כך, מספר ה-refים הייחודיים במעגל המוחזר שווה למספר ה-boxes הייחודיים.

הערך של inject_noise_strategy משפיע על ההערות InjectNoise. הערכים האפשריים הם:

  • modifier_ref='': מומלץ כשאין צורך לשנות את מפות הרעש לפני הדגימה מהן.

  • modifier_ref=ref: מומלץ כשצריך לשנות את קנה המידה של כל מפות הרעש באופן אחיד באותו גורם.

  • ערך ייחודי של modifier_ref: מומלץ כשצריך לשנות את קנה המידה של כל מפת רעש בגורם שונה.

הקוד הבא יוצר מעגל שבו ל-boxes של שערי שני ה-qubits יש הערת InjectNoise עם ערכי modifier_ref ייחודיים.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
inject_noise_targets="gates",
inject_noise_strategy="individual_modification",
)
transpiled_circuit = boxing_pass_manager.run(circuit)

בחירת אסטרטגיית twirling​

ה-boxing pass manager מתחיל בבחירה אילו שערי הסתבכות והוראות מדידה צריכים להופיע באותם boxes. לאחר שזה הושלם, ה-boxes לא יהיו, באופן כללי, ברוחב מלא — סביר שיכללו רק תת-קבוצה של ה-qubits הפעילים במעגל או הקיימים ב-target של ה-backend. בתצורות טיפוסיות של ה-boxing pass manager, מכיוון שכל ה-qubits שהוראת box פועלת עליהם עוברים twirl (גם אלה שאף הוראה בתוך ה-box לא פועלת עליהם), קיום boxes ברוחב חלקי משפיע על אפקטי התאמת הרעש של ה-twirling. ה-qubits הסרק (idle) לא עוברים twirl ויכולים, למשל, לצבור שגיאות קוהרנטיות בזמן שה-box מופעל. הארגומנט twirling_strategy מספק אפשרויות להרחבת ה-qubits שבבעלות כל box, ובכך משנה את מספר ה-qubits הסרק:

  • "active" (ברירת מחדל) לא מרחיב את ה-boxes לאף qubit סרק.

  • "active_accum" מרחיב את כל ה-boxes ל-qubits שכבר הופעלה עליהם הוראה קודמת במעגל. זה שימושי אם רוצים להשאיר qubits בתחילת המעגל במצב היסוד שלהם כמה שיותר זמן, על ידי כך שלא מבצעים להם twirl עד שהם נעשים פעילים.

  • "active_circuit" מרחיב את כל ה-boxes ל-qubits שמופעלת עליהם הוראה כלשהי במעגל. זה שימושי אם יש לכם מעגל מובנה עם שכבות הסתבכות חוזרות ואתם רוצים למזער את מספר ה-boxes הייחודיים, כי צריך ללמוד את הרעש של כל אחד מהם.

  • "all" מרחיב את כל ה-boxes לכל ה-qubits בכל האוגרים הקוונטיים של המעגל. זה שימושי כהרחבה של "active_circuit" כשרוצים שכל ה-qubits ב-QPU יעברו twirl תמיד.

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

circuit = QuantumCircuit(5, 2)
circuit.h(range(4))
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.barrier()
circuit.h(range(4))
circuit.measure([1, 2], [0, 1])

circuit.draw("mpl", scale=0.6)

../_images/cdf089891dabe1650f1303c8c747aa8cf03cdde4dfc42c772fe2264bd7a49a1b.png

import matplotlib.pyplot as plt

plt.figure(figsize=(9, 6))
for idx, strategy in enumerate(["active", "active_accum", "active_circuit", "all"]):
ax = plt.subplot(2, 2, idx + 1)
pm = generate_boxing_pass_manager(twirling_strategy=strategy, remove_barriers="never")
transpiled_circuit = pm.run(circuit)
fig = transpiled_circuit.draw("mpl", scale=0.8, ax=ax)
ax.set_title(f"twirling_strategy='{strategy}'")

plt.tight_layout()

../_images/b810ecc4c65822cf60b3d652792a4089c5f931ad1e8320eccdd89bc50a08ba6d.png

הגדרת הטיפול ב-barriers​

כברירת מחדל, barriers מוסרים מהמעגל לאחר שכל שערי ההסתבכות והוראות המדידה נארזו ב-boxes כפי שהוגדר, כולל ההרחבות שלהם עקב בחירת twirling_strategy, אבל לפני שמוסיפים שערי qubit בודד ל-box שמיד מימינם, אם אפשר.

למשל, המעגל הבא מכיל barrier:

circuit_with_barrier = QuantumCircuit(4)
circuit_with_barrier.h(range(4))
circuit_with_barrier.cz(0, 1)
circuit_with_barrier.barrier()
circuit_with_barrier.cz(2, 3)
circuit_with_barrier.measure_all()

circuit_with_barrier.draw("mpl", scale=0.8)

../_images/f2343807597155ab5301205803954b95d29ba0d7370440bd861439fd83d1a193.png

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

boxing_pass_manager = generate_boxing_pass_manager()
transpiled_circuit = boxing_pass_manager.run(circuit_with_barrier)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/7e0812ac6b3f2405c765338ab25c2e9179165a7257ef1d996bea99f94cb39ca6.png

הגדרת remove_barriers ל-'never' משמרת את ה-barriers כך ששערי ה-qubit הבודד מוגבלים.

boxing_pass_manager = generate_boxing_pass_manager(remove_barriers="never")

transpiled_circuit = boxing_pass_manager.run(circuit_with_barrier)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/6b57e625509dd8ca55fbd96994398b03ac2fe6f76f21535db9bd042d4c68c987.png

לבסוף, אם ה-barriers מוסרים מיד, שערי ההסתבכות כבר לא מוגבלים להגיע ל-boxes נפרדים.

boxing_pass_manager = generate_boxing_pass_manager(remove_barriers="immediately")

transpiled_circuit = boxing_pass_manager.run(circuit_with_barrier)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/9a44c59a05a44a3e8f0ce9b7edd3ccc2896c6a68fb00ed110a7e225f52a7ca73.png

איך עובדת החלוקה לשכבות (stratification)​

ה-boxing pass manager מריץ ברצף שני passes מרכזיים:

  1. GroupGatesIntoBoxes — מחלק לשכבות את שערי ההסתבכות בתוך boxes. שערי qubit בודד מתעלמים מהם בשלב הזה; רק שערי שני qubits מקובצים.

  2. AbsorbSingleQubitGates — סופג כל שער qubit בודד ל-box הזכאי הקרוב ביותר מימינו.

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

  • מחסומים (Barriers)

  • הוראות box קיימות

  • Measurements

שערי qubit בודד אינם תוחמים — אין להם השפעה על הקיבוץ והם נשארים ל-AbsorbSingleQubitGates שיטפל בהם. כרגע לא מתבצע ניתוח חילופיות (commutativity); הקיבוץ מכבד את הסדר הטופולוגי של המעגל כפי שהוא.

ברירת המחדל היא "after_stratification" כי היא משלבת שני יתרונות:

  • Barriers מגבילים איך שערי הסתבכות מקובצים (הם פועלים כתוחמים במהלך החלוקה לשכבות).

  • Barriers מוסרים לפני ש-AbsorbSingleQubitGates רץ, ולכן שערי qubit בודד עדיין יכולים לעבור דרך המיקומים הקודמים של ה-barriers ולהיספג ב-box הקרוב ביותר.

לעומת זאת:

  • "never" שומר על barriers לאורך כל התהליך, מה שלוכד שערי qubit בודד בין barrier ל-box, מונע את ספיגתם ומשאיר סיבובים ללא twirl במעגל.

  • "immediately" מסיר barriers לפני החלוקה לשכבות, ולכן אין להם השפעה על הקיבוץ.

  • "finally" שימושי כשרוצים barriers במעגל הפלט (למשל, לצורכי הצגה חזותית), אבל שערי qubit בודד שבין barrier ל-box לא נספגים.

מעגלי ISA עם Box ו-Barrier​

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

  1. בנו את המעגל הלוגי והוסיפו barriers בגבולות השכבות שאתם רוצים שיהפכו לגבולות box.

  2. בצעו טרנספילציה למעגלי ISA. ה-Transpiler של Qiskit שומר על ה-barriers לאורך הניתוב והאופטימיזציה.

  3. הריצו את generate_boxing_pass_manager() על מעגל ה-ISA.

Barriers נחוצים כשסוף של שכבה אחת לא מכסה את כל ה-Qubits. אחרת, האלגוריתם החמדן היה מציב שערים מהשכבה הבאה, על אותם Qubits "חופשיים", באותה קבוצה. כדוגמה קונקרטית, ניקח סימולציית Heisenberg ZZ בת שני צעדים על טבעת של 5 Qubits. לכל צעד Trotter יש שלוש שכבות קשרים: קשרים זוגיים (0,1), (2,3), קשרים אי-זוגיים (1,2), (3,4) וקשר העטיפה (4,0). אחרי שכבת הקשרים האי-זוגיים, Qubits 0 ו-4 שניהם חופשיים. בלי barrier, קשר העטיפה (4,0) מקובץ בחמדנות עם קשרים מצעד Trotter הבא שמשתמשים באותם Qubits חופשיים, וכך מתערבבים שערים מצעדים שונים באותו box.

from qiskit.circuit import Parameter, QuantumCircuit

n = 5 # 5-qubit ring: bonds (0,1), (1,2), (2,3), (3,4), (4,0)
dt = Parameter("dt")
heisenberg = QuantumCircuit(n)

for step in range(2):
# Layer 1: even bonds (0,1) and (2,3)
for idx in range(0, n - 1, 2):
heisenberg.rzz(dt, idx, idx + 1)
heisenberg.barrier()
# Layer 2: odd bonds (1,2) and (3,4) -- qubits 0 and 4 are now free
for idx in range(1, n - 1, 2):
heisenberg.rzz(dt, idx, idx + 1)
heisenberg.barrier()
# Layer 3: wrap bond (4,0) -- both qubits were free after layer 2
heisenberg.rzz(dt, n - 1, 0)
if step < 1:
heisenberg.barrier() # separates the two Trotter steps

heisenberg.measure_all()

heisenberg.draw("mpl", scale=0.7)

../_images/172fa55c9f02964fef32fc045a50b86971126be728602b3f1e4b2437df2580b7.png

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

from qiskit.transpiler import generate_preset_pass_manager

preset_pm = generate_preset_pass_manager(
basis_gates=["rz", "sx", "cx"],
coupling_map=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]],
optimization_level=1,
)
isa_circuit = preset_pm.run(heisenberg)
isa_circuit.draw("mpl", scale=0.5, fold=200)

../_images/e9a3fbd6ab1a91051c5cd0273d92ecebc6ae8ebbc370c30bc55daee1fd28bab7.png

בשלב הבא, החילו את boxing pass manager על מעגל ה-ISA. כל אחת משלוש שכבות הקשרים הופכת ל-box נפרד בכל צעד Trotter.

boxing_pm = generate_boxing_pass_manager()
boxed_isa = boxing_pm.run(isa_circuit)
boxed_isa.draw("mpl", scale=0.5, fold=100)

../_images/b59e3c047264b3340d9af0f1ca74ad9f7d4c1705d4a5176e441346db9b678213.png

שילוב ה-pass manager של Samplomatic ב-preset pass managers של Qiskit​

הקוד שלהלן מראה איך לשלב את generate_boxing_pass_manager() ב-preset pass manager של Qiskit. המעגל שעבר טרנספילציה הוא ISA ומכיל boxes.

from qiskit.transpiler import generate_preset_pass_manager

preset_pass_manager = generate_preset_pass_manager(
basis_gates=["rz", "sx", "cx"],
coupling_map=[[0, 1], [1, 2]],
optimization_level=0,
)
boxing_pass_manager = generate_boxing_pass_manager()

# Run the boxing pass manager after the scheduling stage
preset_pass_manager.post_scheduling = boxing_pass_manager

circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(0, 2)
circuit.measure_all()

transpiled_circuit = preset_pass_manager.run(circuit)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/fe943b034588a5354a87abcf51b8d805c36f4f2b30a73a39c5886bce9e156b04.png

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

preset_pm = generate_preset_pass_manager(
basis_gates=["rz", "sx", "cx"],
coupling_map=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]],
optimization_level=1,
)
preset_pm.post_scheduling = generate_boxing_pass_manager()

boxed_heisenberg = preset_pm.run(heisenberg)
boxed_heisenberg.draw("mpl", scale=0.5, fold=100)

../_images/4905bf1df63cc83fa581ed006a93beb709be504a4f59fc7f663f4efde62da175.png

בדיקה ושינוי של annotations​

אחרי auto-boxing, ייתכן שתרצו לבדוק את ה-annotations של boxes מסוימים או להתאים אותם. למשל, כדי להוסיף הזרקת רעש, להסיר annotations או לשנות קבוצת twirling. Samplomatic מספקת לשם כך קבוצת פונקציות עזר ב-samplomatic.utils. כולן מחזירות מעגל חדש בלי לשנות את המקורי.

extend_annotations() מוסיפה annotation אחד או יותר לכל box במעגל.

from samplomatic import InjectNoise, Twirl
from samplomatic.utils import extend_annotations

boxed = generate_boxing_pass_manager().run(circuit_with_barrier)

# Add InjectNoise to every box
with_noise = extend_annotations(boxed, InjectNoise("my_noise_ref"))
with_noise.draw("mpl", scale=0.8)

../_images/7e0812ac6b3f2405c765338ab25c2e9179165a7257ef1d996bea99f94cb39ca6.png

filter_annotations() משאירה רק annotations מהסוגים שצוינו ומסירה את השאר. replace_annotations() מפעילה callable על כל annotation; ה-callable מחזיר רשימת annotations שיחליפו אותו (החזירו [] להסרה, רשימה בעלת איבר אחד להחלפה, או רשימה בעלת כמה איברים להרחבה).

from samplomatic.utils import filter_annotations, replace_annotations

# Keep only Twirl annotations, drop everything else
twirl_only = filter_annotations(with_noise, Twirl)

# Replace the twirling group on every Twirl annotation
updated = replace_annotations(
twirl_only, lambda a: [Twirl(group="local_c1")] if isinstance(a, Twirl) else [a]
)

הפונקציה הכללית map_annotations() מקבלת כל callable שממפה רשימת annotations לרשימה חדשה, ונותנת לכם שליטה מלאה בטרנספורמציות לכל box. strip_annotations() היא עטיפה נוחה שמסירה את כל ה-annotations מכל box.

עבור שינויים גורפים, כמו הוספת InjectNoise לכל ה-boxes של שערים, הפרמטר inject_noise_targets של generate_boxing_pass_manager() היא האפשרות התמציתית ביותר. כלי העזר האלה שימושיים לעריכות סלקטיביות לכל box שפרמטרי ה-pass manager לא מכסים.

בניית מעגל​

כל pass manager שמופק על ידי generate_boxing_pass_manager() מחזיר מעגלים שאפשר להפוך בהצלחה לזוג template/samplex באמצעות build(). לדוגמה, הקוד הבא קורא לפונקציה build() על מעגל שהופק על ידי boxing pass manager.

from samplomatic import build

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
)
transpiled_circuit = boxing_pass_manager.run(circuit)

template, samplex = build(transpiled_circuit)

כדי להבטיח שאפשר לבנות בהצלחה כל מעגל שעבר טרנספילציה, ה-pass managers יודעים להוסיף boxes נוספים כשצריך. לדוגמה, ניקח את המעגל שלהלן, שמסתיים ב-Qubit 0 שלא נמדד.

circuit_with_unmeasured_qubit = QuantumCircuit(4, 3)
circuit_with_unmeasured_qubit.cz(0, 1)
circuit_with_unmeasured_qubit.cz(2, 3)
for qubit in range(4):
circuit_with_unmeasured_qubit.rz(Parameter(f"th_{qubit}"), qubit)
circuit_with_unmeasured_qubit.rx(Parameter(f"phi_{qubit}"), qubit)
circuit_with_unmeasured_qubit.rz(Parameter(f"lam_{qubit}"), qubit)
circuit_with_unmeasured_qubit.measure(range(1, 4), range(3))

circuit_with_unmeasured_qubit.draw("mpl", scale=0.8)

../_images/0452779799470d2deb4d32ce19f5aa28dfe8055a064e67c0e8e5684389845b0f.png

הקפת השערים והמדידות ב-boxes עם dressing שמאלי הייתה יוצרת מעגל עם שערים וירטואליים שלא נאספו ב-Qubit 0, וקריאה ל-build() על המעגל הזה הייתה גורמת לשגיאה. כדי להימנע מכך, ה-pass managers שמוחזרים מ-generate_boxing_pass_manager() יכולים להוסיף boxes עם dressing ימני שישמשו כאוספים. לדוגמה, בקוד הבא Qubit 0 מסתיים ב-box עם dressing ימני שאוסף את השער הווירטואלי שלא נאסף. גם השערים החד-Qubitיים הפועלים על Qubit 0 ממוקמים בתוך ה-box, כדי למזער את העומק של המעגל המתקבל.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
)
transpiled_circuit = boxing_pass_manager.run(circuit_with_unmeasured_qubit)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/711ee3c014edf6f70ede5dfa849494286e96870b3bd70a2a89f687d83cc5bfc1.png

בדוגמה אחרת, נוסף box עם dressing ימני כדי לאסוף את השערים הווירטואליים שאחרת היו נשארים לא נאספים בגלל מדידות שלא נכנסו ל-boxes.

boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
)
transpiled_circuit = boxing_pass_manager.run(circuit_with_unmeasured_qubit)
transpiled_circuit.draw("mpl", scale=0.8)

../_images/d59d0c0af3c47f474a964a455533b99e09a65364454ec04ced7581e6afac73ab.png