빠른 시작
이 가이드에서는 해당 qiskit-paulice 패키지의 최소 실행 가능한 예제를 보여줍니다. 우리는 클리포드 회로 실행 중 오류를 탐지하기 위해 시공간 파울리 검증을 사용한 다음, 오류가 탐지되지 않은 샘플만을 사후 선별합니다. 정확도 향상을 수치화한, 보다 상세한 종단간 워크플로를 확인하려면 심층 튜토리얼을 참조하십시오.
워크플로우 단계
- 입력 데이터를 준비합니다: 클리포드 페이로드 회로, 체크 연산을 수행할 대상/보조 큐비트, 그리고 잡음 모델.
- 적절한 시공간 파울리 검사 조건을 찾아 회로에 추가하십시오.
- 체크된 회로의 신호를 측정해 보십시오.
- 오류가 감지되지 않은 샘플만 선별하여 게시하십시오.
1. 입력 데이터 준비하기
add_pauli_checks 최소 하나의 단말 측정이 포함된 클리포드 회로, 검증을 구현하는 데 사용될 대상 큐비트, 그리고 후보 검증에 대한 점수를 매기는 데 사용되는 노이즈 모델을 입력으로 받습니다. ibm_boston여기서는 얕은 랜덤 클리포드 회로를 구축하고, 이를 물리적 큐비트로 구성된 1D 체인에 배치하며, 각 페이로드 큐비트를 인접한 보조 큐비트와 짝지은 뒤(따라서 검사 시 SWAP 게이트가 필요하지 않음), 백엔드 벤치마크 데이터를 바탕으로 대략적인 탈분극 잡음 모델을 도출합니다.
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:
2. 시공간 파울리 검사 조건 찾기 및 추가하기
add_pauli_checks 각 대상 큐비트에 대해 효과적이고 경량인 검사 방법을 찾아 회로에 추가한 뒤, 일련의 CheckedCircuit 인스턴스 시퀀스를 반환합니다. 이 CheckedCircuit 사례들에는 대상 큐비트당 1회 검사까지, 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:
3. 점검한 회로의 신호를 샘플링한다
ibm_boston샘플링을 수행하기 전에, 검증된 회로를 물리적 큐비트(initial_layout = layout + ancilla_qubits)로 변환하고 의 기본 기저 게이트 집합으로 변환합니다. 잡음이 있는 QPU를 모방하기 위해, 체크를 선택하는 데 noise_model 사용된 오류율과 일치하는 잡음이 있는 Aer 안정화 백엔드를 사용하여 샘플링합니다.
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")Output:
sampled 1000 shots
4. 오류가 감지되지 않은 사후 선별 샘플
get_postselection_method 각 샷을 해당 신드롬 벡터에 매핑하며, 신드롬 값이 모두 0인 샷, 즉 오류 검출에서 오류가 발견되지 않은 샷만 유지합니다. 표시된 샷을 제외하면, 남아 있는 분포에서 감지된 오류가 제거되어 샘플링 빈도는 낮아지지만 정확도는 향상됩니다. 정량적인 충실도 비교에 대해서는 튜토리얼 을 참고하세요.
# 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%})")Output:
kept 927 of 1000 shots (93%)