Aller au contenu principal

Créer un gestionnaire de passes pour le découplage dynamique

Versions des packages

Le code de cette page a été développé avec les dépendances suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Cette page montre comment utiliser la passe PadDynamicalDecoupling pour ajouter à un circuit une technique de suppression d'erreurs appelée découplage dynamique.

Le découplage dynamique fonctionne en ajoutant des séquences d'impulsions (appelées séquences de découplage dynamique) aux qubits inactifs afin de les faire pivoter autour de la sphère de Bloch, ce qui annule l'effet des canaux de bruit et supprime ainsi la décohérence. Ces séquences d'impulsions sont similaires aux impulsions de refocalisation utilisées en résonance magnétique nucléaire. Pour une description complète, consulte A Quantum Engineer's Guide to Superconducting Qubits.

Comme la passe PadDynamicalDecoupling ne fonctionne que sur des circuits planifiés et implique des portes qui ne sont pas nécessairement des portes de base de notre cible, tu auras également besoin des passes ALAPScheduleAnalysis et BasisTranslator.

Cet exemple utilise ibm_fez, initialisé précédemment. Récupère les informations target depuis le backend et sauvegarde les noms des opérations sous basis_gates, car le target devra être modifié pour ajouter des informations de timing pour les portes utilisées dans le découplage dynamique.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.backend("ibm_fez")

target = backend.target
basis_gates = list(target.operation_names)

Crée un circuit efficient_su2 à titre d'exemple. Commence par transpiler le circuit vers le backend, car les impulsions de découplage dynamique doivent être ajoutées après que le circuit a été transpilé et planifié. Le découplage dynamique fonctionne souvent mieux lorsqu'il y a beaucoup de temps d'inactivité dans les circuits quantiques — c'est-à-dire lorsque des qubits sont inutilisés pendant que d'autres sont actifs. C'est le cas dans ce circuit, car les portes ecr à deux qubits sont appliquées séquentiellement dans cet ansatz.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)
pm = generate_preset_pass_manager(1, target=target, seed_transpiler=12345)
qc_t = pm.run(qc)
qc_t.draw("mpl", fold=-1, idle_wires=False)

Résultat de la cellule de code précédente

Une séquence de découplage dynamique est une série de portes qui se composent pour former l'identité et sont espacées régulièrement dans le temps. Par exemple, commence par créer une séquence simple appelée XY4, composée de quatre portes.

from qiskit.circuit.library import XGate, YGate

X = XGate()
Y = YGate()

dd_sequence = [X, Y, X, Y]

En raison du timing régulier des séquences de découplage dynamique, des informations sur la YGate doivent être ajoutées au target, car elle n'est pas une porte de base, contrairement à la XGate. Nous savons a priori que la YGate a la même durée et la même erreur que la XGate, donc nous pouvons simplement récupérer ces propriétés depuis le target et les réappliquer pour les objets YGate. C'est aussi pourquoi les basis_gates ont été sauvegardées séparément, puisque nous ajoutons l'instruction YGate au target bien qu'elle ne soit pas une porte de base réelle de ibm_fez.

from qiskit.transpiler import InstructionProperties

y_gate_properties = {}
for qubit in range(target.num_qubits):
y_gate_properties.update(
{
(qubit,): InstructionProperties(
duration=target["x"][(qubit,)].duration,
error=target["x"][(qubit,)].error,
)
}
)

target.add_instruction(YGate(), y_gate_properties)

Les circuits ansatz tels que efficient_su2 sont paramétrés, ils doivent donc se voir attribuer des valeurs avant d'être envoyés au backend. Ici, on leur assigne des paramètres aléatoires.

import numpy as np

rng = np.random.default_rng(1234)
qc_t.assign_parameters(
rng.uniform(-np.pi, np.pi, qc_t.num_parameters), inplace=True
)

Ensuite, exécute les passes personnalisées. Instancie le PassManager avec ALAPScheduleAnalysis et PadDynamicalDecoupling. Exécute d'abord ALAPScheduleAnalysis pour ajouter les informations de timing du circuit quantique avant que les séquences de découplage dynamique espacées régulièrement puissent être ajoutées. Ces passes sont exécutées sur le circuit avec .run().

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes.scheduling import (
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
)

dd_pm = PassManager(
[
ALAPScheduleAnalysis(target=target),
PadDynamicalDecoupling(target=target, dd_sequence=dd_sequence),
]
)
qc_dd = dd_pm.run(qc_t)

Utilise l'outil de visualisation timeline_drawer pour voir le timing du circuit et confirmer qu'une séquence régulièrement espacée d'objets XGate et YGate apparaît dans le circuit.

from qiskit.visualization import timeline_drawer

timeline_drawer(qc_dd, idle_wires=False, target=target)

Résultat de la cellule de code précédente

Enfin, comme la YGate n'est pas une porte de base réelle de notre backend, applique manuellement la passe BasisTranslator (il s'agit d'une passe par défaut, mais elle est exécutée avant la planification, elle doit donc être appliquée à nouveau). La bibliothèque d'équivalences de session est une bibliothèque d'équivalences de circuits qui permet au transpiler de décomposer les circuits en portes de base, également spécifiée en argument.

from qiskit.circuit.equivalence_library import (
SessionEquivalenceLibrary as sel,
)
from qiskit.transpiler.passes import BasisTranslator

qc_dd = BasisTranslator(sel, basis_gates)(qc_dd)
qc_dd.draw("mpl", fold=-1, idle_wires=False)

Résultat de la cellule de code précédente

Désormais, les objets YGate sont absents de notre circuit, et il y a des informations de timing explicites sous forme de portes Delay. Ce circuit transpilé avec le découplage dynamique est maintenant prêt à être envoyé au backend.

Prochaines étapes

Recommandations