Simulasi 2D tilted-field Ising dengan fungsi QESEM
Qiskit Functions adalah fitur eksperimental yang hanya tersedia untuk pengguna IBM Quantum® Premium Plan, Flex Plan, dan On-Prem (via IBM Quantum Platform API) Plan. Fitur ini berada dalam status rilis pratinjau dan dapat berubah sewaktu-waktu.
Estimasi penggunaan: 20 menit pada prosesor Heron r2. (CATATAN: Ini hanya perkiraan. Waktu aktual kamu mungkin berbeda.)
Latar Belakang​
Tutorial ini menunjukkan cara menggunakan QESEM, Qiskit Function dari Qedma, untuk mensimulasikan dinamika model spin kuantum kanonik, yaitu model Ising medan miring 2D (TFI) dengan sudut non-Clifford:
di mana menandakan tetangga terdekat pada sebuah kisi. Mensimulasikan evolusi waktu sistem kuantum banyak-benda adalah tugas yang secara komputasi sangat berat bagi komputer klasik. Komputer kuantum, sebaliknya, secara alami dirancang untuk menyelesaikan tugas ini secara efisien. Model TFI, khususnya, telah menjadi tolok ukur populer pada perangkat keras kuantum karena perilaku fisiknya yang kaya dan implementasinya yang ramah perangkat keras.
Daripada mensimulasikan dinamika waktu kontinu, kita menggunakan model kicked Ising yang berkaitan erat. Dinamika tersebut dapat diekspresikan secara tepat sebagai sirkuit kuantum periodik, di mana setiap langkah evolusi terdiri dari tiga lapisan gate dua Qubit fraksional , diselingi oleh lapisan gate satu Qubit dan .
Kita akan menggunakan sudut-sudut generik yang menantang baik untuk simulasi klasik maupun mitigasi kesalahan. Secara khusus, kita memilih , , dan , menempatkan model ini jauh dari titik integrable mana pun.
Dalam tutorial ini kita akan melakukan hal-hal berikut:
- Memperkirakan waktu QPU yang diharapkan untuk mitigasi kesalahan penuh menggunakan fitur estimasi waktu analitik dan empiris dari QESEM.
- Membangun dan mensimulasikan Circuit model Ising medan miring 2D menggunakan tata letak Qubit yang terinspirasi perangkat keras dan lapisan gate.
- Memvisualisasikan konektivitas Qubit perangkat dan subgraf yang dipilih untuk eksperimen kamu.
- Mendemonstrasikan penggunaan operator backpropagation (OBP) untuk mengurangi kedalaman Circuit. Teknik ini memangkas operasi dari akhir Circuit dengan biaya lebih banyak pengukuran operator.
- Melakukan mitigasi kesalahan (EM) yang tidak bias untuk beberapa observable secara bersamaan menggunakan QESEM, membandingkan hasil ideal, berderau, dan yang telah dimitigasi.
- Menganalisis dan memplot dampak mitigasi kesalahan terhadap magnetisasi di berbagai kedalaman Circuit.
Catatan: OBP pada umumnya akan mengembalikan sekumpulan observable yang mungkin tidak saling komutasi. QESEM secara otomatis mengoptimalkan basis pengukuran ketika observable target mengandung suku-suku yang tidak saling komutasi. QESEM menghasilkan kandidat set basis pengukuran menggunakan beberapa algoritma heuristik dan memilih set yang meminimalkan jumlah basis yang berbeda. Artinya, QESEM mengelompokkan observable yang kompatibel ke dalam basis yang sama untuk mengurangi jumlah total konfigurasi pengukuran yang diperlukan, sehingga meningkatkan efisiensi.
Tentang QESEM​
QESEM adalah perangkat lunak berbasis karakterisasi yang andal dan akurat tinggi, yang mengimplementasikan mitigasi kesalahan kuasi-probabilistik yang efisien dan tidak bias. Perangkat lunak ini dirancang untuk memitigasi kesalahan pada Circuit kuantum generik dan bersifat agnostik terhadap aplikasi. QESEM telah divalidasi di berbagai platform perangkat keras, termasuk eksperimen skala utilitas pada perangkat IBM® Eagle dan Heron. Tahapan alur kerja QESEM adalah sebagai berikut:
- Karakterisasi perangkat — memetakan fidelitas gate dan mengidentifikasi kesalahan koheren, memberikan data kalibrasi waktu nyata. Tahap ini memastikan mitigasi memanfaatkan operasi dengan fidelitas tertinggi yang tersedia.
- Transpilasi sadar-noise — menghasilkan dan mengevaluasi pemetaan Qubit alternatif, set operasi, dan basis pengukuran, memilih varian yang meminimalkan estimasi waktu QPU, dengan paralelisasi opsional untuk mempercepat pengumpulan data.
- Penekanan kesalahan — mendefinisikan ulang gate native, menerapkan Pauli twirling, dan mengoptimalkan kontrol level pulsa (pada platform yang didukung) untuk meningkatkan fidelitas.
- Karakterisasi Circuit — membangun model kesalahan lokal yang disesuaikan dan menyesuaikannya dengan pengukuran QPU untuk mengkuantifikasi noise residual.
- Mitigasi kesalahan — membangun dekomposisi kuasi-probabilistik multi-tipe, dan melakukan sampling dari dekomposisi tersebut dalam proses adaptif yang meminimalkan waktu QPU mitigasi dan sensitivitas terhadap fluktuasi perangkat keras, sehingga mencapai akurasi tinggi pada volume Circuit yang besar.
Untuk informasi lebih lanjut tentang QESEM dan eksperimen skala utilitas dari model ini pada subgraf berkonektivitas tinggi 103-Qubit dari geometri heavy-hex native ibm_marrakesh, lihat Reliable high-accuracy error mitigation for utility-scale quantum circuits.

