Vai al contenuto principale
Questo progetto è in fase beta. Hai trovato un bug? Apri una issue su GitHub. Hai una domanda o un'idea? Chiedi su GitHub Discussions — apprezziamo il tuo feedback!
Com'è la qualità della traduzione su questa pagina?

Guida rapida

Questa guida mostra un esempio minimo funzionante del pacchetto qiskit-paulice. Usiamo i controlli di Pauli spazio-temporali per rilevare errori durante l'esecuzione di un circuito Clifford, quindi post-selezioniamo solo i campioni per i quali non è stato rilevato alcun errore. Per un flusso di lavoro completo e più esplicativo che quantifica il miglioramento della fedeltà, consulta il tutorial approfondito.

Passaggi del flusso di lavoro

  1. Prepara gli input: un circuito Clifford di payload, i qubit target/ancilla che ospiteranno i controlli e un modello di rumore.
  2. Trova buoni controlli di Pauli spazio-temporali e aggiungili al circuito.
  3. Campiona il circuito con i controlli.
  4. Post-seleziona solo i campioni per i quali non è stato rilevato alcun errore.

1. Prepara gli input​

add_pauli_checks accetta un circuito Clifford che termina con misure (oppure, con l'argomento stabilizers, uno senza misure, come nella guida ai codici spazio-temporali), i qubit target che verranno usati per implementare i controlli e un modello di rumore usato per valutare i controlli candidati. Qui costruiamo un circuito Clifford casuale poco profondo, lo disponiamo su una catena 1D di qubit fisici su ibm_boston, abbiniamo ogni qubit di payload a un'ancilla vicina (in modo che un controllo non richieda gate SWAP) e deduciamo un modello di rumore depolarizzante approssimativo dai dati di benchmark del backend.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "qiskit_paulice": "qiskit-paulice"}
_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")
import numpy as np
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_paulice.layout import get_check_qubits
from qiskit_paulice.noise_models import NoiseModel

# Backend and a 1D chain of physical qubits to run on
backend = QiskitRuntimeService().backend("ibm_boston")
layout = [68, 69, 78, 89, 90, 91, 98, 111, 112, 113, 119, 133]

# A shallow brickwork random Clifford payload circuit
rng = np.random.default_rng(1764)
circuit = QuantumCircuit(len(layout))
circuit.h(range(circuit.num_qubits))
for d in range(4):
for i in range(d % 2, circuit.num_qubits - 1, 2):
circuit.cz(i, i + 1)
for q in range(circuit.num_qubits):
if rng.integers(0, 2):
circuit.sx(q)
if rng.integers(0, 2):
circuit.s(q)
circuit.measure_all()

# Pair each payload qubit with a neighboring ancilla to host a check (no SWAPs needed)
target_qubits, ancilla_qubits = get_check_qubits(backend.coupling_map, layout)

# A rough depolarizing noise model from backend benchmark data, used to score checks
noise_model = NoiseModel.from_backend(
backend, layout, uniform_gate_noise=True
)

circuit.draw("mpl", fold=-1)

Output of the previous code cell

2. Trova e aggiungi i controlli di Pauli spazio-temporali​

add_pauli_checks cerca controlli efficaci e di basso peso su ciascun qubit target e li aggiunge al circuito, restituendo una sequenza di istanze CheckedCircuit. Le istanze CheckedCircuit contengono un numero crescente di controlli, da 0 controlli fino a un controllo per ogni qubit target. Ogni controllo migliora la capacità di rilevare errori al costo di una profondità del circuito leggermente maggiore. In questo esempio useremo il circuito con un controllo su ogni qubit target.

from qiskit_paulice import add_pauli_checks

# The circuit has virtual qubits, so we specify our target qubits with virtual indices
target_qubits_v = [layout.index(q) for q in target_qubits]

# Add spacetime Pauli checks
checked_circuit = add_pauli_checks(circuit, target_qubits_v, noise_model)[-1]
checked_circuit.circuit.draw("mpl", fold=-1, scale=0.4, idle_wires=False)

Output of the previous code cell

3. Campiona il circuito con i controlli​

Prima di campionare, eseguiamo il transpile del circuito con i controlli sui qubit fisici (initial_layout = layout + ancilla_qubits) e nell'insieme di gate di base nativi di ibm_boston. Per emulare una QPU rumorosa, campioniamo con un backend stabilizer di Aer rumoroso i cui tassi di errore corrispondono al noise_model usato per scegliere i controlli.

from qiskit import transpile
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel as AerNoiseModel
from qiskit_aer.noise import ReadoutError, depolarizing_error

# Transpile once: lay the checked circuit out on our qubits and into the native basis
isa_circuit = transpile(
checked_circuit.circuit,
backend,
initial_layout=layout + ancilla_qubits,
optimization_level=0,
)

# Build an Aer noise model matching the depolarizing model used to pick checks
aer_noise = AerNoiseModel()
aer_noise.add_all_qubit_quantum_error(
depolarizing_error(noise_model.gate_noise, 2), ["cz"]
)
p = noise_model.readout_noise
aer_noise.add_all_qubit_readout_error(ReadoutError([[1 - p, p], [p, 1 - p]]))
simulator = AerSimulator(method="stabilizer", noise_model=aer_noise)

counts = (
simulator.run(isa_circuit, shots=1000, seed_simulator=1764)
.result()
.get_counts()
)
print(f"sampled {sum(counts.values())} shots")
sampled 1000 shots

4. Post-seleziona i campioni senza errori rilevati​

get_postselection_method associa ogni shot al suo vettore di sindrome; manteniamo solo gli shot con sindrome interamente nulla — quelli in cui nessun controllo ha rilevato un errore. Scartare gli shot segnalati rimuove gli errori rilevati dalla distribuzione che resta, migliorandone la fedeltà al costo di una frequenza di campionamento inferiore. Consulta il tutorial per un confronto quantitativo della fedeltà.

# Keep only the shots in which no check reported an error
ps_fn = checked_circuit.get_postselection_method()
counts_postselected = {
bs: n for bs, n in counts.items() if not ps_fn(bs).any()
}

kept, total = sum(counts_postselected.values()), sum(counts.values())
print(f"kept {kept} of {total} shots ({kept / total:.0%})")
kept 927 of 1000 shots (93%)