Simulasi model Ising terkick dengan fungsi TEM
Metode Tensor-network Error Mitigation (TEM) dari Algorithmiq adalah algoritma kuantum-klasik hibrida yang dirancang untuk melakukan mitigasi noise sepenuhnya dalam tahap post-processing klasik. Dengan TEM, pengguna bisa menghitung nilai ekspektasi observabel, memitigasi error akibat noise yang tak terhindarkan pada hardware kuantum dengan akurasi dan efisiensi biaya yang lebih tinggi, menjadikannya pilihan yang sangat menarik bagi peneliti kuantum dan praktisi industri.
Tutorial ini mendemonstrasikan bagaimana TEM bisa mendapatkan hasil yang bermakna untuk dinamika sistem kuantum, yang tidak dapat diakses tanpa mitigasi error dan memerlukan sumber daya kuantum yang jauh lebih banyak jika metode mitigasi error lain seperti PEC dan ZNE digunakan.
Estimasi penggunaan: Notebook ini menggunakan sekitar 10 menit QPU pada perangkat Heron r3. Waktu runtime bisa sangat bergantung pada perangkat yang dipilih. Estimasi penggunaan per bagian dapat ditemukan di bawah.
Menjalankan eksperimen fisika banyak-benda dengan mitigasi error menggunakan fungsi TEM
Tutorial ini didasarkan pada referensi berikut: L. E. Fischer et al., Nat. Phys. (2026). Referensi ini membahas simulasi nyata pada hardware kuantum dengan hingga 91 qubit. Dalam tutorial ini, kita membuat ulang simulasi serupa pada ukuran sirkuit yang lebih kecil.
Model Ising terkick sesuai dengan model Ising biasa:
yang kemudian diterapkan kick transversal:
Tujuannya adalah mensimulasikan dinamika suatu state di bawah Hamiltonian Ising terkick transversal, yang evolusi waktunya bisa diimplementasikan oleh unitary Floquet . State awal untuk dievolusi adalah yang mana qubit pertama berada dalam state , sementara yang lain dipasangkan dan diatur dalam Bell state .
Besaran yang ingin kita amati adalah fungsi korelasi. Paper referensi membahas bagaimana besaran ini bisa ditulis ulang sebagai operator Pauli pada qubit ke-. Setelah sejumlah langkah waktu fisik , kita menghitung nilai operator Pauli . Bergantung pada parameter sistem, nilai observabel ini sama dengan nilai yang bisa dihitung secara eksak, atau hanya dapat disimulasikan melalui metode perkiraan. Secara khusus, untuk nilainya sama dengan , yang merupakan nilai yang akan kita gunakan sebagai benchmark hasil tutorial ini. Selain itu, pada langkah waktu tertentu , adalah nol. Untuk detail mendapatkan nilai-nilai ini, dan perbandingan dengan hasil simulasi klasik perkiraan di luar parameter ini, lihat L. E. Fischer et al., Nat. Phys. (2026).
TEM bekerja dengan pertama mengkarakterisasi noise untuk setiap layer unik gate dua qubit dalam sirkuit, serta mengkarakterisasi error readout. Kemudian, sirkuit dieksekusi pada mesin kuantum. Akhirnya, mitigasi error tensor network dilakukan pada sumber daya klasik di IBM Cloud® dan nilai yang dimitigasi dikembalikan. Dalam contoh ini, sirkuit memiliki dua layer unik untuk dikarakterisasi.
Pengaturan
Sebagai prasyarat, pastikan dependensi yang diperlukan sudah terinstal.
%pip install numpy matplotlib qiskit qiskit-ibm-catalog qiskit-ibm-runtime pylatexenc qiskit_qasm3_import
import os
from matplotlib import pyplot as plt
import numpy as np
from qiskit.quantum_info import SparsePauliOp
from qiskit.qasm3 import load
from qiskit_ibm_catalog import QiskitFunctionsCatalog
Mitigasi error dengan TEM
Kami menyediakan di sini sirkuit yang mengimplementasikan model Ising terkick yang dijelaskan di atas. Sirkuit disiapkan sebagai berikut. Pertama, ada fase persiapan state, di mana qubit pertama berada dalam state , sementara yang lain dalam pasangan Bell . Ini diikuti oleh struktur brickwork yang mengimplementasikan evolusi unitary . Jumlah langkah waktu fisik sesuai dengan layer sirkuit. Kode berikut mengunduh dua file QASM yang diperlukan untuk tutorial ini.
# Download required QASM files
import urllib
urllib.request.urlretrieve(
"https://ibm.box.com/shared/static/swy5jtq309b0xpzluzlmsmj908yphes8.qasm",
"ki_30q.qasm",
)
urllib.request.urlretrieve(
"https://ibm.box.com/shared/static/et3gkodonw6gsp2trs43lzaozrdtiu7s.qasm",
"ki_12q.qasm",
)
Kita bisa memvisualisasikan versi kecil sirkuit, dengan 12 qubit dan enam langkah waktu:
# Parameters of the kicked Ising model
h = 0.0
num_qubits = 12
t_steps = 6
# Load the circuit for the kicked Ising model
small_circuit = load("ki_12q.qasm")
# Draw the circuit
small_circuit.draw("mpl", scale=0.25, fold=-1)