Persyaratan​
Instal paket Python berikut sebelum menjalankan notebook:
- Qiskit SDK v2.0.0 atau lebih baru (
pip install qiskit) - Qiskit Runtime v0.40.0 atau lebih baru (
pip install qiskit-ibm-runtime) - Qiskit Functions Catalog v0.8.0 atau lebih baru (
pip install qiskit-ibm-catalog) - Addon OBP Qiskit v0.3.0 atau lebih baru (
pip install qiskit-addon-obp) - Addon Qiskit Utils v0.1.1 atau lebih baru (
pip install qiskit-addon-utils) - Simulator Qiskit Aer v0.17.1 atau lebih baru (
pip install qiskit-aer) - Matplotlib v3.10.3 atau lebih baru (
pip install matplotlib)
Pengaturan​
Pertama, impor library yang diperlukan:
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-obp qiskit-addon-utils qiskit-aer qiskit-ibm-catalog qiskit-ibm-runtime
%matplotlib inline
from typing import Sequence
import matplotlib.pyplot as plt
import numpy as np
import qiskit
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_catalog import QiskitFunctionsCatalog
from qiskit_aer import AerSimulator
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types
from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.simplify import OperatorBudget
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.visualization import (
plot_gate_map,
)
Selanjutnya, lakukan autentikasi menggunakan API key kamu dari dashboard IBM Quantum Platform. Kemudian, pilih Qiskit Function sebagai berikut. (Perhatikan bahwa demi keamanan, sebaiknya simpan kredensial akun kamu ke lingkungan lokal kamu, jika kamu menggunakan mesin tepercaya, agar kamu tidak perlu memasukkan API key setiap kali melakukan autentikasi.)
# Paste here your instance and token strings
instance = "YOUR_INSTANCE"
token = "YOUR_TOKEN"
channel = "ibm_quantum_platform"
catalog = QiskitFunctionsCatalog(
channel=channel, token=token, instance=instance
)
qesem_function = catalog.load("qedma/qesem")
Langkah 1: Memetakan input klasik ke masalah kuantum​
Kita mulai dengan mendefinisikan fungsi yang membuat Circuit Trotter:
def trotter_circuit_from_layers(
steps: int,
theta_x: float,
theta_z: float,
theta_zz: float,
layers: Sequence[Sequence[tuple[int, int]]],
init_state: str | None = None,
) -> qiskit.QuantumCircuit:
"""
Generates an ising trotter circuit
:param steps: trotter steps
:param theta_x: RX angle
:param theta_z: RZ angle
:param theta_zz: RZZ angle
:param layers: list of layers (can be list of layers in device)
:param init_state: Initial state to prepare. If None, will not prepare any state. If "+", will
add Hadamard gates to all qubits.
:return: QuantumCircuit
"""
qubits = sorted({i for layer in layers for edge in layer for i in edge})
circ = qiskit.QuantumCircuit(max(qubits) + 1)
if init_state == "+":
print("init_state = +")
for q in qubits:
circ.h(q)
for _ in range(steps):
for q in qubits:
circ.rx(theta_x, q)
circ.rz(theta_z, q)
for layer in layers:
for edge in layer:
circ.rzz(theta_zz, *edge)
circ.barrier(qubits)
return circ
Selanjutnya kita membuat fungsi untuk menghitung nilai ekspektasi ideal menggunakan AerSimulator.
Perlu diingat bahwa untuk Circuit yang besar (30 Qubit atau lebih), kami merekomendasikan penggunaan nilai yang telah dihitung sebelumnya dari simulasi belief-propagation (BP) PEPS. Kode ini menyertakan nilai yang telah dihitung sebelumnya untuk 35 Qubit sebagai contoh, berdasarkan pendekatan BP untuk mengevolusi jaringan tensor PEPS yang diperkenalkan dalam makalah ini (yang kita sebut PEPS-BP), menggunakan paket Python jaringan tensor quimb.
def calculate_ideal_evs(circ, obs, num_qubits, step):
# Predefined results for large circuits - calculated using bppeps for 3, 5, 7, 9 trotter steps
predefined_35 = [
0.79537,
0.78653,
0.79699,
]
if num_qubits == 35:
print(
"Using precalculated ideal values for large circuits calculated with belief propagation PEPS. Currently only for 35 qubits."
)
return predefined_35[step]
else:
simulator = AerSimulator()
# Use Estimator primitive to get expectation value
estimator = Estimator(simulator)
sim_result = estimator.run([(circ, [obs])], precision=0.0001).result()
# Extracting the result
ideal_values = sim_result[0].data.evs[0]
return ideal_values
Kita menggunakan pemetaan lapisan berbasis perangkat keras yang diambil dari perangkat Heron, dari mana kita memotong lapisan-lapisan sesuai dengan jumlah Qubit yang ingin kita simulasikan. Kita mendefinisikan subgraf untuk 10, 21, 28, dan 35 Qubit yang mempertahankan struktur 2D (silakan ubah ke subgraf favorit kamu):
LAYERS_HERON_R2 = [ # the full set of hardware layers for Heron r2
[
(2, 3),
(6, 7),
(10, 11),
(14, 15),
(20, 21),
(16, 23),
(24, 25),
(17, 27),
(28, 29),
(18, 31),
(32, 33),
(19, 35),
(36, 41),
(42, 43),
(37, 45),
(46, 47),
(38, 49),
(50, 51),
(39, 53),
(60, 61),
(56, 63),
(64, 65),
(57, 67),
(68, 69),
(58, 71),
(72, 73),
(59, 75),
(76, 81),
(82, 83),
(77, 85),
(86, 87),
(78, 89),
(90, 91),
(79, 93),
(94, 95),
(100, 101),
(96, 103),
(104, 105),
(97, 107),
(108, 109),
(98, 111),
(112, 113),
(99, 115),
(116, 121),
(122, 123),
(117, 125),
(126, 127),
(118, 129),
(130, 131),
(119, 133),
(134, 135),
(140, 141),
(136, 143),
(144, 145),
(137, 147),
(148, 149),
(138, 151),
(152, 153),
(139, 155),
],
[
(1, 2),
(3, 4),
(5, 6),
(7, 8),
(9, 10),
(11, 12),
(13, 14),
(21, 22),
(23, 24),
(25, 26),
(27, 28),
(29, 30),
(31, 32),
(33, 34),
(40, 41),
(43, 44),
(45, 46),
(47, 48),
(49, 50),
(51, 52),
(53, 54),
(55, 59),
(61, 62),
(63, 64),
(65, 66),
(67, 68),
(69, 70),
(71, 72),
(73, 74),
(80, 81),
(83, 84),
(85, 86),
(87, 88),
(89, 90),
(91, 92),
(93, 94),
(95, 99),
(101, 102),
(103, 104),
(105, 106),
(107, 108),
(109, 110),
(111, 112),
(113, 114),
(120, 121),
(123, 124),
(125, 126),
(127, 128),
(129, 130),
(131, 132),
(133, 134),
(135, 139),
(141, 142),
(143, 144),
(145, 146),
(147, 148),
(149, 150),
(151, 152),
(153, 154),
],
[
(3, 16),
(7, 17),
(11, 18),
(22, 23),
(26, 27),
(30, 31),
(34, 35),
(21, 36),
(25, 37),
(29, 38),
(33, 39),
(41, 42),
(44, 45),
(48, 49),
(52, 53),
(43, 56),
(47, 57),
(51, 58),
(62, 63),
(66, 67),
(70, 71),
(74, 75),
(61, 76),
(65, 77),
(69, 78),
(73, 79),
(81, 82),
(84, 85),
(88, 89),
(92, 93),
(83, 96),
(87, 97),
(91, 98),
(102, 103),
(106, 107),
(110, 111),
(114, 115),
(101, 116),
(105, 117),
(109, 118),
(113, 119),
(121, 122),
(124, 125),
(128, 129),
(132, 133),
(123, 136),
(127, 137),
(131, 138),
(142, 143),
(146, 147),
(150, 151),
(154, 155),
(0, 1),
(4, 5),
(8, 9),
(12, 13),
(54, 55),
(15, 19),
],
]
subgraphs = { # the subgraphs for the different qubit counts such that it's 2D
10: list(range(22, 29)) + [16, 17, 37],
21: list(range(3, 12)) + list(range(23, 32)) + [16, 17, 18],
28: list(range(3, 12))
+ list(range(23, 32))
+ list(range(45, 50))
+ [16, 17, 18, 37, 38],
35: list(range(3, 12))
+ list(range(21, 32))
+ list(range(41, 50))
+ [16, 17, 18, 36, 37, 38],
42: list(range(3, 12))
+ list(range(21, 32))
+ list(range(41, 50))
+ list(range(63, 68))
+ [16, 17, 18, 36, 37, 38, 56, 57],
}
n_qubits = 35 # 21, 28, 35, 42
layers = [
[
edge
for edge in layer
if edge[0] in subgraphs[n_qubits] and edge[1] in subgraphs[n_qubits]
]
for layer in LAYERS_HERON_R2
]
print(layers)
[[(6, 7), (10, 11), (16, 23), (24, 25), (17, 27), (28, 29), (18, 31), (36, 41), (42, 43), (37, 45), (46, 47), (38, 49)], [(3, 4), (5, 6), (7, 8), (9, 10), (21, 22), (23, 24), (25, 26), (27, 28), (29, 30), (43, 44), (45, 46), (47, 48)], [(3, 16), (7, 17), (11, 18), (22, 23), (26, 27), (30, 31), (21, 36), (25, 37), (29, 38), (41, 42), (44, 45), (48, 49), (4, 5), (8, 9)]]
Sekarang kita memvisualisasikan tata letak Qubit pada perangkat Heron untuk subgraf yang dipilih:
service = QiskitRuntimeService(
channel=channel,
token=token,
instance=instance,
)
backend = service.backend("ibm_fez") # or any available device
selected_qubits = subgraphs[n_qubits]
num_qubits = backend.configuration().num_qubits
qubit_color = [
"#ff7f0e" if i in selected_qubits else "#d3d3d3"
for i in range(num_qubits)
]
plot_gate_map(
backend=backend,
figsize=(15, 10),
qubit_color=qubit_color,
)
plt.show()

