Přeskočit na hlavní obsah
Tento projekt je v betě. Našel jsi chybu? Otevřít issue na GitHubu. Máš otázku nebo nápad? Zeptej se v Discussions — rádi si poslechneme tvou zpětnou vazbu!
Jaká je kvalita překladu na této stránce?

Zkracování Pauliho členů během zpětné propagace

Tento průvodce vysvětluje, jak nakonfigurovat mechanismus zkracování Pauliho členů poskytovaný modulem qiskit_addon_obp.utils.truncating.

Zpětnou propagaci operátoru (OBP) lze použít ke snížení hloubky kvantových obvodů za cenu složitější observably. Abychom z OBP získali smysluplné výsledky, je obvykle nutné z observably zkracovat členy, aby příliš nenarostla. Jedním ze způsobů, jak umožnit hlubší zpětnou propagaci do obvodu a přitom zabránit přílišnému růstu operátoru, je zkracovat členy s malými koeficienty místo jejich přidávání do operátoru. Zkracování členů může vést k menšímu počtu kvantových obvodů ke spuštění, ale způsobuje určitou chybu ve výsledném výpočtu střední hodnoty, úměrnou velikosti koeficientů zkrácených členů.

Metoda backpropagate přijímá volitelný TruncationErrorBudget, který konfiguruje zkracování Pauliho členů s nízkou vahou pro každou observablu po úspěšné zpětné propagaci každého řezu. Množství zkracovaných členů závisí na různých konfiguračních parametrech zadaných uživatelem. Zatím je k dispozici jediná strategie zkracování — metoda truncate_binary_search. Pro danou observablu a nějaký rozpočet provede binární vyhledávání mezi Pauliho členy a koeficienty v této observabli, aby našla optimální práh, tak, aby součet zkrácených koeficientů byl maximální, ale nižší než rozpočet.

Poznámka: Ve výchozím nastavení se k vyhodnocení a omezení chyby zkrácení používá norma L1; nastavení p_norm však umožňuje zadat, jaká Lp-norma se má použít. Další informace o používání tohoto nastavení najdeš v průvodci Použití různých Lp-norem pro zkracování Pauliho členů. Následující příklady ilustrují různé způsoby vytvoření TruncationErrorBudget pomocí doprovodné funkce setup_budget.

Sestavení ukázkového obvodu​

Tento průvodce používá následující řezy obvodu:

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"matplotlib": "matplotlib", "qiskit": "qiskit", "qiskit_addon_obp": "qiskit-addon-obp", "qiskit_addon_utils": "qiskit-addon-utils", "rustworkx": "rustworkx"}
_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 rustworkx.generators
from qiskit.synthesis import LieTrotter
from qiskit_addon_utils.problem_generators import (
PauliOrderStrategy,
generate_time_evolution_circuit,
generate_xyz_hamiltonian,
)
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types

# Generate a linear chain of 10 qubits
linear_chain = rustworkx.generators.path_graph(10)

# Use an arbitrary XY model
hamiltonian = generate_xyz_hamiltonian(
linear_chain,
coupling_constants=(0.05, 0.02, 0.0),
ext_magnetic_field=(0.02, 0.08, 0.0),
pauli_order_strategy=PauliOrderStrategy.InteractionThenColor,
)
# Evolve for some time
circuit = generate_time_evolution_circuit(
hamiltonian, synthesis=LieTrotter(reps=3), time=2.0
)
# slice the circuit by gate type
slices = slice_by_gate_types(circuit)

# for visualization purposes, recombine the slices with barriers between them and draw the resulting circuit
combine_slices(slices, include_barriers=True).draw("mpl", fold=50, scale=0.6)

Output of the previous code cell

Podíváme se na jedinou jednoduchou observablu:

from qiskit.quantum_info import SparsePauliOp

obs = SparsePauliOp("IIIIIZIIII")

Nejjednodušší případ: pevný rozpočet zkracování pro každý řez​

