Langkau ke kandungan utama

Gabungkan pilihan mitigasi ralat dengan primitif Estimator

Anggaran penggunaan: Tujuh minit pada pemproses Heron r2 (NOTA: Ini adalah anggaran sahaja. Masa larian anda mungkin berbeza.)

Latar Belakang​

Panduan ini meneroka pilihan penindasan ralat dan mitigasi ralat yang tersedia dengan primitif Estimator daripada Qiskit Runtime. Anda akan membina Circuit dan observable, kemudian menghantar kerja menggunakan primitif Estimator dengan kombinasi tetapan mitigasi ralat yang berbeza. Selepas itu, anda akan memplot hasilnya untuk melihat kesan pelbagai tetapan tersebut. Kebanyakan contoh menggunakan Circuit 10-Qubit untuk memudahkan visualisasi, dan pada penghujung, anda boleh skala naik aliran kerja kepada 50 Qubit.

Ini adalah pilihan penindasan dan mitigasi ralat yang akan anda gunakan:

  • Dynamical decoupling
  • Mitigasi ralat pengukuran
  • Gate twirling
  • Zero-noise extrapolation (ZNE)

Keperluan​

Sebelum memulakan panduan ini, pastikan anda telah memasang yang berikut:

  • Qiskit SDK v2.1 atau lebih baharu, dengan sokongan visualisasi
  • Qiskit Runtime v0.40 atau lebih baharu (pip install qiskit-ibm-runtime)

Persediaan​

# Added by doQumentation β€” required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime
import matplotlib.pyplot as plt
import numpy as np

from qiskit.circuit.library import efficient_su2, unitary_overlap
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Batch, EstimatorV2 as Estimator

Langkah 1: Petakan input klasik kepada masalah kuantum​

Panduan ini mengandaikan bahawa masalah klasik sudah dipetakan kepada kuantum. Mulakan dengan membina Circuit dan observable untuk diukur. Walaupun teknik yang digunakan di sini boleh diaplikasi kepada pelbagai jenis Circuit, untuk kesederhanaan panduan ini menggunakan Circuit efficient_su2 yang disertakan dalam pustaka Circuit Qiskit.

efficient_su2 ialah Circuit kuantum berparameter yang direka untuk dilaksanakan dengan cekap pada perkakasan kuantum dengan sambungan Qubit yang terhad, namun masih cukup ekspresif untuk menyelesaikan masalah dalam domain aplikasi seperti pengoptimuman dan kimia. Ia dibina dengan melapisi lapisan Gate satu-Qubit berparameter secara bergilir dengan lapisan yang mengandungi corak tetap Gate dua-Qubit, untuk bilangan pengulangan yang dipilih. Corak Gate dua-Qubit boleh ditentukan oleh pengguna. Di sini anda boleh menggunakan corak bawaan pairwise kerana ia meminimumkan kedalaman Circuit dengan mengemas Gate dua-Qubit sepadat mungkin. Corak ini boleh dilaksanakan menggunakan sambungan Qubit linear sahaja.

n_qubits = 10
reps = 1

circuit = efficient_su2(n_qubits, entanglement="pairwise", reps=reps)

circuit.decompose().draw("mpl", scale=0.7)

Output of the previous code cell

Output of the previous code cell

Untuk observable kita, mari ambil operator Pauli ZZ yang bertindak pada Qubit terakhir, ZIβ‹―IZ I \cdots I.

# Z on the last qubit (index -1) with coefficient 1.0
observable = SparsePauliOp.from_sparse_list(
[("Z", [-1], 1.0)], num_qubits=n_qubits
)

Pada ketika ini, anda boleh teruskan dengan menjalankan Circuit dan mengukur observable. Walau bagaimanapun, anda juga mahu membandingkan output peranti kuantum dengan jawapan yang betul β€” iaitu, nilai teori observable, sekiranya Circuit dilaksanakan tanpa ralat. Untuk Circuit kuantum kecil, anda boleh mengira nilai ini dengan mensimulasikan Circuit pada komputer klasik, tetapi ini tidak mungkin untuk Circuit yang lebih besar, berskala utiliti. Anda boleh mengatasi isu ini dengan teknik "mirror circuit" (juga dikenali sebagai "compute-uncompute"), yang berguna untuk menanda aras prestasi peranti kuantum.

Circuit cermin​

Dalam teknik Circuit cermin, anda menggabungkan Circuit dengan Circuit songsang (inverse circuit)-nya, yang dibentuk dengan menyongsangkan setiap Gate Circuit dalam susunan terbalik. Circuit yang terhasil melaksanakan operator identiti, yang boleh disimulasikan dengan mudah. Kerana struktur Circuit asal dipelihara dalam Circuit cermin, melaksanakan Circuit cermin tetap memberikan gambaran tentang bagaimana peranti kuantum akan berprestasi pada Circuit asal.

Sel kod berikut menetapkan parameter rawak kepada Circuit anda, kemudian membina Circuit cermin menggunakan kelas unitary_overlap. Sebelum mencerminkan Circuit, tambahkan arahan barrier padanya untuk menghalang Transpiler daripada menggabungkan dua bahagian Circuit di kedua-dua sisi barrier. Tanpa barrier, Transpiler akan menggabungkan Circuit asal dengan songsangnya, menghasilkan Circuit yang telah ditransformasi tanpa sebarang Gate.

# Generate random parameters
rng = np.random.default_rng(1234)
params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)

# Assign the parameters to the circuit
assigned_circuit = circuit.assign_parameters(params)

# Add a barrier to prevent circuit optimization of mirrored operators
assigned_circuit.barrier()

# Construct mirror circuit
mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)

mirror_circuit.decompose().draw("mpl", scale=0.7)

Output of the previous code cell

Output of the previous code cell

Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantum​

Anda mesti mengoptimumkan Circuit anda sebelum menjalankannya pada perkakasan. Proses ini melibatkan beberapa langkah:

  • Pilih susun atur Qubit yang memetakan Qubit maya Circuit anda kepada Qubit fizikal pada perkakasan.
  • Sisipkan Gate swap mengikut keperluan untuk menghala interaksi antara Qubit yang tidak bersambung.
  • Terjemahkan Gate dalam Circuit anda kepada arahan Instruction Set Architecture (ISA) yang boleh dilaksanakan terus pada perkakasan.
  • Lakukan pengoptimuman Circuit untuk meminimumkan kedalaman Circuit dan bilangan Gate.

Transpiler yang dibina dalam Qiskit boleh melakukan semua langkah ini untuk anda. Kerana contoh ini menggunakan Circuit yang cekap dari segi perkakasan, Transpiler sepatutnya dapat memilih susun atur Qubit yang tidak memerlukan sebarang Gate swap disisipkan untuk menghala interaksi.

Anda perlu memilih peranti perkakasan yang hendak digunakan sebelum mengoptimumkan Circuit anda. Sel kod berikut meminta peranti yang paling tidak sibuk dengan sekurang-kurangnya 127 Qubit.

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

Anda boleh mentransformasi Circuit anda untuk Backend yang dipilih dengan membuat pengurus laluan kemudian menjalankan pengurus laluan pada Circuit. Cara mudah untuk membuat pengurus laluan ialah menggunakan fungsi generate_preset_pass_manager. Lihat Transpile with pass managers untuk penjelasan lebih terperinci tentang transformasi dengan pengurus laluan.

pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=1234
)
isa_circuit = pass_manager.run(mirror_circuit)

isa_circuit.draw("mpl", idle_wires=False, scale=0.7, fold=-1)

Output of the previous code cell

Output of the previous code cell

Circuit yang telah ditransformasi kini mengandungi hanya arahan ISA. Gate satu-Qubit telah didekomposisi dalam bentuk Gate X\sqrt{X} dan putaran RzR_z, dan Gate CX telah didekomposisi kepada Gate ECR dan putaran satu-Qubit.

Proses transformasi telah memetakan Qubit maya Circuit kepada Qubit fizikal pada perkakasan. Maklumat tentang susun atur Qubit disimpan dalam atribut layout Circuit yang telah ditransformasi. Observable juga ditakrifkan dari segi Qubit maya, jadi anda perlu menggunakan susun atur ini pada observable, yang boleh anda lakukan dengan kaedah apply_layout bagi SparsePauliOp.

isa_observable = observable.apply_layout(isa_circuit.layout)

print("Original observable:")
print(observable)
print()
print("Observable with layout applied:")
print(isa_observable)
Original observable:
SparsePauliOp(['ZIIIIIIIII'],
coeffs=[1.+0.j])