Selanjutnya, bangun observabel, . Ini dibangun sebagai string Pauli sederhana dengan urutan yang sesuai dengan yang digunakan oleh Qiskit:
def xt_observable(n_qubits, t_steps):
pauli_str = "".join(["I" * t_steps, "X", "I" * (n_qubits - t_steps - 1)])
pauli_str = pauli_str[::-1] # Reverse the string to match qiskit order
return SparsePauliOp(data=pauli_str, coeffs=1.0)
Dalam contoh 12 qubit kecil kita, observabel terlihat seperti ini:
# Build the observable for the kicked Ising model
small_observable = xt_observable(n_qubits=12, t_steps=6)
print(small_observable)
SparsePauliOp(['IIIIIXIIIIII'],
coeffs=[1.+0.j])
Qiskit Functions menggunakan PUB sebagai cara untuk mengumpulkan input. Dalam kasus kita, mari pertimbangkan satu sirkuit dan observabel sebagai PUB kita:
# Collect the input PUBs, in this case composed of a
# single circuit and observable
pubs = [(small_circuit, [small_observable])]
Selanjutnya, kita mendapatkan akses ke fungsi TEM. Pertama kita atur autentikasi yang diperlukan ke IBM Cloud dan pilih Backend dari perangkat yang tersedia. Token, Backend yang tersedia, dan nama sumber daya cloud yang sesuai (CRN) bisa diperoleh dengan masuk ke akun kamu di dasbor IBM Quantum Platform.
# Set IBM Quantum credentials and backend configuration
personal_token = os.environ.get(
"QISKIT_IBM_TOKEN", "<API-KEY>"
) # Replace with your personal token or set the environment variable
channel = "ibm_quantum_platform"
crn = "your_crn" # Replace with the Cloud Resource Name (CRN)
# Select the QPU backend
backend_name = "ibm_qpu_name" # Replace with your desired backend's name
Muat fungsi TEM dari Katalog Qiskit Functions:
# Load the TEM function from the Qiskit Functions Catalog
catalog = QiskitFunctionsCatalog(
channel=channel,
token=personal_token,
instance=crn,
)
tem = catalog.load("algorithmiq/tem")
Sekarang kita bisa menjalankan eksperimen pada sirkuit Ising terkick dengan mitigasi error yang disediakan oleh TEM. Menggunakan pengaturan default, TEM bisa dijalankan dengan cara sederhana dengan perkiraan runtime QPU sekitar 2,5 menit, tergantung QPU:
tem_job = tem.run(pubs=pubs, backend_name=backend_name)
Dengan opsi default, fungsi TEM menjalankan tiga job pada komputer kuantum: pembelajaran noise, mitigasi readout, dan sampling sirkuit. Jumlah shots yang digunakan oleh masing-masing bisa diubah dalam opsi yang diteruskan ke fungsi. Secara default, parameter ini diatur untuk mencapai presisi 0,05 dalam nilai ekspektasi yang dimitigasi. Kamu bisa memeriksa status job kamu di dasbor IBM Quantum Platform atau dengan:
print(tem_job.status())
QUEUED
Ketika statusnya DONE, kita bisa memeriksa hasil mentah dan yang dimitigasi. tem_evs yang didefinisikan di bawah adalah nilai ekspektasi dari observabel yang diminta, dalam hal ini hanya satu observabel, , dan tem_std adalah deviasi standar yang sesuai.
# Get the results of the TEM job
tem_results = tem_job.result()[
0
] # Get the first and only result from the job
tem_evs = tem_results.data.evs[0]
tem_std = tem_results.data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")
TEM Result: 1.031 ± 0.046
Kita juga bisa memeriksa berapa banyak runtime kuantum yang digunakan untuk setiap panggilan di IBM Quantum Platform, atau dengan memeriksa metadata hasil dari kode Python.
# Get the TEM job runtime
tem_runtime = tem_job.result().metadata["resource_usage"][
"RUNNING: EXECUTING_QPU"
]["QPU_TIME"]
print(f"TEM Runtime: {tem_runtime} seconds")
TEM Runtime: 155.0 seconds
Menyesuaikan parameter TEM dan opsi lanjutan
Fungsi TEM menyediakan beberapa opsi lanjutan untuk menyesuaikan alur kerja mitigasi error kamu. Opsi-opsi ini memungkinkan kamu mengontrol presisi, jumlah shots, strategi pembelajaran noise, dan parameter lain agar lebih sesuai dengan kebutuhan eksperimen dan sumber daya kuantum yang tersedia.
Opsi lanjutan yang umum adalah:
precision: Menentukan presisi target untuk nilai ekspektasi yang dimitigasi.default_shots: Sebagai gantiprecision, kamu bisa menentukan jumlah shots yang digunakan dalam job pengukuran.tem_max_bond_dimension: Dimensi bond maksimum yang digunakan dalam tensor network.tem_compression_cutoff: Nilai cutoff yang digunakan untuk tensor network.- Opsi pembelajaran noise: Mengonfigurasi metode karakterisasi noise, seperti jumlah iterasi atau sirkuit kalibrasi tertentu.
private: Memastikan privasi sirkuit dan hasil eksperimen untuk kamu dan menonaktifkan unduhan hasil job ganda.
Lihat dokumentasi TEM atau katalog Qiskit Functions untuk daftar lengkap opsi yang didukung dan deskripsinya. Kamu bisa menyetel parameter ini untuk menyeimbangkan waktu runtime, penggunaan sumber daya, dan akurasi hasil. Kamu bisa meneruskan opsi ini sebagai dictionary ke argumen options saat menjalankan fungsi TEM:
options = {
"default_shots": 10_000,
"tem_max_bond_dimension": 512,
"tem_compression_cutoff": 1e-16,
# This option helps optimizing the measurement
# stage since the observable is strongly biased
# toward the X operator for all the qubits.
"compute_shadows_bias_from_observable": True,
# set to True to keep experiment results private,
# recommended for confidential circuits
"private": False,
}
Opsi kustom juga bisa diteruskan ke noise learner. Definisi yang digunakan mengikuti yang ada di Qiskit Runtime NoiseLearnerOptions:
nl_options = {
"num_randomizations": 32,
"max_layers_to_learn": 2,
"shots_per_randomization": 128,
"layer_pair_depths": [0, 1, 2, 4, 16, 32],
}
# add noise learning options to the overall options
options |= nl_options
Jalankan ulang eksperimen dengan opsi kustom ini yang diatur untuk sirkuit kita. Waktu runtime yang diharapkan adalah sekitar empat menit QPU.
tem_job_custom = tem.run(
pubs=pubs, backend_name=backend_name, options=options
)
Jika job tidak diatur sebagai privat, kita bisa mengambil hasilnya nanti. Untuk melakukan itu, simpan ID job yang dicetak di sini dan gunakan tem_job_custom = catalog.get_job_by_id("your-job-id").
job_id = tem_job_custom.job_id
print(f"Job ID: {job_id}")
Job ID: 1ba10094-a541-457a-9287-dbd49306d12d
results_custom = tem_job_custom.result()
tem_evs = results_custom[0].data.evs[0]
tem_std = results_custom[0].data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")
TEM Result: 0.956 ± 0.018
Sekarang kita bisa memeriksa hasil dan metadata untuk mendapatkan wawasan tentang eksperimen:
metadata_custom = results_custom[0].metadata
unmitigated_evs = metadata_custom["evs_non_mitigated"][0]
unmitigated_stds = metadata_custom["stds_non_mitigated"][0]
print(f"Unmitigated Result: {unmitigated_evs:.3f} ± {unmitigated_stds:.3f}")
# Exact result for the kicked Ising model from the reference paper
exact_evs = np.cos(2 * h) ** t_steps
print("Exact Result:", exact_evs)
Unmitigated Result: 0.894 ± 0.015
Exact Result: 1.0
# Plot comparing the different expectation values
plt.bar(
["Unmitigated", "TEM"],
[unmitigated_evs, tem_evs],
yerr=[unmitigated_stds, tem_std],
color=["grey", "c"],
)
plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors="r", linestyles="dashed")
plt.ylabel("Expectation Value")
plt.ylim(0, 1.1)
plt.show()
Terakhir, kita bisa memeriksa dampak opsi kustom pada runtime QPU dan klasik:
# Get the metadata of the TEM job
job_metadata = results_custom.metadata
# Get the runtime of the TEM job
qpu_runtime = job_metadata["resource_usage"]["RUNNING: EXECUTING_QPU"][
"QPU_TIME"
]
classical_runtime = (
job_metadata["resource_usage"]["RUNNING: OPTIMIZING_FOR_HARDWARE"][
"CPU_TIME"
]
+ job_metadata["resource_usage"]["RUNNING: POST_PROCESSING"]["CPU_TIME"]
)
print(f"QPU Runtime: {qpu_runtime} seconds")
print(f"Classical Runtime: {classical_runtime} seconds")
QPU Runtime: 342.0 seconds
Classical Runtime: 107.632604 seconds
Memperbesar skala TEM ke sirkuit besar
Sirkuit besar secara prinsip bisa dijalankan dengan fungsi TEM. Namun, penting untuk mengetahui keterbatasan sumber daya klasik, karena TEM dieksekusi pada operator IBM Cloud dengan waktu runtime yang berpotensi panjang. Untuk sirkuit yang sangat besar, hubungi tim dukungan TEM di qiskit_ibm@algorithmiq.fi.
Di sini kita menjalankan contoh dengan sirkuit yang lebih besar berukuran utilitas 30 qubit, dengan mengoptimalkan parameter TEM untuk kecepatan daripada presisi.
# Kicked Ising model parameters
n_qubits = 30
t_steps = 15
h = 0.0
# Load the circuit for the kicked Ising model
circuit = load("ki_30q.qasm")
# Build the observable for the kicked Ising model
observable = xt_observable(n_qubits=n_qubits, t_steps=t_steps)
# Collect the input PUBs, in this case composed of a
# single circuit and observable
pubs = [(circuit, [observable])]
Mari tentukan beberapa opsi yang berorientasi pada performa:
options = {
"num_randomizations": 32,
"max_layers_to_learn": 2,
"shots_per_randomization": 128,
"layer_pair_depths": [0, 1, 2, 4, 16, 32, 64],
"default_shots": 5_000,
"tem_max_bond_dimension": 128,
"tem_compression_cutoff": 1e-10,
"compute_shadows_bias_from_observable": True,
"private": False,
}
Terakhir, jalankan eksperimen, dapatkan hasilnya, dan visualisasikan. Ini akan membutuhkan sekitar 3,5 menit QPU.
tem_job_large = tem.run(pubs=pubs, backend_name=backend_name, options=options)
job_id = tem_job_large.job_id
print(f"Job ID: {job_id}")
Job ID: 9f3f190f-f4b0-4dcb-bb83-5f71f37d0d77
results_large = tem_job_large.result()
tem_evs = results_large[0].data.evs[0]
tem_std = results_large[0].data.stds[0]
print(f"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}")
# Get the metadata of the TEM job
job_metadata = tem_job_large.result().metadata
# Get the runtime of the TEM job
qpu_runtime = job_metadata["resource_usage"]["RUNNING: EXECUTING_QPU"][
"QPU_TIME"
]
classical_runtime = (
job_metadata["resource_usage"]["RUNNING: OPTIMIZING_FOR_HARDWARE"][
"CPU_TIME"
]
+ job_metadata["resource_usage"]["RUNNING: POST_PROCESSING"]["CPU_TIME"]
)
print(f"QPU Runtime: {qpu_runtime} seconds")
print(f"Classical Runtime: {classical_runtime} seconds")
TEM Result: 0.794 ± 0.026
QPU Runtime: 203.0 seconds
Classical Runtime: 251.71805499999996 seconds
# Plot comparing the different expectation values
metadata_large = results_large[0].metadata
unmitigated_evs = metadata_large["evs_non_mitigated"][0]
unmitigated_stds = metadata_large["stds_non_mitigated"][0]
exact_evs = np.cos(2 * h) ** t_steps
plt.bar(
["Unmitigated", "TEM"],
[unmitigated_evs, tem_evs],
yerr=[unmitigated_stds, tem_std],
color=["grey", "c"],
)
plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors="r", linestyles="dashed")
plt.ylabel("Expectation Value")
plt.ylim(0, 1.1)
plt.show()