Probabilistické zrušení chyb se stínovanými light cones
Odhad doby použití: 10 minut na procesoru Heron (POZNÁMKA: Jedná se pouze o odhad. Skutečná doba běhu se může lišit.)
Výstupy z učení
-
Co je probabilistické zrušení chyb (PEC) a proč jeho režie vzorkování roste exponenciálně s celkovým šumem působícím na obvod
-
Jak stínované light cones (SLC) omezují příspěvek každého šumového členu k cílové pozorovatelné, takže lze rozpočet na potlačení chyb utratit tam, kde to má význam — a jak, nad rámec redukce režie s nulovým zkreslením, kterou už poskytuje čistě geometrický light cone, stínování umožňuje vyměnit omezené zbytkové zkreslení za ještě nižší režii vzorkování
-
Jak se naučit šum vrstev pomocí
NoiseLearnerV3a vstříknout anti-šum pomocísamplomatica primitivaExecutor -
Jak zkombinovat PEC a PEC+SLC s TREX a postselekcí pro odhad očekávané hodnoty na hardwaru
Předpoklady
-
Pracovní postup Qiskit patterns
-
Použití primitiva Estimator k výpočtu očekávaných hodnot pozorovatelné
-
Techniky potlačení chyb, jako je Pauliho twirling a TREX, popsané v Kombinace možností potlačení chyb s primitivem Estimator
Kontext
Tento tutoriál ukazuje, jak potlačit chyby pomocí addonu stínovaných light cones (SLC). Tento addon je vývojovým pokračováním techniky probabilistického zrušení chyb (PEC), při níž se uživatel naučí šum jedinečných vrstev v Circuit a poté šum zruší pomocí aplikace jednoqubitových gate a technik post-processingu. Ve srovnání s jinými metodami nabízí PEC robustnější meze zkreslení potlačeného výsledku, ale zpravidla trpí vyšší režií co do doby QPU. Během PEC se, aby se kompenzovalo zeslabení očekávané hodnoty šumem, průměrný výsledek přeškáluje faktorem , kde je naučená míra šumu chybové Pauliho matice ve vrstvě v Circuit. Toto přeškálování zvyšuje rozptyl faktorem , a tedy také násobí počet spuštění Circuit potřebných na QPU faktorem , což nazýváme nákladem na vzorkování neboli režií vzorkování. Protože roste exponenciálně, je PEC často omezena na mělké Circuity nebo Circuity s malým počtem qubitů. Více o PEC se dozvíš v Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors.
Pokud dokážeme identifikovat chyby, které nemusí být potlačeny, můžeme tento náklad na vzorkování exponenciálně snížit. Prvním krokem tímto směrem je implementace lokálně uvědomělého potlačení chyb, které pomocí rychle vypočitatelného konvenčního „light cone“ snižuje režii PEC tím, že omezí citlivost pozorovatelné na chyby v celém Circuit, čímž rozšiřuje proveditelnost PEC na větší škály u některých úloh. Chyby mimo tento light cone nemohou ovlivnit naměřený výsledek, a lze je tedy z procedury zrušení chyb vyloučit. Toto vyloučení snižuje režii vzorkování, v některých případech podstatně, aniž by zavádělo dodatečné zkreslení. Konkrétně pro měření lokální pozorovatelné v Circuit s pevnou hloubkou se potřebná režie vzorkování při zvětšování počtu qubitů v Circuit nakonec ustálí (viz obr. 2b v Locality and error mitigation of quantum circuits).
Stínované light cones (SLC) jdou dále a pomocí klasických simulací těsněji omezují citlivost na chyby v celém Circuit. Tím se vymění část doby QPU za dobu CPU a sníží se režie vzorkování potřebná k renormalizaci zkreslení. Namísto tvrdého prahu je každé potenciální chybě v Circuit přiřazen odstupňovaný „odstín“, který horní mezí omezuje citlivost očekávané hodnoty pozorovatelné na danou chybu. (U níže zavedených zpětně propagovaných mezí tato citlivost závisí také na počátečním stavu Circuit — na stavu všech nul v typických pracovních postupech a i v tomto tutoriálu.) Tato zpřesněná charakterizace umožňuje efektivnější, cílenější aplikace PEC se sníženým rozptylem a zároveň dává uživateli možnost kontrolovaně ladit zkreslení při odhadu pozorovatelné. Další podrobnosti viz Lightcone shading for classically accelerated quantum error mitigation.
Náš pracovní postup pro addon SLC využívá knihovnu samplomatic spolu s třídami QuantumProgram a Executor přidanými do Qiskit Runtime v qiskit-ibm-runtime v0.47.0, což uživatelům umožňuje modulárnější kontrolu nastavení spouštění pro potlačení a zrušení chyb při zachování snadného použití. Více se dozvíš v průvodci directed execution model.
Pracovní postup potlačení chyb SLC ve zkratce
Pro modelování šumu QPU používáme řídký Pauli-Lindbladův model šumu s jedno- a dvouqubitovými chybovými rychlostmi Pauliho operátorů, generovanými lokálně pro každý qubit a hranu zařízení. S touto volbou vypadá pracovní postup SLC pro mitigaci chyb prezentovaný v tomto tutoriálu následovně:
a. CPU — Ohraničení dopadu jednotlivých jedno- a dvouqubitových Pauliho chyb
-
Dopředná propagace (ohraničení vlivu na pozorovatelnou veličinu). Propaguj každou chybu na konec obvodu a spočítej její komutátor s pozorovatelnou veličinou.
-
Ořízni operátorové členy během evoluce, aby výpočet zůstal zvládnutelný.
-
Dále zpřesni tato ohraničení volnou zpětnou propagací pozorovatelné veličiny na základě kvantových rychlostních limitů.
-
-
Zpětná propagace (ohraničení vlivu na počáteční stav). Propaguj každou chybu na začátek obvodu a spočítej její komutátor s počátečním stavem.
b. QPU — Nauč se rychlosti šumu. Použij NoiseLearnerV3 k odhadu rychlostí Pauli-Lindbladova modelu šumu.
c. CPU — Stanov prioritu mitigace
-
Aktualizuj sloučená ohraničení naučenými rychlostmi šumu. Zkombinuj dříve vypočtená dopředná a zpětná ohraničení a aktualizuj je naučenými rychlostmi šumu.
-
Seřaď šumové komponenty k mitigaci pomocí vypočtených ohraničení a naučených rychlostí. Stanov prioritu každé možné šumové chyby na základě jejího odhadovaného vlivu na zkreslení a souvisejících nákladů na opravu.
d. QPU — Vlož anti-šum a spusť. Spusť požadovaný obvod s anti-šumem (inverzním šumem) určeným pomocí anotací Box.
e. CPU — Odhadni pozorovatelnou veličinu. Spočítej střední hodnotu, přičemž aplikuj post-selekci založenou na měření pro snížení dopadu nemarkovovského šumu.
Přehled učení šumu
Učení šumu je běžný krok v několika metodách mitigace chyb, prováděný pomocí učicího se modulu šumu; objevuje se také v tutoriálu o pravděpodobnostní amplifikaci chyb. V NoiseLearnerV3 můžeš konkrétně určit vrstvy šumu, které se mají naučit, jako objekty CircuitInstruction, abys mohl vypočítat požadovaná ohraničení šumu SLC pro každou vrstvu popsaným způsobem. Naučený Pauli-Lindbladův model poskytuje koeficienty, které se použijí při stanovení priority PEC+SLC. Způsob, jakým jsou hradla shromažďována do vrstev, lze určit pomocí pohodlných funkcí generate_boxing_pass_manager a find_unique_box_instructions, a poté je předat do nástrojové funkce SLC generate_noise_model_paulis, jak je popsáno v kroku 2 níže.
| Část 1 | Část 2 | Část 3 |
|---|---|---|
| Pauli-twirling dvouqubitových vrstev hradel | Opakuj identitní páry vrstev a nauč se šum | Odvoď fidelitu (chybu pro každý šumový kanál) |
![]() | ![]() |
Přehled následného zpracování
Po provedení výpočtu na kvantovém hardwaru pomocí frameworku samplomatic a Executor převedeme naše měření bitových řetězců na požadovanou hodnotu pozorovatelné veličiny. V tomto tutoriálu demonstrujeme pracovní postup na zrcadleném Isingově obvodu (sestaveném v kroku 1 níže), pro který je ideální střední hodnota měřené pozorovatelné veličiny rovna 1, protože druhá polovina obvodu ruší první. Při výpočtu hodnoty pozorovatelné veličiny pomocí funkce executor_expectation_values aplikujeme několik technik následného zpracování, které snižují dopad šumu. Ty zahrnují odstranění záběrů (shots) ovlivněných nemarkovovským šumem, mitigaci chyb výčtu (readout) a zohlednění detailů naší implementace PEC. Podrobnosti jsou popsány v kroku 4 níže.
Požadavky
Než začneš s tímto tutoriálem, ujisti se, že máš nainstalováno následující:
-
Qiskit SDK v2.2 nebo novější, s podporou vizualizace
-
Qiskit Runtime v0.47 nebo novější (
pip install qiskit-ibm-runtime) -
Qiskit addon Shaded lightcones v0.1 nebo novější (
pip install qiskit-addon-slc) -
Qiskit addon utils v0.3 nebo novější (
pip install qiskit-addon-utils) -
Samplomatic v0.13 nebo novější (
pip install samplomatic)
Nastavení
Nejprve importuj balíčky a funkce potřebné ke spuštění tohoto notebooku.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-slc qiskit-addon-utils qiskit-ibm-runtime 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=1
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
Příklad s malým simulátorem
Stejně jako jiné metody mitigace chyb založené na učení, PEC se stínovanými lightcones mitiguje fyzický šum konkrétního kvantového procesoru, takže závisí na hardwarových službách bez smysluplné obdoby na ideálním simulátoru:
-
NoiseLearnerV3experimentálně charakterizuje řídký Pauli-Lindbladův šumový kanál na každé unikátní dvouqubitové vrstvě. Na bezšumovém simulátoru není žádný šum, který by bylo třeba rušit. -
Primitivum
Executorvzorkuje twirlingované obvody s vloženým anti-šumem generované nástrojemsamplomaticna Backendu.
Výpočet ohraničení stínovaného lightcone je klasický, ale je smysluplný pouze vzhledem k naučeným hardwarovým rychlostem šumu, které určují rozpočet mitigace a režii vzorkování. Z těchto důvodů vynecháváme příklad s malým simulátorem a demonstrujeme celý pracovní postup PEC+SLC přímo na hardwaru, přičemž každý krok Qiskit vzoru je níže rozebrán zvlášť.
Rozsáhlý příklad na hardwaru
Spouštíme kompletní pracovní postup PEC+SLC na 20-qubitovém zrcadleném Isingově obvodu spuštěném na hardwaru IBM Quantum®, podle čtyř kroků Qiskit vzoru.
Krok 1: Namapuj problém
Naše demonstrace je nastavena následovně:
-
Rozhodneme se provádět časovou evoluci podle hamiltoniánu 1D Isingova řetězce. 1D Isingův řetězec dává pěkně hustou strukturu obvodu, což je vhodné pro demonstraci implementací PEC.
-
Rozhodneme se měřit pozorovatelnou veličinu , která obsahuje jednu komponentu a jednu . To je vhodné pro zdůraznění toho, jak ohraničení SLC zachází odlišně s různými typy chyb.
-
Chceme, aby ideální střední hodnota této pozorovatelné veličiny byla přesně 1, aby bylo snadné posoudit kvalitu mitigovaných odhadů. Zrcadlení obvodu nás k tomu dostane z velké části: pro každé hradlo v druhé polovině obvodu existuje inverzní hradlo v první polovině, takže ideální obvod funguje jako identita.
-
Nakonec, získání ideální střední hodnoty 1 vyžaduje, aby obvod začínal — a proto, díky zrcadlení, ideálně také končil — ve vlastním stavu pozorovatelné veličiny s vlastní hodnotou +1. Protože pozorovatelná veličina obsahuje komponentu jinou než , a primitivum
Executorzohledňuje požadovanou měřicí bázi na konci obvodu, přidáváme odpovídající hradla pro přípravu báze na začátek zrcadleného obvodu pomocí funkceprepare_basis. Používáme funkciget_measurement_basesk identifikaci, jaká hradla jsou potřeba a kam je umístit, přičemž sledujeme jemnosti v indexování qubitů vyplývající z konvencí anotacebox, jak je popsáno v části o přípravě měření v kanonických bázích.
# 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 / 4
def 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
)

Krok 2: Optimalizuj
Optimalizujeme detaily spojené s obvodem, který se má spustit, s pozorovatelnou veličinou, která se má měřit, a s parametry učení šumu. Jako výchozí bod vybereme nejméně vytížený procesor Heron a inicializujeme jej se zapnutými zlomkovými hradly (fractional gates). Tato zlomková hradla umožňují větší citlivost v některé z našich filtrů post-selekce.
# 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}")
Selected backend: ibm_kingston
Nejprve transpilujeme náš obvod na instrukce ISA, jak je vyžadováno pro spuštění na našich QPU. Volba fyzických qubitů, na kterých se má obvod spustit, má velký vliv na kvalitu výsledků, protože doby koherence a fidelity hradel se v rámci zařízení liší a v čase se mění. Pro pečlivý experiment se může vyplatit ručně vybrat řetězec qubitů na základě rychlých benchmarkových experimentů (viz například tutoriál Benchmarking v reálném čase pro výběr qubitů). Pro účely tohoto tutoriálu se spoléháme na Transpiler Qiskit, aby vybral rozložení na základě mapy propojení Backendu a jeho nejnovějších kalibračních dat.
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
)
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,
)

Zabal obvod do boxů
Pro snadnější implementaci využíváme transpilační průchod generate_boxing_pass_manager, který umístí instrukce obvodu do anotovaných boxů. Tyto boxy jasně určují, kam by měl být, v případě PEC, vložen anti-šum do obvodu. Podrobnosti o nastavení najdeš v dokumentaci Samplomatic.
Všimni si, že pracovní postup SLC vyžaduje pozdější použití inject_noise_strategy="individual_modification", protože to umožňuje jednoznačně identifikovat anotace InjectNoise instrukcí BoxOp v obvodu. (Boxy bez anotace InjectNoise takto identifikovat nelze.)
Výpočty mezí SLC v současnosti předpokládají, že anotace InjectNoise jsou umístěny s site="after" (viz qiskit-addon-slc#33). Protože se výchozí hodnota tohoto nastavení v nedávných verzích samplomatic změnila (viz samplomatic#372), nastavujeme níže explicitně inject_noise_site="after".
Funkce find_unique_box_instructions prochází poskytnutý obvod rozdělený do boxů a identifikuje ty, které mají unikátní dvouqubitové (2Q) vrstvy nebo měření, za účelem učení šumu a vkládání šumu.
# 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,
)

Připrav měření v kanonických bázích
Všimni si, že musíme věnovat zvláštní pozornost sledování pořadí qubitů. Níže zavádíme pojem canonical_qubits jako prostředek pro vhodnou aktualizaci pořadí qubitů při jeho předávání do Executoru, v důsledku toho, jak je pořadí qubitů zachyceno při zabalování obvodů do boxů a hledání unikátních instrukcí. Podrobnosti najdeš v dokumentaci Konvence pořadí qubitů.
# 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
]
Pracovní postup pro stínování lightcone, učení šumu a vkládání anti-šumu
V tomto tutoriálu spouštíme výpočty mezí SLC ještě předtím, než je dokončeno učení šumu, takže obvod, který má být zmírněn, se spouští v čase co nejblíže naučenému modelu šumu. Tento workflow lze v zásadě dále paralelizovat: úloha učení šumu může běžet, zatímco se souběžně odhadují meze šumu. U libovolného kvantového obvodu může výpočet meze šumu škálovat se slabě exponenciální závislostí, takže paralelizace výpočtu mezí (například napříč mnoha jádry CPU) poskytuje přesnější meze pro daný rozpočet výpočetního času, a samotné spouštění na QPU i výpočty mezí lze paralelizovat pro co nejefektivnější workflow.
Předpověz Pauliho operátory šumového modelu, které se mají naučit
Před spuštěním jakéhokoli učení šumu na hardwaru nejprve vyjmenujeme, jaké Pauliho chybové členy bude náš šumový model obsahovat. Připomeňme, že šum každé unikátní vrstvy modelujeme jako řídký Pauli-Lindbladův model s jednou chybovou rychlostí pro každý Pauliho operátor váhy jedna (, nebo ) na každém aktivním qubitu a jednou pro každý Pauliho operátor váhy dva na každé propojené dvojici aktivních qubitů. Funkce generate_noise_model_paulis prochází každou unikátní vrstvu poskytnutého obvodu rozdělenou do boxů a generuje přesně tento seznam Pauliho členů, přičemž zohledňuje propojení qubitů v obvodu.
Jinými slovy, tento krok předpovídá strukturu šumového modelu, kterou později NoiseLearnerV3 doplní naučenými rychlostmi. Znalost této struktury předem je to, co nám umožňuje vypočítat dopředné i zpětné ohraničení pro každou potenciální chybu ještě před tím, než učení šumu vůbec proběhne.
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. Vypočti dopředná ohraničení
Funkce compute_forward_bounds vyhodnocuje komutační vztahy mezi hradly v každé vrstvě a výše vygenerovanými Pauliho členy z hlediska toho, jak dopředně propagované chyby ovlivňují požadovanou pozorovatelnou veličinu . U hradel, která komutují s Pauliho členy, se nic nedělá. Cliffordova hradla jsou posunuta směrem k začátku obvodu. U necliffordovských hradel aproximujeme jejich vliv na cílové pozorovatelné veličiny, aby jim mohla být později přiřazena priorita pro rušení šumu (poté, co jsou všechna ohraničení sloučena). Toto ohraničení je dosaženo nejprve aplikací normy L2 (konkrétně druhé odmocniny součtu čtverců relevantních koeficientů Pauliho členů). Pokud je zapojeno příliš mnoho qubitových členů, přejdeme na volnější ohraničení využívající trojúhelníkovou nerovnost.
Nastav parametry výpočtu ohraničení
Následující nastavení řídí klasické výpočty ohraničení:
-
slc_atol: absolutní tolerance výpočtů. Operátorové členy s koeficienty pod touto hranicí jsou považovány za zanedbatelné a jsou vyřazeny. -
slc_eigval_max_qubits: maximální počet qubitů, pro který se vyhodnocuje přísnější, ohraničení založené na vlastních hodnotách (norma L2). Operátory podporované na větším počtu qubitů než tento se vrátí k výše popsanému volnějšímu ohraničení pomocí trojúhelníkové nerovnosti. -
slc_evolution_max_terms: maximální počet Pauliho členů zachovaných při propagaci operátorů obvodem. Ořezání nejmenších členů udržuje výpočet zvládnutelný za cenu mírně volnějších ohraničení. -
slc_num_processes: počet CPU procesů, mezi kterými je výpočet ohraničení paralelizován. -
slc_timeout: časový rozpočet (v sekundách) pro výpočet ohraničení. Vrstvám, kterých se v rámci tohoto rozpočtu nedosáhne, je přiřazeno triviální ohraničení 2.
V tomto tutoriálu je timeout dosažen záměrně: hodnotu slc_timeout udržujeme záměrně malou, aby notebook běžel rychle, a abychom ukázali, že dosažení timeoutu je bezpečné. Vypočtené odstíny jsou v každé fázi horní meze, takže dosažení timeoutu meze pro nedosažené vrstvy pouze zvolní (triviálně); nikdy nepodhodnotí vliv chyby. Ve vizualizacích níže se to projeví tak, že nejlevější vrstvy jsou zcela vyplněny triviální mezí. Zvýšení timeoutu (nebo počtu procesů) zpřesní meze a dále sníží režii vzorkování.
slc_atol = 1e-8
slc_eigval_max_qubits = 18
slc_evolution_max_terms = 1000
slc_num_processes = 8
slc_timeout = 60
forward_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,
)
Bounds computation timed out.
Vizualizuj SLC pro ruční kontrolu
Chování stínovaných ohraničení můžeš interpretovat zkoumáním toho, jak měření a Pauliho členy interagují s lokálními chybami. Tyto vzory jsou charakteristické pro tento problém časové evoluce hamiltoniánu kicked Ising a objevují se také v článku Lightcone Shading for Classically Accelerated Quantum Error Mitigation, s několika typickými rysy:
-
Jasně můžeme rozlišit dva kužely vznikající ze dvou neidentitních Pauliho operátorů v pozorovatelné veličině.
-
Vidíme, že měření X na qubitu 6 komutuje s chybou X v nejpravější vrstvě.
-
Vidíme, že Pauliho operátor Z na qubitu 13 komutuje s chybou Z v nejpravější vrstvě.
-
Když dosáhneme výše zadaného časového limitu, zbývající vrstvy vlevo jsou zcela vyplněny triviálními ohraničeními o hodnotě dva.
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,
)
)



b. Zpřesni dopředná ohraničení pomocí kvantových rychlostních limitů
Dále zpřesníme ohraničení pomocí funkce tighten_with_speed_limit. Geometrické šíření lightcone pozorovatelné veličiny je již plně zohledněno ve výše vypočtených dopředných ohraničeních. Tato funkce navíc přidává průchod se sebekonzistencí, který využívá omezenou rychlost, jakou se informace může šířit obvodem — lightcone roste nejvýše o jeden qubit na vrstvu dvouqubitových hradel — ke zpřesnění dříve vypočtených ohraničení vůči sobě navzájem. Informace proudí oběma směry:
-
Od komutátorových ohraničení k ohraničením zpětně propagované pozorovatelné veličiny: pokud pozorovatelná veličina komutuje s chybou na qubitu, pak tam nemůže mít mnoho komponenty nebo .
-
Od ohraničení zpětně propagované pozorovatelné veličiny ke komutátorovým ohraničením: pokud má pozorovatelná veličina malou komponentu a na qubitu, pak tam musí téměř komutovat s .
forward_bounds_tighter = tighten_with_speed_limit(
forward_bounds, boxed_circuit, noise_model_paulis, isa_observable
)
Vizualizuj SLC pro ruční kontrolu
V principu toto zpřesnění poskytuje plynulejší přechod mezi vypočtenými ohraničeními a triviálními ohraničeními přiřazenými vrstvám za časovým limitem. V tomto příkladu je efekt sotva viditelný, protože se lightcones do doby dosažení časového limitu již rozšířily až k okrajům obvodu.
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,
)
)



c. Vypočti zpětná ohraničení
Tato část předpovědi šumu vyhodnocuje, jak může chyba v konkrétní vrstvě ovlivnit vstupní stav . Funkce compute_backward_bounds nejprve invertuje obvod a odstraní měřicí hradla, a poté pokračuje podobnou analýzou, jaká byla provedena pro výpočty dopředných ohraničení.
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,
)
Vizualizuj SLC pro ruční kontrolu
Z výpočtu zpětných ohraničení vidíme, jak struktura počátečního stavu řídí raný průběh šíření chyb:
-
Jasně vidíme, jak chyby Z zpočátku komutují s počátečním stavem |0⟩.
-
Pouze na qubitu 6, kde inicializujeme vlastní stav s vlastní hodnotou +1 v bázi X, chyba Z nekomutuje, zatímco chyba X komutuje.
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,
)
)



Náhled sloučených ohraničení bez naučených rychlostí šumu
Funkce merged_bounds určuje bod v obvodu, kde přechod ze zpětných na dopředná ohraničení minimalizuje celkové odhadované zkreslení požadované pozorovatelné veličiny. Toto zkreslení se počítá jako součet příspěvků zpětných ohraničení pro všechna umístění šumu před tímto bodem plus příspěvků dopředných ohraničení pro všechna umístění šumu po něm. V současnosti se to provádí jednotně pro všechny qubity.
Optimální bod, ve kterém se má přejít ze zpětných na dopředná ohraničení, závisí na naučených rychlostech šumu. V této fázi jsme se ještě žádné rychlosti nenaučili: noise_model_rates bylo pro každou vrstvu inicializováno na None, což merge_bounds interpretuje jako jednotné rychlosti šumu. Zde zobrazená sloučená ohraničení jsou proto pouze náhledem; přepočítáme je se skutečně naučenými rychlostmi v kroku 3.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
noise_model_rates,
)
Missing noise rates. Partitioning backward/forward commutator bounds by assuming uniform error rates.
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
Vizualizuj SLC pro ruční kontrolu
Po sloučení zpětných a zpřesněných dopředných ohraničení se chování kombinovaných SLC vyjasní:
-
Výše uvedená funkce nám říká, ve kterém rozdělení dochází k přechodu ze zpětných na zpřesněná dopředná ohraničení.
-
Níže vidíme, že SLC nyní obsahují částečně zpětná a částečně zpřesněná dopředná ohraničení.
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,
)
)



Krok 3: Spusť
V této části zahajujeme část pracovního postupu, která používá skutečné kvantové zařízení. U této metody mitigace chyb založené na učení jsou dva kroky:
-
Nauč se šum pomocí
NoiseLearnerV3. -
Spusť obvod pro mitigaci chyb pomocí frameworku
samplomaticaExecutor.
S ohraničenými chybami z našeho kvantového obvodu se naučíme příslušné rychlosti šumu, abychom stanovili prioritu našeho chybového rozpočtu, určili režii vzorkování a provedli výpočet na QPU.
a. Nauč se rychlosti šumu
Učicí se modul šumu charakterizuje šumové procesy ovlivňující hradla v jednom nebo více zkoumaných obvodech, na základě řídkého Pauli-Lindbladova modelu šumu. Metoda run() spouští úlohu učení šumu pro poskytnuté unikátní dvouqubitové vrstvy, s použitím možností zadaných v konfiguraci učicího se modulu šumu. Tyto možnosti řídí strategii Pauli-twirlingu, počet randomizací a záběrů (shots), hloubky učení a post-selekci.
Také záměrně volíme hloubky učení. Praktickým poznatkem pro mitigaci založenou na učení s samplomatic je, že je velmi výhodné, aby nejhlubší hloubka učení odpovídala hloubce obvodu, který chceš mitigovat. Protože layer_pair_depths NLv3 se měří v párech vrstev (vrstva plus její inverze), nastavíme nejhlubší hodnotu na polovinu dvouqubitové hloubky vrstev obvodu.
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}"
)
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. Aktualizuj sloučená ohraničení pomocí skutečně naučených rychlostí šumu
Nyní, když byl naučen konkrétní šumový model, můžeme naučené rychlosti šumu aplikovat na předpovězená ohraničení šumu a získat konečné určení toho, která ohraničení mají největší vliv na minimalizaci zkreslení.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
refs_2_plm,
)
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
b.ii. Vypočti local_scales pro spuštění na hardwaru
compute_local_scales se dívá na každou možnou šumovou chybu v obvodu a odhaduje, jak moc by tato chyba mohla zkreslit konečné měření, a také jak nákladné by bylo ji opravit. Poté seřadí chyby podle toho, jak výhodné je je mitigovat, a vybere podmnožinu, která co nejvíce sníží zkreslení, přičemž zůstane v rámci povoleného rozpočtu nákladů na vzorkování (nebo dosáhne požadované přesnosti). Výsledkem je sada škálovacích faktorů udávajících, které chyby budou aktivně mitigovány a které zůstanou nemitigované (local_scales), spolu s předpovězenou celkovou režií nákladů na vzorkování (sampling_costs) a zbývajícím zkreslením (residual_bias_bound).
Schopnost řídit požadované zbývající zkreslení je klíčovou vlastností implementace PEC pomocí SLC. Zatímco v původní implementaci byla režie vzorkování vždy zaměřena na nulové zkreslení, my můžeme ladit požadovanou režii vzorkování s kompromisem v očekávaném zbývajícím zkreslení. To pomáhá uživateli zůstat v rámci pevného rozpočtu vzorkování, což může být zvlášť užitečné při počátečním prototypování pracovního postupu.
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}"
)
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_)
Vyvaž režii vzorkování oproti zbytkovému zkreslení
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")
Text(0.5, 0.98, 'PEC sampling overhead reduction due to SLC')
chosen_bias_thres = 0.1
local_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}%"
)
PEC+SLC sampling cost (gamma^2) = 48.13646509622307 w/ remaining bias = 10.0%
c. Spusť zkoumaný obvod s anti-šumem
c.i. Připrav šablonu obvodu pomocí samplex
samplex je výstupem metody build nástroje Samplomatic, který zakóduje veškeré informace potřebné pro generování randomizovaných parametrů pro template_circuit. Ty se poté použijí k nastavení objektů QuantumProgram, které se následně spouští na QPU pomocí primitiva Executor. Každý QuantumProgram může obsahovat několik položek, o kterých můžeš uvažovat jako o dvojici template a samplex.
Podrobnosti najdeš v tutoriálu 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_circuit
c.ii. Nastav 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. Spusť program pomocí primitiva Executor
executor = Executor(backend)
job_exec = executor.run(program)
results_exec = job_exec.result()
Krok 4: Následné zpracování
Při výpočtu konečné zkoumané střední hodnoty pomocí executor_expectation_values implementujeme několik technik následného zpracování, které pomáhají zajistit, abychom získali co nejkvalitnější výsledky. Nejprve aplikujeme naši metodu twirled readout error extinction (TREX), která zohledňuje jakékoli chyby vzniklé během procesu výčtu (readout). Poté opravíme chyby způsobené nemarkovovským šumem na našich Backendech Heron pomocí post-selekční metody. Tato metoda měří aktivní a divácké (spectator) qubity, poté aplikuje pomalou rotaci na každý qubit a znovu měří. V případech, kdy obě měření nepotvrdí očekávaně převrácený qubit, jsou tyto záběry (shots) vyřazeny aplikací mask z PostSelector. V rámci výpočtu masky lze nastavit konkrétní strategii pro filtrování na základě jednoqubitových uzlů nebo sousedních divácko-hran (spectator edges), což může ovlivnit jak počet vyřazených záběrů, tak kvalitu výsledků.
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 results
gamma_pec = gamma_from_noisy_boxes(refs_2_plm, id_map)
gamma_slc = gamma_from_noisy_boxes(refs_2_plm, id_map, local_scales)
steps = 16
results = {}
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] = res
With node-based post selection (24.1% of shots kept):
With node-based post selection (24.2% of shots kept):
Ze zkoumání experimentálních výsledků můžeme přímo porovnat chování různých přístupů: PEC, PEC kombinované s SLC a nemitigovaný základní výsledek. Několik konkrétních detailů, na které stojí za to upozornit:
-
Nemitigovaný výsledek leží daleko mimo pásmo 10% zkreslení (blízko 0,35) a není ovlivněn počtem randomizací.
-
Na tomto zařízení nese plné PEC režii vzorkování . Po velkých počátečních výkyvech se odhad prostého PEC vrací k signálu a ustaluje se kolem 1,1, mírně přestřeluje přesnou hodnotu. Všimni si, že pásmo 10% zkreslení platí pouze pro odhadovací funkci PEC+SLC: prosté PEC je v principu nezkreslené, takže tato zbytková odchylka není pokryta zárukou zkreslení, ale místo toho odráží statistické fluktuace a nedokonalosti naučeného šumového modelu, což je při této velikosti problému rozumné.
-
SLC snižuje režii dalšími ~3,4krát (na , pro ohraničení zbytkového zkreslení asi 10%). PEC+SLC také silně fluktuuje při malém počtu randomizací, zpočátku dokonce dosahuje do nefyzikální oblasti, ale jeho odhad se stabilně sbíhá k přesné hodnotě, ustaluje se blízko 1,0 dobře uvnitř pásma. Odpovídá přesnosti prostého PEC, nebo ji převyšuje, za zhruba třetinu nákladů na vzorkování, což demonstruje přínos stínování lightcone.
-
Chybové úsečky obou mitigovaných odhadů se s narůstajícím počtem randomizací zmenšují; při pevném počtu randomizací má odhadovací funkce PEC+SLC menší statistický rozptyl, což odpovídá jejímu menšímu .
Všimni si, že naučené rychlosti šumu (a tedy i režie a mitigované odhady) závisí na Backendu a jeho kalibraci v době provedení, takže opětovné spuštění tohoto notebooku může přinést kvantitativně odlišné hodnoty.
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])
(-50.0, 4100.0)

Další kroky
Pokud tě tato práce zaujala, mohl by tě zajímat následující materiál:

