Panduan Cepat
Panduan ini menunjukkan contoh kerja minimal dari paket qiskit-paulice. Kita pakai spacetime Pauli checks untuk mendeteksi error saat eksekusi Clifford circuit, lalu postselect hanya sampel yang tidak terdeteksi errornya. Untuk alur kerja end-to-end yang lebih lengkap dan mengukur peningkatan fidelity, lihat tutorial mendalam.
Langkah-langkah alur kerja
- Siapkan input: sebuah Clifford payload circuit, qubit target/ancilla untuk menampung check, dan sebuah noise model.
- Cari spacetime Pauli checks yang bagus dan tambahkan ke circuit.
- Lakukan sampling pada circuit yang sudah dicek.
- Postselect hanya sampel yang tidak terdeteksi errornya.
1. Siapkan input
add_pauli_checks menerima sebuah Clifford circuit yang diakhiri dengan pengukuran (atau, dengan kwarg stabilizers, circuit tanpa pengukuran, seperti di panduan spacetime codes), qubit target yang akan dipakai untuk mengimplementasikan check, dan noise model yang dipakai untuk menilai kandidat check. Di sini kita membuat Clifford circuit acak yang dangkal, menempatkannya pada rantai 1D qubit fisik di ibm_boston, memasangkan setiap qubit payload dengan ancilla tetangganya (jadi sebuah check tidak butuh gate SWAP), dan menyimpulkan noise model depolarizing kasar dari data benchmark 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)

2. Cari dan tambahkan spacetime Pauli checks
add_pauli_checks mencari check yang efektif dan berbobot rendah pada setiap qubit target lalu menambahkannya ke circuit, dan mengembalikan urutan instance CheckedCircuit. Instance CheckedCircuit berisi jumlah check yang bertambah, dari 0 check sampai satu check per qubit target. Setiap check meningkatkan kemampuan deteksi error dengan harga depth circuit yang sedikit bertambah. Untuk contoh ini kita pakai circuit dengan satu check di setiap 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)

3. Lakukan sampling pada circuit yang sudah dicek
Sebelum sampling, kita transpile circuit yang sudah dicek ke qubit fisik (initial_layout = layout + ancilla_qubits) dan ke himpunan basis gate native milik ibm_boston. Untuk meniru QPU yang noisy, kita lakukan sampling dengan backend stabilizer Aer yang noisy, dengan laju error yang cocok dengan noise_model yang dipakai untuk memilih check.
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. Postselect sampel tanpa error terdeteksi
get_postselection_method memetakan setiap shot ke vektor sindrom-nya; kita hanya menyimpan shot dengan sindrom nol semua — yaitu shot di mana tidak ada check yang mendeteksi error. Membuang shot yang ditandai akan menghilangkan error yang terdeteksi dari distribusi yang tersisa, sehingga fidelity-nya naik dengan konsekuensi laju sampling yang lebih rendah. Lihat tutorial untuk perbandingan fidelity secara kuantitatif.
# 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%)