Observable with layout applied:
SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])

Langkah 3: Jalankan menggunakan primitif Qiskit​

Anda kini sedia untuk menjalankan Circuit menggunakan primitif Estimator.

Di sini anda akan menghantar lima kerja berasingan, bermula tanpa penindasan atau mitigasi ralat, kemudian menghidupkan pelbagai pilihan penindasan dan mitigasi ralat secara berurutan yang tersedia dalam Qiskit Runtime. Untuk maklumat tentang pilihan tersebut, rujuk halaman berikut:

Kerana kerja-kerja ini boleh dijalankan secara bebas antara satu sama lain, anda boleh menggunakan mod batch untuk membolehkan Qiskit Runtime mengoptimumkan masa pelaksanaannya.

pub = (isa_circuit, isa_observable)

jobs = []

with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
# Set number of shots
estimator.options.default_shots = 100_000
# Disable runtime compilation and error mitigation
estimator.options.resilience_level = 0

# Run job with no error mitigation
job0 = estimator.run([pub])
jobs.append(job0)

# Add dynamical decoupling (DD)
estimator.options.dynamical_decoupling.enable = True
estimator.options.dynamical_decoupling.sequence_type = "XpXm"
job1 = estimator.run([pub])
jobs.append(job1)

# Add readout error mitigation (DD + TREX)
estimator.options.resilience.measure_mitigation = True
job2 = estimator.run([pub])
jobs.append(job2)

# Add gate twirling (DD + TREX + Gate Twirling)
estimator.options.twirling.enable_gates = True
estimator.options.twirling.num_randomizations = "auto"
job3 = estimator.run([pub])
jobs.append(job3)

# Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.noise_factors = (1, 3, 5)
estimator.options.resilience.zne.extrapolator = ("exponential", "linear")
job4 = estimator.run([pub])
jobs.append(job4)

Langkah 4: Proses pasca dan kembalikan hasil dalam format klasik yang dikehendaki​

Akhir sekali, anda boleh menganalisis data. Di sini anda akan mendapatkan semula keputusan kerja, mengekstrak nilai jangkaan yang diukur daripadanya, dan memplot nilai tersebut, termasuk bar ralat satu sisihan piawai.

# Retrieve the job results
results = [job.result() for job in jobs]

# Unpack the PUB results (there's only one PUB result in each job result)
pub_results = [result[0] for result in results]

# Unpack the expectation values and standard errors
expectation_vals = np.array(
[float(pub_result.data.evs) for pub_result in pub_results]
)
standard_errors = np.array(
[float(pub_result.data.stds) for pub_result in pub_results]
)

# Plot the expectation values
fig, ax = plt.subplots()
labels = ["No mitigation", "+ DD", "+ TREX", "+ Twirling", "+ ZNE"]
ax.bar(
range(len(labels)),
expectation_vals,
yerr=standard_errors,
label="experiment",
)
ax.axhline(y=1.0, color="gray", linestyle="--", label="ideal")
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_ylabel("Expectation value")
ax.legend(loc="upper left")

plt.show()

Output of the previous code cell

Pada skala kecil ini, sukar untuk melihat kesan kebanyakan teknik mitigasi ralat, tetapi zero-noise extrapolation memang memberikan penambahbaikan yang ketara. Walau bagaimanapun, perlu diingat bahawa penambahbaikan ini tidak percuma, kerana keputusan ZNE juga mempunyai bar ralat yang lebih besar.

Skalakan eksperimen ke atas​

Semasa membangunkan eksperimen, berguna untuk bermula dengan Circuit kecil bagi memudahkan visualisasi dan simulasi. Setelah anda membangunkan dan menguji aliran kerja pada Circuit 10-Qubit, anda boleh skala naik kepada 50 Qubit. Sel kod berikut mengulangi semua langkah dalam panduan ini, tetapi kini mengaplikasikannya kepada Circuit 50-Qubit.

n_qubits = 50
reps = 1

# Construct circuit and observable
circuit = efficient_su2(n_qubits, entanglement="pairwise", reps=reps)
observable = SparsePauliOp.from_sparse_list(
[("Z", [-1], 1.0)], num_qubits=n_qubits
)

