Transpiler
Die Funktion generate_boxing_pass_manager() ist ein flexibles und praktisches Werkzeug zum Erstellen eines, mit dem qiskit.transpiler.PassManager sich die Schaltkreisanweisungen in kommentierte Kästchen gruppieren lassen. Dies bietet eine einfache Alternative zum manuellen Gruppieren und Beschriften von Schaltkreisen und eignet sich zur Automatisierung eines Arbeitsablaufs, zum Testen verschiedener Strategien zur Schaltkreisgruppierung und so weiter.
In dieser Anleitung wird die Verwendung von und generate_boxing_pass_manager() seiner Argumente erläutert. Um die Auswirkungen der einzelnen Argumente der Funktion zu verdeutlichen, beziehen sich die folgenden Abschnitte hauptsächlich auf die unten abgebildete Schaltung.
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)
Vorgänge in Gruppen zusammenfassen
Das Argument enable_gates kann auf oder True gesetzt werden, False um festzulegen, ob die Zwei-Qubit-Gatter in Kästchen gruppiert werden sollen. Ebenso enable_measures legt fest, ob Messungen gruppiert werden sollen oder nicht. Der folgende Ausschnitt zeigt ein Beispiel, bei dem sowohl Gatter als auch Messungen gruppiert sind.
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)
Wie aus der Abbildung ersichtlich ist, erstellt der Pass-Manager zwei Arten von Blöcken: solche, die eine einzelne Schicht aus Zwei-Qubit-Gattern enthalten, und solche, die eine einzelne Schicht aus Messungen enthalten. Diese Trennung entspricht den gängigen Vorgehensweisen bei Protokollen zum Rauschlernen und zur Rauschminderung, die in der Regel auf Schichten mit homogenen Operationen abzielen. Die Zwei-Qubit-Gatter und -Messungen werden in das Feld ganz links platziert, in das sie passen, und jedes Einzel-Qubit-Gatter wird in dasselbe Feld platziert wie das Zwei-Qubit-Gatter oder die Messung, der es vorausgeht.
Der folgende Code zeigt ein Beispiel, in dem auf gesetzt enable_gates wird False. Wie man sieht, sind die Zwei-Qubit-Gatter nicht in Kästchen gruppiert, ebenso wenig wie die ihnen vorausgehenden Ein-Qubit-Gatter.
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)
Wählen Sie aus, wie die Kästchen beschriftet werden sollen
Alle Zwei-Qubit-Gatter und Messboxen in der zurückgegebenen Schaltung sind mit „left-dressed“-Annotationen versehen. Insbesondere sind alle Kästchen, die Zwei-Qubit-Gatter enthalten, mit einem Twirl. gekennzeichnet. Bei Messfeldern können Benutzer zwischen Twirl, BasisTranform (wobei auf mode gesetzt ist "measure") oder beiden Optionen wählen. Der folgende Code erzeugt eine Schaltung, in der alle Kästchen gedreht sind und die Messkästchen zusätzlich mit beschriftet sind BasisTranform.
boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
measure_annotations="all",
)
transpiled_circuit = boxing_pass_manager.run(circuit)Bereiten Sie die Schaltung für die Rauscheinjektion vor
Damit inject_noise_targets können Sie festlegen, welche Felder eine Anmerkung InjectNoise erhalten sollen. Der folgende Code erzeugt beispielsweise einen Schaltkreis, in dem die 2-Qubit-Gatter-Felder eine Anmerkung InjectNoise enthalten, die Messfelder jedoch nicht.
boxing_pass_manager = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
inject_noise_targets="gates",
)
transpiled_circuit = boxing_pass_manager.run(circuit)Enthält eine Schaltung zwei oder mehr Blöcke, die bis auf Einzel-Qubit-Gatter äquivalent sind, werden alle mit einer InjectNoise Anmerkung versehen, die denselben Wert aufweist ref. Somit entspricht die Anzahl der eindeutigen ref„s“ in der zurückgegebenen Schaltung der Anzahl der eindeutigen Kästchen.
Der Wert für wirkt inject_noise_strategy sich auf die Anmerkungen InjectNoise aus. Die folgenden Werte sind gültig:
modifier_ref='': Empfohlen, wenn Sie die Rauschkarten vor der Abtastung nicht ändern müssen.modifier_ref=ref: Empfohlen, wenn alle Noise-Maps einheitlich um denselben Faktor skaliert werden sollen.- Ein eindeutiger Wert von
modifier_ref: Empfohlen, wenn jede Rauschkarte mit einem anderen Faktor skaliert werden muss.
Der folgende Code erzeugt einen Schaltkreis, in dem die Kästchen der Zwei-Qubit-Gatter mit Anmerkungen InjectNoise versehen sind, die eindeutige Werte modifier_ref enthalten.
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)Wähle eine Drehstrategie aus
Der Boxing-Pass-Manager beginnt damit, auszuwählen, welche Verflechtungsgatter und Messanweisungen in denselben Feldern erscheinen sollen. Sobald dies erreicht ist, werden die Felder in der Regel nicht mehr die volle Breite einnehmen – sie werden wahrscheinlich nur noch eine Teilmenge der Qubits enthalten, die in der Schaltung aktiv sind oder im Backend-Ziel vorhanden sind. In typischen Konfigurationen des „Boxing-Pass-Managers“ werden alle Qubits, auf die eine Box-Anweisung wirkt, durch Twirling beeinflusst (auch diejenigen, auf die keine Anweisung innerhalb der Box wirkt); daher wirken sich Boxen mit teilweiser Breite auf die rauschoptimierenden Effekte des Twirling aus. Die im Leerlauf befindlichen Qubits werden nicht gedreht und können beispielsweise kohärente Fehler aufbauen, während die Box angelegt wird. Die bietet twirling_strategy Möglichkeiten, die Anzahl der zu jeder Box gehörenden Qubits zu erweitern und dadurch die Anzahl der inaktivierten Qubits zu verändern:
"active"(Standard) erweitert die Boxen nicht auf inaktivierte Qubits."active_accum"erweitert alle Felder auf jene Qubits, auf die bereits durch einen vorherigen Befehl in der Schaltung eingewirkt wurde. Dies ist nützlich, wenn Sie die Qubits zu Beginn des Schaltkreises so lange wie möglich in ihrem Grundzustand belassen möchten, indem Sie sie erst dann in Rotation versetzen, wenn sie aktiv werden."active_circuit"erweitert alle Kästchen auf jene Qubits, auf die ein beliebiger Befehl im Schaltkreis einwirkt. Dies ist nützlich, wenn Sie eine strukturierte Schaltung mit sich wiederholenden Verschränkungsschichten haben und die Anzahl der einzelnen Boxen minimieren möchten, da für jede einzelne das Rauschen erlernt werden muss."all"erweitert alle Kästchen auf alle Qubits in allen Quantenregistern der Schaltung. Dies ist als Erweiterung nützlich, wenn"active_circuit"man möchte, dass alle Qubits in der QPU stets „twirled“ sind.
Im folgenden Beispiel wird jede der Strategien auf die Basisschaltung angewendet, anschließend werden die Ergebnisse dargestellt.
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)
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()
Legen Sie fest, wie mit Hindernissen umgegangen werden soll
Standardmäßig werden Barrieren aus dem Schaltkreis entfernt, nachdem alle Verschränkungsgatter und Messanweisungen wie angegeben in die Box aufgenommen wurden – einschließlich ihrer Erweiterungen aufgrund der Auswahl twirling_strategy –, jedoch bevor Einzelqubit-Gatter, sofern möglich, in die Box unmittelbar rechts davon eingefügt werden.
Die folgende Schaltung enthält beispielsweise eine Barriere:
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)
Das Standardverhalten verhindert, dass die beiden Verschränkungsgatter in derselben Box landen, lässt jedoch zu, dass die Einzel-Qubit-Gatter trotz der Barriere in die nächste verfügbare Box aufgenommen werden.
boxing_pass_manager = generate_boxing_pass_manager()
transpiled_circuit = boxing_pass_manager.run(circuit_with_barrier)
transpiled_circuit.draw("mpl", scale=0.8)
Durch die Einstellung auf remove_barriers werden die Barrieren 'never' beibehalten, sodass Einzel-Qubit-Gatter eingeschränkt werden.
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)
Wenn schließlich die Barrieren sofort beseitigt werden, sind die Verwickelten nicht mehr dazu gezwungen, in getrennten Kisten zu landen.
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)
So funktioniert die Schichtung
Der Boxing-Pass-Manager führt nacheinander zwei Schlüssel-Passes aus:
GroupGatesIntoBoxes— Unterteilt verschachtelte Gatter in Blöcke. Einzel-Qubit-Gatter werden in dieser Phase außer Acht gelassen; es werden ausschließlich Zwei-Qubit-Gatter gruppiert.AbsorbSingleQubitGates— Ordnet jedes Einzel-Qubit-Gatter dem nächstgelegenen geeigneten Feld rechts davon zu.
Bei der Stratifizierung durchläuft GroupGatesIntoBoxes das Programm den DAG-Zyklus in topologischer Reihenfolge und ordnet jedes Zwei-Qubit-Gatter der frühesten Gruppe zu, deren Qubits noch nicht belegt sind. Drei Arten von Befehlen dienen als Trennzeichen, die die aktuelle Gruppe für ihre Qubits leeren und dadurch bewirken, dass nachfolgende Gatter auf diesen Qubits einer neuen Gruppe zugeordnet werden:
- Hindernisse
- Vorhandene Verpackungsanleitung
- Messungen
Einzel-Qubit-Gatter sind keine Trennzeichen – sie haben keinen Einfluss auf die Gruppierung und werden AbsorbSingleQubitGates der überlassen. Derzeit wird keine Kommutativitätsanalyse durchgeführt; die Gruppierung berücksichtigt die topologische Reihenfolge des Schaltkreises unverändert.
Warum ist remove_barriers="after_stratification" das die empfohlene Standardeinstellung?
Der Standardmodus ist, "after_stratification" da er zwei Vorteile vereint:
- Barrieren schränken die Gruppierung von Verschränkungsgattern ein (sie fungieren bei der Schichtung als Begrenzer).
- Vor den Durchläufen
AbsorbSingleQubitGateswerden die Barrieren entfernt, sodass Einzel-Qubit-Gatter weiterhin über die ehemaligen Barrierepositionen hinwegfließen und von der nächstgelegenen Box aufgenommen werden können.
Im Gegensatz dazu:
"never"behält durchgehend Barrieren bei, wodurch Einzel-Qubit-Gatter zwischen einer Barriere und einer Box eingeschlossen werden, was deren Absorption verhindert und unverdreht bleibende Rotationen im Schaltkreis hinterlässt."immediately"beseitigt Hindernisse vor der Schichtung, sodass diese keinen Einfluss auf die Gruppeneinteilung haben."finally"Dies ist nützlich, wenn Sie Barrieren im Ausgangskreis wünschen (beispielsweise zur Visualisierung), wobei Einzel-Qubit-Gatter zwischen einer Barriere und einer Box jedoch nicht absorbiert werden.
Box-ISA-Schaltungen mit Barrieren
Schaltkreise mit einer sich wiederholenden Struktur – wie beispielsweise Simulationen mit dem Trotterisierten Hamilton-Operator, Variationsansätze und Fehlerverstärkungssequenzen – werden in der Regel programmgesteuert erstellt und anschließend in die ISA-Form transpiliert. Das manuelle Hinzufügen von Blöcken zu einer transpilierten Schaltung ist mühsam, daher sieht der natürliche Arbeitsablauf wie folgt aus:
- Bauen Sie die logische Schaltung auf und fügen Sie dabei Barrieren an den Schichtgrenzen ein, die zu Kastengrenzen werden sollen.
- In ISA-Schaltungen transpilieren. Der Transpiler von Qiskit bewahrt Barrieren durch Routing und Optimierung.
- Fahre
generate_boxing_pass_manager()auf der ISA-Rennstrecke.
Barrieren sind erforderlich, wenn das Ende einer Schicht nicht alle Qubits abdeckt. Andernfalls würde der Greedy-Algorithmus Gatter aus der nächsten Schicht – auf diesen „freien“ Qubits – derselben Gruppe zuordnen. Betrachten wir als konkretes Beispiel eine zweistufige Heisenberg-ZZ-Simulation auf einem Ring aus 5 Qubits. Jeder Trotter-Schritt besteht aus drei Bindungsschichten: geraden Bindungen (0,1), (2,3), ungeraden (1,2), (3,4) Bindungen und der Wickelbindung (4,0). Nach der ungeraden Bindungsschicht sind die Qubits 0 und 4 beide frei. Ohne eine Barriere (4,0) wird die Wrap-Bindung mit Bindungen aus dem nächsten Trotter-Schritt, die diese freien Qubits nutzen, „gierig gruppiert“, wodurch Gatter aus verschiedenen Schritten in derselben Box vermischt werden.
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)
Der folgende Code transpiliert die Schaltung in die ISA-Form, wobei davon ausgegangen wird, dass das zugrunde liegende Gerät CX als nativen Entangler verwendet. Beachten Sie, dass die Barrieren die Transpilierung überstehen und im Ausgabekreis sichtbar bleiben.
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)
Wenden Sie anschließend den Boxing-Pass-Manager auf die ISA-Schaltung an. Jede der drei Bindungsschichten wird in jedem Trotter-Schritt zu einer eigenen Box.
boxing_pm = generate_boxing_pass_manager()
boxed_isa = boxing_pm.run(isa_circuit)
boxed_isa.draw("mpl", scale=0.5, fold=100)
Den Pass-Manager von Samplomatic in die voreingestellten Pass-Manager von Qiskit integrieren
Der folgende Code zeigt, wie man generate_boxing_pass_manager() in einen Qiskit-Preset-Pass-Manager integriert. Die transpilierte Schaltung ist eine ISA und enthält Blöcke.
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)
Dieses Muster lässt sich zudem nahtlos in den auf Barrieren basierenden ISA-Boxing-Workflow integrieren. Der Boxing-Pass-Manager wird als Schritt nach der Planung ausgeführt, nachdem die Barrieren aus dem ursprünglichen logischen Schaltkreis die Transpilierung überstanden haben, sodass sie die Schichtung wie erwartet steuern.
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)
Anmerkungen prüfen und bearbeiten
Nach dem automatischen Einrahmen möchten Sie vielleicht die Beschriftungen bestimmter Rahmen überprüfen oder anpassen. Beispielsweise, um Rauschen einzuspielen, Anmerkungen zu entfernen oder eine sich drehende Gruppe zu ändern. Samplomatic stellt zu samplomatic.utils diesem Zweck eine Reihe von Hilfsfunktionen zur Verfügung. Sie alle geben einen neuen Schaltkreis zurück, ohne den ursprünglichen zu verändern.
extend_annotations() fügt jeder Box im Schaltkreis eine oder mehrere Anmerkungen hinzu.
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)
filter_annotations() behält nur Anmerkungen bestimmter Typen bei und entfernt den Rest. replace_annotations() wendet eine aufrufbare Funktion auf jede Anmerkung an; die aufrufbare Funktion gibt eine Liste von Anmerkungen zurück, die an ihrer Stelle eingesetzt werden sollen (den Wert „return“, um [] sie zu entfernen, eine Liste mit einem Element, um sie zu ersetzen, oder eine Liste mit mehreren Elementen, um sie zu erweitern).
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]
)Die Allzweckfunktion map_annotations() akzeptiert jedes aufrufbare Objekt, das eine Liste von Anmerkungen auf eine neue Liste abbildet, wodurch Sie die volle Kontrolle über die Transformationen für jedes einzelne Feld haben. strip_annotations() ist eine praktische Hülle, die alle Anmerkungen aus jeder Box entfernt.
Für Massenänderungen wie das Hinzufügen von InjectNoise zu allen Gate-Boxen ist generate_boxing_pass_manager() der Parameter inject_noise_targets von die prägnanteste Option. Diese Hilfsfunktionen sind nützlich für selektive Bearbeitungen auf Box-Ebene, die durch die Parameter des Pass-Managers nicht abgedeckt werden.
Eine Schaltung aufbauen
Jeder von erzeugte Pass-Manager liefert generate_boxing_pass_manager() Schaltkreise, die von erfolgreich in ein Template/Samplex-Paar umgewandelt werden können build(). Der folgende Code ruft beispielsweise die Funktion build() für einen Schaltkreis auf, der von einem Boxing-Pass-Manager erzeugt wurde.
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)Um sicherzustellen, dass jede transpilierte Schaltung erfolgreich erstellt werden kann, wissen die Pass-Manager, wie sie bei Bedarf zusätzliche Boxen einbinden können. Betrachten wir zum Beispiel die folgende Schaltung, die mit einem ungemessenen Qubit endet 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)
Würde man linksausgerichtete Kästchen um die Gatter und die Messungen zeichnen, ergäbe dies eine Schaltung mit nicht abgeholten virtuellen Gattern auf dem Qubit 0, und der Aufruf dieser build() Schaltung würde zu einem Fehler führen. Um dies zu vermeiden, generate_boxing_pass_manager() können die von zurückgegebenen Pass-Manager rechtsbündige Boxen hinzufügen, die als Sammler fungieren. Im folgenden Code 0 wird beispielsweise das Qubit durch einen Kasten mit rechter Ausrichtung abgeschlossen, der das nicht gesammelte virtuelle Gatter aufnimmt. Die auf das Qubit wirkenden Einzel-Qubit-Gatter 0 werden ebenfalls innerhalb des Kastens platziert, um die Tiefe der resultierenden Schaltung zu minimieren.
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)
In einem weiteren Beispiel wird eine „right-dressed“-Box hinzugefügt, um die virtuellen Gates zu erfassen, die andernfalls aufgrund der unboxed-Messungen unberücksichtigt bleiben würden.
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)