Benchmarking real-time untuk pemilihan qubit
Estimasi penggunaan: 4 menit pada prosesor Eagle r2 (CATATAN: Ini hanya estimasi. Waktu aktual kamu bisa berbeda.)
# Added by doQumentation β required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-experiments qiskit-ibm-runtime rustworkx
# This cell is hidden from users β it disables some lint rules
# ruff: noqa: E722
Latar Belakangβ
Tutorial ini menunjukkan cara menjalankan eksperimen karakterisasi real-time dan memperbarui properti backend untuk meningkatkan pemilihan qubit saat memetakan Circuit ke qubit fisik pada QPU. Kamu akan mempelajari eksperimen karakterisasi dasar yang digunakan untuk menentukan properti QPU, cara melakukannya di Qiskit, dan cara memperbarui properti yang tersimpan dalam objek backend yang merepresentasikan QPU berdasarkan eksperimen-eksperimen tersebut.
Properti yang dilaporkan QPU diperbarui sekali sehari, tetapi sistem bisa mengalami drift lebih cepat dari interval pembaruan tersebut. Hal ini dapat memengaruhi keandalan rutinitas pemilihan qubit pada tahap Layout dari pass manager, karena mereka menggunakan properti yang dilaporkan yang tidak mencerminkan kondisi QPU saat ini. Oleh karena itu, mungkin ada baiknya mengalokasikan sebagian waktu QPU untuk eksperimen karakterisasi, yang kemudian dapat digunakan untuk memperbarui properti QPU yang dipakai oleh rutinitas Layout.
Prasyaratβ
Sebelum memulai tutorial ini, pastikan kamu sudah menginstal hal-hal berikut:
- Qiskit SDK v2.0 atau lebih baru, dengan dukungan visualisasi
- Qiskit Runtime v0.40 atau lebih baru (
pip install qiskit-ibm-runtime) - Qiskit Experiments v0.12 atau lebih baru (
pip install qiskit-experiments) - Library graf Rustworkx (
pip install rustworkx)
Pengaturanβ
from qiskit_ibm_runtime import SamplerV2
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import hellinger_fidelity
from qiskit.transpiler import InstructionProperties
from qiskit_experiments.library import (
T1,
T2Hahn,
LocalReadoutError,
StandardRB,
)
from qiskit_experiments.framework import BatchExperiment, ParallelExperiment
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session
from datetime import datetime
from collections import defaultdict
import numpy as np
import rustworkx
import matplotlib.pyplot as plt
import copy
Langkah 1: Petakan input klasik ke masalah kuantumβ
Untuk membandingkan perbedaan performa, kita menggunakan Circuit yang mempersiapkan Bell state di sepanjang rantai linear dengan panjang yang bervariasi. Fidelitas Bell state di kedua ujung rantai diukur.
from qiskit import QuantumCircuit
ideal_dist = {"00": 0.5, "11": 0.5}
num_qubits_list = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 127]
circuits = []
for num_qubits in num_qubits_list:
circuit = QuantumCircuit(num_qubits, 2)
circuit.h(0)
for i in range(num_qubits - 1):
circuit.cx(i, i + 1)
circuit.barrier()
circuit.measure(0, 0)
circuit.measure(num_qubits - 1, 1)
circuits.append(circuit)
circuits[-1].draw(output="mpl", style="clifford", fold=-1)


Siapkan backend dan coupling mapβ
Pertama, pilih sebuah backend
# To run on hardware, select the backend with the fewest number of jobs in the queue
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
qubits = list(range(backend.num_qubits))
Kemudian dapatkan coupling map-nya
coupling_graph = backend.coupling_map.graph.to_undirected(multigraph=False)
# Get unidirectional coupling map
one_dir_coupling_map = coupling_graph.edge_list()
Agar bisa melakukan benchmarking pada sebanyak mungkin Gate dua-qubit secara bersamaan, kita pisahkan coupling map menjadi sebuah layered_coupling_map. Objek ini berisi daftar lapisan di mana setiap lapisan adalah daftar edge yang memungkinkan Gate dua-qubit dieksekusi secara bersamaan. Ini juga disebut edge coloring dari coupling map.
# Get layered coupling map
edge_coloring = rustworkx.graph_bipartite_edge_color(coupling_graph)
layered_coupling_map = defaultdict(list)
for edge_idx, color in edge_coloring.items():
layered_coupling_map[color].append(
coupling_graph.get_edge_endpoints_by_index(edge_idx)
)
layered_coupling_map = [
sorted(layered_coupling_map[i])
for i in sorted(layered_coupling_map.keys())
]
Eksperimen karakterisasiβ
Serangkaian eksperimen digunakan untuk mengkarakterisasi properti utama dari qubit dalam sebuah QPU. Properti tersebut meliputi , , readout error, serta error Gate satu-qubit dan dua-qubit. Kita akan merangkas secara singkat apa arti properti-properti ini dan merujuk ke eksperimen dalam paket qiskit-experiments yang digunakan untuk mengkarakterisasinya.
T1β
adalah waktu karakteristik yang dibutuhkan qubit yang tereksitasi untuk kembali ke ground state akibat proses dekoherensi amplitude-damping. Dalam eksperimen , kita mengukur qubit yang tereksitasi setelah suatu penundaan. Semakin besar waktu penundaannya, semakin besar kemungkinan qubit jatuh ke ground state. Tujuan eksperimen ini adalah mengkarakterisasi laju peluruhan qubit menuju ground state.
T2β
merepresentasikan jumlah waktu yang dibutuhkan proyeksi vektor Bloch qubit tunggal pada bidang XY untuk turun hingga sekitar 37% () dari amplitudo awalnya akibat proses dekoherensi dephasing. Dalam eksperimen Hahn Echo, kita dapat memperkirakan laju peluruhan ini.
Karakterisasi error state preparation and measurement (SPAM)β
Dalam eksperimen karakterisasi SPAM error, qubit dipersiapkan dalam keadaan tertentu ( atau ) lalu diukur. Probabilitas mengukur keadaan yang berbeda dari yang dipersiapkan memberikan probabilitas terjadinya error.
Randomized benchmarking satu-qubit dan dua-qubitβ
Randomized benchmarking (RB) adalah protokol yang populer untuk mengkarakterisasi error rate prosesor kuantum. Eksperimen RB terdiri dari pembuatan Circuit Clifford acak pada qubit yang diberikan sedemikian rupa sehingga unitary yang dihitung oleh Circuit tersebut adalah identitas. Setelah menjalankan Circuit, jumlah shot yang menghasilkan error (yaitu, output yang berbeda dari ground state) dihitung, dan dari data ini dapat disimpulkan estimasi error untuk perangkat kuantum dengan menghitung Error Per Clifford.
# Create T1 experiments on all qubit in parallel
t1_exp = ParallelExperiment(
[
T1(
physical_qubits=[qubit],
delays=[1e-6, 20e-6, 40e-6, 80e-6, 200e-6, 400e-6],
)
for qubit in qubits
],
backend,
analysis=None,
)
# Create T2-Hahn experiments on all qubit in parallel
t2_exp = ParallelExperiment(
[
T2Hahn(
physical_qubits=[qubit],
delays=[1e-6, 20e-6, 40e-6, 80e-6, 200e-6, 400e-6],
)
for qubit in qubits
],
backend,
analysis=None,
)
# Create readout experiments on all qubit in parallel
readout_exp = LocalReadoutError(qubits)
# Create single-qubit RB experiments on all qubit in parallel
singleq_rb_exp = ParallelExperiment(
[
StandardRB(
physical_qubits=[qubit], lengths=[10, 100, 500], num_samples=10
)
for qubit in qubits
],
backend,
analysis=None,
)
# Create two-qubit RB experiments on the three layers of disjoint edges of the heavy-hex
twoq_rb_exp_batched = BatchExperiment(
[
ParallelExperiment(
[
StandardRB(
physical_qubits=pair,
lengths=[10, 50, 100],
num_samples=10,
)
for pair in layer
],
backend,
analysis=None,
)
for layer in layered_coupling_map
],
backend,
flatten_results=True,
analysis=None,
)
Properti QPU dari waktu ke waktuβ
Dengan melihat properti QPU yang dilaporkan dari waktu ke waktu (kita akan melihat satu minggu di bawah ini), kita melihat bagaimana properti tersebut dapat berfluktuasi dalam skala satu hari. Fluktuasi kecil pun bisa terjadi dalam sehari. Dalam skenario ini, properti yang dilaporkan (diperbarui sekali per hari) tidak akan secara akurat mencerminkan status QPU saat ini. Selain itu, jika sebuah job di-transpile secara lokal (menggunakan properti yang dilaporkan saat ini) lalu dikirimkan tetapi baru dieksekusi beberapa saat kemudian (menit atau hari), ada risiko bahwa properti yang digunakan untuk pemilihan qubit pada langkah transpilasi sudah kedaluwarsa. Hal ini menyoroti pentingnya memiliki informasi terkini tentang QPU pada saat eksekusi. Pertama, mari kita ambil properti selama rentang waktu tertentu.
instruction_2q_name = "cz" # set the name of the default 2q of the device
errors_list = []
for day_idx in range(10, 17):
calibrations_time = datetime(
year=2025, month=8, day=day_idx, hour=0, minute=0, second=0
)
targer_hist = backend.target_history(datetime=calibrations_time)
t1_dict, t2_dict = {}, {}
for qubit in range(targer_hist.num_qubits):
t1_dict[qubit] = targer_hist.qubit_properties[qubit].t1
t2_dict[qubit] = targer_hist.qubit_properties[qubit].t2
errors_dict = {
"1q": targer_hist["sx"],
"2q": targer_hist[f"{instruction_2q_name}"],
"spam": targer_hist["measure"],
"t1": t1_dict,
"t2": t2_dict,
}
errors_list.append(errors_dict)
Kemudian, mari kita plot nilainya
fig, axs = plt.subplots(5, 1, figsize=(10, 20), sharex=False)
# Plot for T1 values
for qubit in range(targer_hist.num_qubits):
t1s = []
for errors_dict in errors_list:
t1_dict = errors_dict["t1"]
try:
t1s.append(t1_dict[qubit] / 1e-6)
except:
print(f"missing t1 data for qubit {qubit}")
axs[0].plot(t1s)
axs[0].set_title("T1")
axs[0].set_ylabel(r"Time ($\mu s$)")
axs[0].set_xlabel("Days")
# Plot for T2 values
for qubit in range(targer_hist.num_qubits):
t2s = []
for errors_dict in errors_list:
t2_dict = errors_dict["t2"]
try:
t2s.append(t2_dict[qubit] / 1e-6)
except:
print(f"missing t2 data for qubit {qubit}")
axs[1].plot(t2s)
axs[1].set_title("T2")
axs[1].set_ylabel(r"Time ($\mu s$)")
axs[1].set_xlabel("Days")
# Plot SPAM values
for qubit in range(targer_hist.num_qubits):
spams = []
for errors_dict in errors_list:
spam_dict = errors_dict["spam"]
spams.append(spam_dict[tuple([qubit])].error)
axs[2].plot(spams)
axs[2].set_title("SPAM Errors")
axs[2].set_ylabel("Error Rate")
axs[2].set_xlabel("Days")
# Plot 1Q Gate Errors
for qubit in range(targer_hist.num_qubits):
oneq_gates = []
for errors_dict in errors_list:
oneq_gate_dict = errors_dict["1q"]
oneq_gates.append(oneq_gate_dict[tuple([qubit])].error)
axs[3].plot(oneq_gates)
axs[3].set_title("1Q Gate Errors")
axs[3].set_ylabel("Error Rate")
axs[3].set_xlabel("Days")
# Plot 2Q Gate Errors
for pair in one_dir_coupling_map:
twoq_gates = []
for errors_dict in errors_list:
twoq_gate_dict = errors_dict["2q"]
twoq_gates.append(twoq_gate_dict[pair].error)
axs[4].plot(twoq_gates)
axs[4].set_title("2Q Gate Errors")
axs[4].set_ylabel("Error Rate")
axs[4].set_xlabel("Days")
plt.subplots_adjust(hspace=0.5)
plt.show()

