Probabilistic error cancellation dengan shaded lightcones
Perkiraan penggunaan: 10 menit pada prosesor Heron (CATATAN: Ini hanyalah perkiraan. Runtime kamu mungkin berbeda.)
Hasil pembelajaran
-
Apa itu probabilistic error cancellation (PEC), dan mengapa overhead samplingnya tumbuh secara eksponensial seiring total noise yang bekerja pada circuit
-
Bagaimana shaded lightcones (SLC) membatasi kontribusi setiap suku noise terhadap observable target, sehingga kamu dapat menghabiskan anggaran mitigasi di tempat yang penting — dan bagaimana, di luar pengurangan overhead zero-bias yang sudah disediakan oleh lightcone yang murni geometris, shading memungkinkan kamu menukar bias residual yang terbatas dengan overhead sampling yang bahkan lebih rendah
-
Cara mempelajari layer noise dengan
NoiseLearnerV3dan menyuntikkan anti-noise melaluisamplomaticdan primitiveExecutor -
Cara menggabungkan PEC dan PEC+SLC dengan TREX dan postselection untuk mengestimasi nilai ekspektasi pada hardware
Prasyarat
-
Alur kerja Qiskit patterns
-
Menggunakan primitive Estimator untuk menghitung nilai ekspektasi dari sebuah observable
-
Teknik mitigasi error seperti Pauli twirling dan TREX, dibahas dalam Combine error mitigation options with the Estimator primitive
Latar belakang
Tutorial ini mendemonstrasikan cara memitigasi error menggunakan addon shaded lightcone (SLC). Addon ini merupakan pengembangan dari teknik probabilistic error cancellation (PEC), di mana pengguna mempelajari noise dari layer-layer unik dalam sebuah sirkuit lalu membatalkan noise tersebut dengan menerapkan gate satu-qubit dan teknik post-processing. Dibandingkan metode lain, PEC menawarkan batas yang lebih robust pada bias hasil yang dimitigasi, tetapi cenderung memiliki overhead lebih tinggi dari segi waktu QPU. Selama PEC, untuk mengompensasi atenuasi nilai ekspektasi oleh noise, hasil rata-rata diskalakan ulang dengan faktor , dengan adalah laju noise yang dipelajari dari error Pauli pada layer dalam sirkuit. Penskalaan ulang ini meningkatkan varian dengan faktor , dan dengan demikian juga mengalikan jumlah eksekusi sirkuit yang dibutuhkan pada QPU dengan , yang kita sebut biaya sampling atau overhead sampling. Karena tumbuh secara eksponensial, PEC sering kali terbatas pada sirkuit yang dangkal atau memiliki sedikit qubit. Pelajari lebih lanjut tentang PEC di Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors.
Jika kita bisa mengidentifikasi error yang tidak perlu dimitigasi, kita bisa menurunkan biaya sampling ini secara eksponensial. Langkah pertama ke arah ini adalah menerapkan mitigasi error yang sadar-lokal (locally-aware), yang menggunakan "lightcone" konvensional yang cepat dihitung untuk mengurangi overhead PEC dengan membatasi sensitivitas sebuah observable terhadap error di seluruh sirkuit, memperluas kelayakan PEC ke skala yang lebih besar untuk beberapa masalah. Error di luar lightcone ini tidak dapat memengaruhi hasil pengukuran dan karenanya dapat dikecualikan dari prosedur pembatalan error. Pengecualian ini menurunkan overhead sampling, dalam beberapa kasus secara substansial, tanpa memperkenalkan bias tambahan. Secara khusus, untuk mengukur observable lokal dari sebuah sirkuit dengan depth tetap, overhead sampling yang diperlukan akhirnya mendatar (plateau) ketika jumlah qubit dalam sirkuit ditingkatkan (lihat Fig. 2b dalam Locality and error mitigation of quantum circuits).
Shaded lightcones (SLC) melangkah lebih jauh, menggunakan simulasi klasik untuk membatasi sensitivitas terhadap error di seluruh sirkuit dengan lebih ketat. Ini menukar sebagian waktu QPU dengan waktu CPU dan mengurangi overhead sampling yang dibutuhkan untuk menormalisasi ulang bias. Alih-alih pemotongan tegas, setiap potensi error dalam sirkuit diberi "shade" bertingkat yang membatasi dari atas kerentanan nilai ekspektasi observable terhadap error tersebut. (Untuk batas backward-propagated yang diperkenalkan di bawah ini, kerentanan ini juga bergantung pada keadaan awal sirkuit — keadaan all-zero dalam alur kerja tipikal, dan dalam tutorial ini.) Karakterisasi yang lebih halus ini memungkinkan penerapan PEC yang lebih efisien dan tertarget dengan varian yang berkurang, sambil memberikan pengguna kemampuan untuk mengatur bias dalam estimasi observable secara terkendali. Lihat Lightcone shading for classically accelerated quantum error mitigation untuk detail lebih lanjut.
Alur kerja kita untuk addon SLC memanfaatkan library samplomatic bersama dengan kelas QuantumProgram dan Executor yang ditambahkan ke Qiskit Runtime dalam qiskit-ibm-runtime v0.47.0, memungkinkan pengguna memiliki kontrol yang lebih modular atas pengaturan eksekusi untuk penekanan dan mitigasi error sambil tetap mempertahankan kemudahan penggunaan. Baca selengkapnya di panduan directed execution model.
Sekilas alur kerja mitigasi error SLC
Untuk memodelkan noise QPU, kita menggunakan model noise Pauli-Lindblad sparse dengan laju error Pauli satu dan dua-qubit, dihasilkan secara lokal pada setiap qubit dan edge perangkat. Dengan pilihan ini, alur kerja mitigasi error SLC yang disajikan dalam tutorial ini adalah sebagai berikut:
a. CPU — Membatasi dampak per-error dari error Pauli satu dan dua-qubit
-
Forward propagation (membatasi efek pada observable). Merambatkan setiap error hingga akhir sirkuit dan menghitung komutatornya dengan observable.
-
Memotong (truncate) suku operator selama evolusi untuk menjaga komputasi tetap tractable.
-
Memperketat lebih lanjut batas-batas ini melalui back-propagation longgar dari observable berdasarkan batas kecepatan kuantum (quantum speed limits).
-
-
Backward propagation (membatasi efek pada keadaan awal). Merambatkan setiap error hingga awal sirkuit dan menghitung komutatornya dengan keadaan awal.
b. QPU — Mempelajari laju noise. Menggunakan NoiseLearnerV3 untuk mengestimasi laju model noise Pauli-Lindblad.
c. CPU — Memprioritaskan mitigasi
-
Memperbarui batas gabungan dengan laju noise yang dipelajari. Menggabungkan batas forward dan backward yang telah dihitung sebelumnya dan memperbaruinya dengan laju noise yang dipelajari.
-
Merangking komponen noise untuk dimitigasi menggunakan batas yang dihitung dan laju yang dipelajari. Memprioritaskan setiap kemungkinan error noise berdasarkan estimasi dampaknya terhadap bias dan biaya terkait untuk mengoreksinya.
d. QPU — Menyisipkan anti-noise dan menjalankan. Menjalankan sirkuit yang diminati dengan anti-noise (noise invers) yang ditentukan menggunakan anotasi Box.
e. CPU — Mengestimasi observable. Menghitung nilai ekspektasi, menerapkan post-selection berbasis pengukuran untuk mengurangi dampak noise non-Markovian.
Ikhtisar noise learning
Noise learning merupakan langkah umum dalam beberapa metode mitigasi error, dilakukan oleh noise learner; ini juga muncul dalam tutorial probabilistic error amplification. Dalam NoiseLearnerV3, kamu bisa secara spesifik mengidentifikasi layer noise yang akan dipelajari sebagai objek CircuitInstruction, sehingga kamu bisa menghitung batas noise SLC yang diinginkan untuk setiap layer dengan cara yang dijelaskan di atas. Model Pauli-Lindblad yang dipelajari menyediakan koefisien yang akan digunakan dalam prioritisasi PEC+SLC. Cara gate-gate dikumpulkan ke dalam layer dapat ditentukan menggunakan fungsi kemudahan generate_boxing_pass_manager dan find_unique_box_instructions, lalu dimasukkan ke fungsi utilitas SLC generate_noise_model_paulis, sebagaimana dijelaskan pada Langkah 2 di bawah ini.
| Part 1 | Part 2 | Part 3 |
|---|---|---|
| Pauli-twirl layer gate dua-qubit | Ulangi pasangan layer identitas dan pelajari noise | Turunkan sebuah fidelity (error untuk setiap kanal noise) |
![]() | ![]() |
Ikhtisar post-processing
Setelah dieksekusi pada hardware kuantum menggunakan framework samplomatic dan Executor, kita mengonversi pengukuran bitstring kita menjadi nilai observable yang diinginkan. Dalam tutorial ini, kita mendemonstrasikan alur kerja pada sirkuit Ising yang dicerminkan (dibangun pada Langkah 1 di bawah), di mana nilai ekspektasi ideal dari observable yang diukur adalah 1 karena separuh kedua sirkuit membatalkan separuh pertama. Ketika menghitung nilai observable dengan fungsi executor_expectation_values, kita menerapkan beberapa teknik post-processing yang mengurangi dampak noise. Teknik ini meliputi menghapus shot yang terpengaruh noise non-Markovian, mitigasi error readout, dan memperhitungkan detail implementasi PEC kita. Detailnya dibahas pada Langkah 4 di bawah ini.
Persyaratan
Sebelum memulai tutorial ini, pastikan kamu telah menginstal hal-hal berikut:
-
Qiskit SDK v2.2 atau versi lebih baru, dengan dukungan visualization
-
Qiskit Runtime v0.47 atau versi lebih baru (
pip install qiskit-ibm-runtime) -
Shaded lightcones Qiskit addon v0.1 atau versi lebih baru (
pip install qiskit-addon-slc) -
Qiskit addon utils v0.3 atau versi lebih baru (
pip install qiskit-addon-utils) -
Samplomatic v0.13 atau versi lebih baru (
pip install samplomatic)
Pengaturan
Pertama, impor paket dan fungsi yang dibutuhkan untuk menjalankan notebook ini.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-slc qiskit-addon-utils qiskit-ibm-runtime samplomatic
from multiprocessing import set_start_method
# Setting this value prevents itertools.starmap deadlock on UNIX systems
set_start_method("spawn")
# Needed to prevent PySCF from parallelizing internally (SLC only)
%set_env OMP_NUM_THREADS=1
env: OMP_NUM_THREADS=1
import numpy as np
from matplotlib import pyplot as plt
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager, PassManager
from qiskit_ibm_runtime import (
QiskitRuntimeService,
QuantumProgram,
Executor,
NoiseLearnerV3,
)
import samplomatic
from samplomatic.utils import find_unique_box_instructions
from samplomatic.transpiler import generate_boxing_pass_manager
from qiskit_addon_utils.exp_vals.measurement_bases import (
get_measurement_bases,
)
from qiskit_addon_utils.exp_vals.expectation_values import (
executor_expectation_values,
)
from qiskit_addon_utils.noise_management import (
gamma_from_noisy_boxes,
trex_factors,
)
from qiskit_addon_utils.noise_management.post_selection import PostSelector
from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (
AddPostSelectionMeasures,
AddSpectatorMeasures,
)
from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
compute_local_scales,
merge_bounds,
tighten_with_speed_limit,
)
from qiskit_addon_slc.utils import (
generate_noise_model_paulis,
map_modifier_ref_to_ref,
)
from qiskit_addon_slc.visualization import draw_shaded_lightcone
Contoh simulator skala kecil
Seperti metode mitigasi error berbasis pembelajaran lainnya, PEC dengan shaded lightcones memitigasi noise fisik dari prosesor kuantum tertentu, sehingga bergantung pada layanan hardware yang tidak memiliki analog yang bermakna pada simulator ideal:
-
NoiseLearnerV3mengkarakterisasi secara eksperimental kanal noise Pauli-Lindblad sparse pada setiap layer dua-qubit yang unik. Pada simulator bebas-noise, tidak ada noise yang perlu dibatalkan. -
Primitive
Executormelakukan sampling terhadap sirkuit yang telah di-twirl dan disuntik anti-noise yang dihasilkan olehsamplomaticpada sebuah backend.
Komputasi batas shaded-lightcone bersifat klasik, tetapi hanya bermakna relatif terhadap laju noise hardware yang dipelajari, yang menentukan anggaran mitigasi dan overhead sampling. Karena alasan-alasan ini, kita melewati contoh simulator skala kecil dan mendemonstrasikan alur kerja PEC+SLC lengkap langsung pada hardware, dengan setiap langkah pola Qiskit dijabarkan di bawah ini.
Contoh hardware skala besar
Kita menjalankan alur kerja PEC+SLC lengkap pada sirkuit Ising 20-qubit yang dicerminkan, dieksekusi pada hardware IBM Quantum®, mengikuti empat langkah pola Qiskit.
Langkah 1: Memetakan masalah
Demonstrasi kita disiapkan sebagai berikut:
-
Kita memilih untuk melakukan evolusi waktu di bawah Hamiltonian rantai Ising 1D. Rantai Ising 1D memberikan struktur sirkuit yang cukup padat, yang cocok untuk memamerkan implementasi PEC.
-
Kita memilih untuk mengukur observable , yang berisi satu komponen dan satu komponen . Ini cocok untuk menyoroti bagaimana batas SLC memperlakukan berbagai jenis error secara berbeda.
-
Kita ingin nilai ekspektasi ideal dari observable ini persis 1, sehingga kualitas estimasi yang dimitigasi mudah dinilai. Mencerminkan sirkuit membawa kita hampir sepenuhnya ke sana: untuk setiap gate pada separuh kedua sirkuit terdapat gate invers pada separuh pertama, sehingga sirkuit ideal bertindak sebagai identitas.
-
Terakhir, memperoleh nilai ekspektasi ideal sebesar 1 mengharuskan sirkuit dimulai — dan karenanya, berkat pencerminan, idealnya juga berakhir — dalam eigenstate +1 dari observable. Karena observable ini mengandung komponen non-, dan primitive
Executormemperhitungkan basis pengukuran yang diinginkan di akhir sirkuit, kita menambahkan gate persiapan basis yang sesuai di awal sirkuit cermin dengan fungsiprepare_basis. Kita menggunakan fungsiget_measurement_basesuntuk mengidentifikasi gate mana yang dibutuhkan dan di mana menempatkannya, sambil memperhatikan kerumitan indeks qubit yang muncul dari konvensi anotasibox, sebagaimana dibahas di bagian tentang menyiapkan pengukuran basis kanonik.
# Width of the Ising chain (a free parameter of this demonstration)
num_qubits = 20
# The observable to measure: one X component (on qubit 6) and one Z component
# (on qubit 13), as motivated in "Step 1: Map the problem" above
target_obs_sparse = [("XZ", [6, 13], 1.0)]
observable = SparsePauliOp.from_sparse_list(
target_obs_sparse, num_qubits=num_qubits
)
# Determine the measurement basis each qubit requires for this observable.
# The reverser is used during post-processing in Step 4.
bases_virt, reverser_virt = get_measurement_bases(observable)
# Free parameters of the demonstration circuit: the number of Trotter steps
# sets the circuit depth, and rx_angle is the transverse-field rotation angle
# applied in each step (pi/4 makes the dynamics non-Clifford)
num_trotter_steps = 10
rx_angle = np.pi / 4
def construct_ising_circuit(
num_qubits: int,
num_trotter_steps: int,
rx_angle: float,
) -> QuantumCircuit:
circuit = QuantumCircuit(num_qubits)
for _ in range(num_trotter_steps):
circuit.rx(rx_angle, range(num_qubits))
for first_qubit in (1, 2):
for idx in range(first_qubit, num_qubits, 2):
# equivalent to Rzz(-pi/2):
circuit.sdg([idx - 1, idx])
circuit.cz(idx - 1, idx)
return circuit
def prepare_basis(
circuit: QuantumCircuit, basis: list[int]
) -> QuantumCircuit:
# basis is a list of integer values from 0 to 3. These map to the basis measurement as:
# 0 = I; 1 = Z; 2 = X; 3 = Y
assert len(basis) == circuit.num_qubits
out_circ = circuit.copy_empty_like()
for qb, bas in enumerate(basis):
if bas == 2:
out_circ.h(qb)
elif bas == 3:
out_circ.rx(-np.pi / 2, qb)
out_circ.barrier()
out_circ.compose(circuit, inplace=True)
return out_circ
def mirror_circuit(circuit: QuantumCircuit) -> QuantumCircuit:
mirror_circ = circuit.copy_empty_like()
mirror_circ.compose(circuit.inverse(), inplace=True)
mirror_circ.barrier()
mirror_circ.compose(circuit, inplace=True)
mirror_circ.measure_active()
return mirror_circ
# Instantiate the mirrored circuit and prepend the basis-preparation gates
circuit = construct_ising_circuit(num_qubits, num_trotter_steps, rx_angle)
mirrored_circuit = mirror_circuit(circuit)
mirrored_circuit = prepare_basis(mirrored_circuit, bases_virt[0])
mirrored_circuit.draw(
"mpl", fold=-1, scale=0.3, idle_wires=False, measure_arrows=False
)

