Vai al contenuto principale

Creare un pass manager per il decoupling dinamico

Versioni dei pacchetti

Il codice in questa pagina è stato sviluppato usando i seguenti requisiti. Si consiglia di usare queste versioni o versioni più recenti.

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

Questa pagina mostra come usare il pass PadDynamicalDecoupling per aggiungere al circuito una tecnica di soppressione degli errori chiamata decoupling dinamico.

Il decoupling dinamico funziona aggiungendo sequenze di impulsi (note come sequenze di decoupling dinamico) ai qubit inattivi per ruotarli attorno alla sfera di Bloch, il che annulla l'effetto dei canali di rumore e sopprime la decoerenza. Queste sequenze di impulsi sono simili agli impulsi di rifocalizzazione usati nella risonanza magnetica nucleare. Per una descrizione completa, consulta A Quantum Engineer's Guide to Superconducting Qubits.

Poiché il pass PadDynamicalDecoupling opera solo su circuiti schedulati e coinvolge gate che non sono necessariamente gate di base del target, avrai bisogno anche dei pass ALAPScheduleAnalysis e BasisTranslator.

Questo esempio usa ibm_fez, che è stato inizializzato in precedenza. Recupera le informazioni sul target dal backend e salva i nomi delle operazioni come basis_gates, poiché il target dovrà essere modificato per aggiungere informazioni di temporizzazione per i gate usati nel decoupling dinamico.

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

Crea un circuito efficient_su2 come esempio. Prima di tutto, effettua il transpile del circuito verso il backend, poiché gli impulsi di decoupling dinamico devono essere aggiunti dopo che il circuito è stato transpilato e schedulato. Il decoupling dinamico funziona spesso meglio quando c'è molto tempo inattivo nei circuiti quantistici, ovvero quando ci sono qubit che non vengono usati mentre altri sono attivi. È il caso di questo circuito, poiché i gate ecr a due qubit vengono applicati sequenzialmente in questo 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)

Output della cella di codice precedente

Una sequenza di decoupling dinamico è una serie di gate che compongono l'identità e sono distanziati regolarmente nel tempo. Ad esempio, inizia creando una semplice sequenza chiamata XY4 composta da quattro gate.

from qiskit.circuit.library import XGate, YGate

X = XGate()
Y = YGate()

dd_sequence = [X, Y, X, Y]

A causa della temporizzazione regolare delle sequenze di decoupling dinamico, le informazioni su YGate devono essere aggiunte al target, poiché non è un gate di base, mentre XGate lo è. Sappiamo a priori che YGate ha la stessa durata e lo stesso errore di XGate, quindi possiamo semplicemente recuperare quelle proprietà dal target e aggiungerle per gli oggetti YGate. Ecco perché i basis_gates sono stati salvati separatamente: stiamo aggiungendo l'istruzione YGate al target anche se non è un gate di base effettivo di 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)

I circuiti ansatz come efficient_su2 sono parametrizzati, quindi è necessario associare loro dei valori prima di inviarli al backend. Qui assegniamo parametri casuali.

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
)

Successivamente, esegui i pass personalizzati. Istanzia il PassManager con ALAPScheduleAnalysis e PadDynamicalDecoupling. Esegui prima ALAPScheduleAnalysis per aggiungere informazioni di temporizzazione sul circuito quantistico, prima che possano essere inserite le sequenze di decoupling dinamico con spaziatura regolare. Questi pass vengono eseguiti sul circuito con .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)

Usa lo strumento di visualizzazione timeline_drawer per vedere la temporizzazione del circuito e verificare che nel circuito compaiano sequenze di oggetti XGate e YGate con spaziatura regolare.

from qiskit.visualization import timeline_drawer

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

Output della cella di codice precedente

Infine, poiché YGate non è un gate di base effettivo del nostro backend, applica manualmente il pass BasisTranslator (si tratta di un pass predefinito, ma viene eseguito prima della schedulazione, quindi deve essere applicato nuovamente). La session equivalence library è una libreria di equivalenze di circuiti che permette al transpiler di scomporre i circuiti in gate di base, come specificato anche come argomento.

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)

Output della cella di codice precedente

Ora gli oggetti YGate sono assenti dal nostro circuito e ci sono informazioni di temporizzazione esplicite sotto forma di gate Delay. Questo circuito transpilato con decoupling dinamico è ora pronto per essere inviato al backend.

Passi successivi​

Raccomandazioni