Langkau ke kandungan utama

Simulasi 2D medan-condong Ising dengan fungsi QESEM

nota

Qiskit Functions ialah ciri eksperimental yang hanya tersedia untuk pengguna Pelan Premium, Pelan Flex, dan Pelan On-Prem (melalui API IBM Quantum Platform) IBM Quantum®. Ciri ini dalam status pratonton dan boleh berubah pada bila-bila masa.

Anggaran penggunaan: 20 minit pada pemproses Heron r2. (NOTA: Ini hanyalah anggaran. Masa jalan sebenar anda mungkin berbeza.)

Latar Belakang​

Tutorial ini menunjukkan cara menggunakan QESEM, Fungsi Qiskit daripada Qedma, untuk mensimulasikan dinamik model spin kuantum kanonikal, iaitu model Ising medan-condong 2D (TFI) dengan sudut bukan-Clifford:

H=J∑⟨i,j⟩ZiZj+gx∑iXi+gz∑iZi,H = J \sum_{\langle i,j \rangle} Z_i Z_j + g_x \sum_i X_i + g_z \sum_i Z_i ,

di mana ⟨i,j⟩\langle i,j \rangle merujuk kepada jiran terdekat pada kekisi. Mensimulasikan evolusi masa sistem kuantum banyak-jasad merupakan tugas yang sukar secara komputasi untuk komputer klasik. Sebaliknya, komputer kuantum direka bentuk secara semula jadi untuk melaksanakan tugas ini dengan cekap. Model TFI, khususnya, telah menjadi penanda aras popular pada perkakasan kuantum kerana kelakuan fizikalnya yang kaya dan pelaksanaan yang mesra perkakasan.

Berbanding mensimulasikan dinamik masa berterusan, kami menggunakan model Ising terjumpa yang berkaitan rapat. Dinamiknya boleh dinyatakan secara tepat sebagai litar kuantum berkala, di mana setiap langkah evolusi terdiri daripada tiga lapisan get dua-qubit pecahan RZZ(αZZ)R_{ZZ} (\alpha_{ZZ}), diselangi dengan lapisan get satu-qubit RX(αX)R_X (\alpha_X) dan RZ(αZ)R_Z (\alpha_Z).

Kami akan menggunakan sudut generik yang mencabar untuk simulasi klasik dan mitigasi ralat. Khususnya, kami memilih αZZ=1.0\alpha_{ZZ} = 1.0, αX=0.53\alpha_X = 0.53, dan αZ=0.1\alpha_Z = 0.1, yang meletakkan model jauh daripada mana-mana titik integrable.

Dalam tutorial ini, kita akan melakukan perkara berikut:

  • Menganggarkan masa jalan QPU yang dijangka untuk mitigasi ralat penuh menggunakan ciri anggaran masa analitik dan empirikal QESEM.
  • Membina dan mensimulasikan litar model Ising medan-condong 2D menggunakan susun atur qubit berasaskan perkakasan dan lapisan get.
  • Menggambarkan ketersambungan qubit peranti dan subgraf terpilih untuk eksperimen anda.
  • Menunjukkan penggunaan operator backpropagation (OBP) untuk mengurangkan kedalaman litar. Teknik ini memangkas operasi dari penghujung litar dengan kos pengukuran operator yang lebih banyak.
  • Melaksanakan mitigasi ralat (EM) tanpa bias untuk pelbagai observable secara serentak menggunakan QESEM, membandingkan keputusan ideal, bising, dan yang telah dimitigasi.
  • Menganalisis dan memplot kesan mitigasi ralat ke atas pemagnetan merentas kedalaman litar yang berbeza.

Nota: OBP secara amnya akan mengembalikan satu set observable yang mungkin tidak bertukar-tukar. QESEM secara automatik mengoptimumkan asas pengukuran apabila observable sasaran mengandungi terma yang tidak bertukar-tukar. Ia menjana set asas pengukuran calon menggunakan beberapa algoritma heuristik dan memilih set yang meminimumkan bilangan asas yang berbeza. Ini bermakna QESEM mengumpulkan observable yang serasi ke dalam asas bersama untuk mengurangkan jumlah konfigurasi pengukuran yang diperlukan, sekali gus meningkatkan kecekapan.

Tentang QESEM​

QESEM ialah perisian berasaskan pencirian yang boleh dipercayai, ketepatan tinggi, yang melaksanakan mitigasi ralat quasi-probabilistik yang cekap dan tanpa bias. Ia direka bentuk untuk memitigasi ralat dalam litar kuantum generik dan ia bersifat agnostik dari segi aplikasi. Ia telah disahkan merentas pelbagai platform perkakasan, termasuk eksperimen skala utiliti pada peranti Eagle dan Heron IBM®. Peringkat aliran kerja QESEM adalah seperti berikut:

  1. Pencirian peranti - memetakan kesetiaan get dan mengenal pasti ralat koheren, menyediakan data penentukuran masa nyata. Peringkat ini memastikan mitigasi memanfaatkan operasi berkesetiaan tertinggi yang tersedia.
  2. Transpilasi sedar-hingar - menjana dan menilai pemetaan qubit alternatif, set operasi, dan asas pengukuran, memilih varian yang meminimumkan anggaran masa jalan QPU, dengan pilihan selarian untuk mempercepatkan pengumpulan data.
  3. Penindasan ralat - mentakrifkan semula get natif, menggunakan Pauli twirling, dan mengoptimumkan kawalan peringkat denyut (pada platform yang disokong) untuk meningkatkan kesetiaan.
  4. Pencirian litar - membina model ralat tempatan yang disesuaikan dan memasangkannya dengan pengukuran QPU untuk mengkuantifikasikan hingar sisa.
  5. Mitigasi ralat - membina penguraian quasi-probabilistik pelbagai jenis, dan mengambil sampel daripadanya dalam proses adaptif yang meminimumkan masa QPU mitigasi dan kepekaan terhadap turun naik perkakasan, mencapai ketepatan tinggi pada volum litar yang besar.

Untuk maklumat lanjut tentang QESEM dan eksperimen skala utiliti model ini pada subgraf 103-qubit, ketersambungan tinggi pada geometri heavy-hex natif ibm_marrakesh, rujuk Reliable high-accuracy error mitigation for utility-scale quantum circuits. Aliran kerja QESEM.

Keperluan​

Pasang pakej Python berikut sebelum menjalankan notebook:

  • Qiskit SDK v2.0.0 atau lebih baharu (pip install qiskit)
  • Qiskit Runtime v0.40.0 atau lebih baharu (pip install qiskit-ibm-runtime)
  • Qiskit Functions Catalog v0.8.0 atau lebih baharu ( pip install qiskit-ibm-catalog )
  • Tambahan OBP Qiskit v0.3.0 atau lebih baharu ( pip install qiskit-addon-obp )
  • Tambahan Qiskit Utils v0.1.1 atau lebih baharu ( pip install qiskit-addon-utils )
  • Simulator Qiskit Aer v0.17.1 atau lebih baharu ( pip install qiskit-aer )
  • Matplotlib v3.10.3 atau lebih baharu ( pip install matplotlib )

Persediaan​

Pertama, import perpustakaan yang berkaitan:

# 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,
)

Seterusnya, sahkan diri menggunakan kunci API anda dari papan pemuka IBM Quantum Platform. Kemudian, pilih Fungsi Qiskit seperti berikut. (Perhatikan bahawa untuk keselamatan, adalah lebih baik untuk menyimpan kelayakan akaun anda ke persekitaran tempatan anda, jika anda berada pada mesin yang dipercayai, supaya anda tidak perlu memasukkan kunci API setiap kali anda mengesahkan diri.)

# 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: Petakan input klasik kepada masalah kuantum​

Kita mulakan dengan mentakrifkan fungsi yang mencipta litar 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

Seterusnya kita cipta fungsi untuk mengira nilai jangkaan ideal menggunakan AerSimulator.

Perhatikan bahawa untuk litar besar (30 qubit atau lebih) kami mengesyorkan penggunaan nilai yang telah dikira terlebih dahulu daripada simulasi PEPS perbanyakan kepercayaan (BP). Kod ini merangkumi nilai yang telah dikira terlebih dahulu untuk 35 qubit sebagai contoh, berdasarkan pendekatan BP untuk mengevolusi rangkaian tensor PEPS yang diperkenalkan dalam makalah ini (yang kami rujuk sebagai PEPS-BP), menggunakan pakej Python rangkaian 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

Kami menggunakan pemetaan lapisan RZZR_{ZZ} berasaskan perkakasan yang diambil dari peranti Heron, di mana kami memotong lapisan mengikut bilangan qubit yang ingin disimulasikan. Kami mentakrifkan subgraf untuk 10, 21, 28, dan 35 qubit yang mengekalkan struktur 2D (anda bebas menukarnya kepada subgraf kegemaran anda):

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 visualisasikan susun atur qubit pada peranti 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()

Output of the previous code cell

Perhatikan bahawa ketersambungan susun atur qubit yang dipilih tidak semestinya linear, dan boleh meliputi kawasan yang luas pada peranti Heron bergantung kepada bilangan qubit yang dipilih.

Sekarang kita jana litar Trotter dan observable pemagnetan purata untuk bilangan 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:

Output of the previous code cell

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: Optimumkan masalah untuk pelaksanaan perkakasan kuantum​

Anggaran masa QPU dengan dan tanpa OBP​

Pengguna umumnya ingin tahu berapa lama masa QPU yang diperlukan untuk eksperimen mereka. Walau bagaimanapun, ini dianggap sebagai masalah yang sukar untuk komputer klasik.

QESEM menawarkan dua mod anggaran masa untuk memaklumkan pengguna tentang kemungkinan eksperimen mereka:

  1. Anggaran masa analitik - memberi anggaran yang sangat kasar dan tidak memerlukan masa QPU. Ini boleh digunakan untuk menguji sama ada suatu laluan transpilasi berpotensi mengurangkan masa QPU.
  2. Anggaran masa empirikal (ditunjukkan di sini) - memberi anggaran yang agak baik dan menggunakan beberapa minit masa QPU.

Dalam kedua-dua kes, QESEM mengeluarkan anggaran masa untuk mencapai ketepatan yang diperlukan bagi 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 maklumat lanjut tentang tambahan OBP Qiskit.) Kita akan mencipta fungsi yang menjana hirisan litar 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 panggil fungsi tersebut:

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:

Output of the previous code cell

Kita dapat lihat bahawa backpropagation telah mengurangkan dua lapisan litar. Sekarang setelah kita mempunyai litar yang telah dikurangkan dan observable yang telah dikembangkan, mari lakukan anggaran masa pada litar yang telah di-backpropagate:

# 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 dapat lihat bahawa OBP mengurangkan kos masa untuk mitigasi litar.

Langkah 3: Laksanakan menggunakan primitif Qiskit​

Jalankan dengan Backend sebenar​

Sekarang kita jalankan eksperimen penuh pada beberapa langkah Trotter. Bilangan qubit, ketepatan yang diperlukan, dan masa QPU maksimum boleh diubah suai mengikut sumber QPU yang tersedia. Perhatikan bahawa mengehadkan masa QPU maksimum akan mempengaruhi ketepatan akhir, seperti yang akan anda lihat dalam plot akhir di bawah.

Kita menganalisis empat litar dengan 5, 7, dan 9 langkah Trotter pada ketepatan 0.05, membandingkan nilai jangkaan ideal, bising, dan yang telah dimitigasi ralatnya:

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 lakukan OBP pada setiap litar untuk mengurangkan masa jalan:

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 jalankan satu kumpulan kerja QESEM penuh. Kita hadkan masa jalan QPU maksimum untuk setiap titik untuk kawalan lebih baik ke atas belanjawan 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 semak status setiap kerja:

for job in job_list:
print(job.status())
DONE
DONE
DONE
DONE

Langkah 4: Pasca-proses dan kembalikan keputusan dalam format klasik yang dikehendaki​

Apabila semua kerja selesai dijalankan, kita boleh membandingkan nilai jangkaan bising dan yang telah dimitigasi.

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

Akhirnya, kita boleh memplot pemagnetan berbanding bilangan langkah. Ini merumuskan manfaat menggunakan Fungsi Qiskit QESEM untuk mitigasi ralat tanpa bias pada peranti kuantum bising.

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')

Output of the previous code cell

nota

Langkah kesembilan mempunyai bar ralat statistik yang besar kerana kita mengehadkan masa QPU kepada 5 minit. Jika anda menjalankan langkah ini selama 15 minit (seperti yang dicadangkan oleh anggaran masa empirikal), anda akan mendapat bar ralat yang lebih kecil. Oleh itu, nilai yang dimitigasi akan menjadi lebih hampir kepada nilai ideal.

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