Pengundur-belakang pengoperasi (OBP) untuk penganggaran nilai jangkaan
Anggaran penggunaan: 4 minit pada pemproses Heron r3 (NOTA: Ini hanyalah anggaran. Masa larian anda mungkin berbeza.)
Hasil pembelajaran
Setelah melalui tutorial ini, pengguna seharusnya faham:
- Cara menggunakan
qiskit-addon-obpuntuk mengurangkan kedalaman Circuit kuantum dengan kos peningkatan bilangan pelaksanaan Circuit - Cara menggunakan
qiskit-addon-utilsuntuk membina Hamiltonian XYZ dan Circuit evolusi masanya
Prasyarat
Kami mencadangkan pengguna sudah biasa dengan topik berikut sebelum melalui tutorial ini:
- Menggunakan primitif Estimator untuk mengira nilai jangkaan sesuatu observable
Latar Belakang
Pengundur-belakang pengoperasi ialah teknik yang melibatkan penyerapan operasi dari hujung Circuit kuantum ke dalam observable yang diukur, yang secara amnya mengurangkan kedalaman Circuit dengan kos tambahan terma dalam observable. Matlamatnya ialah untuk mengundurkan sebanyak mungkin Circuit tanpa membiarkan observable membesar terlalu besar. Pelaksanaan berasaskan Qiskit tersedia dalam addon OBP Qiskit. Baca dokumentasi yang berkaitan untuk maklumat lanjut.
Pertimbangkan contoh Circuit di mana observable hendak diukur, di mana ialah Pauli dan ialah pekali. Mari kita tandakan Circuit tersebut sebagai satu kesatuan , yang boleh dibahagikan secara logik kepada seperti yang ditunjukkan dalam rajah di bawah.

Pengundur-belakang pengoperasi menyerap kesatuan ke dalam observable dengan mengevolusinya sebagai . Dengan kata lain, sebahagian pengiraan dilakukan secara klasik melalui evolusi observable daripada kepada . Masalah asal kini boleh diformulasi semula sebagai pengukuran observable untuk Circuit kedalaman rendah baru yang kesatuannya ialah .
Kesatuan diwakili sebagai beberapa hirisan . Terdapat pelbagai cara untuk mentakrifkan hirisan. Sebagai contoh, dalam Circuit contoh di atas, setiap lapisan dan setiap lapisan gate boleh dianggap sebagai hirisan individu. Pengundur-belakang melibatkan pengiraan secara klasik. Setiap hirisan boleh diwakili sebagai , di mana ialah Pauli -Qubit dan ialah skalar. Mudah untuk disahkan bahawa
Dalam contoh di atas, jika , maka kita perlu melaksanakan dua Circuit kuantum, dan bukannya satu, untuk mengira nilai jangkaan. Oleh itu, pengundur-belakang mungkin meningkatkan bilangan terma dalam observable, yang membawa kepada bilangan pelaksanaan Circuit yang lebih tinggi. Satu cara untuk membenarkan pengundur-belakang yang lebih dalam ke dalam Circuit, sambil mencegah pengoperasi daripada membesar terlalu besar, ialah dengan memangkas terma yang mempunyai pekali kecil, dan bukannya menambahkannya ke dalam pengoperasi. Sebagai contoh, dalam contoh di atas, seseorang mungkin memilih untuk memangkas terma yang melibatkan dengan syarat cukup kecil. Pemangkasan terma boleh menghasilkan lebih sedikit Circuit kuantum untuk dilaksanakan, tetapi melakukan demikian mengakibatkan sedikit ralat dalam pengiraan nilai jangkaan akhir yang berkadar dengan magnitud pekali terma yang dipangkas.
Keperluan
Sebelum memulakan tutorial ini, pastikan anda telah memasang perkara berikut:
- Qiskit SDK v2.0 atau lebih baru, dengan sokongan visualisasi
- Qiskit Runtime v0.22 atau lebih baru (
pip install qiskit-ibm-runtime) - OBP Qiskit addon 0.3 atau lebih baru (
pip install qiskit-addon-obp) - Qiskit addon utils 0.3 atau lebih baru (
pip install qiskit-addon-utils)
Persediaan
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-obp qiskit-addon-utils qiskit-ibm-runtime rustworkx
import numpy as np
import matplotlib.pyplot as plt
from qiskit.primitives import StatevectorEstimator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import CouplingMap
from qiskit.synthesis import LieTrotter
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit_addon_utils.slicing import slice_by_depth, combine_slices
from qiskit_addon_obp.utils.simplify import OperatorBudget
from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.truncating import setup_budget
from rustworkx.visualization import graphviz_draw
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2, EstimatorOptions
Contoh simulator skala kecil
Tutorial ini melaksanakan corak Qiskit untuk mensimulasi dinamik kuantum rantai spin Heisenberg menggunakan addon OBP Qiskit. Perlu diingat bahawa dalam simulator tanpa hingar, nilai jangkaan yang diperoleh dengan dan tanpa backpropagation adalah sama.
Langkah 1: Petakan input klasik kepada masalah kuantum
Petakan evolusi masa model kuantum Heisenberg kepada eksperimen kuantum
Pertama, kita akan menggunakan fungsi generate_xyz_hamiltonian daripada qiskit-addon-utils untuk menjana Hamiltonian seperti Heisenberg pada graf sambungan yang diberikan. Graf ini boleh berupa sama ada rustworkx.PyGraph atau CouplingMap. Berikut, kita akan menggunakan CouplingMap rantai linear 10 qubit.
num_qubits = 10
layout = [(i - 1, i) for i in range(1, num_qubits)]
# Instantiate a CouplingMap object
coupling_map = CouplingMap(layout)
graphviz_draw(coupling_map.graph, method="circo")
Seterusnya, kita menjana pengoperasi Pauli yang memodelkan Hamiltonian Heisenberg XYZ:
di mana ialah graf peta gandingan. Untuk tutorial ini, kami menggunakan masing-masing sebagai , dan masing-masing sebagai .
# Get a qubit operator describing the Heisenberg XYZ model
hamiltonian = generate_xyz_hamiltonian(
coupling_map,
coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),
ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),
)
print(hamiltonian)
SparsePauliOp(['IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIIIX', 'IIIIIIIIIY', 'IIIIIIIIIZ', 'IIIIIIIIXI', 'IIIIIIIIYI', 'IIIIIIIIZI', 'IIIIIIIXII', 'IIIIIIIYII', 'IIIIIIIZII', 'IIIIIIXIII', 'IIIIIIYIII', 'IIIIIIZIII', 'IIIIIXIIII', 'IIIIIYIIII', 'IIIIIZIIII', 'IIIIXIIIII', 'IIIIYIIIII', 'IIIIZIIIII', 'IIIXIIIIII', 'IIIYIIIIII', 'IIIZIIIIII', 'IIXIIIIIII', 'IIYIIIIIII', 'IIZIIIIIII', 'IXIIIIIIII', 'IYIIIIIIII', 'IZIIIIIIII', 'XIIIIIIIII', 'YIIIIIIIII', 'ZIIIIIIIII'],
coeffs=[0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j,
0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j,
1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j,
0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j,
0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j,
1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j,
0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j,
1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j,
1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j])
Daripada pengoperasi qubit, kita boleh menjana Circuit kuantum yang memodelkan evolusi masanya. Kami menggunakan generate_time_evolution_circuit dengan penguraian Lie Trotter untuk membina Circuit evolusi masa.
circuit = generate_time_evolution_circuit(
hamiltonian,
time=0.2,
synthesis=LieTrotter(reps=2),
)
circuit.draw("mpl", style="iqp", fold=-1)

Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantum
Cipta hirisan Circuit untuk pengundur-belakang
Fungsi backpropagate mengundurkan keseluruhan hirisan Circuit pada satu masa. Oleh itu, pilihan penghirisan boleh memberi impak terhadap prestasi pengundur-belakang untuk masalah tertentu. Di sini, kita akan mengumpulkan gate yang sama jenis ke dalam hirisan menggunakan fungsi slice_by_depth.
Untuk perbincangan yang lebih terperinci tentang penghirisan Circuit, semak panduan cara-cara ini daripada pakej qiskit-addon-utils.
slices = slice_by_depth(circuit, max_slice_depth=1)
print(f"Separated the circuit into {len(slices)} slices.")
Separated the circuit into 18 slices.
Hadkan saiz maksimum pengoperasi semasa pengundur-belakang
Semasa pengundur-belakang, bilangan terma dalam pengoperasi umumnya akan mendekati dengan cepat, di mana ialah bilangan hirisan. Apabila dua terma dalam pengoperasi tidak bertukar-ganti secara qubit-wise, kita memerlukan Circuit berasingan untuk mendapatkan nilai jangkaan yang sepadan dengannya. Sebagai contoh, jika kita mempunyai observable dua-Qubit , maka oleh kerana , pengukuran dalam satu asas sudah cukup untuk mengira nilai jangkaan bagi dua terma ini. Namun, anti-bertukar-ganti dengan dua terma lain, jadi kita memerlukan pengukuran asas yang berasingan untuk mengira nilai jangkaan . Dengan kata lain, kita memerlukan dua Circuit dan bukannya satu untuk mengira . Apabila bilangan terma dalam pengoperasi bertambah, terdapat kemungkinan bilangan pelaksanaan Circuit yang diperlukan juga bertambah.
Saiz pengoperasi boleh dibatasi dengan menentukan argumen kata kunci operator_budget bagi fungsi backpropagate, yang menerima instans OperatorBudget.
Untuk mengawal jumlah sumber tambahan (bilangan pelaksanaan Circuit, dan seterusnya masa QPU yang diperlukan) yang diperuntukkan, kita hadkan bilangan maksimum kumpulan Pauli bertukar-ganti secara qubit-wise yang dibenarkan untuk dimiliki oleh observable yang telah diundurkan. Di sini kita tentukan bahawa pengundur-belakang harus berhenti apabila bilangan kumpulan Pauli bertukar-ganti secara qubit-wise dalam pengoperasi melebihi lapan.
op_budget = OperatorBudget(max_qwc_groups=8)
Undurkan hirisan dari Circuit
Pertama kita tentukan observable sebagai , dengan ialah bilangan qubit. Kita akan mengundurkan hirisan dari Circuit evolusi masa sehingga terma dalam observable tidak lagi boleh digabungkan ke dalam lapan atau lebih sedikit kumpulan Pauli bertukar-ganti secara qubit-wise.
observable = SparsePauliOp.from_sparse_list(
[("Z", [i], 1 / num_qubits) for i in range(num_qubits)],
num_qubits=num_qubits,
)
observable
SparsePauliOp(['IIIIIIIIIZ', 'IIIIIIIIZI', 'IIIIIIIZII', 'IIIIIIZIII', 'IIIIIZIIII', 'IIIIZIIIII', 'IIIZIIIIII', 'IIZIIIIIII', 'IZIIIIIIII', 'ZIIIIIIIII'],
coeffs=[0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j,
0.1+0.j, 0.1+0.j])
Di bawah anda akan melihat bahawa kita telah mengundurkan enam hirisan, dan terma-terma digabungkan ke dalam enam dan bukan lapan kumpulan. Ini menunjukkan bahawa mengundurkan satu lagi hirisan akan menyebabkan bilangan kumpulan Pauli melebihi lapan. Kita boleh mengesahkan bahawa ini memang benar dengan memeriksa metadata yang dikembalikan. Juga perhatikan bahawa dalam bahagian ini transformasi Circuit adalah tepat. Iaitu, tiada terma observable baru yang dipangkas. Circuit yang telah diundurkan dan pengoperasi yang telah diundurkan memberikan hasil yang sama persis dengan Circuit asal dan pengoperasi asal.
# Backpropagate slices onto the observable
bp_obs, remaining_slices, metadata = backpropagate(
observable, slices, operator_budget=op_budget
)
# Recombine the slices remaining after backpropagation
bp_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {metadata.num_backpropagated_slices} slices.")
print(
f"New observable has {len(bp_obs.paulis)} terms, which can be combined into "
f"{len(bp_obs.group_commuting(qubit_wise=True))} groups."
)
print(
f"Note that backpropagating one more slice would result in "
f"{metadata.backpropagation_history[-1].num_paulis[0]} terms "
f"across {metadata.backpropagation_history[-1].num_qwc_groups} groups."
)
print("The remaining circuit after backpropagation looks as follows:")
bp_circuit.draw("mpl", fold=-1, scale=0.6)
Backpropagated 6 slices.
New observable has 60 terms, which can be combined into 6 groups.
Note that backpropagating one more slice would result in 114 terms across 12 groups.
The remaining circuit after backpropagation looks as follows:
Untuk contoh skala kecil pada simulator, kita tidak akan menggunakan pemangkasan. Ini kerana tanpa hingar, Circuit dengan dan tanpa backpropagation memberikan hasil yang sama, dan pemangkasan memburukkan hasil akibat penambahan penghampiran.
Transpile litar ke set gate asas
Kini kita mentranspile litar asal dan litar backpropagasi ke gate asas backend. Kita tidak perlu mentranspile pada backend sebenar kerana kita akan menjalankan pada simulator untuk contoh skala kecil ini.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=133
)
print(backend)
<IBMBackend('ibm_kingston')>
pm_basis = generate_preset_pass_manager(
optimization_level=3, basis_gates=backend.configuration().basis_gates
)
isa_circuit = pm_basis.run(circuit)
isa_bp_circuit = pm_basis.run(bp_circuit)
Langkah 3: Laksanakan menggunakan primitif Qiskit
Pertama, kita cipta dua Primitive Unified Blocs (PUB) yang sepadan dengan litar asal dan litar backpropagasi. Kemudian kita laksanakan pub tersebut pada Estimator ideal untuk mendapatkan nilai jangkaan.
pubs = [(isa_circuit, observable), (isa_bp_circuit, bp_obs)]
rng = np.random.default_rng()
estimator = StatevectorEstimator(seed=rng)
job = estimator.run(pubs)
Langkah 4: Proses pasca dan kembalikan hasil ke format klasik yang dikehendaki
Kini kita dapatkan nilai jangkaan bagi litar asal dan litar backpropagasi.
primitive_result = job.result()
circuit_expval = primitive_result[0].data.evs.item()
bp_circuit_expval = primitive_result[1].data.evs.item()
methods = [
"No backpropagation",
"Backpropagation",
]
values = [circuit_expval, bp_circuit_expval]
ax = plt.gca()
plt.bar(methods, values, color="#a56eff", width=0.4, edgecolor="#8a3ffc")
ax.set_ylim([0.6, 0.92])
ax.set_ylabel(r"$M_Z$", fontsize=12)
Text(0, 0.5, '$M_Z$')
Seperti yang dijangkakan, kedua-dua nilai jangkaan bersetuju. Kerana kita menjalankan pada simulator statevector tanpa hingar, backpropagation ialah transformasi tepat bagi pasangan litar-observable, jadi aliran kerja asal dan backpropagasi mesti menghasilkan nilai yang sama. Faedah backpropagation hanya menjadi ketara pada perkakasan berlingar, di mana litar backpropagasi yang lebih pendek mengumpul lebih sedikit ralat, seperti yang diilustrasikan dalam contoh perkakasan berskala besar di bawah.
Contoh perkakasan berskala besar
Semasa membangunkan eksperimen, berguna untuk bermula dengan litar kecil bagi memudahkan visualisasi dan simulasi. Kini kita melihat pengundur-belakang pengoperasi untuk Hamiltonian Heisenberg 50-Qubit dengan set nilai yang sama untuk parameter dan serta observable yang sama, tetapi dengan empat langkah Trotter. Nilai jangkaan ideal pada skala ini tidak dapat dikira menggunakan kaedah brute force, jadi kita menggunakan rangkaian tensor dan mendapatkan nilai jangkaan ideal sebagai .
Bersama-sama dengan backpropagation, dalam contoh berskala besar ini, kita juga memperkenalkan backpropagation dengan pemangkasan. Ideanya ialah kita mahu mengundurkan sebanyak mungkin untuk mengurangkan kedalaman litar berkesan. Namun, ini sering membawa kepada bilangan terma tidak-bertukar-ganti yang besar dalam observable yang dikemas kini, meningkatkan kos kuantum. Oleh itu, kita boleh menghapuskan terma observable dengan pekali kecil menggunakan amalan yang dipanggil pemangkasan. Walaupun pemangkasan membolehkan lebih banyak pengundur-belakang dengan mengurangkan bilangan terma dalam observable yang dikemas kini, ia juga memperkenalkan sedikit penghampiran. Oleh itu, perlu membatasi pemangkasan dalam had tertentu supaya ralat penghampiran tidak mengatasi pengurangan hingar yang diperoleh daripada pengundur-belakang yang lebih dalam.
Untuk membatasi jumlah pemangkasan, kita memperuntukkan bajet ralat untuk setiap hirisan serta jumlah bajet ralat keseluruhan bagi keseluruhan litar backpropagasi menggunakan fungsi setup_budget. Ini memastikan pemangkasan terkawal untuk setiap hirisan mahupun keseluruhan litar. Lihat juga panduan ini untuk cara lain mengagihkan bajet.
num_qubits = 50
layout = [(i - 1, i) for i in range(1, num_qubits)]
# Instantiate a CouplingMap object
coupling_map = CouplingMap(layout)
hamiltonian = generate_xyz_hamiltonian(
coupling_map,
coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),
ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),
)
# Generate a time evolution circuit for the Hamiltonian
circuit = generate_time_evolution_circuit(
hamiltonian,
time=0.2,
synthesis=LieTrotter(reps=4),
)
# Define the observable to measure
observable = SparsePauliOp.from_sparse_list(
[("Z", [i], 1 / num_qubits) for i in range(num_qubits)],
num_qubits,
)
slices = slice_by_depth(circuit, max_slice_depth=1)
# Define the maximum number of qwc groups allowed in the
# backpropagated observable,
# and the truncation error budget
op_budget = OperatorBudget(max_qwc_groups=15)
truncation_error_budget = setup_budget(
max_error_total=0.03, max_error_per_slice=0.005
)
# First backpropagation without truncation
bp_obs, remaining_slices, metadata = backpropagate(
observable, slices, operator_budget=op_budget
)
bp_circuit = combine_slices(remaining_slices)
# Now backpropagate with truncation, using the same operator budget and
# the defined truncation error budget
bp_obs_trunc, remaining_slices_trunc, metadata = backpropagate(
observable,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
bp_circuit_trunc = combine_slices(
remaining_slices_trunc, include_barriers=False
)
# Now we transpile the original circuit and the two backpropagated circuits,
# and apply the layout to the corresponding observables
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
isa_circuit = pm.run(circuit)
isa_bp_circuit = pm.run(bp_circuit)
isa_bp_circuit_trunc = pm.run(bp_circuit_trunc)
isa_observable = observable.apply_layout(isa_circuit.layout)
isa_bp_observable = bp_obs.apply_layout(isa_bp_circuit.layout)
isa_bp_observable_trunc = bp_obs_trunc.apply_layout(
isa_bp_circuit_trunc.layout
)
# Compare the 2-qubit depth of each transpiled circuit to see how much
# depth backpropagation saved
print(
f"2-qubit depth without backpropagation: "
f"{isa_circuit.depth(lambda x: x.operation.num_qubits == 2)}"
)
print(
f"2-qubit depth with backpropagation: "
f"{isa_bp_circuit.depth(lambda x: x.operation.num_qubits == 2)}"
)
print(
f"2-qubit depth with backpropagation and truncation: "
f"{isa_bp_circuit_trunc.depth(lambda x: x.operation.num_qubits == 2)}"
)
pubs = [
(isa_circuit, isa_observable),
(isa_bp_circuit, isa_bp_observable),
(isa_bp_circuit_trunc, isa_bp_observable_trunc),
]
# Now we instantiate the Estimator primitive for the hardware with
# ZNE and measurement error
# mitigation and compute the three circuits and observables
options = EstimatorOptions()
options.default_precision = 0.01
options.resilience_level = 2
options.resilience.zne.noise_factors = [1, 1.2, 1.4]
options.resilience.zne.extrapolator = ["linear"]
estimator = EstimatorV2(mode=backend, options=options)
estimator.options.environment.job_tags = ["TUT_OBP"]
job = estimator.run(pubs)
# Retrieve the results and the standard deviations
result_no_bp = job.result()[0].data.evs.item()
result_bp = job.result()[1].data.evs.item()
result_bp_trunc = job.result()[2].data.evs.item()
std_no_bp = job.result()[0].data.stds.item()
std_bp = job.result()[1].data.stds.item()
std_bp_trunc = job.result()[2].data.stds.item()
2-qubit depth without backpropagation: 24
2-qubit depth with backpropagation: 20
2-qubit depth with backpropagation and truncation: 18
print(f"Expectation value without backpropagation: {result_no_bp}")
print(f"Backpropagated expectation value: {result_bp}")
print(f"Backpropagated expectation value with truncation: {result_bp_trunc}")
Expectation value without backpropagation: 0.9543907942381811
Backpropagated expectation value: 0.9445337385406468
Backpropagated expectation value with truncation: 0.934050286970965
# Plot the results
methods = [
"No backpropagation",
"Backpropagation",
"Backpropagation w/ truncation",
]
values = [result_no_bp, result_bp, result_bp_trunc]
error_bars = [std_no_bp, std_bp, std_bp_trunc]
ax = plt.gca()
plt.bar(methods, values, color="#a56eff", width=0.4, edgecolor="#8a3ffc")
plt.errorbar(methods, values, yerr=error_bars, fmt="o", color="r", capsize=5)
plt.axhline(0.89)
ax.set_ylim([0.8, 0.98])
plt.text(0.25, 0.895, "Exact result")
ax.set_ylabel(r"$M_Z$", fontsize=12)
Text(0, 0.5, '$M_Z$')
Langkah seterusnya
Jika anda mendapati kerja ini menarik, anda mungkin berminat dengan bahan berikut:
- Pengkompilan kuantum hampiran untuk Circuit evolusi masa
- Formula berbilang produk untuk mengurangkan ralat Trotter
pauli-prop, pakej berakselerasi Rust untuk perambatan Pauli, dengan tutorial yang merangkumi OBP, anggaran nilai jangkaan klasik, dan simulasi berlingar