Pakai Lp-norm yang berbeda untuk pemotongan suku Pauli
Catatan: Sebelum membaca panduan ini, sebaiknya baca dulu panduan Truncate Pauli terms, yang menjelaskan pemangkasan suku Pauli berbobot rendah yang sudah tertanam di metode backpropagate berdasarkan TruncationErrorBudget yang ditentukan.
Di panduan ini, kamu akan belajar tentang argumen kata kunci backpropagate, yaitu p_norm, yang bisa dipakai untuk mengubah norma Lp yang digunakan untuk memperkirakan error akibat suku Pauli yang dipangkas.
Membangun contoh circuit
Panduan ini memakai contoh circuit yang sama seperti di panduan 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)

Definisikan observable untuk magnetisasi 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
)
Sebagai acuan, hitung nilai ekspektasi yang tepat:
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
Gunakan norma L1
Secara default, dan seperti yang sudah kamu lihat di panduan Truncate Pauli terms, p_norm=1, artinya error diperkirakan sebagai:
dengan adalah state kuantum, adalah selisih sebenarnya antara observable yang tepat dan yang sudah dipangkas (yang tidak diketahui), adalah himpunan suku Pauli yang dipangkas, dan adalah koefisien suku Pauli.
Ketidaksamaan ini adalah batas atas yang ketat secara matematis tapi sangat longgar di sebagian besar skenario.
Panduan ini melakukan backpropagation pada enam slice dari contoh circuit, dengan error konstan per slice sebesar 0.001. Nilai ini dipahami sebagai budget dalam p_norm yang diberikan.
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.
Sekarang kita bisa menghitung nilai ekspektasi dari observable hasil backpropagation, beserta error terhadap acuan yang tepat:
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
Terakhir, kita bisa memplot error yang muncul selama backpropagation tiap slice, beserta error akumulasinya. Error akumulasi adalah jumlah dari error tiap slice. Kita bisa lihat bahwa error akumulasi merupakan batas atas yang sangat longgar terhadap error sebenarnya.
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])

Gunakan norma L2
Bisa dibilang norma L2 adalah pendekatan yang lebih baik untuk error yang muncul dibanding norma L1. Sebabnya, kita bisa mengasumsikan state kuantum diambil dari ensemble acak Haar, yang dalam hal ini error yang muncul mengikuti distribusi dengan rata-rata nol dan varians yang kira-kira bisa dibatasi oleh norma L2:
Meski batas ini tidak ketat secara matematis, batas ini hanya akan dilanggar pada kasus patologis.
Kita kembali melakukan backpropagation pada enam slice dari contoh circuit, dengan error maksimum per slice sebesar 0.001 (kali ini diartikan pada 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.
Sekali lagi, kita hitung nilai ekspektasi dari observable hasil backpropagation dan error terhadap acuan yang tepat:
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
Memplot error yang muncul per slice dan error akumulasi menghasilkan gambaran yang mirip seperti sebelumnya.
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])

Perhatikan bahwa error akumulasi lagi-lagi adalah jumlah dari error tiap slice. Ini adalah batas longgar lainnya akibat ketidaksamaan Minkowski, karena kita harus menghitung batas ini secara rekursif:
dengan subskrip baru menunjukkan iterasi slice saat ini, sehingga adalah error sebenarnya pada iterasi backpropagation , adalah error pemangkasan hasil pendekatan dari iterasi , dan adalah himpunan suku Pauli yang dipangkas pada iterasi .