انتقل إلى المحتوى الرئيسي
هذا المشروع في مرحلة تجريبية. وجدت خطأ؟ افتح مشكلة على GitHub. لديك سؤال أو فكرة؟ اسأل في Discussions — نحب سماع ملاحظاتك!
كيف جودة الترجمة في هذه الصفحة؟

البداية السريعة

يوضح هذا الدليل مثالاً عملياً بسيطاً لحزمة qiskit-paulice. نستخدم فحوصات باولي الزمكانية لاكتشاف الأخطاء أثناء تنفيذ دائرة Clifford، ثم نُبقي فقط على العينات التي لم يُكتشف فيها أي خطأ (postselection). لسير عمل أشمل من البداية للنهاية يقيس تحسّن الدقة (fidelity)، راجع الدرس المتعمق.

خطوات سير العمل

  1. جهّز المدخلات: دائرة Clifford الحمولة، والكيوبتات الهدف/المساعدة التي ستستضيف الفحوصات، ونموذج ضوضاء.
  2. اعثر على فحوصات باولي زمكانية جيدة وأضفها إلى الدائرة.
  3. خذ عينات من الدائرة المفحوصة.
  4. أبقِ فقط على العينات التي لم يُكتشف فيها أي خطأ.

1. جهّز المدخلات​

تأخذ add_pauli_checks دائرة Clifford circuit تنتهي بقياسات (أو، مع المعامل stabilizers، دائرة بلا قياسات، كما في دليل الشيفرات الزمكانية)، والكيوبتات الهدف التي ستُستخدم لتنفيذ الفحوصات، ونموذج ضوضاء يُستخدم لتقييم الفحوصات المرشحة. هنا نبني دائرة Clifford عشوائية ضحلة، ونضعها على سلسلة أحادية البعد من الكيوبتات الفيزيائية على ibm_boston، ونقرن كل كيوبت حمولة بكيوبت مساعد مجاور (حتى لا يحتاج الفحص إلى بوابات SWAP)، ونستنتج نموذج ضوضاء إزالة استقطاب تقريبياً من بيانات قياس أداء الـ 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. ابحث عن فحوصات باولي الزمكانية وأضفها​

تبحث add_pauli_checks عن فحوصات فعّالة ومنخفضة الوزن على كل كيوبت هدف وتضيفها إلى الدائرة، وتُرجع تسلسلاً من كائنات CheckedCircuit. تحتوي كائنات CheckedCircuit على أعداد متزايدة من الفحوصات، من 0 فحص وحتى فحص واحد لكل كيوبت هدف. كل فحص يحسّن القدرة على اكتشاف الأخطاء على حساب زيادة طفيفة في عمق الدائرة. في هذا المثال سنستخدم الدائرة التي فيها فحص على كل كيوبت هدف.

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. خذ عينات من الدائرة المفحوصة​

قبل أخذ العينات، نقوم بترجمة (transpile) الدائرة المفحوصة إلى كيوبتات فيزيائية (initial_layout = layout + ancilla_qubits) وإلى مجموعة البوابات الأساسية الأصلية لـ ibm_boston. ولمحاكاة QPU ضوضائي، نأخذ العينات باستخدام Backend مثبّتات Aer ضوضائي تطابق معدلات أخطائه noise_model المستخدم لاختيار الفحوصات.

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. أبقِ على العينات التي لم يُكتشف فيها خطأ​

تربط get_postselection_method كل لقطة (shot) بمتجه العَرَض (syndrome) الخاص بها؛ ونُبقي فقط على اللقطات التي عرضها كله أصفار — أي التي لم يكتشف فيها أي فحص خطأً. استبعاد اللقطات المُعلَّمة يزيل الأخطاء المكتشفة من التوزيع المتبقي، فتتحسن دقته على حساب انخفاض معدل أخذ العينات. راجع الدرس لمقارنة كمية للدقة.

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