Eksperimen skala utilitas I
Tamiya Onodera (5 Juli 2024)
Unduh pdf dari kuliah aslinya. Perlu diperhatikan bahwa beberapa cuplikan kode mungkin sudah tidak berlaku karena ini adalah gambar statis.
Perkiraan waktu QPU untuk menjalankan eksperimen ini adalah 45 detik.
1. Pengenalan makalah utilitas
Di pelajaran ini, kita menjalankan sirkuit skala utilitas yang muncul dalam apa yang kita sebut secara informal sebagai "makalah utilitas" yang diterbitkan di Nature Vol 618, 15 Juni 2023. Makalah ini membahas evolusi waktu dari model Ising 2D medan transversal. Secara khusus, mereka mempertimbangkan dinamika waktu dari Hamiltonian,
di mana adalah kopling spin tetangga terdekat dengan dan adalah medan transversal global. Mereka mensimulasikan dinamika spin dari keadaan awal menggunakan dekomposisi Trotter orde pertama dari operator evolusi waktu,
di mana waktu evolusi didiskretisasi menjadi langkah Trotter dan dan adalah Gate rotasi dan masing-masing.
Mereka menjalankan eksperimen pada prosesor IBM Quantum® Eagle, yaitu perangkat 127-Qubit dengan konektivitas heavy-hex, menerapkan interaksi ke semua Qubit dan interaksi untuk semua tepi dari peta kopling. Perlu dicatat bahwa semua interaksi tidak dapat diterapkan secara bersamaan karena "ketergantungan data". Oleh karena itu, mereka mewarnai peta kopling untuk mengelompokkannya ke dalam lapisan. Yang ada dalam satu lapisan diberi warna yang sama, dan dapat diterapkan secara paralel.
Selain itu, untuk kesederhanaan eksperimen, mereka fokus pada kasus .
Kontribusi baru dari makalah ini adalah bahwa mereka membangun sirkuit kuantum pada skala yang melampaui simulasi statevector, menjalankannya pada komputer kuantum yang bising, dan berhasil mengekstrak hasil yang dapat diandalkan. Artinya, mereka mendemonstrasikan kegunaan komputer kuantum yang bising. Dalam melakukan itu, mereka menerapkan zero-noise extrapolation (ZNE) dengan probabilistic error amplification (PEA) untuk memitigasi kesalahan dari perangkat yang bising.
Sejak saat itu, kita menyebut eksperimen dan sirkuit semacam itu sebagai "skala utilitas".
1.1 Tujuanmu
Tujuanmu di pelajaran ini adalah membangun sirkuit skala utilitas dan menjalankannya pada prosesor Eagle. Mengekstrak hasil yang dapat diandalkan berada di luar cakupan notebook ini, sebagian karena PEA adalah fitur eksperimental dari Qiskit pada saat penulisan ini dan sebagian karena menerapkan ZNE dengan PEA akan membutuhkan waktu yang cukup lama.
Secara konkret, kamu diminta untuk membangun dan menjalankan sirkuit yang sesuai dengan Gambar 4b dari makalah, dan memplot titik-titik "tanpa mitigasi" milikmu sendiri. Seperti yang kamu lihat, ini adalah sirkuit 127-Qubit 60-lapisan (20 langkah Trotter) dengan sebagai observable.
Kedengarannya besar? Jangan khawatir. Tiga pelajaran terakhir dari kursus ini menyediakan batu loncatan. Untuk memulai, kita akan mendemonstrasikan eksperimen skala lebih kecil yaitu membangun dan menjalankan pada perangkat palsu sirkuit 27-Qubit 6-lapisan (2 langkah Trotter) dengan sebagai observable.
Itu saja untuk pengenalan. Mari kita mulai petualangan skala utilitas!
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime rustworkx
import qiskit
qiskit.__version__
'2.0.2'
#!pip install qiskit_ibm_runtime
#!pip install qiskit_aer
import matplotlib.pyplot as plt
import numpy as np
import rustworkx as rx
from qiskit import QuantumCircuit, transpile
from qiskit.circuit import Parameter
from qiskit.circuit.library import YGate
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import (
QiskitRuntimeService,
fake_provider,
EstimatorV2 as Estimator,
)
from qiskit_aer import AerSimulator
service = QiskitRuntimeService()
2. Persiapan
2.1 Membangun RZZ(- / 2)
Pertama, perhatikan bahwa Gate RZZ secara umum memerlukan dua Gate .
from qiskit.circuit.library import RZZGate
θ_h = Parameter("$\\theta_h$")
qc1 = QuantumCircuit(2)
qc1.append(RZZGate(θ_h), [0, 1])
qc1.decompose(reps=1).draw("mpl")
Seperti disebutkan di atas, kita fokus pada Gate RZZ dengan sudut tertentu, - / 2, untuk eksperimen ini. Seperti yang ditunjukkan dalam makalah, ini dapat direalisasikan hanya dengan satu Gate .
qc2 = QuantumCircuit(2)
qc2.sdg([0, 1])
qc2.append(YGate().power(1 / 2), [1])
qc2.cx(0, 1)
qc2.append(YGate().power(1 / 2).adjoint(), [1])
qc2.draw("mpl")
Kita mendefinisikan sebuah Gate berdasarkan sirkuit ini untuk referensi ke depan.
rzz = qc2.to_gate(label="RZZ")
Mari kita gunakan rzz yang baru didefinisikan secara acak.
qc3 = QuantumCircuit(3)
qc3.append(rzz, [0, 1])
qc3.append(rzz, [0, 2])
display(qc3.draw("mpl"))
# display(qc.decompose(reps=1).draw("mpl"))
Sebelum menggunakannya lebih lanjut, mari kita verifikasi kesetaraan logis dari qc1 (Gate RZZ) untuk -pi/2 dan Gate rzz atau qc2 yang baru kita definisikan:
from qiskit.quantum_info import Operator
op1 = Operator(qc1.assign_parameters([-np.pi / 2]))
op2 = Operator(qc2)
op1.equiv(op2)
True
2.2 Mewarnai peta kopling
Mari kita pelajari cara mewarnai peta kopling dari sebuah Backend. Ini diperlukan untuk mengelompokkan interaksi ke dalam lapisan.
Untuk memulai, mari kita visualisasikan peta kopling dari sebuah Backend. Perlu dicatat bahwa peta kopling berbentuk heavy-hexagonal untuk semua perangkat IBM Quantum saat ini.
backend = service.least_busy(operational=True, simulator=False)
backend.coupling_map.draw()

Untuk mewarnai peta kopling, kita menggunakan rustworkx, yang merupakan paket Python untuk bekerja dengan graf dan jaringan kompleks. Ini menyediakan beberapa algoritma pewarnaan, yang semuanya bersifat heuristik dan karenanya tidak dijamin menemukan pewarnaan minimal.
Dengan demikian, karena graf heavy-hex bersifat bipartit, kita memilih graph_bipartite_edge_color, yang seharusnya menemukan pewarnaan minimal untuk graf-graf ini.
def color_coupling_map(backend):
graph = backend.coupling_map.graph
undirected_graph = graph.to_undirected(multigraph=False)
edge_color_map = rx.graph_bipartite_edge_color(undirected_graph)
if edge_color_map is None:
edge_color_map = rx.graph_greedy_edge_color(undirected_graph)
# build a map from color to a list of edges
edge_index_map = undirected_graph.edge_index_map()
color_edges_map = {color: [] for color in edge_color_map.values()}
for edge_index, color in edge_color_map.items():
color_edges_map[color].append(
(edge_index_map[edge_index][0], edge_index_map[edge_index][1])
)
return edge_color_map, color_edges_map
Graf heavy-hexagonal harus diwarnai dengan tiga warna. Mari kita periksa ini untuk peta kopling di atas.
edge_color_map, color_edges_map = color_coupling_map(backend)
print(
f"{backend.name}, {backend.num_qubits}-qubit device, {len(color_edges_map.keys())} colors assigned."
)
ibm_strasbourg, 127-qubit device, 3 colors assigned.
Ya, memang begitu!
Untuk bersenang-senang, mari kita warnai peta kopling dengan pewarnaan yang diperoleh, menggunakan fitur visualisasi rustworkx.
color_str_map = {0: "green", 1: "red", 2: "blue"}
undirected_graph = backend.coupling_map.graph.to_undirected(multigraph=False)
for i in undirected_graph.edge_indices():
undirected_graph.get_edge_data_by_index(i)["color"] = color_str_map[
edge_color_map[i]
]
rx.visualization.graphviz_draw(
undirected_graph, method="neato", edge_attr_fn=lambda edge: {"color": edge["color"]}
)