Perhatikan bahwa konektivitas tata letak Qubit yang dipilih tidak harus linear, dan dapat mencakup wilayah yang luas dari perangkat Heron tergantung pada jumlah Qubit yang dipilih.
Sekarang kita menghasilkan Circuit Trotter dan observable magnetisasi rata-rata untuk jumlah Qubit dan parameter yang dipilih:
# Chosen parameters:
theta_x = 0.53
theta_z = 0.1
theta_zz = 1.0
steps = 9
circ = trotter_circuit_from_layers(steps, theta_x, theta_z, theta_zz, layers)
print(
f"Circuit 2q layers: {circ.depth(filter_function=lambda instr: len(instr.qubits) == 2)}"
)
print("\nCircuit structure:")
circ.draw("mpl", scale=0.8, fold=-1, idle_wires=False)
plt.show()
observable = qiskit.quantum_info.SparsePauliOp.from_sparse_list(
[("Z", [q], 1 / n_qubits) for q in subgraphs[n_qubits]],
np.max(subgraphs[n_qubits]) + 1,
) # Average magnetization observable
print(observable)
obs_list = [observable]
Circuit 2q layers: 27
Circuit structure:

SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j,
0.02857143+0.j, 0.02857143+0.j, 0.02857143+0.j])
Langkah 2: Optimalkan masalah untuk eksekusi pada perangkat keras kuantum​
Estimasi waktu QPU dengan dan tanpa OBP​
Pengguna umumnya ingin mengetahui berapa banyak waktu QPU yang dibutuhkan untuk eksperimen mereka. Namun, ini dianggap sebagai masalah yang sulit bagi komputer klasik.
QESEM menawarkan dua mode estimasi waktu untuk memberi tahu pengguna tentang kelayakan eksperimen mereka:
- Estimasi waktu analitis - memberikan perkiraan yang sangat kasar dan tidak membutuhkan waktu QPU. Ini dapat digunakan untuk menguji apakah suatu transpilation pass berpotensi mengurangi waktu QPU.
- Estimasi waktu empiris (didemonstrasikan di sini) - memberikan perkiraan yang cukup baik dan menggunakan beberapa menit waktu QPU.
Dalam kedua kasus, QESEM menghasilkan estimasi waktu untuk mencapai presisi yang diperlukan untuk semua observable.
run_on_real_hardware = True
precision = 0.05
if run_on_real_hardware:
backend_name = "ibm_fez"
else:
backend_name = "fake_fez"
# Start a job for empirical time estimation
estimation_job_wo_obp = qesem_function.run(
pubs=[(circ, obs_list)],
instance=instance,
backend_name=backend_name, # E.g. "ibm_brisbane"
options={
"estimate_time_only": "empirical", # "empirical" - gets actual time estimates without running full mitigation
"max_execution_time": 120, # Limits the QPU time, specified in seconds.
"default_precision": precision,
},
)
print(estimation_job_wo_obp.job_id)
print(estimation_job_wo_obp.status())
17d3828e-9fdb-482e-8e9b-392f3eefe313
DONE
# Get the result object (blocking method). Use job.status() in a loop for non-blocking.
# This takes 1-3 minutes
result = estimation_job_wo_obp.result()
print(
f"Empirical time estimation (sec): {result[0].metadata['time_estimation_sec']}"
)
Empirical time estimation (sec): 1200
Sekarang kita akan menggunakan operator backpropagation (OBP). (Lihat panduan OBP untuk detail lebih lanjut tentang addon Qiskit OBP.) Kita akan membuat fungsi yang menghasilkan potongan Circuit untuk backpropagation:
def run_backpropagation(circ_vec, observable, steps_vec, max_qwc_groups=8):
"""
Runs backpropagation for a list of circuits and observables.
Returns lists of backpropagated circuits and observables.
"""
op_budget = OperatorBudget(max_qwc_groups=max_qwc_groups)
bp_circuit_vec = []
bp_observable_vec = []
for i, circ in enumerate(circ_vec):
slices = slice_by_gate_types(circ)
bp_observable, remaining_slices, metadata = backpropagate(
observable,
slices,
operator_budget=op_budget,
)
bp_circuit = combine_slices(remaining_slices, include_barriers=True)
bp_circuit_vec.append(bp_circuit)
bp_observable_vec.append(bp_observable)
print(f"n.o. steps: {steps_vec[i]}")
print(f"Backpropagated {metadata.num_backpropagated_slices} slices.")
print(
f"New observable has {len(bp_observable.paulis)} terms, which can be combined into "
f"{len(bp_observable.group_commuting(qubit_wise=True))} groups.\n"
f"After truncation, the error in our observable is bounded by {metadata.accumulated_error(0):.3e}"
)
print("-----------------")
return bp_circuit_vec, bp_observable_vec
Kita memanggil fungsinya:
bp_circ_vec, bp_obs_vec = run_backpropagation([circ], observable, [steps])
n.o. steps: 9
Backpropagated 11 slices.
New observable has 363 terms, which can be combined into 4 groups.
After truncation, the error in our observable is bounded by 0.000e+00
-----------------
print("The remaining circuit after backpropagation looks as follows:")
bp_circ_vec[-1].draw("mpl", scale=0.8, fold=-1, idle_wires=False)
None
The remaining circuit after backpropagation looks as follows:

Kita bisa melihat bahwa backpropagation mengurangi dua lapisan Circuit. Sekarang setelah kita memiliki Circuit yang telah diperkecil dan observable yang telah diperluas, mari lakukan estimasi waktu untuk Circuit yang telah di-backpropagasi:
# Start a job for empirical time estimation
estimation_job_obp = qesem_function.run(
pubs=[(bp_circ_vec[-1], [bp_obs_vec[-1]])],
instance=instance,
backend_name=backend_name,
options={
"estimate_time_only": "empirical",
"max_execution_time": 120,
"default_precision": precision,
},
)
print(estimation_job_obp.job_id)
print(estimation_job_obp.status())
8bae699d-a16b-4d39-bbd9-d123fbcce55d
DONE
result_obp = estimation_job_obp.result()
print(
f"Empirical time estimation (sec): {result_obp[0].metadata['time_estimation_sec']}"
)
Empirical time estimation (sec): 900
Kita melihat bahwa OBP mengurangi biaya waktu untuk mitigasi Circuit.
Langkah 3: Eksekusi menggunakan primitif Qiskit​
Jalankan dengan Backend nyata​
Sekarang kita menjalankan eksperimen penuh pada beberapa langkah Trotter. Jumlah Qubit, presisi yang diperlukan, dan waktu QPU maksimal dapat dimodifikasi sesuai dengan sumber daya QPU yang tersedia. Perlu diingat bahwa membatasi waktu QPU maksimal akan memengaruhi presisi akhir, seperti yang akan terlihat pada plot di bawah.
Kita menganalisis empat Circuit dengan 5, 7, dan 9 langkah Trotter pada presisi 0.05, membandingkan nilai ekspektasi ideal, noisy, dan error-mitigated:
steps_vec = [5, 7, 9]
circ_vec = []
for steps in steps_vec:
circ = trotter_circuit_from_layers(
steps, theta_x, theta_z, theta_zz, layers
)
circ_vec.append(circ)
Sekali lagi, kita melakukan OBP pada setiap Circuit untuk mengurangi waktu eksekusi:
bp_circ_vec_35, bp_obs_vec_35 = run_backpropagation(
circ_vec, observable, steps_vec
)
n.o. steps: 5
Backpropagated 11 slices.
New observable has 363 terms, which can be combined into 4 groups.
After truncation, the error in our observable is bounded by 0.000e+00
-----------------
n.o. steps: 7
Backpropagated 11 slices.
New observable has 363 terms, which can be combined into 4 groups.
After truncation, the error in our observable is bounded by 0.000e+00
-----------------
n.o. steps: 9
Backpropagated 11 slices.
New observable has 363 terms, which can be combined into 4 groups.
After truncation, the error in our observable is bounded by 0.000e+00
-----------------
Sekarang kita menjalankan sekumpulan job QESEM penuh. Kita membatasi waktu eksekusi QPU maksimal untuk setiap titik demi kontrol yang lebih baik terhadap anggaran QPU.
run_on_real_hardware = True
precision = 0.05
if run_on_real_hardware:
backend_name = "ibm_marrakesh"
else:
backend_name = "fake_fez"
# Running full jobs for:
pubs_list = [
[(bp_circ_vec_35[i], bp_obs_vec_35[i])] for i in range(len(bp_obs_vec_35))
]
# Initiating multiple jobs for different lengths
job_list = []
for pubs in pubs_list:
job_obp = qesem_function.run(
pubs=pubs,
instance=instance,
backend_name=backend_name, # E.g. "ibm_brisbane"
options={
"max_execution_time": 300, # Limits the QPU time, specified in seconds.
"default_precision": 0.05,
},
)
job_list.append(job_obp)
Di sini kita memeriksa status setiap job:
for job in job_list:
print(job.status())
DONE
DONE
DONE
DONE
Langkah 4: Pasca-proses dan kembalikan hasil dalam format klasik yang diinginkan​
Ketika semua job selesai dijalankan, kita bisa membandingkan nilai ekspektasi noisy dan mitigated-nya.
ideal_values = []
noisy_values = []
error_mitigated_values = []
error_mitigated_stds = []
for i in range(len(job_list)):
job = job_list[i]
result = job.result() # Blocking - takes 3-5 minutes
noisy_results = result[0].metadata["noisy_results"]
ideal_val = calculate_ideal_evs(circ_vec[i], observable, n_qubits, i)
print("---------------------------------")
print(f"Ideal: {ideal_val}")
print(f"Noisy: {noisy_results.evs}")
print(f"QESEM: {result[0].data.evs} \u00b1 {result[0].data.stds}")
ideal_values.append(ideal_val)
noisy_values.append(noisy_results.evs)
error_mitigated_values.append(result[0].data.evs)
error_mitigated_stds.append(result[0].data.stds)
Using precalculated ideal values for large circuits calculated with belief propagation PEPS. Currently only for 35 qubits.
---------------------------------
Ideal: 0.79537
Noisy: 0.7039237951821501
QESEM: 0.7828018244130982 ± 0.013257266977728376
Using precalculated ideal values for large circuits calculated with belief propagation PEPS. Currently only for 35 qubits.
---------------------------------
Ideal: 0.78653
Noisy: 0.6478583812958806
QESEM: 0.7875259197423828 ± 0.02703045139248604
Using precalculated ideal values for large circuits calculated with belief propagation PEPS. Currently only for 35 qubits.
---------------------------------
Ideal: 0.79699
Noisy: 0.6171787879868142
QESEM: 0.6918791909168913 ± 0.0740873782039517
Terakhir, kita bisa memplot magnetisasi versus jumlah langkah. Ini merangkum manfaat menggunakan Fungsi Qiskit QESEM untuk mitigasi error bebas bias pada perangkat kuantum yang noisy.
plt.plot(steps_vec, ideal_values, "--", label="ideal")
plt.scatter(steps_vec, noisy_values, label="noisy")
plt.errorbar(
steps_vec,
error_mitigated_values,
yerr=error_mitigated_stds,
fmt="o",
capsize=5,
label="QESEM mitigation",
)
plt.legend()
plt.xlabel("n.o. steps")
plt.ylabel("Magnetization")
Text(0, 0.5, 'Magnetization')
Langkah kesembilan memiliki error bar statistik yang besar karena kita membatasi waktu QPU hingga 5 menit. Jika kamu menjalankan langkah ini selama 15 menit (seperti yang disarankan oleh estimasi waktu empiris), kamu akan mendapatkan error bar yang lebih kecil. Oleh karena itu, nilai mitigated akan menjadi lebih dekat ke nilai ideal.