Folosește diferite norme Lp pentru trunchierea termenilor Pauli
Notă: Înainte de a citi acest ghid, ar trebui să citești ghidul Truncate Pauli terms, care descrie trunchierea termenilor Pauli de pondere mică, integrată în metoda backpropagate pe baza unui TruncationErrorBudget specificat.
În acest ghid vei învăța despre argumentul cuvânt-cheie p_norm al metodei backpropagate, care poate fi folosit pentru a schimba norma Lp utilizată la estimarea erorii introduse de termenii Pauli trunchiați.
Construiește un circuit exemplu
Acest ghid folosește același circuit exemplu ca ghidul Truncate Pauli terms:
# 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
num_qubits = 10
linear_chain = rustworkx.generators.path_graph(num_qubits)
# 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 only, 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)

Definește o observabilă pentru magnetizarea totală:
from qiskit.quantum_info import SparsePauliOp
obs = SparsePauliOp.from_sparse_list(
[("Z", [i], 1.0) for i in range(num_qubits)], num_qubits=num_qubits
)
Pentru referință, calculează valoarea de așteptare exactă:
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
job = estimator.run([(circuit, obs)])
res = job.result()
exact_exp = res[0].data.evs
print(exact_exp)
9.318197859862146
Folosește norma L1
Implicit, și așa cum ai văzut deja în ghidul Truncate Pauli terms, p_norm=1, ceea ce înseamnă că eroarea este estimată astfel:
unde este starea cuantică, este diferența reală dintre observabila exactă și cea trunchiată (care este necunoscută), este mulțimea termenilor Pauli care au fost trunchiați, iar este coeficientul termenului Pauli.
Această inegalitate este o margine superioară riguroasă, dar foarte largă în majoritatea scenariilor.
Acest ghid aplică backpropagation pe șase felii ale circuitului exemplu, folosind o eroare constantă de 0.001 pe felie. Această valoare trebuie înțeleasă ca bugetul în cadrul p_norm dat.
from qiskit_addon_obp.utils.truncating import setup_budget
l1_truncation_error_budget = setup_budget(max_error_per_slice=0.001, p_norm=1)
print(l1_truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
from qiskit_addon_obp import backpropagate
max_slices = 6
l1_bp_obs, l1_remaining_slices, l1_metadata = backpropagate(
obs,
slices[-max_slices:],
truncation_error_budget=l1_truncation_error_budget,
)
l1_reduced_circuit = combine_slices(
slices[:-max_slices] + l1_remaining_slices
)
print(
f"Backpropagated {max_slices - len(l1_remaining_slices)} circuit slices."
)
print(
f"New observable contains {len(l1_bp_obs)} terms and {len(l1_bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 6 circuit slices.
New observable contains 116 terms and 10 commuting groups.
Acum putem calcula valoarea de așteptare a observabilei retropropagate, precum și eroarea față de referința exactă:
estimator = StatevectorEstimator()
job = estimator.run([(l1_reduced_circuit, l1_bp_obs)])
res = job.result()
l1_exp = res[0].data.evs
l1_error = exact_exp - l1_exp
print(l1_exp, l1_error)
9.317869899338842 0.00032796052330397174
În final, putem reprezenta grafic eroarea introdusă în timpul retropropagării fiecărei felii, precum și eroarea acumulată. Eroarea acumulată este suma erorilor feliilor. Putem vedea că eroarea acumulată este o margine superioară foarte largă a erorii reale.
from matplotlib import pyplot as plt
from qiskit_addon_obp.utils.visualization import (
plot_accumulated_error,
plot_slice_errors,
)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[1].plot([6], [l1_error], "x", color="red", label="actual error")
plot_slice_errors(l1_metadata, axes[0])
plot_accumulated_error(l1_metadata, axes[1])

Folosește norma L2
Se poate argumenta că norma L2 aproximează mai bine eroarea introdusă decât norma L1. Aceasta deoarece putem presupune că starea cuantică este extrasă dintr-un ansamblu aleatoriu Haar, caz în care eroarea introdusă urmează o distribuție cu media nulă și o varianță care poate fi aproximativ mărginită de norma L2:
Deși marginea nu este riguroasă, ea va fi încălcată doar în cazuri patologice.
Retropropagăm din nou șase felii ale circuitului exemplu, folosind o eroare maximă de 0.001 pe felie (de data aceasta, interpretată în norma L2).
l2_truncation_error_budget = setup_budget(max_error_per_slice=0.001, p_norm=2)
print(l2_truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=2)
max_slices = 6
l2_bp_obs, l2_remaining_slices, l2_metadata = backpropagate(
obs,
slices[-max_slices:],
truncation_error_budget=l2_truncation_error_budget,
)
l2_reduced_circuit = combine_slices(
slices[:-max_slices] + l2_remaining_slices
)
print(
f"Backpropagated {max_slices - len(l2_remaining_slices)} circuit slices."
)
print(
f"New observable contains {len(l2_bp_obs)} terms and {len(l2_bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 6 circuit slices.
New observable contains 84 terms and 6 commuting groups.
Din nou, calculăm valoarea de așteptare a observabilei retropropagate și eroarea față de referința exactă:
estimator = StatevectorEstimator()
job = estimator.run([(l2_reduced_circuit, l2_bp_obs)])
res = job.result()
l2_exp = res[0].data.evs
l2_error = exact_exp - l2_exp
print(l2_exp, l2_error)
9.317829770853422 0.00036808900872387085
Reprezentarea grafică a erorilor introduse pe felie și a erorii acumulate produce o imagine similară cu cea de dinainte.
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[1].plot([6], [l2_error], "x", color="red", label="actual error")
plot_slice_errors(l2_metadata, axes[0])
plot_accumulated_error(l2_metadata, axes[1])

Reține că eroarea acumulată este din nou suma erorilor feliilor individuale. Aceasta este o altă margine largă, din cauza inegalității Minkowski, deoarece trebuie să calculăm această margine recursiv:
unde noul indice indică iterația curentă a feliei, făcând din eroarea reală la iterația de retropropagare , din eroarea de trunchiere aproximată din iterația , iar din mulțimea termenilor Pauli trunchiați la iterația .