Tworzenie menedżera przejść dla dynamicznego rozsprzęgania
Wersje pakietów
Kod na tej stronie został opracowany przy użyciu poniższych wymagań. Zalecamy korzystanie z tych wersji lub nowszych.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Ta strona pokazuje, jak używać przejścia PadDynamicalDecoupling w celu dodania do Circuit techniki tłumienia błędów zwanej dynamicznym rozsprzęganiem.
Dynamiczne rozsprzęganie działa poprzez dodawanie sekwencji impulsów (znanych jako sekwencje dynamicznego rozsprzęgania) do bezczynnych Qubitów, aby obracać je wokół sfery Blocha, co znosi efekt kanałów szumów, tłumiąc w ten sposób dekoherencję. Te sekwencje impulsów są podobne do impulsów refokusujących stosowanych w magnetycznym rezonansie jądrowym. Pełny opis znajdziesz w artykule A Quantum Engineer's Guide to Superconducting Qubits.
Ponieważ przejście PadDynamicalDecoupling działa wyłącznie na zaplanowanych Circuit i obejmuje Gate, które niekoniecznie są bramkami bazowymi naszego celu, będziesz potrzebować również przejść ALAPScheduleAnalysis i BasisTranslator.
Ten przykład korzysta z ibm_fez, który był wcześniej zainicjalizowany. Pobierz informacje o target z backend i zapisz nazwy operacji jako basis_gates, ponieważ target będzie wymagał modyfikacji w celu dodania informacji o czasie trwania bramek używanych w dynamicznym rozsprzęganiu.
# 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)
Utwórz Circuit efficient_su2 jako przykład. Najpierw dokonaj transpilacji Circuit do Backend, ponieważ impulsy dynamicznego rozsprzęgania muszą być dodane po transpilacji i zaplanowaniu Circuit. Dynamiczne rozsprzęganie często działa najlepiej, gdy w Circuit kwantowych jest dużo czasu bezczynności – tzn. gdy niektóre Qubit nie są używane, podczas gdy inne są aktywne. Właśnie tak jest w tym Circuit, ponieważ dwu-Qubitowe Gate ecr są stosowane sekwencyjnie w tym ansatzu.
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)
Sekwencja dynamicznego rozsprzęgania to seria Gate, które składają się do operacji identyczności i są rozmieszczone regularnie w czasie. Na przykład zacznij od stworzenia prostej sekwencji zwanej XY4, składającej się z czterech bramek.
from qiskit.circuit.library import XGate, YGate
X = XGate()
Y = YGate()
dd_sequence = [X, Y, X, Y]
Ze względu na regularne rozmieszczenie w czasie sekwencji dynamicznego rozsprzęgania, informacje o YGate muszą zostać dodane do target, ponieważ nie jest to bramka bazowa, podczas gdy XGate nią jest. Wiemy jednak a priori, że YGate ma taki sam czas trwania i błąd co XGate, więc możemy po prostu pobrać te właściwości z target i dodać je z powrotem dla obiektów YGate. Właśnie dlatego basis_gates zostały zapisane osobno – dodajemy instrukcję YGate do target, mimo że nie jest ona rzeczywistą bramką bazową 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)
Circuit ansatzu takie jak efficient_su2 są sparametryzowane, więc przed wysłaniem do Backend muszą mieć przypisane wartości parametrów. Tutaj przypisz losowe parametry.
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
)
Następnie wykonaj niestandardowe przejścia. Utwórz instancję PassManager z ALAPScheduleAnalysis i PadDynamicalDecoupling. Najpierw uruchom ALAPScheduleAnalysis, aby dodać informacje o czasie do Circuit kwantowego, zanim będzie można dodać regularnie rozmieszczone sekwencje dynamicznego rozsprzęgania. Te przejścia są uruchamiane na Circuit za pomocą .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)
Użyj narzędzia wizualizacji timeline_drawer, aby zobaczyć rozkład czasu Circuit i potwierdzić, że regularnie rozmieszczona sekwencja obiektów XGate i YGate pojawia się w Circuit.
from qiskit.visualization import timeline_drawer
timeline_drawer(qc_dd, idle_wires=False, target=target)
Na koniec, ponieważ YGate nie jest rzeczywistą bramką bazową naszego Backend, ręcznie zastosuj przejście BasisTranslator (jest to domyślne przejście, ale jest wykonywane przed planowaniem, więc musi zostać zastosowane ponownie). Biblioteka równoważności sesji to biblioteka równoważności Circuit, która umożliwia Transpilerowi rozkładanie Circuit na bramki bazowe, co jest również określone jako 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)
Teraz obiekty YGate są nieobecne w naszym Circuit, a informacje o czasie trwania są jawnie reprezentowane w postaci Gate Delay. Ten przetranspilowany Circuit z dynamicznym rozsprzęganiem jest teraz gotowy do wysłania do Backend.
Następne kroki
- Aby dowiedzieć się, jak używać funkcji
generate_preset_passmanagerzamiast pisać własne przejścia, zacznij od tematu Domyślne ustawienia i opcje konfiguracji Transpilera. - Wypróbuj przewodnik Porównaj ustawienia Transpilera.
- Zobacz dokumentację API Transpilera.