Wizualizacja czasu wykonania obwodu
Wersje pakietów
Kod na tej stronie został opracowany przy użyciu następujących wymagań. Zalecamy używanie tych lub nowszych wersji.
qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
Chociaż rysownik osi czasu wbudowany w Qiskit jest przydatny dla statycznych obwodów, może nie dokładnie odzwierciedlać czasu wykonania obwodów dynamicznych ze względu na niejawne operacje, takie jak rozgłaszanie i określanie gałęzi. W ramach obsługi obwodów dynamicznych IBM Quantum Compute Service zwraca dokładne informacje o czasie wykonania obwodu wewnątrz wyników zadania, gdy jest to wymagane.
- Jest to funkcja eksperymentalna. Jest w fazie wersji zapoznawczej i dlatego może ulec zmianie.
- Ta funkcja dotyczy tylko zadań IBM Quantum Sampler i Executor.
- Chociaż całkowity czas obwodu jest zwracany w metadanych "compilation", NIE jest to czas używany do rozliczeń (czas QPU).
Ta opcja działa również z zadaniami dry-run. Przekaż dry_run=True do run(), aby uzyskać harmonogram czasowy obwodu bez zużywania czasu QPU.
Włączanie pobierania danych czasowych
Aby włączyć pobieranie danych czasowych, ustaw eksperymentalną flagę scheduler_timing na True podczas uruchamiania zadania prymitywu.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_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")
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager
# Legacy server-side primitive before qiskit-ibm-runtime v0.50.0
# from qiskit_ibm_runtime import Sampler
# Client-side primitive introduced in qiskit-ibm-runtime v0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
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 = Sampler(backend)
sampler.options.experimental = {
"execution": {
"scheduler_timing": True,
},
}
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
Dostęp do danych czasowych obwodu
Gdy jest to wymagane, dane czasowe obwodu dla każdego PUB są zwracane w metadanych wynikowych zadania, pod ["compilation"]["scheduler_timing"]["timing"]. To pole zawiera surowe informacje o czasie. Aby wyświetlić informacje o czasie, użyj wbudowanego narzędzia wizualizacji, jak opisano w sekcji Wizualizacja czasów.
Użyj poniższego kodu, aby uzyskać dostęp do danych czasowych obwodu dla pierwszego PUB:
job_result = sampler_job.result()
circuit_schedule = job_result[0].metadata["compilation"]["scheduler_timing"]
circuit_schedule_timing = circuit_schedule["timing"]
Zrozumienie surowych danych czasowych
Chociaż wizualizacja danych czasowych obwodu za pomocą metody draw_circuit_schedule_timing jest najczęstszym przypadkiem użycia, może być przydatne zrozumienie struktury zwracanych surowych danych czasowych. Może to pomóc, na przykład, w programowym wyodrębnianiu informacji.
Dane czasowe zwracane w ["compilation"]["scheduler_timing"]["timing"] to lista ciągów znaków. Każdy ciąg reprezentuje pojedynczą instrukcję na jakimś kanale i jest rozdzielony przecinkami na następujące typy danych:
-
Branch- Określa, czy instrukcja jest w przepływie sterowania (then / else) czy w gałęzi głównej. -
Instruction- Bramka i kubit, na którym ma działać. -
Channel- Kanał, do którego przypisana jest instrukcja. Może być jednym z następujących:-
Qubit x- Kanał sterowania dla kubitu x. -
AWGRx_y(generator dowolnych przebiegów do odczytu) - Używany przez kanały odczytu do komunikacji podczas pomiaru kubitów. Argumenty x i y odpowiadają odpowiednio identyfikatorowi instrumentu odczytu i numerowi kubitu.
-
-
T0- Czas rozpoczęcia instrukcji w pełnym harmonogramie -
Duration- Czas trwania instrukcji, w jednostkach dt sekund, gdzie 1 dt = 1 cykl harmonogramowania. Wartośćdtbackendu można znaleźć za pomocąbackend.dt. -
Pulse- Typ używanej operacji impulsowej.
Przykład:
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
...
Wizualizacja czasów
W wersji qiskit-ibm-runtime v0.43.0 lub nowszej możesz wizualizować czasy obwodów. Aby zwizualizować czasy, musisz najpierw przekonwertować metadane wynikowe na fig za pomocą metody draw_circuit_schedule_timing. Ta metoda zwraca figurę plotly, którą możesz wyświetlić bezpośrednio, zapisać do pliku lub zrobić jedno i drugie. Aby uzyskać więcej informacji o poleceniach plotly, zobacz fig.show() i 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")

