음영 처리된 광뿔을 이용한 확률적 오차 상쇄
예상 소요 시간: 헤론 프로세서에서 10분 (참고: 이는 단지 추정치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)
학습 성과
- 확률적 오차 상쇄(PEC)란 무엇이며, 왜 그 샘플링 오버헤드 가 회로에 작용하는 총 잡음에 따라 기하급수적으로 증가하는가
- 쉐이딩된 라이트콘(SLC)이 각 노이즈 항이 대상 관측량에 미치는 영향을 어떻게 제한하여, 중요한 부분에 완화 예산을 집중할 수 있게 하는지 — 그리고 순수 기하학적 라이트콘이 이미 제공하는 제로 바이어스 오버헤드 감소 외에도, 쉐이딩을 통해 제한된 잔여 바이어스를 감수함으로써 샘플링 오버헤드를 더욱 낮출 수 있는 방법
- 를 사용하여
NoiseLearnerV3레이어 노이즈를 학습하고, 및 프리미티브를Executor통해samplomatic안티노이즈를 주입하는 방법 - 하드웨어에서 기대값을 추정하기 위해 PEC 및 PEC+SLC를 TREX 및 사후선별과 결합하는 방법
전제조건
- Qiskit 패턴 워크플로우
- Estimator 프리미티브를 사용하여 관측 가능한 변수의 기대값 계산하기
- ‘추정기(Estimator) 프리미티브와 오류 완화 옵션 결합 ’에서 다룬 파울리 트위링(Pauli twirling) 및 TREX와 같은 오류 완화 기법
배경
이 튜토리얼에서는 SLC(Shaded Light Cone) 애드온을 사용하여 오류를 완화하는 방법을 설명합니다. 이 애드온은 확률적 오차 상쇄(PEC) 기법의 발전된 형태로, 사용자가 회로 내 개별 레이어의 잡음을 학습한 뒤, 단일 큐비트 게이트와 후처리 기법을 적용하여 잡음을 상쇄하는 방식입니다. 다른 방법들과 비교했을 때, PEC는 완화된 결과의 편향에 대해 더 견고한 상한을 제공하지만, QPU 시간 측면에서 더 많은 오버헤드가 발생하는 경향이 있습니다. PEC 수행 중, 잡음에 의한 기대값의 감쇠를 보상하기 위해 평균 결과에 라는 계수를 곱하여 재조정한다. 여기서 는 회로의 레이어에서 학습된 오류 파울리 의 잡음 비율이다. 이러한 재스케일링으로 인해 분산이 배 증가하며, 이에 따라 QPU에서 필요한 회로 실행 횟수도 배로 늘어납니다. 이를 ‘샘플링 비용’ 또는 ‘샘플링 오버헤드’라고 부릅니다. 가 지수적으로 증가하기 때문에, PEC는 대개 얕은 회로나 큐비트 수가 적은 회로로 제한된다. “잡음이 있는 양자 프로세서에서 스파스 파울리-린드블라드 모델을 이용한 확률적 오차 상쇄”에서 PEC에 대해 자세히 알아보세요.
완화 조치가 필요 없는 오류를 파악할 수 있다면, 이러한 표본 추출 비용을 기하급수적으로 줄일 수 있습니다. 이를 위한 첫 번째 단계는 국소적 특성을 고려한 오류 완화 기법을 구현하는 것으로, 이 기법은 계산 속도가 빠른 기존의 “라이트콘(lightcone)”을 활용하여 회로 전반에 걸쳐 관측 변수의 오류 민감도를 제한함으로써 PEC의 오버헤드를 줄여, 일부 문제에 대해 PEC의 적용 범위를 더 큰 규모로 확장할 수 있게 합니다. 이 광뿔 밖에서 발생하는 오차는 측정 결과에 영향을 미칠 수 없으므로, 오차 상쇄 절차에서 제외할 수 있다. 이러한 제외는 추가적인 편향을 유발하지 않으면서, 경우에 따라 상당히 샘플링 오버헤드를 줄여줍니다. 특히, 고정 깊이 회로의 국소 관측량 을 측정할 때, 회로 내 큐비트 수를 늘려가면 필요한 샘플링 오버헤드는 결국 일정 수준에서 정체된다( ‘양자 회로의 국소성 및 오류 완화’에 수록된 그림 2b 참조).
음영 처리된 광뿔(SLC)은 한 걸음 더 나아가, 고전적 시뮬레이션을 활용하여 회로 전반에 걸친 오류에 대한 민감도를 더욱 엄격하게 제한합니다. 이는 QPU 시간을 일부 CPU 시간으로 대체함으로써, 바이어스를 재정규화하는 데 필요한 샘플링 오버헤드를 줄여줍니다. 명확한 구분 기준 대신, 회로 내의 각 잠재적 오류에는 관측량의 기대값이 해당 오류에 의해 영향을 받을 수 있는 정도를 상한으로 하는 단계별 “정도의 수준”이 할당된다. (아래에서 소개할 역전파된 경계값의 경우, 이 민감도는 회로의 초기 상태(일반적인 워크플로우와 이 튜토리얼에서는 모두 0인 상태)에 따라서도 달라집니다.) 이러한 정교한 특성 분석을 통해 PEC를 더 효율적이고 목표에 맞춰 적용할 수 있을 뿐만 아니라, 분산을 줄일 수 있으며, 동시에 사용자가 관측 가능한 추정값의 바이어스를 제어 가능하게 조정할 수 있게 해줍니다. 자세한 내용은 ‘고전적 가속을 이용한 양자 오류 완화 : 라이트콘 셰이딩’을 참조하십시오.
SLC 애드온을 위한 당사의 워크플로는 라이브러리와 samplomatic 함께, qiskit-ibm-runtimev0.47.0 에서 Qiskit Runtime 에 추가된 및 Executor 클래스를 QuantumProgram 활용함으로써, 사용자가 사용 편의성을 유지하면서도 오류 억제 및 완화를 위한 실행 설정을 보다 모듈식으로 제어할 수 있도록 합니다. 자세한 내용은 지시형 실행 모델 가이드에서 확인하세요.
SLC 오류 완화 워크플로우 개요
QPU의 노이즈를 모델링하기 위해, 각 큐비트와 디바이스의 에지에서 국소적으로 생성되는 1-큐비트 및 2-큐비트 파울리 오류율을 갖는 스파스 파울리-린드블라드 노이즈 모델을 사용합니다. 이 선택을 통해, 이 튜토리얼에서 소개한 SLC 오류 완화 워크플로는 다음과 같습니다:
a. CPU — 1퀀핏 및 2퀀핏 파울리 오류별 영향
- 전방 전파 (관측량에 대한 경계 효과). 각 오류를 회로 끝까지 전파하고, 관측량과의 코뮤테이터를 계산한다.
- 계산 부담을 줄이기 위해 진화 과정에서 연산 항을 잘라내십시오.
- 양자 속도 한계를 바탕으로 관측 가능한 양에 대한 느슨한 역전파를 통해 이러한 경계를 더욱 엄격하게 조정한다.
- 역전파 (초기 상태에 대한 경계 효과). 각 오류를 회로의 시작점으로 전파하고, 초기 상태와의 교환자를 계산한다.
b. QPU — 소음 발생 빈도를 파악하세요. 를 사용하여 NoiseLearnerV3 파울리-린드블라드 잡음 모델의 발생률을 추정합니다.
c. CPU — 완화 조치 우선순위 지정
- 학습된 노이즈 발생률로 병합된 경계를 업데이트합니다. 이전에 계산된 전방 및 후방 경계를 결합하고, 학습된 노이즈 비율을 적용하여 이를 업데이트합니다.
- 계산된 범위와 학습된 비율을 사용하여 완화해야 할 노이즈 구성 요소를 순위별로 정렬합니다. 편향에 미칠 것으로 예상되는 영향과 이를 수정하는 데 드는 비용을 기준으로, 발생할 수 있는 각 노이즈 오류를 우선순위화하십시오.
d. QPU — 노이즈 제거 기능을 삽입하고 실행하세요. 주석(annotations)을 사용하여 Box 지정된 반잡음(역잡음)을 적용한 상태에서 대상 회로를 실행합니다.
e. CPU — 추정 가능. 비마르코프적 잡음의 영향을 줄이기 위해 측정 기반 사후 선별을 적용하여 기대값을 계산한다.
노이즈 학습 개요
노이즈 학습은 여러 오차 완화 기법에서 흔히 등장하는 단계로, 노이즈 학습기 (noise learner)에 의해 수행되며, 확률적 오차 증폭 튜토리얼 에서도 다루어집니다. NoiseLearnerV3에서, 학습 대상인 노이즈 레이어를 객체로 CircuitInstruction 구체적으로 식별할 수 있으므로, 앞서 설명한 방식에 따라 각 레이어에 대해 원하는 SLC 노이즈 상한을 계산할 수 있습니다. 파울리-린드블라드 모델은 PEC+SLC 우선순위 결정에 사용되는 계수를 제공합니다. generate_noise_model_paulis게이트를 계층별로 묶는 방식은 및 find_unique_box_instructions 편의 함수를 generate_boxing_pass_manager 사용하여 결정할 수 있으며, 이후 아래 2단계에 설명된 대로 SLC 유틸리티 함수 에 입력할 수 있습니다.
1부 | 2부 | 3부 |
|---|---|---|
| 파울리 회전 2-큐비트 게이트 층 | 레이어의 동일성 쌍을 반복하고 노이즈를 학습한다 | 정확도(각 노이즈 채널에 대한 오차)를 도출한다 |
![]() | ![]() | ![]() |
후처리 개요
와 Executor 프레임워크를 samplomatic 사용하여 양자 하드웨어에서 연산을 수행한 후, 비트스트링 측정 결과를 원하는 관측값으로 변환합니다. 이 튜토리얼에서는 (아래 1단계에서 구성한) 대칭 이징 회로를 예로 들어 워크플로를 설명합니다. 이 회로의 경우, 회로의 후반부가 전반부의 효과를 상쇄하기 때문에 측정된 관측량의 이상적 기대값은 1입니다. 함수를 executor_expectation_values 사용하여 관측값을 계산할 때, 노이즈의 영향을 줄여주는 몇 가지 후처리 기법을 적용합니다. 여기에는 비마르코프 잡음의 영향을 받은 샷 제거, 판독 오류 완화, 그리고 PEC 구현의 세부 사항을 고려하는 작업이 포함됩니다. 자세한 내용은 아래 4단계에서 설명합니다.
요구사항
이 튜토리얼을 시작하기 전에 다음 항목이 설치되어 있는지 확인하십시오:
- Qiskit SDK v2.2 또는 그 이후 버전, 시각화 기능 지원
- Qiskit Runtime v0.47 또는 그 이후 (
pip install qiskit-ibm-runtime) - 음영 처리된 라이트콘 Qiskit 애드온 v0.1 이상 (
pip install qiskit-addon-slc) - Qiskit 애드온 유틸리티 v0.3 이상 (
pip install qiskit-addon-utils) - Samplomatic v0.13 이상 (
pip install samplomatic)
설정
먼저, 이 노트북을 실행하는 데 필요한 패키지와 함수를 불러옵니다.
from multiprocessing import set_start_method
# Setting this value prevents itertools.starmap deadlock on UNIX systems
set_start_method("spawn")
# Needed to prevent PySCF from parallelizing internally (SLC only)
%set_env OMP_NUM_THREADS=1Output:
env: OMP_NUM_THREADS=1
import numpy as np
from matplotlib import pyplot as plt
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager, PassManager
from qiskit_ibm_runtime import (
QiskitRuntimeService,
QuantumProgram,
Executor,
NoiseLearnerV3,
)
import samplomatic
from samplomatic.utils import find_unique_box_instructions
from samplomatic.transpiler import generate_boxing_pass_manager
from qiskit_addon_utils.exp_vals.measurement_bases import (
get_measurement_bases,
)
from qiskit_addon_utils.exp_vals.expectation_values import (
executor_expectation_values,
)
from qiskit_addon_utils.noise_management import (
gamma_from_noisy_boxes,
trex_factors,
)
from qiskit_addon_utils.noise_management.post_selection import PostSelector
from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (
AddPostSelectionMeasures,
AddSpectatorMeasures,
)
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
compute_local_scales,
merge_bounds,
tighten_with_speed_limit,
)
from qiskit_addon_slc.utils import (
generate_noise_model_paulis,
map_modifier_ref_to_ref,
)
from qiskit_addon_slc.visualization import draw_shaded_lightcone소규모 시뮬레이터 예시
다른 학습 기반 오류 완화 기법과 마찬가지로, 음영 처리된 라이트콘을 사용하는 PEC는 특정 양자 프로세서의 물리적 노이즈를 완화하므로, 이상적인 시뮬레이터에서는 이에 상응하는 기능을 찾을 수 없는 하드웨어 서비스에 의존합니다:
NoiseLearnerV3각 고유한 2-큐비트 층에서 스파스 파울리-린드블라드 잡음 채널을 실험적으로 규명한다. 소음이 없는 시뮬레이터에서는 제거할 소음이 없습니다.- 이
Executor프라이미티브는 백엔드에서samplomatic생성된, 회전 처리되고 반소음이 주입된 회로들을 샘플링합니다.
음영 처리된 광뿔 경계 계산은 고전적인 방법이지만, 이는 완화 예산과 샘플링 오버헤드를 결정하는 학습된 하드웨어 노이즈 발생률과 관련해서만 의미가 있습니다. 이러한 이유로 소규모 시뮬레이터 예제는 생략하고, 하드웨어에서 직접 전체 PEC+SLC 워크플로를 시연하며, Qiskit 패턴의 각 단계를 아래에 상세히 설명합니다.
대규모 하드웨어 예시
우리는 Qiskit 패턴의 네 단계를 따라, IBM Quantum® 하드웨어에서 실행되는 20 큐비트 미러링된 이징 회로에서 PEC+SLC 워크플로우 전체를 실행합니다.
1단계: 문제 파악하기
이번 시연은 다음과 같이 구성되어 있습니다:
- 우리는 1D 이징 사슬 해밀토니안 하에서 시간 진화를 수행하기로 한다. 1D 이징 사슬은 매우 조밀한 회로 구조를 보여주며, 이는 PEC 구현을 시연하는 데 유용합니다.
- 우리는 관측 가능한 양인 을 측정하기로 했는데, 여기에는 성분 하나와 성분 하나가 포함되어 있습니다. 이는 SLC 경계 조건이 서로 다른 유형의 오류를 어떻게 다르게 처리하는지 강조하는 데 유용합니다.
- 우리는 이 관측량의 이상적인 기대값이 정확히 1이 되기를 원합니다. 그래야만 완화된 추정치의 품질을 쉽게 판단할 수 있기 때문입니다. 회로를 대칭으로 배치하면 목표에 거의 도달하게 됩니다. 회로 후반부의 모든 게이트에 대해 전반부에 역 게이트가 하나씩 존재하므로, 이상적인 회로는 항등 회로 역할을 합니다.
- 마지막으로, 기대값이 1인 이상적인 결과를 얻으려면 회로가 관측량의 +1 고유상태에서 시작해야 하며 — 따라서 대칭성 덕분에 이상적으로는 그 상태에서 끝나야 한다. 관측 가능량은 비 성분을 포함하고 있으며, 프라이머리 회로는
Executor회로 끝에서 원하는 측정 기저를 제공하므로, 미러 회로 시작 부분에 함수를prepare_basis사용하여 해당 기저 준비 게이트를 추가합니다. 우리는 함수를get_measurement_bases사용하여 어떤 게이트가 필요한지, 그리고 이를 어디에 배치해야 하는지 파악하는 한편, 표준 기저 측정 준비에 관한 절에서 논의한 바와 같이, 주석 표기 규칙에서box비롯되는 큐비트 인덱스의 미묘한 차이점도 함께 고려합니다.
# Width of the Ising chain (a free parameter of this demonstration)
num_qubits = 20
# The observable to measure: one X component (on qubit 6) and one Z component
# (on qubit 13), as motivated in "Step 1: Map the problem" above
target_obs_sparse = [("XZ", [6, 13], 1.0)]observable = SparsePauliOp.from_sparse_list(
target_obs_sparse, num_qubits=num_qubits
)# Determine the measurement basis each qubit requires for this observable.
# The reverser is used during post-processing in Step 4.
bases_virt, reverser_virt = get_measurement_bases(observable)# Free parameters of the demonstration circuit: the number of Trotter steps
# sets the circuit depth, and rx_angle is the transverse-field rotation angle
# applied in each step (pi/4 makes the dynamics non-Clifford)
num_trotter_steps = 10
rx_angle = np.pi / 4def construct_ising_circuit(
num_qubits: int,
num_trotter_steps: int,
rx_angle: float,
) -> QuantumCircuit:
circuit = QuantumCircuit(num_qubits)
for _ in range(num_trotter_steps):
circuit.rx(rx_angle, range(num_qubits))
for first_qubit in (1, 2):
for idx in range(first_qubit, num_qubits, 2):
# equivalent to Rzz(-pi/2):
circuit.sdg([idx - 1, idx])
circuit.cz(idx - 1, idx)
return circuit
def prepare_basis(
circuit: QuantumCircuit, basis: list[int]
) -> QuantumCircuit:
# basis is a list of integer values from 0 to 3. These map to the basis measurement as:
# 0 = I; 1 = Z; 2 = X; 3 = Y
assert len(basis) == circuit.num_qubits
out_circ = circuit.copy_empty_like()
for qb, bas in enumerate(basis):
if bas == 2:
out_circ.h(qb)
elif bas == 3:
out_circ.rx(-np.pi / 2, qb)
out_circ.barrier()
out_circ.compose(circuit, inplace=True)
return out_circ
def mirror_circuit(circuit: QuantumCircuit) -> QuantumCircuit:
mirror_circ = circuit.copy_empty_like()
mirror_circ.compose(circuit.inverse(), inplace=True)
mirror_circ.barrier()
mirror_circ.compose(circuit, inplace=True)
mirror_circ.measure_active()
return mirror_circ# Instantiate the mirrored circuit and prepend the basis-preparation gates
circuit = construct_ising_circuit(num_qubits, num_trotter_steps, rx_angle)
mirrored_circuit = mirror_circuit(circuit)
mirrored_circuit = prepare_basis(mirrored_circuit, bases_virt[0])mirrored_circuit.draw(
"mpl", fold=-1, scale=0.3, idle_wires=False, measure_arrows=False
)Output:
2단계: 최적화
우리는 실행할 회로, 측정할 관측량, 그리고 잡음 학습 매개변수와 관련된 세부 사항을 최적화합니다. 우선, 가장 처리량이 적은 헤론 프로세서를 선택하고, 소수 게이트가 활성화된 상태로 이를 인스턴스화합니다. 이러한 분수 게이트를 사용하면 일부 사후 선별 필터링 과정에서 감도를 더욱 높일 수 있습니다.
# Initialize IBM Quantum Compute Service using your saved credentials
service = QiskitRuntimeService()
# Select the least busy Heron device. This tutorial targets Heron processors:
# the usage estimate and the non-Markovian-noise post-selection discussed in
# Step 4 are specific to this processor family.
backend = service.least_busy(
operational=True,
simulator=False,
filters=lambda b: b.processor_type["family"] == "Heron",
)
# Re-fetch with fractional gates enabled (least_busy does not forward this)
# Fractional gates are enabled so the non-Clifford Rx rotations are supported natively.
backend = service.backend(backend.name, use_fractional_gates=True)
print(f"Selected backend: {backend.name}")Output:
Selected backend: ibm_kingston
먼저, QPU에서 실행하기 위해 필요한 대로 회로를 ISA 명령어로 변환하겠습니다. 실행에 사용할 물리적 큐비트를 선택하는 것은 결과의 품질에 큰 영향을 미치는데, 이는 코히어런스 시간과 게이트 충실도가 장치마다 다르며 시간이 지남에 따라 변동하기 때문이다. 정밀한 실험을 수행할 때는 간단한 벤치마킹 실험 결과를 바탕으로 큐비트 사슬을 직접 선별하는 것이 효과적일 수 있습니다(예를 들어, ‘큐비트 선정을 위한 실시간 벤치마킹 ’ 튜토리얼 참조). 이 튜토리얼에서는 Qiskit 트랜스파일러를 활용하여 백엔드의 커플링 맵과 최신 보정 데이터를 기반으로 레이아웃을 선택합니다.
isa_pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = isa_pm.run(mirrored_circuit)
# The chain of physical qubits selected by the transpiler
layout = isa_circuit.layout.final_index_layout()
print(f"Selected layout: {layout}")
isa_observable = observable.apply_layout(
layout, num_qubits=isa_circuit.num_qubits
)Output:
Selected layout: [71, 58, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 36, 21, 22, 23, 16, 3, 2]
wire_order = layout + [
q for q in range(isa_circuit.num_qubits) if q not in layout
]
isa_circuit.draw(
"mpl",
fold=-1,
scale=0.3,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)Output:
회로를 상자에 담으세요
구현의 편의성을 위해, 회로 명령어를 주석이 달린 상자에 배치하는 트랜스파일레이션 단계를 generate_boxing_pass_manager 활용합니다. 이 상자들은 PEC의 경우 회로에 노이즈 제거 신호를 어디에 주입해야 하는지를 명확히 보여줍니다. 설정에 대한 자세한 내용은 Samplomatic 설명서를 참조하십시오.
SLC 워크플로에서는 프로세스 후반부에 를 inject_noise_strategy="individual_modification" 사용해야 한다는 점에 유의하십시오. 이를 통해 회로 내 명령어의 BoxOp 주석을 InjectNoise 고유하게 식별할 수 있기 때문입니다. (주석이 InjectNoise 없는 상자는 이 방법으로 식별할 수 없습니다.)
현재 SLC 바인딩 계산은 주석이 InjectNoise 와 site="after" 함께 배치된다고 가정합니다( qiskit-addon-slc#33 참조). 이 설정의 기본값이 최신 버전에서 samplomatic 변경되었기 때문에( samplomatic#372 참조), 아래에서 명시적으로 설정합니다 inject_noise_site="after" .
이 find_unique_box_instructions 함수는 제공된 박스화된 회로를 순회하며, 노이즈 학습 및 노이즈 주입을 위해 고유한 2-큐비트( 2Q ) 레이어나 측정값을 가진 회로를 식별합니다.
# Box circuit with Twirl and InjectNoise annotations
boxes_pm = generate_boxing_pass_manager(
twirling_strategy="active",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
inject_noise_targets="gates",
measure_annotations="all",
)
boxed_circuit = boxes_pm.run(isa_circuit)
# Find the unique instructions (layers) from boxed circuit
unique_2q_instructions = find_unique_box_instructions(
boxed_circuit, normalize_annotations=None, undress_boxes=True
)boxed_circuit.draw(
"mpl",
fold=-1,
scale=0.3,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)Output:
표준 염기 측정 준비
큐비트의 순서를 정확히 파악하기 위해 각별한 주의를 기울여야 한다는 점에 유의하십시오. 아래에서는 회로를 박싱하고 고유한 명령어를 도출하는 과정에서 큐비트 순서가 어떻게 반영되는지에 따라, Executor에 큐비트 순서를 전달할 때 이를 적절히 업데이트하기 위한 수단으로서 라는 canonical_qubits 개념을 소개합니다. 자세한 내용은 큐비트 순서 지정 규칙 문서를 참조하십시오.
# Determine the canonical qubits order
meas_box = boxed_circuit.data[-1]
canonical_qubits = [
idx
for idx, qubit in enumerate(boxed_circuit.qubits)
if qubit in meas_box.qubits
]
# map canonical qubit to physical (isa) qubit
c_2_p = {c: p for c, p in enumerate(canonical_qubits)}
# map physical (isa) qubit to virtual qubit (index in original circuit)
p_2_v = {p: v for v, p in enumerate(layout)}
# compute map between virtual and canonical qubit indices.
c_2_v = {c: p_2_v[p] for c, p in c_2_p.items()}
assert len(c_2_v) == num_qubits
bases_canon = [
np.array([base_i[c_2_v[c]] for c in range(num_qubits)], dtype=np.uint8)
for base_i in bases_virt
]라이트콘 셰이딩, 노이즈 학습 및 안티노이즈 주입을 위한 워크플로우
이 튜토리얼에서는 노이즈 학습이 완료되기 전에 SLC 경계 계산을 수행하므로, 노이즈 완화 대상 회로는 학습된 노이즈 모델과 시간적으로 최대한 가까운 시점에 실행됩니다. 원칙적으로 이 워크플로는 더 병렬화할 수 있습니다. 즉, 노이즈 학습 작업이 실행되는 동안 동시에 노이즈 범위를 추정할 수 있습니다. 임의의 양자 회로의 경우, 노이즈에 의해 제한되는 연산은 약한 지수적 의존성을 보일 수 있으므로, 제한된 연산을 병렬화(예: 다수의 CPU 코어에 분산)하면 주어진 연산 시간 범위 내에서 더 엄격한 상한을 얻을 수 있으며, 가장 효율적인 워크플로우를 위해 QPU 실행과 제한된 연산 자체를 병렬화할 수도 있다.
향후 학습될 노이즈 모델 폴리스 예측
하드웨어에서 노이즈 학습을 실행하기 전에, 먼저 노이즈 모델에 어떤 파울리 오차 항이 포함될지 열거합니다. 앞서 설명한 바와 같이, 각 고유 레이어의 잡음은 각 활성 큐비트에 대해 가중치 1인 파울리( , 또는 )마다 하나의 오류율과, 연결된 활성 큐비트 쌍마다 가중치 2인 파울리마다 하나의 오류율을 갖는 스파스 파울리-린드블라드 모델로 모형화합니다. 이 generate_noise_model_paulis 함수는 주어진 회로의 각 고유한 박스형 레이어를 순차적으로 처리하며, 회로의 큐비트 연결 관계를 고려하여 정확히 이 파울리 항 목록을 생성합니다.
NoiseLearnerV3 다시 말해, 이 단계에서는 나중에 학습된 발생률로 채워질 노이즈 모델의 구조를 예측합니다. 이러한 구조를 미리 파악하고 있기 때문에, 노이즈 학습이 실행되기도 전에 모든 잠재적 오류에 대한 상한과 하한을 계산할 수 있습니다.
noise_model_paulis = generate_noise_model_paulis(
unique_2q_instructions, backend.coupling_map, boxed_circuit
)noise_model_rates = {ref: None for ref in noise_model_paulis}a. 전방 경계 계산
이 compute_forward_bounds 함수는 각 층의 게이트와 앞서 생성된 파울리 항들 간의 교환 관계를, 전방 전파 오류가 목표 관측량 에 미치는 영향의 관점에서 평가합니다. 파울리 항과 교환하는 게이트의 경우, 아무런 조치도 취하지 않습니다. 클리포드 게이트의 경우, 회로의 시작 부분 쪽으로 배치됩니다. 클리포드 게이트가 아닌 게이트의 경우, 대상 관측량에 미치는 영향을 근사화하여 (모든 경계가 통합된 후) 노이즈 제거를 위해 우선순위를 정합니다. 이 상한은 먼저 L2 노름(즉, 관련 파울리 항 계수들의 제곱합에 대한 제곱근)을 적용함으로써 얻어집니다. 관련된 큐비트 항이 너무 많을 때는 삼각 부등식을 이용한 더 느슨한 상한으로 돌아갑니다.
바운드 계산 매개변수 설정
다음 설정들은 고전적 경계 계산을 제어합니다:
slc_atol: 계산의 절대 오차. 이 임계값 미만의 계수를 가진 연산자 항은 무시할 수 있는 것으로 간주되어 제외됩니다.slc_eigval_max_qubits: 더 엄격한 고유값 기반( L2-norm ) 상한이 평가되는 큐비트의 최대 개수. 이보다 더 많은 큐비트에서 지원되는 연산자는 앞서 설명한, 더 느슨한 삼각 부등식 상한으로 대체됩니다.slc_evolution_max_terms: 회로를 통해 연산자를 전파할 때 유지되는 파울리 항의 최대 개수. 가장 작은 항들을 생략하면, 경계값의 정확도가 약간 떨어지는 대신 계산을 처리 가능한 수준으로 유지할 수 있다.slc_num_processes: 바인딩된 계산이 병렬화되는 CPU 프로세스의 수.slc_timeout: 결합 연산에 소요되는 시간(초 단위). 이 예산 범위 내에서 도달하지 못한 레이어에는 2라는 사소한 상한값이 할당됩니다.
이 튜토리얼에서는 타임아웃이 의도적으로 발생하도록 설계되었습니다. 노트북이 빠르게 실행되도록 하고, 타임아웃에 도달하는 것이 안전하다는 점을 보여주기 위해 타임아웃 시간을 slc_timeout 의도적으로 짧게 설정했습니다. 계산된 음영은 각 단계에서 상한값이므로, 타임아웃이 발생하더라도 아직 도달하지 않은 레이어에 대해서는 그 상한값이 더 느슨해질 뿐(사소한 변화)이며, 오류의 영향을 과소평가하는 일은 결코 없습니다. 이는 아래 시각화 자료에서 가장 왼쪽에 위치한 레이어들이 전부 사소 경계로 채워진 형태로 나타납니다. 타임아웃 시간(또는 프로세스 수)을 늘리면 범위가 좁아지고 샘플링 오버헤드가 더욱 줄어듭니다.
slc_atol = 1e-8
slc_eigval_max_qubits = 18
slc_evolution_max_terms = 1000
slc_num_processes = 8
slc_timeout = 60forward_bounds = compute_forward_bounds(
boxed_circuit,
noise_model_paulis,
isa_observable,
evolution_max_terms=slc_evolution_max_terms,
eigval_max_qubits=slc_eigval_max_qubits,
atol=slc_atol,
num_processes=slc_num_processes,
timeout=slc_timeout,
)Output:
Bounds computation timed out.
수동 검사를 위해 SLC를 시각화하십시오
음영 처리된 범위의 거동을 해석하려면, 측정값과 파울리 항이 국소 오차와 어떻게 상호작용하는지 살펴보기만 하면 됩니다. 이러한 패턴은 이 ‘킥(kicked)’ 이징 해밀토니안 시간 진화 문제의 특징이며, “Lightcone Shading for Classically Accelerated Quantum Error Mitigation ”이라는 논문에서도 나타나는데, 여기에는 몇 가지 뚜렷한 특징이 있습니다:
- 우리는 관측량에서 나타나는 두 개의 비정체 파울리 연산자로부터 비롯된 두 개의 콘을 명확히 구별할 수 있다.
- 큐비트 6에 대한 X 측정값이 가장 오른쪽 층의 X 오류와 교환 관계를 맺는 것을 알 수 있습니다.
- 큐비트 13의 Z 파울리 연산이 가장 오른쪽 층의 Z 오류와 교환 관계를 맺는 것을 알 수 있습니다.
- 위에서 지정한 타임아웃에 도달하면, 왼쪽에 남아 있는 레이어들은 모두 2라는 사소한 경계값으로 완전히 채워집니다.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
forward_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)Output:
b. 양자 속도 한계를 통해 상한을 더 엄격하게 설정하다
다음으로, 함수를 tighten_with_speed_limit 사용하여 상한과 하한을 더 좁혀줍니다. 관측 대상의 광뿔이 갖는 기하학적 확산은 위에서 계산된 전방 경계에서 이미 완전히 고려되어 있습니다. 이 함수가 추가하는 것은, 회로를 통해 정보가 흐르는 제한된 속도(2큐비트 게이트로 구성된 각 층마다 라이트콘이 최대 1큐비트씩만 확장됨)를 활용하여, 이전에 계산된 상한값들 간의 관계를 더욱 엄격하게 만드는 자기일관성 검증 단계입니다. 정보는 양방향으로 흐릅니다:
- 커뮤테이터의 경계에서 역전파된 관측량의 경계까지: 만약 해당 관측량이 큐비트의 오류와 교환 관계를 이룬다면, 그곳에서는 나 성분이 크게 존재할 수 없다.
- 역전파된 관측량의 상한에서 교환자 상한으로: 만약 관측량이 큐비트에서 및 성분이 미미하다면, 그곳에서 와 거의 교환 관계를 이루어야 한다.
forward_bounds_tighter = tighten_with_speed_limit(
forward_bounds, boxed_circuit, noise_model_paulis, isa_observable
)수동 검사를 위해 SLC를 시각화하십시오
원칙적으로 이러한 강화 조치는 계산된 경계와 타임아웃을 초과한 레이어에 할당된 기본 경계 사이의 전환을 보다 원활하게 해줍니다. 이 예시에서는 타임아웃이 도래할 무렵에는 광뿔이 이미 회로의 가장자리까지 퍼져 있기 때문에 그 효과가 거의 보이지 않습니다.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
forward_bounds_tighter,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)Output:
c. 역방향 하한값 계산
소음 예측의 이 부분에서는 특정 층에서 발생한 오류가 입력 상태 에 어떤 영향을 미칠 수 있는지 평가합니다. 이 compute_backward_bounds 함수는 먼저 회로를 역전환하고 측정 게이트를 제거한 다음, 순방향 계산에서 수행했던 것과 유사한 분석을 진행합니다.
backward_bounds = compute_backward_bounds(
boxed_circuit,
noise_model_paulis,
evolution_max_terms=slc_evolution_max_terms,
num_processes=slc_num_processes,
timeout=slc_timeout,
)수동 검사를 위해 SLC를 시각화하십시오
역방향 상한을 계산해 보면, 초기 상태 구조가 오차 전파의 초기 양상을 어떻게 좌우하는지 알 수 있습니다:
- Z 오류가 초기 상태 |0⟩와 어떻게 교환 관계를 이루는지 명확히 알 수 있다.
- X 기저의 +1 고유상태를 초기화하는 6번 큐비트에서만 Z 오류가 교환 법칙을 따르지 않는 반면, X 오류는 교환 법칙을 따른다.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
backward_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)Output:
학습된 노이즈 비율을 적용하지 않은 상태에서 병합된 경계를 미리 보기
이 merged_bounds 함수는 회로에서 역방향 바운스에서 순방향 바운스로 전환하는 지점이, 목표 관측량에 대한 총 추정 편향을 최소화하는 지점을 결정합니다. 이 바이어스는 해당 지점 이전의 모든 노이즈 위치에 대한 역방향 기여도의 합과, 해당 지점 이후의 모든 노이즈 위치에 대한 순방향 기여도를 더하여 계산됩니다. 현재는 모든 큐비트에 대해 일률적으로 처리되고 있습니다.
후방 경계에서 전방 경계로 전환하는 최적의 시점은 학습된 잡음 발생률에 따라 달라집니다. 현재 단계에서는 아직 어떤 발생률도 학습하지 않았습니다. noise_model_rates 모든 레이어에 대해 로 None 초기화되었으며, 이는 merge_bounds 가 이를 균일한 잡음 발생률로 간주합니다. 따라서 여기에 표시된 병합된 경계는 단지 미리보기일 뿐이며, 3단계에서 실제로 학습된 비율을 바탕으로 이를 다시 계산합니다.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
noise_model_rates,
)Output:
Missing noise rates. Partitioning backward/forward commutator bounds by assuming uniform error rates.
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
수동 검사를 위해 SLC를 시각화하십시오
후방 경계와 축소된 전방 경계를 병합한 후, 통합된 SLC의 동작 양상이 명확해집니다:
- 위의 함수는 후방 경계에서 더 엄격한 전방 경계로 전환되는 지점에서 파티션이 선택된다는 것을 알려줍니다.
- 아래에서 볼 수 있듯이, SLC에는 이제 부분적인 후방 경계와 부분적으로 강화된 전방 경계가 포함되어 있습니다.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)Output:
3단계: 실행
이 섹션에서는 실제 양자 장치를 사용하는 워크플로우의 단계로 들어갑니다. 이 학습 기반 오류 완화 방법에는 두 단계가 있습니다:
NoiseLearnerV3...를 사용하여 소음을 파악하세요.- 및
Executor프레임워크를samplomatic사용하여 오류 완화 회로를 구현하십시오.
양자 회로에서 발생하는 오차가 제한적이라는 점을 바탕으로, 관련 노이즈 발생률을 파악하여 오류 예산을 우선순위화하고, 샘플링 오버헤드를 결정하며, QPU에서 실행합니다.
a. 소음 발생 빈도를 알아보세요
노이즈 학습기는 스파스 파울리-린드블라드 노이즈 모델을 기반으로, 관심 대상인 하나 이상의 회로 내 게이트에 영향을 미치는 노이즈 과정을 특성화합니다. 이 run() 메서드는 noise-learner 구성에 지정된 옵션을 사용하여, 제공된 고유한 2-큐비트 레이어에 대한 노이즈 학습 작업을 시작합니다. 이 옵션들은 파울리 회전 전략, 무작위화 횟수와 시뮬레이션 횟수, 학습 깊이, 그리고 사후 선별을 제어합니다.
또한 학습 깊이를 신중하게 결정합니다. 를 활용한 samplomatic 학습 기반 완화 기법에 대한 실질적인 연구 결과에 따르면, 완화 대상 회로의 깊이와 학습 깊이를 일치시키는 것이 매우 유익한 것으로 나타났다. NLv3layer_pair_depths 는 레이어 쌍 (레이어와 그 역함수) 단위로 측정되므로, 가장 깊은 값을 회로의 2-큐비트 레이어 깊이의 절반으로 설정합니다.
post_selection_enabled = True# Match the deepest noise-learning depth to the depth of the circuit being
# mitigated. NLv3 ``layer_pair_depths`` are measured in layer pairs (a layer
# plus its inverse), so the deepest value is half the circuit's two-qubit-layer
# depth. Learning to this depth markedly improves the quality of the mitigation.
#
# We measure the two-qubit-layer depth on the pre-boxed ISA circuit: after
# boxing, every two-qubit gate is hidden inside a full-width ``BoxOp``, so a
# ``num_qubits == 2`` filter on ``boxed_circuit`` matches nothing (and
# ``QuantumCircuit.depth`` does not recurse into boxes).
depth_2q = isa_circuit.depth(lambda instr: instr.operation.num_qubits == 2)
max_layer_pair_depth = depth_2q // 2 # dividing by 2 since we want pairs
# Use a fixed schedule of learning depths, but drop any that exceed the circuit's
# depth and always cap the deepest value at ``max_layer_pair_depth`` so we never
# learn deeper than the circuit being mitigated.
candidate_depths = [1, 2, 4, 8, 12, 16, 24, 32, 40, 48]
layer_pair_depths = sorted(
{d for d in candidate_depths if d < max_layer_pair_depth}
| {max_layer_pair_depth}
)
noise_learner_options = {
"num_randomizations": 64,
"shots_per_randomization": 128,
"layer_pair_depths": layer_pair_depths,
"post_selection": {
"enable": post_selection_enabled,
"strategy": "edge",
"x_pulse_type": "rx",
},
"environment": {"job_tags": ["TUT_SLC"]},
}
noise_learner = NoiseLearnerV3(backend, noise_learner_options)noise_learner_job = noise_learner.run(unique_2q_instructions)noise_learner_result = noise_learner_job.result()if post_selection_enabled:
print(
"Minimum fraction of shots kept for noise learning experiments: ",
end="",
)
print(
f"{min([min(d.values()) for d in [nlr.metadata['post_selection']['fraction_kept'] for nlr in noise_learner_result[:2]]]):.2f}"
)Output:
Minimum fraction of shots kept for noise learning experiments: 0.71
# Get a dict mapping each InjectNoise.ref to its learned PauliLindbladMap
refs_2_plm = noise_learner_result.to_dict(
unique_2q_instructions, require_refs=False
)b.i. 학습된 실제 노이즈 발생률로 병합된 범위를 업데이트합니다
이제 구체적인 노이즈 모델을 학습했으므로, 학습된 노이즈 발생률을 예측된 노이즈 범위에 적용하여, 편향을 최소화하는 데 가장 큰 영향을 미치는 범위가 무엇인지 최종적으로 파악할 수 있습니다.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
refs_2_plm,
)Output:
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
b.ii. 하드웨어 실행에 대한 값을 local_scales 계산하십시오
compute_local_scales 회로에서 발생할 수 있는 각 잡음 오류를 검토하고, 해당 오류가 최종 측정값에 얼마나 큰 편향을 일으킬 수 있는지, 그리고 이를 보정하는 데 드는 비용이 얼마나 될지를 추정합니다. 그런 다음, 오류를 완화할 가치가 있는 정도에 따라 순위를 매기고, 허용된 표본 추출 비용 한도 내에서(또는 원하는 정확도를 달성하면서) 편향을 최대한 줄일 수 있는 부분 집합을 선택합니다. 그 결과, 어떤 오류는 적극적으로 완화되고 어떤 오류는 완화되지 않을 것인지를 나타내는 일련의 가중치와 함께, 예측된 총 표본 추출 비용 오버헤드(sampling_costs) 및 잔여 편향(residual_bias_bound)이 도출됩니다(local_scales).
원하는 잔류 바이어스를 제어할 수 있는 능력은 PEC의 SLC 구현 방식에서 매우 중요한 특징입니다. 기존 구현에서는 샘플링 오버헤드가 항상 제로 바이어스를 목표로 했으나, 기대 잔여 바이어스와의 절충점을 통해 필요한 샘플링 오버헤드를 조정할 수 있습니다. 이를 통해 사용자는 정해진 샘플링 예산 범위 내에서 작업할 수 있으며, 이는 특히 워크플로우를 처음 프로토타이핑할 때 매우 유용할 수 있습니다.
id_map = map_modifier_ref_to_ref(boxed_circuit)summed_rates = 0.0
for box_id, noise_id in id_map.items():
learned_plm = refs_2_plm[noise_id]
summed_rates += np.sum(learned_plm.rates)
# print(f"{box_id}:\tgamma = {np.exp(2 * summed_rates):1.6e}\tsampling cost = {np.exp(4 * summed_rates):1.6e}")
total_gamma = np.exp(2 * summed_rates)
print(
f"Full PEC gamma={total_gamma}, sampling cost (gamma^2) = {total_gamma**2}"
)Output:
Full PEC gamma=12.750876317157042, sampling cost (gamma^2) = 162.58484685543633
biases = []
costs = []
for bias in [0.0] + np.arange(0.001, 0.102, 0.01).tolist():
_, cost_, bias_ = compute_local_scales(
boxed_circuit,
merged_bounds,
refs_2_plm,
sampling_cost_budget=np.inf,
bias_tolerance=bias,
)
biases.append(bias_)
costs.append(cost_)표본 추출 오버헤드와 잔차 편향을 절충한다
xticks = np.arange(0, 11)
fig, ax = plt.subplots()
ax.scatter(
[0], [total_gamma**2], marker="D", c="tab:orange", label="full PEC"
)
ax.plot(
100 * np.array(biases),
np.array(costs),
"o-",
c="tab:blue",
label="PEC+SLC",
)
ax.set_yscale("log")
ax.set_xticks(xticks, [f"{x:.1f}" for x in xticks])
ax.set_xlabel("Remaining bias [%]")
ax.set_ylabel(r"Sampling overhead, $\gamma^2$")
ax.grid()
ax.legend()
fig.suptitle("PEC sampling overhead reduction due to SLC")Output:
Text(0.5, 0.98, 'PEC sampling overhead reduction due to SLC')
chosen_bias_thres = 0.1local_scales, sampling_cost, residual_bias_bound = compute_local_scales(
boxed_circuit,
merged_bounds,
refs_2_plm,
sampling_cost_budget=np.inf,
bias_tolerance=chosen_bias_thres,
)
print(
f"PEC+SLC sampling cost (gamma^2) = {sampling_cost} "
f"w/ remaining bias = {100 * residual_bias_bound:.1f}%"
)Output:
PEC+SLC sampling cost (gamma^2) = 48.13646509622307 w/ remaining bias = 10.0%
c. antinoise를 사용하여 대상 회로를 실행하십시오
c.i. 다음과 같이 템플릿 회로를 준비합니다. samplex
template_circuit는 samplex Samplomatic의 build 메서드에서 생성된 결과물로, 에 대한 무작위 매개변수를 생성하는 데 필요한 모든 정보를 포함하고 있습니다. 이들은 이후 객체를 QuantumProgram 설정하는 데 사용되며, 설정된 객체는 다시 QPU에서 해당 Executor 프리미티브와 함께 실행됩니다. samplex각 QuantumProgram 항목에는 여러 개의 요소가 포함될 수 있으며, 이를 와 의 template 짝으로 생각할 수 있습니다.
자세한 내용은 ‘Hello samplomatic’ 튜토리얼을 참고하세요.
# Build template circuit and samplex for later use with the "Executor"
template_circuit, samplex = samplomatic.build(boxed_circuit)# Set up postselection if it's been enabled
if post_selection_enabled:
# Set up post selection PM (to add PS instructions)
post_selection_pm = PassManager(
[
AddSpectatorMeasures(backend.coupling_map),
AddPostSelectionMeasures(x_pulse_type="rx"),
]
)
final_template_circuit = post_selection_pm.run(template_circuit)
else:
final_template_circuit = template_circuitc.ii. 다음과 같이 설정하십시오. QuantumProgram
num_randomizations = 4096
shots_per_randomization = 64
chunk_size = 256# Set up QuantumProgram
program = QuantumProgram(shots=shots_per_randomization, noise_maps=refs_2_plm)
# no EM
# Collect up a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(0) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)
# plain PEC
# Collect a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(-1) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)
# PEC+SLC
# Collect a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(-1) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
samplex_inputs |= {"local_scales": local_scales}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)c.iii. 기본 연산자를 Executor 사용하여 프로그램을 실행합니다
executor = Executor(backend)job_exec = executor.run(program)results_exec = job_exec.result()4단계: 후처리
executor_expectation_values를 사용하여 관심 대상인 최종 기대값을 계산할 때, 가능한 한 최고 품질의 결과를 얻을 수 있도록 몇 가지 후처리 기법을 적용합니다. 먼저, 판독 과정에서 발생하는 모든 오류를 고려한 당사의 ‘트윌드 판독 오류 소거(TREX) ’ 기법을 적용합니다. 그런 다음, 사후 선별(post-selection) 기법을 사용하여 헤론(Heron) 백엔드에서 발생하는 비마르코프 잡음으로 인한 오류를 수정합니다. 이 방법은 활성 큐비트와 관찰자 큐비트를 측정한 다음, 각 큐비트에 느린 회전을 가한 후 다시 측정합니다. PostSelector두 측정 결과가 예상대로 뒤집힌 큐비트를 확인하지 못하는 경우, 해당 측정 데이터는 에서 mask 적용된 에 따라 제외됩니다. 마스크 계산 과정에서 단일 큐비트 노드나 인접한 스펙테이터 에지를 기준으로 필터링하도록 특정 전략을 설정할 수 있으며, 이는 필터링되어 제외되는 시도의 수와 결과의 품질 모두에 영향을 미칠 수 있다.
measurement_noise_map = noise_learner_result[2].to_pauli_lindblad_map()
trex_scale_factors = trex_factors(measurement_noise_map, reverser_virt)post_selection_strategy = "node"def post_process_conv(datum, steps=16, gamma=None, ps=False, trex=False):
meas = datum["meas"]
flips = datum["measurement_flips.meas"]
signs = datum.get("pauli_signs", None)
meas_basis_axis = None
avg_axis = 0
mask = None
if ps and post_selection_enabled:
# Post-select the results
post_selector = PostSelector.from_circuit(
circuit=final_template_circuit, coupling_map=backend.coupling_map
)
# Compute the ps mask for filtering results
mask = post_selector.compute_mask(
datum, strategy=post_selection_strategy
)
# Compute fraction of shots kept from post selection
total_num_shots = num_randomizations * shots_per_randomization
ps_ratio = np.sum(mask) * 100 / total_num_shots / len(bases_canon)
print(
f"With {post_selection_strategy}-based post selection ({ps_ratio:.1f}% of shots kept):"
)
results = []
for i in range(steps, num_randomizations + 1, steps):
# Compute mitigated expvals w/out post-selection
res = executor_expectation_values(
meas[:i],
reverser_virt,
meas_basis_axis,
avg_axis=avg_axis,
measurement_flips=flips[:i],
pauli_signs=signs[:i] if signs is not None else None,
postselect_mask=mask[:i] if mask is not None else None,
rescale_factors=trex_scale_factors if trex else None,
gamma_factor=gamma,
)
results.append(res[0])
return resultsgamma_pec = gamma_from_noisy_boxes(refs_2_plm, id_map)
gamma_slc = gamma_from_noisy_boxes(refs_2_plm, id_map, local_scales)steps = 16results = {}
for label, result_idx, gamma, use_ps, use_trex in [
("PEC", 1, gamma_pec, True, True),
("PEC+SLC", 2, gamma_slc, True, True),
("Unmitigated", 0, None, False, False),
]:
res = post_process_conv(
results_exec[result_idx],
steps=steps,
gamma=gamma,
ps=use_ps,
trex=use_trex,
)
results[label] = resOutput:
With node-based post selection (24.1% of shots kept):
With node-based post selection (24.2% of shots kept):
실험 결과를 분석함으로써, PEC, SLC와 결합된 PEC, 그리고 완화 조치가 적용되지 않은 기준선 등 서로 다른 접근 방식들의 거동을 직접 비교할 수 있다. 특히 주목할 만한 몇 가지 구체적인 사항은 다음과 같습니다:
- 이 순수한 결과는 10% 편향 범위( 0.35 근처)를 훨씬 벗어난 곳에 위치하며, 무작위 배정 횟수의 영향을 받지 않습니다.
- 이 장치에서 풀 PEC는 의 샘플링 오버헤드를 수반합니다. 초기 큰 변동 이후, 일반 PEC 추정치는 신호를 회복하여 1.1 부근에서 안정화되며, 정확한 값을 약간 초과합니다. 10% 편향 범위는 PEC+SLC 추정기에만 적용된다는 점에 유의하십시오. 일반 PEC는 원칙적으로 무편향이므로, 이러한 잔여 편차는 편향 보증의 대상이 아니며, 대신 통계적 변동과 학습된 노이즈 모델의 불완전성을 반영하는 것으로, 이 정도의 문제 규모에서는 타당한 현상입니다.
- SLC는 오버헤드를 추가로 ~3.4-fold 만큼 줄여줍니다( 로, 잔여 편향 상한은 약 10%입니다). PEC+SLC 역시 무작위화 횟수가 적을 때 큰 변동을 보이며, 초기에는 비물리적 영역까지 도달하기도 하지만, 그 추정치는 정확한 값으로 꾸준히 수렴하여 밴드 내부 깊숙한 곳인 1.0 근처에 안착합니다. 이 방법은 샘플링 비용이 약 3분의 1 수준임에도 일반 PEC와 동등하거나 그 이상의 정확도를 보여주며, 라이트콘 셰이딩의 이점을 입증합니다.
- 무작위 배정이 누적됨에 따라 두 가지 완화 추정치의 오차 막대 폭은 모두 좁아지며, 무작위 배정 횟수가 일정할 때 PEC+SLC 추정기는 통계적 분산이 더 작으며, 이는 이 추정기의 더 작은 와 일치한다.
학습된 노이즈 발생률(그리고 이에 따른 오버헤드 및 완화 추정값)은 백엔드와 실행 시점의 보정 상태에 따라 달라지므로, 이 노트북을 다시 실행하면 수치적으로 다른 결과가 나올 수 있습니다.
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
ax.axhline(1.0, color="black", label="Exact")
ax.fill_between(
[-50, 4100], -10, 0, color="grey", alpha=0.25, label="Unphysical"
)
ax.fill_between([-50, 4100], 1, 10, color="grey", alpha=0.25)
ax.fill_between(
[-50, 4100], 0.9, 1.1, color="red", alpha=0.25, label="10% bias"
)
for label, res in results.items():
ax.errorbar(
list(range(steps, num_randomizations + 1, steps)),
[r[0] for r in res],
yerr=[r[1] for r in res],
alpha=0.75,
marker="o",
linestyle="",
markerfacecolor="none",
label=label,
)
ax.set_ylabel(r"$\langle X_{6}Z_{13}\rangle$")
ax.set_xlabel("# randomizations")
ax.grid()
ax.legend(ncols=2)
ax.set_ylim([-0.1, 2.0])
ax.set_xlim([-50, 4100])Output:
(-50.0, 4100.0)
다음 단계
이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:


