속도 제한으로 경계를 강화하는 방법
두 큐비트 게이트로 이루어진 회로에서 정보는 임의로 빠르게 퍼질 수 없습니다. 끝에서 여러 층 앞서, 관측량의 지지 영역에서 멀리 떨어진 큐비트에서 발생한 오류는 관측량에 도달할 경로가 없습니다. tighten_with_speed_limit은 이러한 기하학적 논거(Lieb-Robinson 경계의 배경이 되는 것과 같은 직관)를 더 엄격한 순방향 경계로 바꿉니다.
이 단계는 비용이 적게 들고, 순방향 경계가 이미 요구한 것 외에는 아무것도 필요하지 않으며, 경계를 더 엄격하게만 만들 수 있습니다. 따져봐야 할 정확도 트레이드오프가 없습니다.
먼저 답해 볼 만한 질문은 *"언제 도움이 되는가?"*입니다. 완전히 수렴한 순방향 경계에서는 도움이 되는 경우가 많지 않기 때문입니다.
설정
빠른 시작 가이드와 같은 Trotter화된 Ising 회로를 사용하며, 관측량은 체인 가운데의 단일 큐비트에 둡니다. 1D 기하 구조 덕분에 효과를 쉽게 추론할 수 있습니다. 영향은 층마다 결합 하나씩 체인을 가로질러야 합니다.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_slc": "qiskit-addon-slc", "samplomatic": "samplomatic"}
_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 Pauli
from qiskit_addon_slc.bounds import (
compute_forward_bounds,
tighten_with_speed_limit,
)
from qiskit_addon_slc.utils import generate_noise_model_paulis
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions
def trotter_ising_circuit(num_qubits, num_steps, rx_angle, rzz_angle):
"""Trotterized transverse-field Ising evolution on a 1D chain."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(rx_angle, range(num_qubits))
circuit.barrier()
for start in (0, 1): # even then odd bonds
for i in range(start, num_qubits - 1, 2):
circuit.rzz(rzz_angle, i, i + 1)
circuit.barrier()
return circuit
num_qubits = 10
circuit = trotter_ising_circuit(
num_qubits, num_steps=4, rx_angle=np.pi / 16, rzz_angle=-np.pi / 3
)
# A single-qubit observable in the middle of the chain.
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])
boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)
def compare(label, bounds):
"""Tightens a set of bounds and prints what changed."""
tightened = tighten_with_speed_limit(
bounds, boxed_circuit, noise_model_paulis, observable
)
before = np.concatenate([bound.rates for bound in bounds.values()])
after = np.concatenate([bound.rates for bound in tightened.values()])
print(
f"{label:30} mean {before.mean():.4f} -> {after.mean():.4f} "
f"tightened {np.count_nonzero(after < before - 1e-12):4} of {len(before)} "
f"loosened {np.count_nonzero(after > before + 1e-12)}"
)
print(
f"observable: Z on qubit {num_qubits // 2}, circuit depth {circuit.depth()}"
)
observable: Z on qubit 5, circuit depth 12
도움이 되는 경우와 그렇지 않은 경우
tighten_with_speed_limit은 이미 가지고 있는 경계를 받아 강화된 사본을 반환하며, 원래 경계는 절대 수정되지 않습니다. 얼마나 개선되는지는 전적으로 입력이 얼마나 느슨했는지에 달려 있습니다.
# 1. Fully computed forward bounds.
full_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
compare("fully computed", full_bounds)
# 2. Bounds where the eigenvalue step was skipped, leaving the looser triangle inequality.
loose_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable, eigval_max_qubits=0
)
compare("triangle inequality only", loose_bounds)
# 3. Bounds computed only for the first few boxes, the rest left at the trivial bound of 2.0.
shallow_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable, max_num_boxes=2
)
compare("max_num_boxes=2", shallow_bounds)
fully computed mean 0.3639 -> 0.3639 tightened 0 of 792 loosened 0
triangle inequality only mean 0.5081 -> 0.4842 tightened 105 of 792 loosened 0
max_num_boxes=2 mean 1.5707 -> 0.5284 tightened 450 of 792 loosened 0
주목해야 할 것은 첫 번째 줄입니다. 완전히 계산된 순방향 경계에서는 속도 제한이 아무것도 바꾸지 않습니다. 이는 실패가 아닙니다. 연산자 발전이 사실상 라이트콘을 스스로 찾아냈기 때문에, 경계가 이미 기하학적 논거로 증명할 수 있는 만큼 이상으로 엄격했다는 뜻입니다.
개선은 경계가 완전히 계산되지 않은 경우에 나타납니다.
-
eigval_max_qubits=0은 삼각 부등식 폴백을 강제하므로, 경계가 더 이상 교환자의 실제 스펙트럼 노름을 반영하지 않습니다. 속도 제한은 그 손실의 일부를 복구합니다. -
max_num_boxes=2는 대부분의 층을 자명한 경계 2.0(아무 정보도 담지 않은 경계)으로 남겨 둡니다. 이 경우 속도 제한이 도움이 되어 평균을 대략 3분의 1로 줄입니다.
모든 경우에 "느슨해진" 열은 0입니다. 어떤 항도 나빠지지 않으며, 이것이 이 단계를 무조건 적용해도 안전하게 만드는 보장입니다.
샘플링 오버헤드에서 얻는 이점
경계가 더 엄격하면 주어진 편향 허용치에 대해 완화해야 하는 오류 항이 줄어들며, 이는 하드웨어에서 중요한 수치입니다.
from qiskit.quantum_info import PauliLindbladMap, QubitSparsePauliList
from qiskit_addon_slc.bounds import compute_local_scales
# Stand-in for rates that a noise-learning experiment would measure on hardware.
rng = np.random.default_rng(42)
noise_rates = {
layer: PauliLindbladMap.from_components(
rng.random(len(terms)) * 5e-3,
QubitSparsePauliList.from_sparse_list(
terms.to_sparse_list(), terms.num_qubits
),
)
for layer, terms in noise_model_paulis.items()
}
tightened_shallow = tighten_with_speed_limit(
shallow_bounds, boxed_circuit, noise_model_paulis, observable
)
print(
f"{'bounds':30} {'overhead':>9} {'mitigated':>10} {'residual bias':>14}"
)
for label, bounds in (
("max_num_boxes=2", shallow_bounds),
("max_num_boxes=2 + speed limit", tightened_shallow),
("fully computed", full_bounds),
):
scales, cost, bias = compute_local_scales(
boxed_circuit, bounds, noise_rates, bias_tolerance=0.05
)
mitigated = sum(int(np.count_nonzero(scale)) for scale in scales.values())
total = sum(len(scale) for scale in scales.values())
print(
f"{label:30} {cost:9.4f} {f'{mitigated}/{total}':>10} {bias:>14.4f}"
)
bounds overhead mitigated residual bias
max_num_boxes=2 420.2823 617/792 0.0490
max_num_boxes=2 + speed limit 7.8511 226/792 0.0485
fully computed 5.4031 188/792 0.0494
언제 사용하나요
순방향 경계가 완전히 수렴하지 않았을 때마다(본질적으로, 구성 가이드의 옵션을 사용해 정확도를 속도와 맞바꾼 경우마다) 적용하세요. 경계 계산에 비해 비용이 적게 들고, 아무것도 나쁘게 만들 수 없으며, max_num_boxes 또는 eigval_max_qubits 한도로 잃은 것의 상당 부분을 복구합니다.
완전히 계산된 경계에서는 아무 동작도 하지 않으므로 무조건 적용해도 해가 없습니다.
두 가지 제한 사항이 있습니다.
-
순방향 경계에만 적용됩니다. 역방향 경계는 오류가 관측량이 아니라 초기 상태에 미치는 영향을 다루므로 이 논거가 그대로 적용되지 않습니다.
-
관측량은 단일 Pauli 항이어야 합니다. 여러 항으로 이루어진 관측량의 경우 Pauli마다 한 번씩 호출하고 결과를 직접 결합하세요. 관측량이 단일 Pauli 항이 아니면
NotImplementedError가 발생합니다.
표준 워크플로에서는 빠른 시작 가이드에 나와 있듯이 순방향 경계를 계산한 후, 역방향 경계와 병합하기 전에 사용합니다.