# Assign parameters to circuit
params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)
assigned_circuit = circuit.assign_parameters(params)
assigned_circuit.barrier()

# Construct mirror circuit
mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)

# Transpile circuit and observable
isa_circuit = pass_manager.run(mirror_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)

# Run jobs
pub = (isa_circuit, isa_observable)

jobs = []

with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
# Set number of shots
estimator.options.default_shots = 100_000
# Disable runtime compilation and error mitigation
estimator.options.resilience_level = 0

# Run job with no error mitigation
job0 = estimator.run([pub])
jobs.append(job0)

# Add dynamical decoupling (DD)
estimator.options.dynamical_decoupling.enable = True
estimator.options.dynamical_decoupling.sequence_type = "XpXm"
job1 = estimator.run([pub])
jobs.append(job1)

# Add readout error mitigation (DD + TREX)
estimator.options.resilience.measure_mitigation = True
job2 = estimator.run([pub])
jobs.append(job2)

# Add gate twirling (DD + TREX + Gate Twirling)
estimator.options.twirling.enable_gates = True
estimator.options.twirling.num_randomizations = "auto"
job3 = estimator.run([pub])
jobs.append(job3)

# Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.noise_factors = (1, 3, 5)
estimator.options.resilience.zne.extrapolator = ("exponential", "linear")
job4 = estimator.run([pub])
jobs.append(job4)

# Retrieve the job results
results = [job.result() for job in jobs]

# Unpack the PUB results (there's only one PUB result in each job result)
pub_results = [result[0] for result in results]

# Unpack the expectation values and standard errors
expectation_vals = np.array(
[float(pub_result.data.evs) for pub_result in pub_results]
)
standard_errors = np.array(
[float(pub_result.data.stds) for pub_result in pub_results]
)

# Plot the expectation values
fig, ax = plt.subplots()
labels = ["No mitigation", "+ DD", "+ TREX", "+ Twirling", "+ ZNE"]
ax.bar(
range(len(labels)),
expectation_vals,
yerr=standard_errors,
label="experiment",
)
ax.axhline(y=1.0, color="gray", linestyle="--", label="ideal")
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_ylabel("Expectation value")
ax.legend(loc="upper left")

plt.show()

Output of the previous code cell

Apabila anda membandingkan keputusan 50-Qubit dengan keputusan 10-Qubit tadi, anda mungkin perhatikan perkara berikut (keputusan anda mungkin berbeza antara larian):

  • Keputusan tanpa mitigasi ralat adalah lebih teruk. Menjalankan Circuit yang lebih besar melibatkan pelaksanaan lebih banyak Gate, jadi terdapat lebih banyak peluang untuk ralat terkumpul.
  • Penambahan dynamical decoupling mungkin telah memperburukkan prestasi. Ini tidak menghairankan, kerana Circuit ini sangat padat. Dynamical decoupling terutamanya berguna apabila terdapat jurang besar dalam Circuit semasa Qubit duduk melahu tanpa Gate diaplikasikan kepadanya. Apabila jurang ini tidak wujud, dynamical decoupling tidak berkesan, malah boleh memperburukkan prestasi akibat ralat dalam nadi dynamical decoupling itu sendiri. Circuit 10-Qubit mungkin terlalu kecil untuk kita perhatikan kesan ini.
  • Dengan zero-noise extrapolation, hasilnya sama baiknya, atau hampir sama baik, dengan keputusan 10-Qubit, walaupun bar ralatnya jauh lebih besar. Ini menunjukkan kehebatan teknik ZNE!

Kesimpulan​

Dalam panduan ini, anda menyiasat pelbagai pilihan mitigasi ralat yang tersedia untuk primitif Estimator Qiskit Runtime. Anda membangunkan aliran kerja menggunakan Circuit 10-Qubit, kemudian menaikkan skalanya kepada 50 Qubit. Anda mungkin mendapati bahawa menghidupkan lebih banyak pilihan penindasan dan mitigasi ralat tidak semestinya meningkatkan prestasi (khususnya, menghidupkan dynamical decoupling dalam kes ini). Kebanyakan pilihan menerima konfigurasi tambahan, yang boleh anda uji dalam kerja anda sendiri!

Source: IBM Quantum docs β€” updated 27 Apr 2026
English version on doQumentation β€” updated 7 Mei 2026
This translation based on the English version of 9 Apr 2026