Memangkas suku Pauli selama backpropagation
Panduan ini menjelaskan cara mengonfigurasi mekanisme pemangkasan suku Pauli yang disediakan oleh modul qiskit_addon_obp.utils.truncating.
Operator backpropagation (OBP) bisa dipakai untuk mengurangi depth circuit kuantum dengan konsekuensi observable yang lebih kompleks. Supaya OBP memberi hasil yang bermakna, biasanya kita perlu memangkas suku dari observable agar tidak tumbuh terlalu besar. Salah satu cara untuk memungkinkan backpropagation lebih dalam ke circuit sambil menjaga operator tidak terlalu besar adalah memangkas suku berkoefisien kecil, alih-alih menambahkannya ke operator. Pemangkasan suku bisa menghasilkan lebih sedikit circuit kuantum yang harus dijalankan, tapi akibatnya ada error pada perhitungan akhir nilai ekspektasi, sebanding dengan besar koefisien suku yang dipangkas.
Metode backpropagate menerima TruncationErrorBudget opsional, yang mengonfigurasi pemangkasan suku Pauli berbobot rendah untuk setiap observable setelah backpropagation tiap slice berhasil. Jumlah suku yang dipangkas bergantung pada berbagai parameter konfigurasi yang ditentukan pengguna. Saat ini, hanya satu strategi pemangkasan yang tersedia - metode truncate_binary_search. Diberikan sebuah observable dan sebuah budget, metode ini akan melakukan pencarian biner atas suku dan koefisien Pauli di dalam observable tersebut untuk menemukan threshold yang optimal, sehingga jumlah koefisien yang dipangkas maksimal tapi lebih kecil dari budget.
Catatan: Secara default, norma L1 dipakai untuk mengevaluasi dan membatasi error pemangkasan; namun, pengaturan p_norm memungkinkan penentuan norma Lp yang akan dipakai.
Untuk informasi lebih lanjut tentang cara memakai pengaturan itu, lihat panduan Use different Lp-norms for Pauli term truncation.
Contoh-contoh berikut menggambarkan berbagai cara membangun TruncationErrorBudget dengan fungsi pendampingnya, setup_budget.
Membangun contoh circuit
Panduan ini memakai slice circuit berikut:
# 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)

Kita akan melihat satu observable sederhana:
from qiskit.quantum_info import SparsePauliOp
obs = SparsePauliOp("IIIIIZIIII")
Kasus paling sederhana: budget pemangkasan tetap untuk setiap slice
Budget yang tersedia untuk memangkas suku Pauli bisa berbeda di setiap langkah backpropagation. Untuk memahami cara kerjanya, kita lihat dulu kasus paling sederhana, yaitu budget pemangkasan tetap yang ditentukan oleh pengguna.
Cara paling lugas untuk menentukan budget pemangkasan adalah dengan argumen max_error_per_slice.
Sebenarnya, inilah yang dilakukan di tutorial Reducing depth of circuits with operator backpropagation. Mengatur max_error_per_slice ke sebuah float membuat setiap slice mendapat budget sebesar nilai tersebut.
Di contoh di bawah, kita mengatur nilai ini ke 0.001, yang menjamin error pemangkasan implisit paling besar 0.018, jika semua 18 slice di-backpropagate.
Perhatikan bahwa sisa error budget apa pun setelah backpropagation sebuah slice dan pemangkasan suku berkoefisien kecil akan selalu ditambahkan ke error budget slice berikutnya.
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.
Selanjutnya kita memakai instance OBPMetadata dan tool dari modul visualization untuk memvisualisasikan proses backpropagation.
-
Plot kiri atas menunjukkan bahwa kita punya cukup budget untuk mulai memangkas suku observable setelah backpropagation slice ketiga. Mulai dari slice ketiga, kita tahu bahwa kita memangkas setidaknya satu suku dari setiap slice yang kita backpropagate karena kita menanggung sejumlah error pemangkasan setelah tiap slice.
-
Plot kanan atas menunjukkan bahwa error budget naik menjadi
.003untuk slice ketiga. Kita melihat penurunan tajam pada sisa budget, yang berarti ada suku yang dipangkas dari observable. Ini konsisten dengan yang kita simpulkan dari plot kiri atas. -
Plot kiri bawah menunjukkan bahwa saat kita memangkas suku dari observable, error akumulasi keseluruhan kita naik secara monoton. Grafik ini juga mengonfirmasi bahwa tidak ada suku yang dipangkas sampai slice ketiga selesai di-backpropagate.
-
Plot kanan bawah menunjukkan bahwa jumlah grup Pauli yang commute di observable kita sudah tumbuh sampai batas yang ditentukan, yaitu
10. Plot ini juga menunjukkan bagaimana backpropagation satu layer lagi akan membuat observable kita melewati batas yang ditentukan, seperti terlihat dari persilangan garis hitam dan merah.
Perhatikan bahwa di semua plot ini, sumbu x menghitung slice yang di-backpropagate, tapi karena OBP bekerja dari ujung circuit, slice 1 adalah slice paling akhir, slice 2 adalah slice sebelumnya, dan seterusnya.
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)])