Kamu bisa melihat bahwa selama beberapa hari, sebagian properti qubit bisa berubah cukup signifikan. Hal ini menyoroti pentingnya memiliki informasi terkini tentang status QPU agar kita bisa memilih qubit dengan performa terbaik untuk sebuah eksperimen.
Langkah 2: Optimalkan masalah untuk eksekusi pada perangkat keras kuantumβ
Tidak ada optimasi Circuit atau operator yang dilakukan dalam tutorial ini.
Langkah 3: Eksekusi menggunakan primitif Qiskitβ
Eksekusi Circuit kuantum dengan pemilihan Qubit defaultβ
Sebagai hasil referensi performa, kita akan mengeksekusi Circuit kuantum pada QPU menggunakan Qubit default, yaitu Qubit yang dipilih berdasarkan properti Backend yang dilaporkan. Kita akan menggunakan optimization_level = 3. Pengaturan ini mencakup optimasi transpilasi paling canggih dan menggunakan properti target (seperti error operasi) untuk memilih Qubit berkinerja terbaik untuk eksekusi.
pm = generate_preset_pass_manager(target=backend.target, optimization_level=3)
isa_circuits = pm.run(circuits)
initial_qubits = [
[
idx
for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()
if qb._register.name != "ancilla"
]
for circuit in isa_circuits
]
Eksekusi Circuit kuantum dengan pemilihan Qubit secara real-timeβ
Di bagian ini, kita akan menyelidiki pentingnya memiliki informasi terkini tentang properti Qubit pada QPU untuk hasil yang optimal. Pertama, kita akan menjalankan serangkaian eksperimen karakterisasi QPU secara lengkap (, , SPAM, RB satu Qubit, dan RB dua Qubit), yang kemudian bisa kita gunakan untuk memperbarui properti Backend. Ini memungkinkan pass manager memilih Qubit untuk eksekusi berdasarkan informasi segar tentang QPU, yang berpotensi meningkatkan performa eksekusi. Kedua, kita mengeksekusi Circuit Bell pair dan membandingkan fidelitas yang diperoleh setelah memilih Qubit dengan properti QPU yang diperbarui dibandingkan fidelitas yang kita peroleh sebelumnya saat menggunakan properti yang dilaporkan secara default untuk pemilihan Qubit.
Perlu diperhatikan bahwa beberapa eksperimen karakterisasi mungkin gagal ketika rutinitas fitting tidak dapat menyesuaikan kurva dengan data yang diukur. Jika kamu melihat peringatan dari eksperimen-eksperimen ini, periksa untuk memahami karakterisasi mana yang gagal pada Qubit mana, dan coba sesuaikan parameter eksperimen (seperti waktu untuk , , atau panjang jumlah eksperimen RB).
# Prepare characterization experiments
batches = [t1_exp, t2_exp, readout_exp, singleq_rb_exp, twoq_rb_exp_batched]
batches_exp = BatchExperiment(batches, backend) # , analysis=None)
run_options = {"shots": 1e3, "dynamic": False}
with Session(backend=backend) as session:
sampler = SamplerV2(mode=session)
# Run characterization experiments
batches_exp_data = batches_exp.run(
sampler=sampler, **run_options
).block_for_results()
EPG_sx_result_list = batches_exp_data.analysis_results("EPG_sx")
EPG_sx_result_q_indices = [
result.device_components.index for result in EPG_sx_result_list
]
EPG_x_result_list = batches_exp_data.analysis_results("EPG_x")
EPG_x_result_q_indices = [
result.device_components.index for result in EPG_x_result_list
]
T1_result_list = batches_exp_data.analysis_results("T1")
T1_result_q_indices = [
result.device_components.index for result in T1_result_list
]
T2_result_list = batches_exp_data.analysis_results("T2")
T2_result_q_indices = [
result.device_components.index for result in T2_result_list
]
Readout_result_list = batches_exp_data.analysis_results(
"Local Readout Mitigator"
)
EPG_2q_result_list = batches_exp_data.analysis_results(
f"EPG_{instruction_2q_name}"
)
# Update target properties
target = copy.deepcopy(backend.target)
for i in range(target.num_qubits - 1):
qarg = (i,)
if qarg in EPG_sx_result_q_indices:
target.update_instruction_properties(
instruction="sx",
qargs=qarg,
properties=InstructionProperties(
error=EPG_sx_result_list[i].value.nominal_value
),
)
if qarg in EPG_x_result_q_indices:
target.update_instruction_properties(
instruction="x",
qargs=qarg,
properties=InstructionProperties(
error=EPG_x_result_list[i].value.nominal_value
),
)
err_mat = Readout_result_list.value.assignment_matrix(i)
readout_assignment_error = (
err_mat[0, 1] + err_mat[1, 0]
) / 2 # average readout error
target.update_instruction_properties(
instruction="measure",
qargs=qarg,
properties=InstructionProperties(error=readout_assignment_error),
)
if qarg in T1_result_q_indices:
target.qubit_properties[i].t1 = T1_result_list[
i
].value.nominal_value
if qarg in T2_result_q_indices:
target.qubit_properties[i].t2 = T2_result_list[
i
].value.nominal_value
for pair_idx, pair in enumerate(one_dir_coupling_map):
qarg = tuple(pair)
try:
target.update_instruction_properties(
instruction=instruction_2q_name,
qargs=qarg,
properties=InstructionProperties(
error=EPG_2q_result_list[pair_idx].value.nominal_value
),
)
except:
target.update_instruction_properties(
instruction=instruction_2q_name,
qargs=qarg[::-1],
properties=InstructionProperties(
error=EPG_2q_result_list[pair_idx].value.nominal_value
),
)
# transpile circuits to updated target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
isa_circuit_updated = pm.run(circuits)
updated_qubits = [
[
idx
for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()
if qb._register.name != "ancilla"
]
for circuit in isa_circuit_updated
]
n_trials = 3 # run multiple trials to see variations
# interleave circuits
interleaved_circuits = []
for original_circuit, updated_circuit in zip(
isa_circuits, isa_circuit_updated
):
interleaved_circuits.append(original_circuit)
interleaved_circuits.append(updated_circuit)
# Run circuits
# Set simple error suppression/mitigation options
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XY4"
job_interleaved = sampler.run(interleaved_circuits * n_trials)
Langkah 4: Pasca-proses dan kembalikan hasil dalam format klasik yang diinginkanβ
Terakhir, mari kita bandingkan fidelitas Bell state yang diperoleh dalam dua pengaturan berbeda:
original, yaitu dengan Qubit default yang dipilih oleh Transpiler berdasarkan properti Backend yang dilaporkan.updated, yaitu dengan Qubit yang dipilih berdasarkan properti Backend yang diperbarui setelah eksperimen karakterisasi dijalankan.
results = job_interleaved.result()
all_fidelity_list, all_fidelity_updated_list = [], []
for exp_idx in range(n_trials):
fidelity_list, fidelity_updated_list = [], []
for idx, num_qubits in enumerate(num_qubits_list):
pub_result_original = results[
2 * exp_idx * len(num_qubits_list) + 2 * idx
]
pub_result_updated = results[
2 * exp_idx * len(num_qubits_list) + 2 * idx + 1
]
fid = hellinger_fidelity(
ideal_dist, pub_result_original.data.c.get_counts()
)
fidelity_list.append(fid)
fid_up = hellinger_fidelity(
ideal_dist, pub_result_updated.data.c.get_counts()
)
fidelity_updated_list.append(fid_up)
all_fidelity_list.append(fidelity_list)
all_fidelity_updated_list.append(fidelity_updated_list)
plt.figure(figsize=(8, 6))
plt.errorbar(
num_qubits_list,
np.mean(all_fidelity_list, axis=0),
yerr=np.std(all_fidelity_list, axis=0),
fmt="o-.",
label="original",
color="b",
)
# plt.plot(num_qubits_list, fidelity_list, '-.')
plt.errorbar(
num_qubits_list,
np.mean(all_fidelity_updated_list, axis=0),
yerr=np.std(all_fidelity_updated_list, axis=0),
fmt="o-.",
label="updated",
color="r",
)
# plt.plot(num_qubits_list, fidelity_updated_list, '-.')
plt.xlabel("Chain length")
plt.xticks(num_qubits_list)
plt.ylabel("Fidelity")
plt.title("Bell pair fidelity at the edge of N-qubits chain")
plt.legend()
plt.grid(
alpha=0.2,
linestyle="-.",
)
plt.show()

Tidak semua eksekusi akan menunjukkan peningkatan performa berkat karakterisasi real-time β dan seiring bertambahnya panjang rantai, sehingga semakin sedikit kebebasan untuk memilih Qubit fisik, pentingnya informasi perangkat yang diperbarui menjadi semakin berkurang. Namun, sangat baik untuk mengumpulkan data segar tentang properti perangkat demi memahami performanya. Sesekali, sistem dua level yang bersifat sementara dapat memengaruhi performa beberapa Qubit. Data real-time dapat memberi tahu kita kapan kejadian seperti itu terjadi dan membantu kita menghindari kegagalan eksperimen dalam kasus tersebut.
Coba terapkan metode ini pada eksekusi kamu dan tentukan seberapa besar manfaat yang kamu dapatkan! Kamu juga bisa mencoba melihat seberapa besar peningkatan yang kamu peroleh dari Backend yang berbeda.
Survei tutorialβ
Silakan isi survei singkat ini untuk memberikan masukan tentang tutorial ini. Wawasan kamu akan membantu kami meningkatkan konten dan pengalaman pengguna kami.
Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.