Zum Hauptinhalt springen
Dieses Projekt befindet sich in der Beta-Phase. Einen Fehler gefunden? GitHub Issue erstellen. Frage oder Idee? In Discussions fragen — wir freuen uns über dein Feedback!
Wie ist die Übersetzungsqualität auf dieser Seite?

Schnellstart

Diese Anleitung zeigt ein minimales Beispiel für das Paket qiskit-paulice. Wir verwenden Spacetime-Pauli-Checks, um Fehler während der Ausführung eines Clifford-Circuits zu erkennen, und selektieren anschließend nur die Samples nach, bei denen kein Fehler erkannt wurde. Einen ausführlicheren End-to-End-Workflow, der die Verbesserung der Fidelity quantifiziert, findest du im ausführlichen Tutorial.

Workflow-Schritte

  1. Bereite die Eingaben vor: einen Clifford-Payload-Circuit, die Ziel-/Ancilla-Qubits, die die Checks aufnehmen, und ein Rauschmodell.
  2. Finde gute Spacetime-Pauli-Checks und füge sie dem Circuit hinzu.
  3. Führe das Sampling des geprüften Circuits durch.
  4. Selektiere nur die Samples nach, bei denen kein Fehler erkannt wurde.

1. Die Eingaben vorbereiten​

add_pauli_checks erwartet einen Clifford-Circuit, der mit Messungen endet (oder, mit dem Argument stabilizers, einen ohne Messungen, wie im Leitfaden zu Spacetime-Codes), die Ziel-Qubits, die zur Implementierung der Checks verwendet werden, und ein Rauschmodell, mit dem Kandidaten-Checks bewertet werden. Hier erstellen wir einen flachen zufälligen Clifford-Circuit, legen ihn auf einer 1D-Kette physischer Qubits auf ibm_boston aus, ordnen jedem Payload-Qubit ein benachbartes Ancilla-Qubit zu (damit ein Check keine SWAP-Gates benötigt) und leiten aus Backend-Benchmarkdaten ein grobes depolarisierendes Rauschmodell ab.

# 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. Spacetime-Pauli-Checks finden und hinzufügen​

add_pauli_checks sucht für jedes Ziel-Qubit effektive Checks mit niedrigem Gewicht und fügt sie dem Circuit hinzu. Zurückgegeben wird eine Folge von CheckedCircuit-Instanzen. Die CheckedCircuit-Instanzen enthalten eine zunehmende Anzahl von Checks, von 0 Checks bis zu einem Check pro Ziel-Qubit. Jeder Check verbessert die Fehlererkennung auf Kosten einer etwas größeren Circuit-Tiefe. In diesem Beispiel verwenden wir den Circuit mit einem Check auf jedem Ziel-Qubit.

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. Den geprüften Circuit samplen​

Bevor wir samplen, transpilieren wir den geprüften Circuit auf physische Qubits (initial_layout = layout + ancilla_qubits) und in den nativen Basis-Gate-Satz von ibm_boston. Um eine verrauschte QPU zu emulieren, samplen wir mit einem verrauschten Aer-Stabilizer-Backend, dessen Fehlerraten dem noise_model entsprechen, das zur Auswahl der Checks verwendet wurde.

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. Samples ohne erkannten Fehler nachselektieren​

get_postselection_method bildet jeden Shot auf seinen Syndromvektor ab; wir behalten nur die Shots mit einem Syndrom aus lauter Nullen — also diejenigen, bei denen kein Check einen Fehler erkannt hat. Das Verwerfen der markierten Shots entfernt erkannte Fehler aus der verbleibenden Verteilung und verbessert deren Fidelity auf Kosten einer geringeren Sampling-Rate. Einen quantitativen Fidelity-Vergleich findest du im Tutorial.

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