Tentukan budget slice secara eksplisit
Kalau kamu tahu cara menetapkan budget ke tiap slice sehingga performa backpropagation optimal, kamu mungkin ingin menetapkan budget secara eksplisit untuk tiap slice. Sebagai demonstrasi, kita akan memberi tiga slice pertama budget nol dan memakai budget .001 per slice untuk slice sisanya.
# 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.
Menghilangkan budget dari tiga layer pertama membuat tidak ada suku yang dipangkas sampai setelah layer keempat, seperti yang bisa dikonfirmasi di tiga plot ini. Yang mungkin agak mengejutkan adalah, meski slice keempat tidak mendapat sisa budget, ada suku yang tetap dipangkas dengan memakai budget .001 yang dialokasikan. Ini jelas terlihat dari plot kiri atas, tapi juga bisa dilihat di plot kanan atas, karena kurva sisa budget mendatar antara slice tiga dan empat. Detail penting lainnya adalah bahwa mulai dari titik ini setidaknya satu suku dipangkas, sama seperti pada contoh sebelumnya.
Poin utamanya: meski kita menanggung error pemangkasan yang lebih kecil di contoh kedua karena budget beberapa slice dinolkan, kita tetap bisa melakukan backpropagation pada jumlah slice yang sama, dan observable kita berisi jumlah grup Pauli commuting yang sama. Kita bisa mengonfirmasi bahwa batas error kita lebih kecil di contoh kedua dengan memeriksa plot kiri bawah.
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)])

Tentukan budget secara siklik
Kalau kamu punya circuit dengan pola yang berulang, seperti circuit Trotter, kamu mungkin ingin menentukan budget untuk subset slice yang berulang itu dan memakai budget tersebut untuk semua pengulangan slice berikutnya.
Lebih konkretnya, contoh circuit yang kita pakai punya enam slice yang diulang tiga kali, totalnya 18 slice. Kita akan menetapkan budget nol secara sembarang untuk layer satu-qubit dan RYY, dan budget .003 untuk tiap layer RXX. Kita akan melihat bagaimana menentukan budget sebagai urutan sepanjang 6 membuat budget diterapkan ke semua 18 slice secara siklik.
Sekali lagi, perhatikan bahwa slice di-backpropagate dalam urutan terbalik (yaitu, mulai dari akhir). Jadi, entri pertama di budget siklik kita sebenarnya dipakai untuk slice terakhir, entri kedua untuk slice sebelumnya, dan seterusnya.
# 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.
Seperti terlihat di gambar kiri atas dan kiri bawah, tidak ada pemangkasan pada empat slice pertama karena slice tersebut tidak dialokasikan error budget. Slice lima dan enam punya beberapa suku yang dipangkas begitu budget tersedia.
Seperti terlihat di gambar kiri atas, error yang muncul cukup besar setelah backpropagation slice tujuh, padahal slice itu tidak dialokasikan budget. Ini karena hanya sekitar .002 dari total budget .006 yang dialokasikan ke slice lima dan enam yang terpakai, sehingga sisanya diteruskan ke slice tujuh dan hampir habis terpakai, seperti terlihat di gambar kanan atas.
Gambar kiri atas dan kanan atas menunjukkan bahwa sedikit sisa budget habis terpakai di antara slice 8-10, dan budget baru tersedia di slice 11, seperti yang diharapkan. Gambar kiri atas, kanan atas, dan kiri bawah semuanya memperlihatkan perilaku siklik dari argumen max_error_per_slice saat panjangnya kurang dari jumlah slice. Perilaku siklik ini akan berlanjut sampai semua slice, tapi kriteria berhenti max_qwc_groups tercapai setelah backpropagation 13 slice, seperti terlihat di gambar kanan bawah.
Yang juga menarik, jumlah grup Pauli justru turun setelah putaran kedua budget tersedia di slice 11. Ini karena ada grup berkoefisien kecil yang tidak bisa dipangkas sampai ada lebih banyak budget setelah backpropagation slice 11, sehingga grup-grup itu menumpuk di observable selama beberapa iterasi. Kasus ini juga menyoroti bahwa max_qwc_groups harus dilampaui agar algoritma berhenti.
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)])

Batasi error total
Selain menentukan error budget per slice, kamu bisa menentukan jumlah maksimum error yang ditanggung dari pemangkasan. Begitu batas itu tercapai, tidak ada pemangkasan lagi; namun, backpropagation akan terus berlanjut sampai observable menjadi terlalu besar dan salah satu kriteria berhenti terpenuhi.
Selanjutnya kita menjalankan ulang eksperimen di atas, dengan menetapkan batas pada max_error_total sehingga error budget habis setelah backpropagation slice tujuh.
# 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.
Seperti yang diharapkan, error pemangkasan kita mentok di .006 (grafik kiri bawah). Yang patut dicatat, di run ini kita tidak bisa melakukan backpropagation slice 11. Ini karena kita tidak punya cukup budget untuk memangkas suku dan jumlah grup Pauli yang commute tumbuh melewati batas 20, seperti terlihat di gambar kanan bawah.
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)])

Mungkin kamu ingin membatasi budget keseluruhan dengan max_error_total saja tanpa menentukan 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)
Output dari cell di atas mungkin agak mengejutkan karena per_slice_budget diatur sama dengan max_error_total. Ini menandakan bahwa seluruh budget yang tersedia akan dihabiskan secara greedy.
Bayangkan begini: seluruh budget tersedia untuk setiap slice (karena kita melakukan loop atas per_slice_budget). Tapi budget apa pun yang sudah terpakai akan dikurangkan dari budget yang tersedia pada titik tertentu di algoritma.
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.
Gambar kanan atas menunjukkan bagaimana seluruh error budget .018 disediakan untuk slice pertama. Tidak ada pemangkasan sampai slice ketiga, sehingga sisa budget tetap konstan. Budget menurun secara monoton, karena budget penuh disediakan untuk setiap slice yang di-backpropagate sampai habis.
Yang patut dicatat, eksperimen ini menghasilkan dua slice yang di-backpropagate lebih sedikit dibanding eksperimen pertama di notebook ini, yang hampir identik. Ini menunjukkan bahwa untuk beberapa masalah, membagi budget secara merata mungkin optimal. Untuk masalah lain, membiarkan slice menghabiskan budget penuh secara greedy mungkin memberi performa lebih baik.
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)])