3. Selesaikan evolusi waktu Trotterisasi dari model Ising 2D.
Mari kita definisikan sebuah rutinitas untuk membangun sirkuit dari makalah utilitas untuk evolusi waktu model Ising 2D. Rutinitas ini mengambil tiga parameter: sebuah Backend, bilangan bulat yang menunjukkan jumlah langkah Trotter, dan Boolean yang mengontrol penyisipan barrier.
def get_utility_circuit(backend, num_steps: int, barrier: bool = False):
num_qubits = backend.num_qubits
_, color_edges_map = color_coupling_map(backend)
θ_h = Parameter("$\\theta_h$")
qc = QuantumCircuit(num_qubits)
for i in range(num_steps):
qc.rx(θ_h, range(num_qubits))
for _, edge_list in color_edges_map.items():
for edge in edge_list:
qc.append(rzz, edge)
if barrier:
qc.barrier()
return qc
Perlu dicatat bahwa kita telah secara manual melakukan pemetaan dan routing Qubit untuk sirkuit yang dibangun. Oleh karena itu, saat kita men-transpile sirkuit nanti, kita tidak (tidak seharusnya) meminta Transpiler untuk melakukan pemetaan dan routing Qubit. Seperti yang akan segera kamu lihat, kita memanggilnya dengan tingkat optimasi 1 dan metode tata letak sebagai "trivial".
Selanjutnya kita mendefinisikan rutinitas sederhana untuk mendapatkan informasi tentang sirkuit yang dibangun untuk pemeriksaan cepat.
def get_circuit_info(qc: QuantumCircuit, reps: int = 0):
qc0 = qc.decompose(reps=reps)
return (
f"{qc0.num_qubits} qubits × {qc0.depth(lambda x: x.operation.num_qubits == 2)} layers ({qc0.depth()}-depth)"
+ ", "
+ f"""Gate breakdown: {", ".join([f"{k.upper()} {v}" for k, v in qc0.count_ops().items()])}"""
)
Mari kita jalankan rutinitas-rutinitas ini. Kamu seharusnya melihat sirkuit 27 Qubit 15 lapisan (5 langkah Trotter). Karena perangkat palsu memiliki 28 tepi, seharusnya ada 28*5 Gate entangling.
backend = fake_provider.FakeTorontoV2()
num_steps = 5
qc = get_utility_circuit(backend, num_steps, True)
display(qc.draw(output="mpl", fold=-1))
print(get_circuit_info(qc, reps=0))
print(get_circuit_info(qc, reps=1))