Zrozumienie wygenerowanej figury
Obraz wyjściowy danych czasowych obwodu generowany przez draw_circuit_schedule_timing przekazuje następujące informacje:
-
Oś X to czas w jednostkach dt sekund, gdzie 1 dt = 1 cykl harmonogramowania. Wartość
dtbackendu można znaleźć za pomocąbackend.dt. -
Oś Y to kanał (kanały można traktować jako instrumenty emitujące impulsy).
-
Receive channel- Jedyny kanał, który sam w sobie nie jest instrumentem. Jest to instrukcja odtwarzana na wszystkich kanałach, które są częścią procedury komunikacji z centrum w danym czasie. -
Qubit x- Kanał sterowania dla kubitu x. -
AWGRx_y(generator dowolnych przebiegów do odczytu) - Używany przez kanały odczytu do komunikacji podczas pomiaru kubitów. Argumenty x i y odpowiadają odpowiednio identyfikatorowi instrumentu odczytu i numerowi kubitu. -
Hub- Kontroluje rozgłaszanie.
-
Ponadto każda instrukcja ma format X_Y, gdzie X to nazwa instrukcji, a Y to typ impulsu. Typ play stosuje impulsy sterujące, a capture rejestruje stan kubitu. Możesz również najechać kursorem na każdą instrukcję, aby uzyskać więcej szczegółów. Na przykład poprzednia figura pokazuje impuls sterujący dla bramki X zastosowany do kubitu 10 w czasie 1161 dt.
Przykład end-to-end
Ten przykład pokazuje, jak włączyć opcję, uzyskać informacje o czasie obwodu z metadanych i wyświetlić je jako obraz.
Najpierw skonfiguruj środowisko, zdefiniuj obwody i przekonwertuj je na obwody ISA, a następnie zdefiniuj i uruchom zadania.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
# Legacy server-side primitive before qiskit-ibm-runtime v0.50.0
# from qiskit_ibm_runtime import Sampler
# Client-side primitive introduced in qiskit-ibm-runtime v0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
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 = Sampler(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: dbjed5pkdqps7390ev00 (DONE)
Następnie pobierz harmonogram czasu obwodu:
# Get the circuit schedule timing
result[0].metadata["compilation"]["scheduler_timing"]["timing"]
'main,rz_0,Qubit 0,875,0,shift_phase\nmain,sx_0,Qubit 0,875,6,play\nmain,sx_0,Qubit 0,879,0,shift_phase\nmain,rz_0,Qubit 0,882,0,shift_phase\nmain,barrier,Qubit 0,882,0,barrier\nmain,measure_0,Qubit 0,882,180,play\nmain,measure_0,AWGR0_0,1003,205,capture\nmain,barrier,Qubit 0,1409,0,barrier\nmain,broadcast,Hub,1003,406,broadcast\nmain,receive,Receive,1409,7,receive\nthen,x_0,Qubit 0,1424,6,play\nmain,barrier,Qubit 0,1437,0,barrier\nmain,measure_0,Qubit 0,1437,180,play\nmain,measure_0,AWGR0_0,1558,205,capture\nmain,barrier,Qubit 0,1852,0,barrier\nmain,barrier,Qubit 0,1852,0,barrier\nmain,FINI_0,Qubit 0,1852,180,play\nmain,FINI_0,AWGR0_0,1973,205,capture\nmain,FINI_0,Qubit 0,2267,6,play\nmain,FINI_0,Qubit 0,2273,180,play\nmain,FINI_0,AWGR0_0,2394,205,capture\nmain,FINI_0,Qubit 0,2688,6,play\nmain,barrier,Qubit 0,2694,0,barrier\n'
Na koniec możesz zwizualizować i zapisać czas:
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")
Następne kroki
- Klasyczne sprzężenie w przód (feedforward) i przepływ sterowania (obwody dynamiczne)
- Wizualizacja obwodów