Dostupný rozpočet pro zkracování Pauliho členů se může v každém kroku zpětné propagace lišit. Abychom pochopili, jak to funguje, podíváme se nejprve na nejjednodušší případ pevného rozpočtu zkracování zadaného uživatelem.

Nejpřímočařejší způsob zadání rozpočtu zkracování je pomocí argumentu max_error_per_slice. Ve skutečnosti se tak děje v tutoriálu Snižování hloubky obvodů pomocí zpětné propagace operátoru. Nastavení max_error_per_slice na float vede k tomu, že každému řezu je přidělen rozpočet rovný této hodnotě. V příkladu níže nastavujeme tuto hodnotu na 0.001, což zaručuje implicitní chybu zkrácení nejvýše 0.018, pokud by se zpětně propagovalo všech 18 řezů.

Všimni si, že jakýkoli rozpočet chyby, který zbude po zpětné propagaci řezu a zkrácení členů s malými koeficienty, se vždy přičte k rozpočtu chyby následujícího řezu.

from qiskit_addon_obp.utils.truncating import setup_budget

truncation_error_budget = setup_budget(max_error_per_slice=0.001)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.simplify import OperatorBudget

op_budget = OperatorBudget(max_qwc_groups=10)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
New observable contains 29 terms and 10 commuting groups.

Dále použijeme instanci OBPMetadata a nástroje poskytované modulem visualization k vizualizaci procesu zpětné propagace.

  • Levý horní graf ukazuje, že máme dost rozpočtu, abychom mohli začít zkracovat členy observably po zpětné propagaci třetího řezu. Počínaje třetím řezem víme, že z každého zpětně propagovaného řezu zkrátíme alespoň jeden člen, protože po každém řezu vzniká určitá chyba zkrácení.

  • Pravý horní graf ukazuje, že rozpočet chyby pro třetí řez roste na .003. Vidíme prudký pokles zbývajícího rozpočtu, což znamená, že z observably byly zkráceny členy. To je v souladu s tím, co jsme usoudili z levého horního grafu.

  • Levý dolní graf ukazuje, že s tím, jak z observably zkracujeme členy, naše celková akumulovaná chyba monotónně roste. Tento graf také potvrzuje, že žádné členy nebyly zkráceny, dokud nebyl zpětně propagován třetí řez.

  • Pravý dolní graf ukazuje, že počet komutujících Pauliho skupin v naší observabli vzrostl na zadaný limit 10. Tento graf také ukazuje, jak by zpětná propagace dalších jedné vrstvy způsobila, že by naše observabla přerostla zadanou mez, což je vidět z křížení černé a červené čáry.

Všimni si, že ve všech těchto grafech osa x čísluje zpětně propagované řezy, ale protože OBP pracuje od konce obvodu, slice 1 je úplně poslední řez, slice 2 je ten před ním a tak dále.

from matplotlib import pyplot as plt
from qiskit_addon_obp.utils.visualization import (
plot_accumulated_error,
plot_left_over_error_budget,
plot_num_qwc_groups,
plot_slice_errors,
)

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Explicitní zadání rozpočtu řezů​

Pokud víš, jak přidělit rozpočet každému řezu tak, aby byl výkon zpětné propagace optimalizován, můžeš chtít přidělit rozpočet každému řezu explicitně. Pro demonstraci přidělíme prvním třem řezům nulový rozpočet a ostatním řezům rozpočet .001 na řez.

# Zero out the first 3 slices' budgets
max_error_per_slice = [0.0] * 3 + [0.001] * (len(slices) - 3)

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001], max_error_total=inf, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
New observable contains 32 terms and 10 commuting groups.