27 qubits × 15 layers (20-depth), Gate breakdown: CIRCUIT-165 140, RX 135, BARRIER 5
27 qubits × 15 layers (60-depth), Gate breakdown: SDG 280, UNITARY 280, CX 140, R 135, BARRIER 5
4. Selesaikan versi 27-Qubit dari masalah ini.
Kita sekarang mendemonstrasikan versi skala lebih kecil dari eksperimen utilitas. Kita membangun sirkuit 27-Qubit 6-lapisan (2 langkah Trotter) dengan sebagai observable, dan menjalankannya baik pada AerSimulator maupun perangkat palsu.
Tentu saja, kita mengikuti alur kerja empat langkah kita, "pola Qiskit", yang terdiri dari Map, Optimize, Execute, dan Post-Process. Lebih konkretnya:
- Petakan input klasik ke komputasi kuantum.
- Optimalkan sirkuit untuk komputasi kuantum.
- Jalankan sirkuit menggunakan primitives.
- Post-process dan kembalikan hasil dalam format klasik.
Berikut ini, kita memiliki langkah Map untuk membuat sirkuit eksperimen skala lebih kecil. Kemudian kita memiliki satu set Optimize dan Execute untuk AerSimulator dan satu lagi untuk perangkat palsu. Terakhir, kita memiliki langkah Post-Process untuk memplot hasilnya.
4.1 Langkah 1: Map
backend = fake_provider.FakeTorontoV2() # a 27 qubit fake device.
num_steps = 2
qc = get_utility_circuit(backend, num_steps)
obs = SparsePauliOp.from_sparse_list(
[("Z", [13], 1)], num_qubits=backend.num_qubits
) # Falcon
angles = [
0,
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8,
1.0,
np.pi / 2,
] # We try 11 angles for theta_h.
4.2 Langkah 2 dan 3: Optimize dan Execute (Simulator)
backend_sim = AerSimulator()
transpiled_qc_sim = transpile(
qc, backend_sim, optimization_level=1, layout_method="trivial"
)
transpiled_obs_sim = obs.apply_layout(layout=transpiled_qc_sim.layout)
print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc_sim, reps=1))
27 qubits × 6 layers (23-depth), Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54
27 qubits × 6 layers (16-depth), Gate breakdown: U3 80, CX 56, R 54, U1 32, U 28
Seorang pengguna menjalankan sel berikutnya menggunakan MacBook Pro dengan Prosesor Intel Core i7 quad-core 2.3 GHz yang dilengkapi dengan RAM 32GB 3LPDDR4X, yang menjalankan macOS 14.5. Ini memakan waktu 161ms dalam wall time. Setiap laptop akan sedikit berbeda.
%%time
params = [[p] for p in angles]
estimator = Estimator(mode=backend_sim)
pub = (transpiled_qc_sim, transpiled_obs_sim, params)
result_sim = estimator.run([pub]).result()
CPU times: user 231 ms, sys: 186 ms, total: 417 ms
Wall time: 111 ms
4.3 Langkah 2 dan 3: Optimize dan execute (perangkat palsu)
backend_fake = fake_provider.FakeTorontoV2()
transpiled_qc_fake = transpile(
qc, backend_fake, optimization_level=1, layout_method="trivial"
)
transpiled_obs_fake = obs.apply_layout(layout=transpiled_qc_fake.layout)
print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc_fake, reps=1))
27 qubits × 6 layers (23-depth), Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54
27 qubits × 6 layers (49-depth), Gate breakdown: SDG 324, U1 274, H 162, CX 56, U3 14
Ketika pengguna yang sama menjalankan sel berikutnya dengan lingkungan yang sama seperti di atas, dibutuhkan 2 menit 19 detik dalam Wall Time. Menjalankan sirkuit pada perangkat palsu memerlukan simulasi bergangguan yang membutuhkan waktu jauh lebih lama daripada simulasi eksak. Kami menyarankan kamu untuk tidak menjalankan sirkuit yang lebih besar (seperti 27-Qubit 9 lapisan dengan 3 langkah Trotter) pada perangkat palsu.
%%time
params = [[p] for p in angles]
estimator = Estimator(mode=backend_fake)
pub = (transpiled_qc_fake, transpiled_obs_fake, params)
result_fake = estimator.run([pub]).result()
CPU times: user 4min 42s, sys: 9.35 s, total: 4min 51s
Wall time: 38.3 s
4.4 Langkah 4: Post-process
Kita memplot hasil dari simulasi eksak dan bergangguan. Kamu melihat efek gangguan yang parah pada FakeToronto.
plt.plot(angles, result_fake[0].data.evs, "o", label="Fake Device")
plt.plot(angles, result_sim[0].data.evs, "o", label="AerSimulator")
plt.xlabel("$\\mathrm{R_x}$ angle $\\theta_h$")
plt.title("$\\langle Z_{13} \\rangle$")
plt.legend()
plt.show()
5. Selesaikan versi 127-Qubit dari masalah ini
Tujuanmu adalah menjalankan eksperimen skala utilitas seperti yang disebutkan di awal. Kamu akan membuat dan menjalankan sirkuit 127-Qubit dan 60-lapisan (20 langkah Trotter) dengan sebagai observable. Kami menyarankan kamu mencoba melakukan ini sendiri, menggunakan kode untuk versi 27-Qubit bila sesuai. Namun solusinya disediakan di sini.
Solusi:
5.1 Langkah 1: Map
# backend_map = service.backend("ibm_brisbane")
backend_map = service.least_busy(operational=True, simulator=False)
num_steps = 20
qc = get_utility_circuit(backend_map, num_steps)
obs = SparsePauliOp.from_sparse_list(
[("Z", [62], 1)], num_qubits=backend_map.num_qubits
) # Eagle
angles = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1.0, np.pi / 2]
5.2 Langkah 2 dan 3: Optimize dan execute
Perlu dicatat bahwa peta kopling prosesor Eagle memiliki 144 tepi.
# backend = service.backend("ibm_brisbane")
backend = backend_map
transpiled_qc = transpile(qc, backend, optimization_level=1, layout_method="trivial")
transpiled_obs = obs.apply_layout(layout=transpiled_qc.layout)
print(get_circuit_info(qc, reps=1))
print(get_circuit_info(transpiled_qc))
156 qubits × 60 layers (221-depth), Gate breakdown: SDG 7040, UNITARY 7040, CX 3520, R 3120
156 qubits × 60 layers (201-depth), Gate breakdown: RZ 11933, SX 6240, CZ 3520
params = [[p] for p in angles]
estimator = Estimator(mode=backend)
pub = (transpiled_qc, transpiled_obs, params)
job = estimator.run([pub])
job_id = job.job_id()
print(f"job id={job_id}")
job id=d1479n6qf56g0081sxa0
5.3 Post-process
Kita menyediakan nilai-nilai untuk titik-titik "yang dimitigasi" dalam Gambar 4b dari makalah utilitas. Plot ini bersama dengan hasilmu.
result_paper = [
1.0171,
1.0044,
0.9563,
0.9602,
0.8394,
0.8120,
0.5466,
0.4556,
0.1953,
0.0141,
0.0117,
]
# REPLACE WITH YOUR OWN JOB ID
job = service.job(job_id)
plt.plot(angles, job.result()[0].data.evs, "o", label=f"{job.backend().name}")
plt.plot(angles, result_paper, "o", label="Utility Paper")
plt.xlabel("$\\mathrm{R_x}$ angle $\\theta_h$")
plt.title("$\\langle Z_{62} \\rangle$")
plt.legend()
plt.show()
Apakah hasilmu mirip dengan titik "tanpa mitigasi" dalam Gambar 4b? Bisa sangat berbeda, tergantung pada perangkat dan kondisinya saat eksperimen. Jangan khawatir tentang hasilnya sendiri. Yang akan kita periksa adalah apakah kamu telah melakukan pengkodean dengan benar. Jika ya, selamat, kamu telah mencapai garis awal era utilitas.
Seperti dalam makalah Utility, para ilmuwan di seluruh dunia telah menunjukkan kecerdikan luar biasa dalam mengekstrak hasil yang bermakna bahkan di tengah kebisingan. Tujuan akhir dari upaya kolektif ini adalah quantum advantage: suatu keadaan di mana komputer kuantum dapat memecahkan beberapa masalah yang berguna dalam industri lebih cepat, dengan fidelitas lebih tinggi, atau lebih murah daripada komputer klasik. Ini kemungkinan bukan satu peristiwa tunggal, melainkan sebuah era di mana reproduksi klasik dari hasil kuantum membutuhkan waktu semakin lama, hingga pada suatu titik waktu keunggulan kuantum itu menjadi sangat penting. Satu hal yang jelas tentang quantum advantage: kita hanya bisa sampai ke sana melalui eksperimen skala utilitas. Jika kursus ini menghasilkan kamu bergabung dalam pencarian ini, yang penuh tantangan dan kesenangan, kami akan sangat senang.
Referensi
- Kim, Y., Eddins, A., Anand, S. et al. Evidence for the utility of quantum computing before fault tolerance. Nature 618, 500–505 (2023). https://doi.org/10.1038/s41586-023-06096-3