Langkah 2: Optimalkan
Kita mengoptimalkan detail yang terkait dengan sirkuit yang akan dijalankan, observable yang akan diukur, dan parameter noise-learning. Sebagai titik awal, kita memilih prosesor Heron yang paling tidak sibuk dan menginstansiasinya dengan fractional gates diaktifkan. Fractional gates ini memungkinkan sensitivitas yang lebih besar dalam beberapa filtering post-selection kita.
# Initialize IBM Quantum Compute Service using your saved credentials
service = QiskitRuntimeService()
# Select the least busy Heron device. This tutorial targets Heron processors:
# the usage estimate and the non-Markovian-noise post-selection discussed in
# Step 4 are specific to this processor family.
backend = service.least_busy(
operational=True,
simulator=False,
filters=lambda b: b.processor_type["family"] == "Heron",
)
# Re-fetch with fractional gates enabled (least_busy does not forward this)
# Fractional gates are enabled so the non-Clifford Rx rotations are supported natively.
backend = service.backend(backend.name, use_fractional_gates=True)
print(f"Selected backend: {backend.name}")
Selected backend: ibm_kingston
Pertama, kita akan mentranspilasi sirkuit kita menjadi instruksi ISA, sebagaimana diperlukan untuk eksekusi pada QPU kita. Pilihan qubit fisik untuk dijalankan memiliki dampak besar pada kualitas hasil, karena waktu koherensi dan fidelity gate bervariasi di seluruh perangkat dan berubah seiring waktu (drift). Untuk eksperimen yang cermat, memilih sendiri rantai qubit berdasarkan eksperimen benchmarking cepat bisa sangat bermanfaat (lihat, misalnya, tutorial Real-time benchmarking for qubit selection). Untuk tujuan tutorial ini, kita mengandalkan transpiler Qiskit untuk memilih layout berdasarkan coupling map backend dan data kalibrasi terbarunya.
isa_pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = isa_pm.run(mirrored_circuit)
# The chain of physical qubits selected by the transpiler
layout = isa_circuit.layout.final_index_layout()
print(f"Selected layout: {layout}")
isa_observable = observable.apply_layout(
layout, num_qubits=isa_circuit.num_qubits
)
Selected layout: [71, 58, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 36, 21, 22, 23, 16, 3, 2]
wire_order = layout + [
q for q in range(isa_circuit.num_qubits) if q not in layout
]
isa_circuit.draw(
"mpl",
fold=-1,
scale=0.3,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)