Odebrání rozpočtu prvním třem vrstvám vedlo k tomu, že se nezkrátily žádné členy až po čtvrté vrstvě, což lze potvrdit ve třech z těchto grafů. Poněkud překvapivé může být, že ačkoli čtvrtý řez nezdědil žádný zbývající rozpočet, pomocí přiděleného rozpočtu .001 byl přesto zkrácen jeden člen. To je zřejmé z grafu vlevo nahoře, ale lze to pozorovat i v grafu vpravo nahoře, protože křivka zbývajícího rozpočtu se mezi třetím a čtvrtým řezem narovná. Další pozoruhodný detail je, že od tohoto bodu byl zkrácen alespoň jeden člen, stejně jako v předchozím příkladu.

Hlavní poznatek je, že ačkoli jsme ve druhém příkladu způsobili menší chybu zkrácení díky vynulování rozpočtů některých řezů, dokázali jsme zpětně propagovat stejný počet řezů a naše observabla obsahuje stejný počet komutujících Pauliho skupin. Prohlédnutím grafu vlevo dole můžeme potvrdit, že mez naší chyby je ve druhém příkladu menší.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Cyklické zadání rozpočtu​

Pokud máš obvod s nějakým opakujícím se vzorem, například Trotterův obvod, můžeš chtít zadat rozpočet pro tuto opakovanou podmnožinu řezů a použít ho pro všechna následující opakování těchto řezů.

Konkrétněji, ukázkový obvod, který používáme, má šest řezů opakovaných třikrát, celkem tedy 18 řezů. Libovolně přidělíme nulový rozpočet jednoqubitovým vrstvám a vrstvám RYY a rozpočet .003 každé vrstvě RXX. Uvidíme, jak zadání rozpočtu jako posloupnosti délky 6 způsobí, že se rozpočet aplikuje cyklicky na všech 18 řezů.

Znovu si všimni, že řezy se zpětně propagují v opačném pořadí (tedy od konce). První položka našeho cyklického rozpočtu se proto ve skutečnosti použije pro poslední řez, druhá pro řez před ním a tak dále.

# Specify a length-6 per-slice budget.
# This will be cycled over three times to be applied to the 18 slices
max_error_per_slice = [0.0] * 4 + [0.003] * 2

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.0, 0.003, 0.003], max_error_total=inf, p_norm=1)
op_budget = OperatorBudget(max_qwc_groups=20)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 13 circuit slices.
New observable contains 49 terms and 14 commuting groups.

Jak je vidět na obrázcích vlevo nahoře a vlevo dole, během prvních čtyř řezů nedošlo k žádnému zkracování, protože jim nebyl přidělen žádný rozpočet chyby. U řezů pět a šest byly některé členy zkráceny, jakmile se rozpočet uvolnil.

Jak je vidět na obrázku vlevo nahoře, po zpětné propagaci sedmého řezu vznikla poměrně velká chyba, přestože tomuto řezu nebyl přidělen žádný rozpočet. Je to proto, že z celkového rozpočtu .006 přiděleného řezům pět a šest se využilo jen asi .002, takže zbytek byl předán řezu sedm a většinou vyčerpán, jak je vidět na obrázku vpravo nahoře.

Obrázky vlevo nahoře a vpravo nahoře ukazují, že malý zbylý rozpočet se vyčerpá mezi řezy 8–10 a nový rozpočet se uvolní v řezu 11, jak se očekává. Obrázky vlevo nahoře, vpravo nahoře a vlevo dole všechny dokládají cyklické chování argumentu max_error_per_slice, je-li jeho délka menší než počet řezů. Toto cyklické chování by pokračovalo všemi řezy, ale zastavovací kritérium max_qwc_groups bylo dosaženo po zpětné propagaci 13 řezů, jak je vidět na obrázku vpravo dole.

Zajímavé je také, že počet Pauliho skupin po uvolnění druhého kola rozpočtu v řezu 11 skutečně klesne. Je to proto, že existovaly skupiny s malými koeficienty, které nebylo možné zkrátit, dokud po zpětné propagaci řezu 11 nebyl k dispozici další rozpočet, takže se v observabli několik iterací hromadily. Tento případ také zdůrazňuje, že max_qwc_groups musí být překročeno, aby algoritmus skončil.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Omezení celkové chyby​

