Skip to main content
IBM Quantum Platform

Visualiser la synchronisation du circuit

  • Le code présenté sur cette page a été développé en tenant compte des exigences suivantes. Nous vous recommandons d'utiliser ces versions ou des versions plus récentes.

    qiskit[all]~=2.5.1
    qiskit-ibm-runtime~=0.47.0
    

Si le volet « Timeline » intégré à Qiskit s'avère utile pour les circuits statiques, il se peut qu'il ne reflète pas fidèlement la synchronisation des circuits dynamiques en raison d'opérations implicites telles que la diffusion et la détermination des branches. Dans le cadre de la prise en charge dynamique des circuits, le service de calcul d' IBM Quantum fournit, sur demande, des informations précises sur la synchronisation des circuits dans les résultats des tâches.

Remarques
  • Il s'agit d'une fonctionnalité expérimentale. Il s'agit d'une version préliminaire et elle est donc susceptible d'être modifiée.
  • Cette fonction s'applique uniquement aux tâches de l'échantillonneur « IBM Quantum ».
  • Bien que la durée totale d'exécution soit indiquée dans les métadonnées de « compilation », il ne s'agit PAS de la durée prise en compte pour la facturation (temps de QPU).

Activer la récupération des données de synchronisation

Pour activer la récupération des données de chronométrage, activez l'indicateur scheduler_timing expérimental lors True de l'exécution de la tâche primitive.

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()

Accéder aux données de chronométrage du circuit

Sur demande, les données de chronométrage du circuit pour chaque « PUB » sont fournies dans les métadonnées du résultat de la tâche, sous ["compilation"]["scheduler_timing"]["timing"]. Ce champ contient les informations brutes relatives au timing. Pour afficher les informations de synchronisation, utilisez l'outil de visualisation intégré, comme décrit dans la section « Visualiser les synchronisations ».

Utilisez le code suivant pour accéder aux données de temps de circuit pour le premier circuit « PUB » :

job_result = sampler_job.result()
circuit_schedule = job_result[0].metadata["compilation"]["scheduler_timing"]
circuit_schedule_timing = circuit_schedule["timing"]

Comprendre les données brutes de synchronisation

Bien que la visualisation des données de synchronisation du circuit à l'aide de cette draw_circuit_schedule_timing méthode constitue le cas d'utilisation le plus courant, il peut être utile de comprendre la structure des données de synchronisation brutes renvoyées. Cela pourrait vous aider, par exemple, à extraire des informations par programmation.

Les données de synchronisation renvoyées dans ["compilation"]["scheduler_timing"]["timing"] sont une liste de chaînes de caractères. Chaque chaîne représente une instruction unique sur un canal donné et est divisée par des virgules en types de données suivants :

  • Branch - Détermine si l'instruction se trouve dans une branche de contrôle (then / else) ou dans une branche principale.
  • Instruction - La porte et le qubit sur lequel opérer.
  • Channel - Le canal auquel l'instruction est attribuée. Il peut s'agir de l'un des éléments suivants :
    • Qubit x - Le canal de commande du qubit x.
    • AWGRx_y (affichage du générateur de formes d'onde arbitraires) - Utilisé par les canaux d'affichage pour communiquer lors de la mesure des qubits. Les arguments x et y correspondent respectivement à l'identifiant de l'instrument de lecture et au numéro du qubit.
  • T0 - L'heure de début du cours dans le planning complet
  • Duration - La durée de l'instruction, exprimée en unités de dt secondes, où 1 dt = 1 cycle de planification. Vous pouvez trouver la dt valeur d'un backend en utilisant backend.dt.
  • Pulse - Le type de fonctionnement par impulsions utilisé.

Exemple :

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
...

Visualisez les durées

Avec qiskit-ibm-runtimev0.43.0 ou une version ultérieure, vous pouvez visualiser les temps de propagation des circuits. Pour visualiser les durées, vous devez d'abord convertir les métadonnées du résultat en fig à l'aide de draw_circuit_schedule_timing méthode. Cette méthode renvoie une plotly figure que vous pouvez afficher directement, enregistrer dans un fichier, ou les deux. Pour plus d'informations sur les plotly commandes à utiliser, consultez fig.show() et 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")
En passant la souris sur le résultat, vous pouvez voir des informations telles que l'heure de début, l'heure de fin et la durée.
Exemple de figure générée

Comprendre le graphique généré

L'image des données de synchronisation du circuit fournies par draw_circuit_schedule_timing fournit les informations suivantes :

  • L'axe X représente le temps en unités de dt secondes, où 1 dt = 1 cycle de planification. Vous pouvez trouver la dt valeur d'un backend en utilisant backend.dt.
  • L'axe Y correspond au canal (considérez les canaux comme des instruments qui émettent des impulsions).
    • Receive channel - Le seul canal qui n'est pas un instrument en soi. Il s'agit d'une instruction diffusée sur tous les canaux participant à une procédure de communication avec le concentrateur à ce moment-là.
    • Qubit x - Le canal de commande du qubit x.
    • AWGRx_y (affichage du générateur de formes d'onde arbitraires) - Utilisé par les canaux d'affichage pour communiquer lors de la mesure des qubits. Les arguments x et y correspondent respectivement à l'identifiant de l'instrument de lecture et au numéro du qubit.
    • Hub - Gère la diffusion.

De plus, chaque instruction se présente sous la forme X_Y, où X correspond au nom de l'instruction et Y au type d'impulsion. L'un play applique des impulsions de commande, et l'autre capture enregistre l'état du qubit. Vous pouvez également passer la souris sur chaque instruction pour obtenir plus de détails. Par exemple, la figure précédente montre une impulsion de commande pour la porte X appliquée au qubit 10 à 1161 dt.

Exemple de bout en bout

Cet exemple vous montre comment activer cette option, extraire les informations de synchronisation du circuit à partir des métadonnées et les afficher sous forme d'image.

Commencez par configurer l'environnement, définissez les circuits et convertissez-les en circuits ISA, puis définissez et exécutez les tâches.

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()})"
)

Output:

>>>  Job ID:    d9mqmk7urbec73e67nng (DONE)

Ensuite, consultez les horaires du circuit :

# Get the circuit schedule timing
result[0].metadata["compilation"]["scheduler_timing"]["timing"]

Output:

'main,rz_0,Qubit 0,1393,0,shift_phase\nmain,sx_0,Qubit 0,1393,9,play\nmain,sx_0,Qubit 0,1397,0,shift_phase\nmain,rz_0,Qubit 0,1402,0,shift_phase\nmain,barrier,Qubit 0,1402,0,barrier\nmain,measure_0,Qubit 0,1402,64,play\nmain,measure_0,Qubit 0,1466,108,play\nmain,measure_0,AWGR0_0,1523,325,capture\nmain,measure_0,Qubit 0,1574,64,play\nmain,measure_0,Qubit 0,1638,64,play\nmain,barrier,Qubit 0,2049,0,barrier\nmain,broadcast,Hub,1523,526,broadcast\nmain,receive,Receive,2049,7,receive\nthen,x_0,Qubit 0,2064,9,play\nmain,barrier,Qubit 0,2082,0,barrier\nmain,measure_0,Qubit 0,2082,64,play\nmain,measure_0,Qubit 0,2146,108,play\nmain,measure_0,AWGR0_0,2203,325,capture\nmain,measure_0,Qubit 0,2254,64,play\nmain,measure_0,Qubit 0,2318,64,play\nmain,barrier,Qubit 0,2753,0,barrier\nmain,barrier,Qubit 0,2753,0,barrier\nmain,FINI_0,Qubit 0,2753,64,play\nmain,FINI_0,Qubit 0,2817,108,play\nmain,FINI_0,AWGR0_0,2874,325,capture\nmain,FINI_0,Qubit 0,2925,64,play\nmain,FINI_0,Qubit 0,2989,64,play\nmain,FINI_0,Qubit 0,3424,9,play\nmain,FINI_0,Qubit 0,3433,64,play\nmain,FINI_0,Qubit 0,3497,108,play\nmain,FINI_0,AWGR0_0,3554,325,capture\nmain,FINI_0,Qubit 0,3605,64,play\nmain,FINI_0,Qubit 0,3669,64,play\nmain,FINI_0,Qubit 0,4104,9,play\nmain,barrier,Qubit 0,4113,0,barrier\n'

Enfin, vous pouvez visualiser et enregistrer la chronométrie :

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")

Etapes suivantes

Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.