Mem-box sirkuit
Untuk kemudahan implementasi, kita memanfaatkan pass transpilasi generate_boxing_pass_manager, yang menempatkan instruksi sirkuit ke dalam box beranotasi. Box-box ini dengan jelas menunjukkan di mana, dalam kasus PEC, anti-noise harus disuntikkan ke dalam sirkuit. Untuk detail pengaturan, lihat dokumentasi Samplomatic.
Perlu dicatat bahwa alur kerja SLC memerlukan penggunaan inject_noise_strategy="individual_modification" nanti dalam proses karena ini memungkinkan kita mengidentifikasi secara unik anotasi InjectNoise dari instruksi BoxOp dalam sirkuit. (Box tanpa anotasi InjectNoise tidak dapat diidentifikasi dengan cara ini.)
Perhitungan bound SLC saat ini mengasumsikan bahwa anotasi InjectNoise ditempatkan dengan site="after" (lihat qiskit-addon-slc#33). Karena nilai default dari pengaturan ini berubah pada versi terbaru samplomatic (lihat samplomatic#372), kita menetapkan inject_noise_site="after" secara eksplisit di bawah ini.
Fungsi find_unique_box_instructions melakukan iterasi melalui sirkuit yang telah di-box yang diberikan dan mengidentifikasi mana yang memiliki layer dua-qubit (2Q) atau pengukuran yang unik, untuk keperluan noise learning dan penyuntikan noise.
# Box circuit with Twirl and InjectNoise annotations
boxes_pm = generate_boxing_pass_manager(
twirling_strategy="active",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
inject_noise_targets="gates",
measure_annotations="all",
)
boxed_circuit = boxes_pm.run(isa_circuit)
# Find the unique instructions (layers) from boxed circuit
unique_2q_instructions = find_unique_box_instructions(
boxed_circuit, normalize_annotations=None, undress_boxes=True
)
boxed_circuit.draw(
"mpl",
fold=-1,
scale=0.3,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)

Menyiapkan pengukuran basis kanonik
Perlu dicatat bahwa kita harus berhati-hati khusus untuk melacak urutan qubit. Di bawah ini, kita memperkenalkan konsep canonical_qubits sebagai cara untuk memperbarui urutan qubit dengan tepat saat memberikannya ke Executor, sebagai akibat dari bagaimana urutan qubit ditangkap ketika mem-box sirkuit dan menemukan instruksi unik. Lihat dokumentasi Qubit ordering convention untuk detailnya.
# Determine the canonical qubits order
meas_box = boxed_circuit.data[-1]
canonical_qubits = [
idx
for idx, qubit in enumerate(boxed_circuit.qubits)
if qubit in meas_box.qubits
]
# map canonical qubit to physical (isa) qubit
c_2_p = {c: p for c, p in enumerate(canonical_qubits)}
# map physical (isa) qubit to virtual qubit (index in original circuit)
p_2_v = {p: v for v, p in enumerate(layout)}
# compute map between virtual and canonical qubit indices.
c_2_v = {c: p_2_v[p] for c, p in c_2_p.items()}
assert len(c_2_v) == num_qubits
bases_canon = [
np.array([base_i[c_2_v[c]] for c in range(num_qubits)], dtype=np.uint8)
for base_i in bases_virt
]
Alur kerja untuk lightcone shading, noise learning, dan penyuntikan anti-noise
Dalam tutorial ini, kita menjalankan perhitungan bound SLC sebelum noise learning selesai, sehingga sirkuit yang akan dimitigasi dijalankan sedekat mungkin secara waktu dengan model noise yang dipelajari. Pada prinsipnya, workflow ini bisa diparalelkan lebih lanjut: job noise-learning bisa berjalan sementara, secara paralel, bound noise diestimasi. Untuk sirkuit kuantum yang arbitrer, perhitungan noise-bound bisa berskala dengan ketergantungan eksponensial lemah, sehingga memparalelkan perhitungan bound (misalnya, di banyak CPU core) menghasilkan bound yang lebih ketat untuk anggaran waktu komputasi tertentu, dan eksekusi QPU serta perhitungan bound itu sendiri bisa diparalelkan untuk workflow yang paling efisien.
Memprediksi Pauli model-noise yang akan dipelajari
Sebelum menjalankan noise learning apa pun pada hardware, kita pertama-tama mendaftar term error Pauli mana saja yang akan ada di noise model kita. Perlu diingat bahwa kita memodelkan noise dari setiap layer unik sebagai sparse Pauli-Lindblad model dengan satu error rate untuk setiap Pauli berbobot satu (, , atau ) pada setiap qubit aktif, dan satu untuk setiap Pauli berbobot dua pada setiap pasangan qubit aktif yang terhubung. Fungsi generate_noise_model_paulis menelusuri setiap boxed layer unik dari circuit yang diberikan dan menghasilkan tepat daftar term Pauli ini, dengan mempertimbangkan konektivitas qubit dari circuit tersebut.
Dengan kata lain, langkah ini memprediksi struktur dari noise model yang nantinya akan diisi oleh NoiseLearnerV3 dengan rate yang telah dipelajari. Mengetahui struktur ini sebelumnya adalah yang memungkinkan kita menghitung bound maju dan mundur untuk setiap potensi error bahkan sebelum noise learning dijalankan.
noise_model_paulis = generate_noise_model_paulis(
unique_2q_instructions, backend.coupling_map, boxed_circuit
)
noise_model_rates = {ref: None for ref in noise_model_paulis}
a. Menghitung forward bounds
Fungsi compute_forward_bounds mengevaluasi relasi komutasi antara gate di setiap layer dan term Pauli yang dihasilkan di atas dalam hal bagaimana error forward-propagation memengaruhi observable yang diinginkan. Untuk gate yang berkomutasi dengan term Pauli, tidak ada yang dilakukan. Untuk gate Clifford, gate tersebut didorong ke arah awal circuit. Untuk gate non-Clifford, kita mengaproksimasi pengaruhnya terhadap observable target agar nantinya bisa diprioritaskan untuk noise cancellation (setelah semua bound digabungkan). Bound ini dicapai dengan pertama-tama menerapkan norma L2 (yaitu akar kuadrat dari jumlah kuadrat koefisien term Pauli yang relevan). Ketika terlalu banyak term qubit yang terlibat, kita kembali ke bound yang lebih longgar menggunakan pertidaksamaan segitiga.
Mengatur parameter perhitungan bound
Pengaturan berikut mengontrol perhitungan bound klasik:
-
slc_atol: toleransi absolut dari perhitungan. Term operator dengan koefisien di bawah threshold ini dianggap dapat diabaikan dan dibuang. -
slc_eigval_max_qubits: jumlah maksimum qubit di mana bound yang lebih ketat berbasis eigenvalue (norma L2) dievaluasi. Operator yang bekerja pada lebih banyak qubit dari ini akan menggunakan bound pertidaksamaan segitiga yang lebih longgar seperti dijelaskan di atas. -
slc_evolution_max_terms: jumlah maksimum term Pauli yang dipertahankan saat mempropagasikan operator melalui circuit. Memangkas term terkecil menjaga perhitungan tetap tractable dengan biaya bound yang sedikit lebih longgar. -
slc_num_processes: jumlah proses CPU yang digunakan untuk memparalelkan perhitungan bound. -
slc_timeout: anggaran waktu (dalam detik) untuk perhitungan bound. Layer mana pun yang tidak tercapai dalam anggaran ini akan diberikan bound trivial sebesar 2.
Dalam tutorial ini, timeout tercapai secara sengaja: kita membuat slc_timeout sengaja kecil agar notebook berjalan cepat, dan untuk menunjukkan bahwa mencapai timeout itu aman. Shade yang dihitung adalah upper bound di setiap tahap, jadi mencapai timeout hanya membuat bound lebih longgar (trivial) untuk layer yang belum tercapai; ini tidak pernah meremehkan efek dari sebuah error. Ini muncul dalam visualisasi di bawah sebagai layer paling kiri yang terisi penuh dengan trivial bound. Menambah timeout (atau jumlah proses) mempersempit bound dan lebih lanjut mengurangi sampling overhead.
slc_atol = 1e-8
slc_eigval_max_qubits = 18
slc_evolution_max_terms = 1000
slc_num_processes = 8
slc_timeout = 60
forward_bounds = compute_forward_bounds(
boxed_circuit,
noise_model_paulis,
isa_observable,
evolution_max_terms=slc_evolution_max_terms,
eigval_max_qubits=slc_eigval_max_qubits,
atol=slc_atol,
num_processes=slc_num_processes,
timeout=slc_timeout,
)
Bounds computation timed out.
Memvisualisasikan SLC untuk inspeksi manual
Anda dapat menginterpretasikan perilaku bound yang diarsir dengan memeriksa bagaimana measurement dan term Pauli berinteraksi dengan error lokal. Pola-pola ini merupakan karakteristik dari masalah time-evolution kicked Ising Hamiltonian ini dan juga muncul dalam paper Lightcone Shading for Classically Accelerated Quantum Error Mitigation, dengan beberapa fitur khas:
-
Kita bisa dengan jelas membedakan dua cone yang muncul dari dua Pauli non-identity dalam observable.
-
Kita bisa melihat bahwa measurement X pada qubit 6 berkomutasi dengan error X pada layer paling kanan.
-
Kita bisa melihat bahwa Pauli Z pada qubit 13 berkomutasi dengan error Z pada layer paling kanan.
-
Ketika kita mencapai timeout yang ditentukan di atas, layer yang tersisa di sebelah kiri diisi seluruhnya dengan bound trivial sebesar dua.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
forward_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)