Kromě zadání rozpočtu chyby na řez lze zadat i maximální míru chyby způsobené zkracováním. Jakmile je tento limit dosažen, žádné další zkracování se neprovádí; zpětná propagace však pokračuje, dokud observabla nepřeroste a nenaplní se jedno ze zastavovacích kritérií.

Nyní znovu spustíme výše uvedený experiment a nastavíme strop max_error_total tak, aby se rozpočet chyby vyčerpal po zpětné propagaci sedmého řezu.

# Specify a length-6 per-slice budget.
# This will be cycled over 3 times to be applied to the 18 slices
max_error_per_slice = [0.0] * 4 + [0.003] * 2

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice, max_error_total=0.006
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.0, 0.003, 0.003], max_error_total=0.006, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 10 circuit slices.
New observable contains 67 terms and 20 commuting groups.

Jak se očekávalo, naše chyba zkrácení dosáhne stropu .006 (graf vlevo dole). Pozoruhodné je, že v tomto běhu se nám nepodařilo zpětně propagovat řez 11. Je to proto, že jsme neměli dost rozpočtu na zkracování členů a počet komutujících Pauliho skupin přerostl limit 20, jak je vidět na obrázku vpravo dole.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Může být žádoucí jednoduše omezit celkový rozpočet pomocí max_error_total bez zadání max_error_per_slice.

truncation_error_budget = setup_budget(max_error_total=0.018)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.018], max_error_total=0.018, p_norm=1)

Výstup buňky výše může být mírně překvapivý, protože per_slice_budget je nastaven na max_error_total. To znamená, že celý dostupný rozpočet bude spotřebován chamtivě. Můžeš si to představit takto: celý rozpočet je k dispozici každému řezu (protože cyklujeme přes per_slice_budget). Ale jakýkoli rozpočet, který už byl spotřebován, se odečte od rozpočtu dostupného v daném bodě algoritmu.

op_budget = OperatorBudget(max_qwc_groups=10)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 9 circuit slices.
New observable contains 25 terms and 9 commuting groups.

Obrázek vpravo nahoře ukazuje, jak je celý rozpočet chyby .018 zpřístupněn prvnímu řezu. Až do třetího řezu se neprovádí žádné zkracování, takže zbylý rozpočet zůstává konstantní. Rozpočet monotónně klesá, protože celý rozpočet je zpřístupněn každému zpětně propagovanému řezu, dokud se nevyčerpá.

Pozoruhodné je, že tento experiment vedl ke dvěma méně zpětně propagovaným řezům ve srovnání s prvním experimentem v tomto notebooku, který je téměř shodný. To ukazuje, že pro některé problémy může být optimální rozdělit rozpočet rovnoměrně. Pro jiné problémy může lepšího výkonu dosáhnout to, že řezy chamtivě vyčerpají celý rozpočet.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Omezení počtu zpětně propagovaných řezů a celkové chyby společně​

Pokud nechceš rozdělovat rozpočet chyby po celém obvodu, ale nechceš ho ani chamtivě vyčerpat, můžeš zadat počet řezů, které hodláš zpětně propagovat (num_slices), spolu s celkovým rozpočtem chyby (max_error_total). Rozpočet chyby se tak rozdělí rovnoměrně (podle p_norm) mezi vstupní řezy.

Zde omezíme počet řezů, které bychom mohli zpětně propagovat, na 12 a ponecháme stejný celkový rozpočet chyby.

num_slices = 12

truncation_error_budget = setup_budget(
max_error_total=0.018, num_slices=num_slices, p_norm=1
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0014999999999999998], max_error_total=0.018, p_norm=1)

Nyní se pokusíme zpětně propagovat 12 řezů, kterým jsme v předchozím kroku přidělili nějaký rozpočet. Uděláme to tak, že předáme posledních 12 řezů našeho obvodu. S p_norm=1 má každý z 12 řezů k dispozici rozpočet 0.018 / num_slices = 0.0015.

bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices[-num_slices:],
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)