Batasi jumlah slice yang di-backpropagate dan error total sekaligus
Kalau kamu tidak ingin mendistribusikan error budget sampai ke seluruh circuit tapi juga tidak ingin menghabiskannya secara greedy, kamu bisa menentukan jumlah slice yang ingin kamu backpropagate (num_slices), bersama dengan error budget total (max_error_total). Ini akan mendistribusikan error budget secara merata (sesuai p_norm) ke seluruh slice input.
Di sini, kita akan membatasi jumlah slice yang mungkin kita backpropagate pada 12, dan kita akan mempertahankan error budget total yang sama.
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)
Sekarang kita akan mencoba melakukan backpropagation pada 12 slice yang sudah kita alokasikan budget-nya di langkah sebelumnya. Caranya, cukup memasukkan 12 slice terakhir di circuit kita. Dengan p_norm=1, masing-masing dari 12 slice punya budget tersedia sebesar 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,
)
Karena kita mengirim subset slice kita (di kode slices[-num_slices:]) ke backpropagate, kita harus menggabungkan slice yang tersisa setelah backpropagation dengan slice yang tidak pernah dikirim untuk backpropagation (di kode slices[:-num_slices]).
Setelah kita menggabungkan semua slice yang tersisa, kita bisa memakai combine_slices untuk menghasilkan QuantumCircuit dengan depth yang sudah dikurangi. Selanjutnya, kita periksa berapa banyak slice yang di-backpropagate dibandingkan seberapa besar observable kita jadinya.
# 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.
Plot-plot tersebut menunjukkan bahwa kita berhasil melakukan backpropagation pada seluruh 12 slice sambil menjaga observable kita tetap di bawah 10 grup Pauli yang saling komut. Kita juga bisa melihat bahwa penggunaan num_slices bersama max_error_total menghasilkan distribusi budget ke seluruh slice, dan budget yang tidak terpakai kembali diteruskan ke slice berikutnya. Hal ini paling jelas terlihat di plot kanan atas, karena budget dipakai sekaligus diisi ulang selama backpropagation.
Perlu dicatat bahwa cara mendistribusikan error ini menghasilkan hasil terbaik (lebih banyak slice yang berhasil di-backpropagate) dibandingkan eksperimen pertama di notebook ini dan contoh sebelumnya. Semua contoh ini mengalokasikan budget error .018, tetapi backpropagation memberikan hasil yang berbeda tergantung bagaimana budget tersebut didistribusikan.
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)])

Bekerja dengan beberapa observable
Method qiskit_addon_obp.backpropagate memungkinkan kita memasukkan sekuens observable. Ini menyederhanakan alur kerja saat berhadapan dengan beberapa observable target.
Kita menyebutkannya secara eksplisit di sini supaya kamu paham bagaimana strategi truncation menangani kasus seperti ini. Untuk keperluan contoh ini, kita menambahkan satu observable ekstra ke observable yang sudah kita pakai sejauh ini:
obs = [SparsePauliOp("IIIIIZIIII"), SparsePauliOp("IIIIIXIIII")]
Terakhir, kita mengulang eksperimen pertama dari tutorial ini, tetapi dengan dua observable sebagai tujuan backpropagation circuit.
Untuk contoh ini, hal tersebut tidak memengaruhi jumlah slice yang bisa di-backpropagate. Namun, kita bisa melihat bahwa kedua observable menghasilkan jumlah suku Pauli dan grup komutatif yang berbeda.
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.
Plot di bawah ini membantu mengilustrasikan bagaimana algoritma backpropagation menangani beberapa observable.
Pertama, plot di kiri atas, kanan atas, dan kiri bawah menunjukkan bahwa budget untuk memotong suku ditetapkan secara terpisah untuk setiap observable. Dengan kata lain, kedua observable bisa memotong suku dengan asumsi error sebesar 0.001 per slice yang di-backpropagate.
Karena sifat observable yang berbeda, konsumsi budgetnya pun berbeda. Dalam contoh ini, keduanya banyak tumpang tindih, padahal itu tidak selalu terjadi.
Plot di kanan bawah menggambarkan bahwa max_qwc_groups memperhitungkan semua observable. Artinya, suku-suku dari semua observable dikelompokkan bersama untuk mendapatkan satu angka akhir grup yang komut secara qubit-wise, yang kemudian dibandingkan dengan max_qwc_paulis. Hal yang sama dilakukan untuk threshold max_paulis (tidak dibahas di notebook ini), yang memungkinkan kamu menetapkan batas jumlah suku Pauli di semua observable.
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)])
