Circuit-Timing visualisieren
Paketversionen
Der Code auf dieser Seite wurde mit den folgenden Anforderungen entwickelt. Wir empfehlen, diese Versionen oder neuere zu verwenden.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
Während die in Qiskit integrierte Timeline-Ansicht für statische Circuits nützlich ist, spiegelt sie das Timing von dynamischen Circuits möglicherweise nicht korrekt wider – aufgrund impliziter Operationen wie Broadcasting und Branch-Bestimmung. Als Teil der Unterstützung für dynamische Circuits gibt Qiskit Runtime auf Anfrage genaue Circuit-Timing-Informationen in den Job-Ergebnissen zurück.
- Dies ist eine experimentelle Funktion. Sie befindet sich im Vorschau-Status und kann sich daher ändern.
- Diese Funktion gilt nur für Qiskit Runtime Sampler-Jobs.
- Obwohl die gesamte Circuit-Zeit in den Metadaten unter „compilation" zurückgegeben wird, ist dies NICHT die für die Abrechnung verwendete Zeit (QPU-Zeit).
Timing-Datenabruf aktivieren
Um den Timing-Datenabruf zu aktivieren, setze das experimentelle Flag scheduler_timing auf True, wenn du den Primitive-Job ausführst.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
sampler = SamplerV2(backend)
sampler.options.experimental = {
"execution": {
"scheduler_timing": True,
},
}
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
Auf die Circuit-Timing-Daten zugreifen
Wenn angefordert, werden die Circuit-Timing-Daten für jeden PUB in den Job-Ergebnis-Metadaten unter ["compilation"]["scheduler_timing"]["timing"] zurückgegeben. Dieses Feld enthält die rohen Timing-Informationen. Um die Timing-Informationen anzuzeigen, verwende das integrierte Visualisierungswerkzeug, wie im Abschnitt Timings visualisieren beschrieben.
Nutze den folgenden Code, um auf die Circuit-Timing-Daten für den ersten PUB zuzugreifen:
job_result = sampler_job.result()
circuit_schedule = job_result[0].metadata["compilation"]["scheduler_timing"]
circuit_schedule_timing = circuit_schedule["timing"]
Die rohen Timing-Daten verstehen
Obwohl das Visualisieren der Circuit-Timing-Daten mit der Methode draw_circuit_schedule_timing der häufigste Anwendungsfall ist, kann es nützlich sein, die Struktur der zurückgegebenen rohen Timing-Daten zu verstehen. Das kann dir beispielsweise helfen, Informationen programmatisch zu extrahieren.
Die in ["compilation"]["scheduler_timing"]["timing"] zurückgegebenen Timing-Daten sind eine Liste von Zeichenketten. Jede Zeichenkette stellt eine einzelne Anweisung auf einem Kanal dar und ist durch Kommas in folgende Datentypen unterteilt:
Branch– Bestimmt, ob die Anweisung in einem Control-Flow-Zweig (then / else) oder im Hauptzweig ist.Instruction– Das Gate und das Qubit, auf dem es ausgeführt wird.Channel– Der Kanal, dem die Anweisung zugewiesen ist. Es kann einer der folgenden sein:Qubit x– Der Drive-Kanal für Qubit x.AWGRx_y(arbitrary waveform generator readout) – Wird von Ausleskanälen genutzt, um beim Messen von Qubits zu kommunizieren. Die Argumente x und y entsprechen der Auslesgeräte-ID und der Qubit-Nummer.
T0– Die Startzeit der Anweisung im gesamten Schedule.Duration– Die Dauer der Anweisung in Einheiten von dt Sekunden, wobei 1 dt = 1 Scheduling-Zyklus. Dendt-Wert eines Backends findest du mitbackend.dt.Pulse– Der Typ der verwendeten Pulsoperation.
Beispiel:
main,barrier,Qubit 0,7,0,barrier # A barrier on the main branch on qubit 0 at time 7 with 0 duration
main,reset_0,Qubit 0,7,64,play # A reset instruction on the main branch on qubit 0 at time 7 with duration 64 and a play operation
...
Timings visualisieren
Ab qiskit-ibm-runtime v0.43.0 kannst du Circuit-Timings visualisieren. Um die Timings zu visualisieren, musst du zunächst die Ergebnis-Metadaten mit der Methode draw_circuit_schedule_timing in fig umwandeln. Diese Methode gibt eine plotly-Abbildung zurück, die du direkt anzeigen, in eine Datei speichern oder beides tun kannst. Weitere Informationen zu den zu verwendenden plotly-Befehlen findest du unter fig.show() und fig.write_image("<path.format>").
from qiskit_ibm_runtime.visualization import draw_circuit_schedule_timing
# Create a figure from the metadata
fig = draw_circuit_schedule_timing(
circuit_schedule=circuit_schedule_timing,
included_channels=None,
filter_readout_channels=False,
filter_barriers=False,
width=1000,
)
# Uncomment the following line to display the figure
# fig.show(renderer="notebook")
# Save to a file
# fig.write_html("scheduler_timing.html")
Die generierte Abbildung verstehen
Das Bild der von draw_circuit_schedule_timing ausgegebenen Circuit-Timing-Daten vermittelt folgende Informationen:
- Die X-Achse ist die Zeit in Einheiten von dt Sekunden, wobei 1 dt = 1 Scheduling-Zyklus. Den
dt-Wert eines Backends findest du mitbackend.dt. - Die Y-Achse ist der Kanal (stell dir Kanäle als Instrumente vor, die Pulse ausgeben).
Receive channel– Der einzige Kanal, der selbst kein Instrument ist. Es ist eine Anweisung, die auf allen Kanälen gespielt wird, die zu diesem Zeitpunkt an einem Kommunikationsverfahren mit dem Hub beteiligt sind.Qubit x– Der Drive-Kanal für Qubit x.AWGRx_y(arbitrary waveform generator readout) – Wird von Ausleskanälen genutzt, um beim Messen von Qubits zu kommunizieren. Die Argumente x und y entsprechen der Auslesgeräte-ID und der Qubit-Nummer.Hub– Steuert das Broadcasting.
Zusätzlich hat jede Anweisung das Format X_Y, wobei X der Name der Anweisung und Y der Pulstyp ist. Ein play-Typ wendet Kontrollpulse an, und ein capture zeichnet den Zustand des Qubits auf. Du kannst auch über jede Anweisung hovern, um weitere Details zu erhalten. Zum Beispiel zeigt die vorherige Abbildung einen Kontrollpuls für das X-Gate, das bei 1161 dt auf Qubit 10 angewendet wird.
End-to-End-Beispiel
Dieses Beispiel zeigt dir, wie du die Option aktivierst, die Circuit-Timing-Informationen aus den Metadaten holst und sie als Bild darstellst.
Richte zunächst die Umgebung ein, definiere die Circuits und konvertiere sie zu ISA-Circuits, und definiere und starte die Jobs.
from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = SamplerV2(backend)
sampler.options.experimental = {"execution": {"scheduler_timing": True}}
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d8287kugbeec73alfbug (DONE)
Hole anschließend das Circuit-Schedule-Timing:
# Get the circuit schedule timing
result[0].metadata["compilation"]["scheduler_timing"]["timing"]
'main,rz_0,Qubit 0,1365,0,shift_phase\nmain,sx_0,Qubit 0,1365,9,play\nmain,sx_0,Qubit 0,1369,0,shift_phase\nmain,rz_0,Qubit 0,1374,0,shift_phase\nmain,barrier,Qubit 0,1374,0,barrier\nmain,measure_0,Qubit 0,1374,64,play\nmain,measure_0,Qubit 0,1438,108,play\nmain,measure_0,AWGR0_0,1485,360,capture\nmain,measure_0,Qubit 0,1546,64,play\nmain,measure_0,Qubit 0,1610,64,play\nmain,barrier,Qubit 0,2046,0,barrier\nmain,broadcast,Hub,1485,561,broadcast\nmain,receive,Receive,2046,7,receive\nthen,x_0,Qubit 0,2061,9,play\nmain,barrier,Qubit 0,2079,0,barrier\nmain,measure_0,Qubit 0,2079,64,play\nmain,measure_0,Qubit 0,2143,108,play\nmain,measure_0,AWGR0_0,2190,360,capture\nmain,measure_0,Qubit 0,2251,64,play\nmain,measure_0,Qubit 0,2315,64,play\nmain,barrier,Qubit 0,2725,0,barrier\nmain,barrier,Qubit 0,2725,0,barrier\n'
Schließlich kannst du das Timing visualisieren und speichern:
from qiskit_ibm_runtime.visualization import draw_circuit_schedule_timing
circuit_schedule = result[0].metadata["compilation"]["scheduler_timing"][
"timing"
]
fig = draw_circuit_schedule_timing(
circuit_schedule=circuit_schedule,
included_channels=None,
filter_readout_channels=False,
filter_barriers=False,
width=1000,
)
# Uncomment the following line to display the figure
# fig.show(renderer="notebook")
# Save to a file
# fig.write_html("scheduler_timing.html")
Nächste Schritte
- Klassisches Feedforward und Control Flow (dynamische Circuits)
- Circuits visualisieren