Protože jsme backpropagate předali podmnožinu našich řezů (v kódu slices[-num_slices:]), musíme řezy zbylé po zpětné propagaci spojit s řezy, které nebyly do zpětné propagace vůbec poslány (v kódu slices[:-num_slices]).

Jakmile spojíme všechny zbylé řezy, můžeme pomocí combine_slices vygenerovat QuantumCircuit se sníženou hloubkou. Poté zkontrolujeme, kolik řezů bylo zpětně propagováno oproti tomu, jak velká se stala naše observabla.

# Recombine the slices remaining after backprop with the rest of the original circuit
reduced_circuit = combine_slices(slices[:-num_slices] + remaining_slices)

print(f"Backpropagated {num_slices - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 12 circuit slices.
New observable contains 29 terms and 9 commuting groups.

Grafy ukazují, že se nám úspěšně podařilo provést zpětnou propagaci všech 12 řezů a zároveň udržet naši observable pod 10 komutujícími Pauliho skupinami. Vidíme také, že použití num_slices spolu s max_error_total vede k rozložení rozpočtů mezi řezy a nevyužitý rozpočet se opět přenáší do dalšího řezu. Nejlépe je to vidět v grafu vpravo nahoře, kde se rozpočet během zpětné propagace jak spotřebovává, tak doplňuje.

Je pozoruhodné, že tento způsob rozdělení chyby přinesl nejlepší výsledky (více zpětně propagovaných řezů) ve srovnání s prvním experimentem v tomto notebooku a s předchozím příkladem. Všechny tyto příklady přidělily rozpočet chyby .018, ale zpětná propagace dopadla různě podle toho, jak byl tento rozpočet rozdělen.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Práce s více observables​

Metoda qiskit_addon_obp.backpropagate umožňuje předat posloupnost observables. Tím se zjednoduší postup při práci s několika cílovými observables.

Zmiňujeme to zde výslovně, abychom ti ukázali, jak strategie ořezávání takový případ zvládá. Pro účely tohoto příkladu přidáme k observable, kterou jsme dosud používali, další:

obs = [SparsePauliOp("IIIIIZIIII"), SparsePauliOp("IIIIIXIIII")]

Nakonec zopakujeme první experiment z tohoto tutoriálu, ale se dvěma observables, do kterých obvod zpětně propagujeme.

V tomto příkladu to neovlivní počet řezů, které bylo možné zpětně propagovat. Vidíme ale, že obě observables vedly k různému počtu Pauliho členů a komutujících skupin.

truncation_error_budget = setup_budget(max_error_per_slice=0.001)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"The new first observable contains {len(bp_obs[0])} terms and {len(bp_obs[0].group_commuting(qubit_wise=True))} commuting groups."
)
print(
f"The new second observable contains {len(bp_obs[1])} terms and {len(bp_obs[1].group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
The new first observable contains 29 terms and 10 commuting groups.
The new second observable contains 23 terms and 8 commuting groups.

Níže uvedené grafy pomáhají ilustrovat, jak algoritmus zpětné propagace zachází s více observables.

Nejprve grafy vlevo nahoře, vpravo nahoře a vlevo dole ukazují, že rozpočet na ořezávání členů je nastaven pro každou observable zvlášť. Jinými slovy, obě observables mohou ořezávat členy za předpokladu chyby 0.001 na každý zpětně propagovaný řez. Kvůli odlišné povaze observables to vede k různé spotřebě rozpočtu. V tomto příkladu se výrazně překrývají, což se nestává vždy.

Graf vpravo dole ilustruje, že max_qwc_groups bere v úvahu všechny observables. To znamená, že členy všech observables se seskupí dohromady, aby vznikl jeden výsledný počet qubitově komutujících skupin, který se porovnává s max_qwc_paulis. Totéž se děje u prahu max_paulis (v tomto notebooku se jím nezabýváme), který umožňuje stanovit limit počtu Pauliho členů napříč všemi observables.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell