빠른 시작
이 가이드는 qiskit-addon-pna 패키지의 최소한의 작동 예제를 보여 줍니다. 전파 노이즈 흡수(PNA)를 사용해 노이즈를 완화하는 관측량을 만듭니다. 회로와 Pauli-Lindblad 노이즈 모델이 주어지면 PNA는 관측량을 역노이즈 채널을 통해 고전적으로 전파합니다. 결과로 얻은 관측량을 노이즈가 있는 QPU에서 측정하면 학습된 게이트 노이즈가 완화됩니다.
NoiseLearnerV3로 노이즈 모델을 학습하는 것을 포함해, 직접 실행 모델로 현실적인 워크플로를 구성하고 양자 하드웨어에서 실행하는 방법은 IBM Quantum Platform의 PNA 튜토리얼을 확인하세요.
1. PNA 입력 준비하기
PNA는 회로, 노이즈 모델, 관측량을 입력으로 받습니다. 여기서는 1차원 체인 위의 10큐비트 Trotter화된 횡자기장 Ising 모델을 만듭니다. 각 얽힘 게이트마다 무작위 2-국소 Pauli-Lindblad 노이즈 모델을 생성하고, 해당 게이트 바로 앞에 Qiskit Aer PauliLindbladError 명령으로 삽입합니다. 측정할 관측량으로는 가중치 4의 Pauli-Z 관측량을 선택합니다.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_pna": "qiskit-addon-pna", "qiskit_aer": "qiskit-aer"}
_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.quantum_info import SparsePauliOp, pauli_basis
from qiskit_aer.noise import PauliLindbladError
def random_pauli_lindblad_noise(generators, seed, noise_scale=2e-3):
rates = np.random.default_rng(seed).random(len(generators)) * noise_scale
return PauliLindbladError(generators, rates)
def ising_circuit(
num_qubits,
layers,
edge_noise=None,
*,
num_steps=3,
rx_angle=np.pi / 8,
rzz_angle=-np.pi / 2,
):
"""Trotterized transverse-field Ising model; edge_noise=None gives the noiseless circuit."""
qc = QuantumCircuit(num_qubits)
for _ in range(num_steps):
qc.rx(rx_angle, range(num_qubits))
for layer in layers:
for edge in layer:
if edge_noise is not None:
qc.append(
edge_noise[edge], edge
) # inject synthetic gate noise
qc.rzz(rzz_angle, *edge)
return qc
num_qubits = 10
# Two entangling layers per Trotter step: even and odd bonds of a 1D chain
layers = [
[(i, i + 1) for i in range(0, num_qubits - 1, 2)],
[(i, i + 1) for i in range(1, num_qubits - 1, 2)],
]
edges = [edge for layer in layers for edge in layer]
# Random 2-local Pauli-Lindblad noise, one instance per entangling gate
two_qubit_paulis = SparsePauliOp(
[p for p in pauli_basis(2) if np.sum(p.x + p.z)]
).paulis
edge_noise = {
edge: random_pauli_lindblad_noise(two_qubit_paulis, seed=1234 + j)
for j, edge in enumerate(edges)
}
noisy_circuit = ising_circuit(num_qubits, layers, edge_noise)
# A single weight-4 observable: <Z3 Z4 Z5 Z6>
observable = SparsePauliOp.from_sparse_list(
[("ZZZZ", [3, 4, 5, 6], 1.0)], num_qubits=num_qubits
)
noisy_circuit.draw("mpl", fold=-1, scale=0.6)

2. 노이즈 완화 관측량 생성하기
generate_noise_mitigating_observable은 역노이즈 채널의 각 Pauli 생성자를 회로의 끝까지 순방향으로 전파합니다. 그런 다음 관측량을 역노이즈 채널을 통해 역전파하여 새 관측량 를 반환합니다. 세 가지 핵심 매개변수가 계산 비용에 영향을 줍니다:
-
max_err_terms: 각 반노이즈 생성자를 순방향으로 전파하는 동안 유지하는 항의 수. -
max_obs_terms: 에서 유지하는 항의 수. -
atol: 계수의 크기가 이 임계값보다 작은 항은 버립니다.
이처럼 작고 Clifford에 가까운 회로에서는 항 개수 제한을 높게 설정하고 적당한 atol을 사용하므로, 가 작게 유지되어 모든 항을 측정할 수 있습니다.
참고: 이 함수는 Python multiprocessing을 사용합니다. 스크립트로 실행할 때는 if __name__ == "__main__": 가드 안에서 호출하세요.
from qiskit_addon_pna import generate_noise_mitigating_observable
mitigating_observable = generate_noise_mitigating_observable(
noisy_circuit,
observable,
max_err_terms=100_000,
max_obs_terms=100_000,
atol=1e-5,
num_processes=4,
)
print(f"Original observable: {len(observable)} term")
print(f"Noise-mitigating observable: {len(mitigating_observable)} terms")
Original observable: 1 term
Noise-mitigating observable: 207 terms
3. 노이즈 완화 관측량을 측정하여 게이트 오류 완화하기
여기서 새 관측량이 실험에 영향을 주는 게이트 노이즈를 효과적으로 완화하는 것을 볼 수 있습니다.
import matplotlib.pyplot as plt
from qiskit_aer.primitives import EstimatorV2
noiseless_circuit = ising_circuit(num_qubits, layers)
# density_matrix method at zero precision -> exact expectation values (no shot noise)
estimator = EstimatorV2(
options={
"backend_options": {"method": "density_matrix"},
"default_precision": 0.0,
}
)
ideal, noisy, mitigated = (
result.data.evs
for result in estimator.run(
[
(noiseless_circuit, observable),
(noisy_circuit, observable),
(noisy_circuit, mitigating_observable),
]
).result()
)
print(f"Ideal (noiseless): {ideal:.4f}")
print(f"Noisy (unmitigated): {noisy:.4f}")
print(f"Mitigated (PNA): {mitigated:.4f}")
fig, ax = plt.subplots()
ax.bar(
["Noisy", "Mitigated"],
[noisy, mitigated],
width=0.6,
color=["#b0b0b0", "#4c4c4c"],
)
ax.axhline(ideal, color="green", linestyle="--", label="Ideal (noiseless)")
ax.set_ylabel(r"$\langle Z_3 Z_4 Z_5 Z_6 \rangle$")
ax.legend()
plt.show()
Ideal (noiseless): 0.8073
Noisy (unmitigated): 0.6431
Mitigated (PNA): 0.8071