b. Memperketat forward bounds dengan quantum speed limits
Selanjutnya kita memperketat bound dengan menggunakan fungsi tighten_with_speed_limit. Penyebaran geometris dari lightcone observable sudah sepenuhnya diperhitungkan dalam forward bounds yang dihitung di atas. Yang ditambahkan oleh fungsi ini adalah passa self-consistency yang memanfaatkan kecepatan terbatas di mana informasi dapat mengalir melalui circuit — lightcone tumbuh paling banyak satu qubit per layer gate dua-qubit — untuk memperketat bound yang telah dihitung sebelumnya satu sama lain. Informasi mengalir dalam dua arah:
-
Dari commutator bounds ke bound pada observable yang di-backpropagate: jika observable berkomutasi dengan error pada suatu qubit, maka tidak mungkin memiliki komponen atau yang besar di sana.
-
Dari bound pada observable yang di-backpropagate ke commutator bounds: jika observable memiliki komponen dan yang kecil pada suatu qubit, maka observable tersebut hampir pasti berkomutasi dengan di sana.
forward_bounds_tighter = tighten_with_speed_limit(
forward_bounds, boxed_circuit, noise_model_paulis, isa_observable
)
Memvisualisasikan SLC untuk inspeksi manual
Pada prinsipnya, penajaman ini memberikan transisi yang lebih halus antara bound yang dihitung dan bound trivial yang diberikan pada layer di luar timeout. Dalam contoh ini efeknya nyaris tidak terlihat, karena lightcone sudah menyebar hingga ke tepi circuit pada saat timeout tercapai.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
forward_bounds_tighter,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)



c. Menghitung backward bounds
Bagian dari prediksi noise ini mengevaluasi bagaimana error pada layer tertentu dapat memengaruhi input state . Fungsi compute_backward_bounds pertama-tama membalik circuit dan menghapus gate measurement, lalu melanjutkan dengan analisis yang serupa dengan yang dilakukan untuk perhitungan forward-bound.
backward_bounds = compute_backward_bounds(
boxed_circuit,
noise_model_paulis,
evolution_max_terms=slc_evolution_max_terms,
num_processes=slc_num_processes,
timeout=slc_timeout,
)
Memvisualisasikan SLC untuk inspeksi manual
Dari perhitungan backward bounds, kita bisa melihat bagaimana struktur initial state mengatur perilaku awal dari propagasi error:
-
Kita bisa dengan jelas melihat bagaimana error Z awalnya berkomutasi dengan initial state |0⟩.
-
Hanya pada qubit 6, di mana kita menginisialisasi eigenstate +1 dari basis X, error Z gagal berkomutasi, sementara error X berkomutasi.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
backward_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)



Pratinjau merged bounds tanpa noise rate yang dipelajari
Fungsi merged_bounds menentukan titik dalam circuit di mana peralihan dari backward bounds ke forward bounds meminimalkan total bias estimasi pada observable yang diinginkan. Bias ini dihitung sebagai jumlah dari kontribusi backward-bound untuk semua lokasi noise sebelum titik tersebut, ditambah kontribusi forward-bound untuk semua lokasi noise setelahnya. Saat ini, hal ini dilakukan secara seragam untuk semua qubit.
Titik optimal untuk beralih dari backward ke forward bounds bergantung pada noise rate yang dipelajari. Pada tahap ini kita belum mempelajari rate apa pun: noise_model_rates diinisialisasi ke None untuk setiap layer, yang diperlakukan oleh merge_bounds sebagai noise rate yang seragam. Merged bounds yang ditampilkan di sini karenanya hanyalah pratinjau; kita akan menghitungnya ulang dengan rate yang benar-benar dipelajari pada Langkah 3.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
noise_model_rates,
)
Missing noise rates. Partitioning backward/forward commutator bounds by assuming uniform error rates.
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
Memvisualisasikan SLC untuk inspeksi manual
Setelah menggabungkan backward bounds dan tightened forward bounds, perilaku dari SLC gabungan menjadi jelas:
-
Fungsi di atas memberi tahu kita bahwa sebuah partisi dipilih di mana peralihan dari backward ke tightened forward bounds terjadi.
-
Kita bisa lihat di bawah bahwa SLC sekarang berisi backward bounds parsial dan tightened forward bounds parsial.
for p in "XYZ":
display(
draw_shaded_lightcone(
boxed_circuit,
merged_bounds,
noise_model_paulis,
pauli_filter=p,
scale=0.15,
fold=-1,
idle_wires=False,
wire_order=wire_order,
measure_arrows=False,
)
)



Langkah 3: Eksekusi
Dalam bagian ini kita memulai bagian dari alur kerja yang menggunakan perangkat kuantum sungguhan. Untuk metode error mitigation berbasis learning ini, ada dua langkah:
-
Mempelajari noise dengan menggunakan
NoiseLearnerV3. -
Mengeksekusi circuit error-mitigation dengan framework
samplomaticdanExecutor.
Dengan error yang telah dibatasi dari circuit kuantum kita, kita mempelajari noise rate terkait untuk memprioritaskan error budget kita, menentukan sampling overhead, dan mengeksekusi pada QPU.
a. Mempelajari noise rate
Noise learner mengkarakterisasi proses noise yang memengaruhi gate dalam satu atau lebih circuit yang diminati, berdasarkan sparse Pauli-Lindblad noise model. Metode run() meluncurkan job noise-learning untuk layer dua-qubit unik yang diberikan, menggunakan opsi yang ditentukan dalam konfigurasi noise-learner. Opsi ini mengontrol strategi Pauli-twirling, jumlah randomisasi dan shot, kedalaman learning, dan post-selection.
Temuan praktis untuk mitigasi berbasis learning dengan samplomatic: sangat menguntungkan jika kedalaman learning terdalam sama dengan kedalaman circuit yang ingin kamu mitigasi. Karena layer_pair_depths NLv3 diukur dalam layer pairs (satu layer beserta inversnya), kita menetapkan nilai terdalam menjadi setengah dari kedalaman layer dua-qubit circuit tersebut.
post_selection_enabled = True
# Match the deepest noise-learning depth to the depth of the circuit being
# mitigated. NLv3 ``layer_pair_depths`` are measured in layer pairs (a layer
# plus its inverse), so the deepest value is half the circuit's two-qubit-layer
# depth. Learning to this depth markedly improves the quality of the mitigation.
#
# We measure the two-qubit-layer depth on the pre-boxed ISA circuit: after
# boxing, every two-qubit gate is hidden inside a full-width ``BoxOp``, so a
# ``num_qubits == 2`` filter on ``boxed_circuit`` matches nothing (and
# ``QuantumCircuit.depth`` does not recurse into boxes).
depth_2q = isa_circuit.depth(lambda instr: instr.operation.num_qubits == 2)
max_layer_pair_depth = depth_2q // 2 # dividing by 2 since we want pairs
# Use a fixed schedule of learning depths, but drop any that exceed the circuit's
# depth and always cap the deepest value at ``max_layer_pair_depth`` so we never
# learn deeper than the circuit being mitigated.
candidate_depths = [1, 2, 4, 8, 12, 16, 24, 32, 40, 48]
layer_pair_depths = sorted(
{d for d in candidate_depths if d < max_layer_pair_depth}
| {max_layer_pair_depth}
)
noise_learner_options = {
"num_randomizations": 64,
"shots_per_randomization": 128,
"layer_pair_depths": layer_pair_depths,
"post_selection": {
"enable": post_selection_enabled,
"strategy": "edge",
"x_pulse_type": "rx",
},
"environment": {"job_tags": ["TUT_SLC"]},
}
noise_learner = NoiseLearnerV3(backend, noise_learner_options)
noise_learner_job = noise_learner.run(unique_2q_instructions)
noise_learner_result = noise_learner_job.result()
if post_selection_enabled:
print(
"Minimum fraction of shots kept for noise learning experiments: ",
end="",
)
print(
f"{min([min(d.values()) for d in [nlr.metadata['post_selection']['fraction_kept'] for nlr in noise_learner_result[:2]]]):.2f}"
)
Minimum fraction of shots kept for noise learning experiments: 0.71
# Get a dict mapping each InjectNoise.ref to its learned PauliLindbladMap
refs_2_plm = noise_learner_result.to_dict(
unique_2q_instructions, require_refs=False
)
b.i. Memperbarui merged bounds dengan noise rate yang benar-benar dipelajari
Sekarang setelah noise model spesifik telah dipelajari, kita bisa menerapkan noise rate yang dipelajari pada bound noise yang diprediksi dan mendapatkan penentuan akhir mengenai bound mana yang memiliki dampak paling besar dalam meminimalkan bias.
merged_bounds = merge_bounds(
boxed_circuit,
forward_bounds_tighter,
backward_bounds,
refs_2_plm,
)
Optimal spacetime partitioning not implemented!Just partitioning list of noisy boxes.
b.ii. Menghitung local_scales untuk eksekusi hardware
compute_local_scales melihat setiap kemungkinan error noise dalam circuit dan memperkirakan seberapa besar error tersebut bisa membiaskan measurement akhir, serta seberapa mahal biaya untuk mengoreksinya. Fungsi ini kemudian meranking error berdasarkan seberapa berharga untuk dimitigasi dan memilih subset yang mengurangi bias sebanyak mungkin, sambil tetap berada dalam anggaran biaya sampling yang diizinkan (atau mencapai akurasi yang diinginkan). Hasilnya adalah sekumpulan faktor skala yang menunjukkan error mana yang akan dimitigasi secara aktif dan mana yang akan dibiarkan tidak dimitigasi (local_scales), beserta prediksi total overhead biaya sampling (sampling_costs) dan sisa bias (residual_bias_bound).
Kemampuan untuk mengontrol sisa bias yang diinginkan merupakan fitur penting dari implementasi SLC pada PEC. Sementara pada implementasi asli, sampling overhead selalu menargetkan bias nol, kita bisa menyesuaikan sampling overhead yang dibutuhkan dengan trade-off pada sisa bias yang diharapkan. Ini membantu pengguna tetap berada dalam anggaran sampling yang tetap, yang bisa sangat berguna saat pertama kali membuat prototipe alur kerja.
id_map = map_modifier_ref_to_ref(boxed_circuit)
summed_rates = 0.0
for box_id, noise_id in id_map.items():
learned_plm = refs_2_plm[noise_id]
summed_rates += np.sum(learned_plm.rates)
# print(f"{box_id}:\tgamma = {np.exp(2 * summed_rates):1.6e}\tsampling cost = {np.exp(4 * summed_rates):1.6e}")
total_gamma = np.exp(2 * summed_rates)
print(
f"Full PEC gamma={total_gamma}, sampling cost (gamma^2) = {total_gamma**2}"
)
Full PEC gamma=12.750876317157042, sampling cost (gamma^2) = 162.58484685543633
biases = []
costs = []
for bias in [0.0] + np.arange(0.001, 0.102, 0.01).tolist():
_, cost_, bias_ = compute_local_scales(
boxed_circuit,
merged_bounds,
refs_2_plm,
sampling_cost_budget=np.inf,
bias_tolerance=bias,
)
biases.append(bias_)
costs.append(cost_)
Trade off antara sampling overhead dan sisa bias
xticks = np.arange(0, 11)
fig, ax = plt.subplots()
ax.scatter(
[0], [total_gamma**2], marker="D", c="tab:orange", label="full PEC"
)
ax.plot(
100 * np.array(biases),
np.array(costs),
"o-",
c="tab:blue",
label="PEC+SLC",
)
ax.set_yscale("log")
ax.set_xticks(xticks, [f"{x:.1f}" for x in xticks])
ax.set_xlabel("Remaining bias [%]")
ax.set_ylabel(r"Sampling overhead, $\gamma^2$")
ax.grid()
ax.legend()
fig.suptitle("PEC sampling overhead reduction due to SLC")
Text(0.5, 0.98, 'PEC sampling overhead reduction due to SLC')
chosen_bias_thres = 0.1
local_scales, sampling_cost, residual_bias_bound = compute_local_scales(
boxed_circuit,
merged_bounds,
refs_2_plm,
sampling_cost_budget=np.inf,
bias_tolerance=chosen_bias_thres,
)
print(
f"PEC+SLC sampling cost (gamma^2) = {sampling_cost} "
f"w/ remaining bias = {100 * residual_bias_bound:.1f}%"
)
PEC+SLC sampling cost (gamma^2) = 48.13646509622307 w/ remaining bias = 10.0%
c. Mengeksekusi circuit yang diminati dengan antinoise
c.i. Menyiapkan template circuit dengan menggunakan samplex
samplex adalah output dari metode build milik Samplomatic, yang mengkodekan semua informasi yang diperlukan untuk menghasilkan parameter acak untuk template_circuit. Ini kemudian digunakan untuk menyiapkan objek QuantumProgram, yang selanjutnya dijalankan pada QPU dengan primitive Executor. Setiap QuantumProgram bisa berisi beberapa item, yang bisa Anda pikirkan sebagai pasangan template dan samplex.
Lihat tutorial Hello samplomatic untuk detailnya.
# Build template circuit and samplex for later use with the "Executor"
template_circuit, samplex = samplomatic.build(boxed_circuit)
# Set up postselection if it's been enabled
if post_selection_enabled:
# Set up post selection PM (to add PS instructions)
post_selection_pm = PassManager(
[
AddSpectatorMeasures(backend.coupling_map),
AddPostSelectionMeasures(x_pulse_type="rx"),
]
)
final_template_circuit = post_selection_pm.run(template_circuit)
else:
final_template_circuit = template_circuit
c.ii. Menyiapkan QuantumProgram
num_randomizations = 4096
shots_per_randomization = 64
chunk_size = 256
# Set up QuantumProgram
program = QuantumProgram(shots=shots_per_randomization, noise_maps=refs_2_plm)
# no EM
# Collect up a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(0) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)
# plain PEC
# Collect a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(-1) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)
# PEC+SLC
# Collect a dict of the other arguments that need to be bound to samplex_inputs
samplex_inputs = {
f"noise_scales.{ref}": float(-1) for ref in local_scales.keys()
}
samplex_inputs |= {"basis_changes": {"basis0": bases_canon[0]}}
samplex_inputs |= {"local_scales": local_scales}
# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().bind(**samplex_inputs).make_broadcastable()
)
program.append_samplex_item(
circuit=final_template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations,),
chunk_size=chunk_size,
)
c.iii. Mengeksekusi program dengan primitive Executor
executor = Executor(backend)
job_exec = executor.run(program)
results_exec = job_exec.result()
Langkah 4: Post-process
Saat kita menghitung expectation value akhir yang diinginkan dengan menggunakan executor_expectation_values, kita menerapkan beberapa teknik post-processing untuk membantu memastikan kita mendapatkan hasil berkualitas setinggi mungkin. Pertama, kita menerapkan twirled readout error extinction (TREX), yang memperhitungkan error apa pun yang terjadi selama proses readout. Kemudian, kita memperbaiki error akibat noise non-Markovian pada backend Heron kita dengan menggunakan metode post-selection. Metode ini mengukur qubit aktif dan spectator, lalu menerapkan rotasi lambat pada setiap qubit, kemudian mengukur lagi. Pada kasus di mana kedua measurement tidak mengonfirmasi qubit yang dibalik seperti yang diharapkan, shot tersebut dibuang dengan menerapkan mask dari PostSelector. Dalam perhitungan mask, strategi tertentu dapat ditetapkan untuk menyaring berdasarkan single-qubit node atau neighboring spectator edge, yang bisa memengaruhi baik jumlah shot yang disaring maupun kualitas hasil.
measurement_noise_map = noise_learner_result[2].to_pauli_lindblad_map()
trex_scale_factors = trex_factors(measurement_noise_map, reverser_virt)
post_selection_strategy = "node"
def post_process_conv(datum, steps=16, gamma=None, ps=False, trex=False):
meas = datum["meas"]
flips = datum["measurement_flips.meas"]
signs = datum.get("pauli_signs", None)
meas_basis_axis = None
avg_axis = 0
mask = None
if ps and post_selection_enabled:
# Post-select the results
post_selector = PostSelector.from_circuit(
circuit=final_template_circuit, coupling_map=backend.coupling_map
)
# Compute the ps mask for filtering results
mask = post_selector.compute_mask(
datum, strategy=post_selection_strategy
)
# Compute fraction of shots kept from post selection
total_num_shots = num_randomizations * shots_per_randomization
ps_ratio = np.sum(mask) * 100 / total_num_shots / len(bases_canon)
print(
f"With {post_selection_strategy}-based post selection ({ps_ratio:.1f}% of shots kept):"
)
results = []
for i in range(steps, num_randomizations + 1, steps):
# Compute mitigated expvals w/out post-selection
res = executor_expectation_values(
meas[:i],
reverser_virt,
meas_basis_axis,
avg_axis=avg_axis,
measurement_flips=flips[:i],
pauli_signs=signs[:i] if signs is not None else None,
postselect_mask=mask[:i] if mask is not None else None,
rescale_factors=trex_scale_factors if trex else None,
gamma_factor=gamma,
)
results.append(res[0])
return results
gamma_pec = gamma_from_noisy_boxes(refs_2_plm, id_map)
gamma_slc = gamma_from_noisy_boxes(refs_2_plm, id_map, local_scales)
steps = 16
results = {}
for label, result_idx, gamma, use_ps, use_trex in [
("PEC", 1, gamma_pec, True, True),
("PEC+SLC", 2, gamma_slc, True, True),
("Unmitigated", 0, None, False, False),
]:
res = post_process_conv(
results_exec[result_idx],
steps=steps,
gamma=gamma,
ps=use_ps,
trex=use_trex,
)
results[label] = res
With node-based post selection (24.1% of shots kept):
With node-based post selection (24.2% of shots kept):
Dari pemeriksaan hasil eksperimen, kita bisa langsung membandingkan perilaku dari pendekatan yang berbeda: PEC, PEC yang dikombinasikan dengan SLC, dan baseline yang tidak dimitigasi. Beberapa detail spesifik yang perlu disorot:
-
Hasil yang tidak dimitigasi berada jauh di luar bias band 10% (mendekati 0,35) dan tidak dipengaruhi oleh jumlah randomisasi.
-
Pada perangkat ini, full PEC memiliki sampling overhead sebesar . Setelah ayunan awal yang besar, estimasi plain-PEC memulihkan sinyal dan mengendap di sekitar 1,1, sedikit melebihi nilai eksak. Perlu dicatat bahwa bias band 10% hanya berlaku untuk estimator PEC+SLC: plain PEC pada prinsipnya tidak bias, sehingga deviasi sisa ini tidak tercakup oleh jaminan bias melainkan mencerminkan fluktuasi statistik dan ketidaksempurnaan dalam noise model yang dipelajari, yang wajar pada skala masalah ini.
-
SLC mengurangi overhead lebih jauh sekitar ~3,4 kali lipat (menjadi , untuk residual-bias bound sekitar 10%). PEC+SLC juga berfluktuasi kuat pada sedikit randomisasi, bahkan awalnya mencapai wilayah yang tidak fisis, tetapi estimasinya konvergen secara stabil menuju nilai eksak, mengendap dekat 1,0 jauh di dalam band. Ia menyamai atau melampaui akurasi plain PEC dengan sekitar sepertiga biaya sampling, menunjukkan manfaat dari lightcone shading.
-
Error bar dari kedua estimasi yang dimitigasi menyusut seiring bertambahnya randomisasi; pada jumlah randomisasi yang tetap, estimator PEC+SLC memiliki varians statistik yang lebih kecil, konsisten dengan -nya yang lebih kecil.
Perlu dicatat bahwa noise rate yang dipelajari (dan karenanya overhead serta estimasi yang dimitigasi) bergantung pada backend dan kalibrasinya pada saat eksekusi, sehingga menjalankan ulang notebook ini bisa menghasilkan nilai yang berbeda secara kuantitatif.
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
ax.axhline(1.0, color="black", label="Exact")
ax.fill_between(
[-50, 4100], -10, 0, color="grey", alpha=0.25, label="Unphysical"
)
ax.fill_between([-50, 4100], 1, 10, color="grey", alpha=0.25)
ax.fill_between(
[-50, 4100], 0.9, 1.1, color="red", alpha=0.25, label="10% bias"
)
for label, res in results.items():
ax.errorbar(
list(range(steps, num_randomizations + 1, steps)),
[r[0] for r in res],
yerr=[r[1] for r in res],
alpha=0.75,
marker="o",
linestyle="",
markerfacecolor="none",
label=label,
)
ax.set_ylabel(r"$\langle X_{6}Z_{13}\rangle$")
ax.set_xlabel("# randomizations")
ax.grid()
ax.legend(ncols=2)
ax.set_ylim([-0.1, 2.0])
ax.set_xlim([-50, 4100])
(-50.0, 4100.0)

Langkah selanjutnya
Jika Anda merasa hal ini menarik, Anda mungkin tertarik dengan materi berikut:

