Optimisasi Transpilasi dengan SABRE
Estimasi penggunaan: kurang dari satu menit pada prosesor Heron r2 (CATATAN: Ini hanya estimasi. Waktu aktual kamu bisa berbeda.)
Latar Belakang​
Transpilasi adalah langkah penting dalam Qiskit yang mengubah Circuit kuantum ke bentuk yang kompatibel dengan perangkat keras kuantum tertentu. Proses ini melibatkan dua tahap utama: qubit layout (memetakan qubit logis ke qubit fisik di perangkat) dan gate routing (memastikan gate multi-qubit mematuhi konektivitas perangkat dengan menyisipkan gate SWAP sesuai kebutuhan).
SABRE (SWAP-Based Bidirectional heuristic search algorithm) adalah alat optimasi yang kuat untuk layout maupun routing. SABRE sangat efektif untuk sirkuit berskala besar (100+ qubit) dan perangkat dengan coupling map yang kompleks, seperti IBM® Heron, di mana pertumbuhan eksponensial kemungkinan pemetaan qubit membutuhkan solusi yang efisien.
Mengapa Menggunakan SABRE?​
SABRE meminimalkan jumlah gate SWAP dan mengurangi kedalaman sirkuit, sehingga meningkatkan performa sirkuit di perangkat keras nyata. Pendekatan berbasis heuristik membuat SABRE ideal untuk perangkat keras canggih dan sirkuit besar yang kompleks. Peningkatan terbaru yang diperkenalkan dalam algoritma LightSABRE semakin mengoptimalkan performa SABRE, menawarkan runtime yang lebih cepat dan lebih sedikit gate SWAP. Peningkatan ini membuatnya semakin efektif untuk sirkuit berskala besar.
Apa yang Akan Kamu Pelajari​
Tutorial ini dibagi menjadi dua bagian:
- Belajar menggunakan SABRE dengan pola Qiskit untuk optimasi lanjutan pada sirkuit besar.
- Memanfaatkan qiskit_serverless untuk memaksimalkan potensi SABRE dalam transpilasi yang skalabel dan efisien.
Kamu akan:
- Mengoptimalkan SABRE untuk sirkuit dengan 100+ qubit, melampaui pengaturan transpilasi default seperti
optimization_level=3. - Menjelajahi peningkatan LightSABRE yang meningkatkan runtime dan mengurangi jumlah gate.
- Menyesuaikan parameter kunci SABRE (
swap_trials,layout_trials,max_iterations,heuristic) untuk menyeimbangkan kualitas sirkuit dan runtime transpilasi.
Persyaratan​
Sebelum memulai tutorial ini, pastikan kamu sudah menginstal hal-hal berikut:
- Qiskit SDK v1.0 atau lebih baru, dengan dukungan visualisasi
- Qiskit Runtime v0.28 atau lebih baru (
pip install qiskit-ibm-runtime) - Serverless (
pip install qiskit-ibm-catalog qiskit_serverless)
Pengaturan​
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-catalog qiskit-ibm-runtime qiskit-serverless
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_catalog import QiskitServerless, QiskitFunction
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorOptions
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit.transpiler import CouplingMap
from qiskit.transpiler.passes import SabreLayout, SabreSwap
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
import matplotlib.pyplot as plt
import numpy as np
import time
Bagian I. Menggunakan SABRE dengan Pola Qiskit​
SABRE dapat digunakan di Qiskit untuk mengoptimalkan Circuit kuantum dengan menangani tahap qubit layout dan gate routing. Di bagian ini, kita akan memandu kamu melalui contoh minimal penggunaan SABRE dengan pola Qiskit, dengan fokus utama pada langkah 2 optimasi.
Untuk menjalankan SABRE, kamu membutuhkan:
- Representasi DAG (Directed Acyclic Graph) dari Circuit kuantum kamu.
- Coupling map dari Backend, yang menentukan bagaimana qubit terhubung secara fisik.
- Pass SABRE, yang menerapkan algoritma untuk mengoptimalkan layout dan routing.
Untuk bagian ini, kita akan fokus pada pass SabreLayout. Pass ini melakukan uji layout maupun routing, bekerja untuk menemukan layout awal yang paling efisien sambil meminimalkan jumlah gate SWAP yang dibutuhkan. Yang penting, SabreLayout sendiri secara internal mengoptimalkan layout dan routing dengan menyimpan solusi yang menambah jumlah gate SWAP paling sedikit. Perlu dicatat bahwa saat menggunakan hanya SabreLayout, kita tidak bisa mengubah heuristik SABRE, tetapi kita bisa menyesuaikan jumlah layout_trials.
Langkah 1: Petakan Input Klasik ke Masalah Kuantum​
Sebuah Circuit GHZ (Greenberger-Horne-Zeilinger) adalah Circuit kuantum yang mempersiapkan keadaan terjalin di mana semua qubit berada dalam keadaan |0...0⟩ atau |1...1⟩. Keadaan GHZ untuk qubit direpresentasikan secara matematis sebagai:
Circuit ini dibangun dengan menerapkan:
- Gate Hadamard pada qubit pertama untuk menciptakan superposisi.
- Serangkaian gate CNOT untuk menjalin qubit-qubit lainnya dengan qubit pertama.
Untuk contoh ini, kita sengaja membangun Circuit GHZ topologi bintang alih-alih topologi linier. Dalam topologi bintang, qubit pertama bertindak sebagai "hub," dan semua qubit lain dijerat langsung dengannya menggunakan gate CNOT. Pilihan ini disengaja karena, meskipun keadaan GHZ topologi linier secara teori dapat diimplementasikan dengan kedalaman pada coupling map linier tanpa gate SWAP, SABRE akan dengan mudah menemukan solusi optimal dengan memetakan Circuit GHZ 100 qubit ke subgraf coupling map heavy-hex Backend.
Circuit GHZ topologi bintang menghadirkan masalah yang jauh lebih menantang. Meskipun secara teori masih dapat dieksekusi dengan kedalaman tanpa gate SWAP, menemukan solusi ini membutuhkan identifikasi layout awal yang optimal, yang jauh lebih sulit karena konektivitas circuit yang non-linier. Topologi ini berfungsi sebagai kasus uji yang lebih baik untuk mengevaluasi SABRE, karena menunjukkan bagaimana parameter konfigurasi memengaruhi performa layout dan routing dalam kondisi yang lebih kompleks.

Perlu diperhatikan:
- Alat HighLevelSynthesis dapat menghasilkan solusi kedalaman yang optimal untuk Circuit GHZ topologi bintang tanpa memperkenalkan gate SWAP, seperti yang ditunjukkan pada gambar di atas.
- Sebagai alternatif, pass StarPrerouting dapat mengurangi kedalaman lebih lanjut dengan memandu keputusan routing SABRE, meskipun mungkin masih memperkenalkan beberapa gate SWAP. Namun, StarPrerouting meningkatkan runtime dan membutuhkan integrasi ke dalam proses transpilasi awal.
Untuk keperluan tutorial ini, kita mengecualikan HighLevelSynthesis dan StarPrerouting agar dapat mengisolasi dan menyoroti dampak langsung dari konfigurasi SABRE pada runtime dan kedalaman sirkuit. Dengan mengukur nilai ekspektasi untuk setiap pasangan qubit, kita menganalisis:
- Seberapa baik SABRE mengurangi gate SWAP dan kedalaman sirkuit.
- Efek optimasi ini pada fidelitas Circuit yang dieksekusi, di mana penyimpangan dari menunjukkan hilangnya jeratan.!
# set seed for reproducibility
seed = 42
num_qubits = 110
# Create GHZ circuit
qc = QuantumCircuit(num_qubits)
qc.h(0)
for i in range(1, num_qubits):
qc.cx(0, i)
qc.measure_all()
Selanjutnya, kita akan memetakan operator yang diminati untuk mengevaluasi perilaku sistem. Secara khusus, kita akan menggunakan operator ZZ antara qubit untuk memeriksa bagaimana jeratan menurun seiring qubit semakin berjauhan. Analisis ini penting karena ketidakakuratan dalam nilai ekspektasi untuk qubit yang jauh dapat mengungkapkan dampak noise dan kesalahan dalam eksekusi sirkuit. Dengan mempelajari penyimpangan ini, kita mendapatkan wawasan tentang seberapa baik sirkuit mempertahankan jeratan di bawah konfigurasi SABRE yang berbeda dan seberapa efektif SABRE meminimalkan dampak kendala perangkat keras.
# ZZII...II, ZIZI...II, ... , ZIII...IZ
operator_strings = [
"Z" + "I" * i + "Z" + "I" * (num_qubits - 2 - i)
for i in range(num_qubits - 1)
]
print(operator_strings)
print(len(operator_strings))
operators = [SparsePauliOp(operator) for operator in operator_strings]
['ZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZI', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZ']
109
Langkah 2: Optimalkan Masalah untuk Eksekusi Perangkat Keras Kuantum​
Pada langkah ini, kita fokus mengoptimalkan layout sirkuit untuk eksekusi pada perangkat keras kuantum tertentu dengan 127 qubit. Ini adalah fokus utama tutorial, karena kita melakukan optimasi SABRE dan transpilasi untuk mencapai performa sirkuit terbaik. Menggunakan pass SabreLayout, kita menentukan pemetaan qubit awal yang meminimalkan kebutuhan gate SWAP selama routing. Dengan meneruskan coupling_map dari Backend target, SabreLayout mengadaptasi layout ke kendala konektivitas perangkat.
Kita akan menggunakan generate_preset_pass_manager dengan optimization_level=3 untuk proses transpilasi dan menyesuaikan pass SabreLayout dengan berbagai konfigurasi. Tujuannya adalah menemukan pengaturan yang menghasilkan sirkuit yang ditranspilasi dengan ukuran dan/atau kedalaman terendah, menunjukkan dampak optimasi SABRE.
Mengapa Ukuran dan Kedalaman Sirkuit Penting?​
- Ukuran lebih kecil (jumlah gate): Mengurangi jumlah operasi, meminimalkan peluang kesalahan terakumulasi.
- Kedalaman lebih rendah: Mempersingkat total waktu eksekusi, yang penting untuk menghindari dekoherensi dan mempertahankan fidelitas keadaan kuantum.
Dengan mengoptimalkan metrik ini, kita meningkatkan keandalan dan akurasi eksekusi sirkuit pada perangkat keras kuantum yang berisik. Pilih Backend.
service = QiskitRuntimeService()
# backend = service.least_busy(
# operational=True, simulator=False, min_num_qubits=127
# )
backend = service.backend("ibm_boston")
print(f"Using backend: {backend.name}")
Using backend: ibm_boston
Untuk mengevaluasi dampak berbagai konfigurasi pada optimasi sirkuit, kita akan membuat tiga pass manager, masing-masing dengan pengaturan unik untuk pass SabreLayout. Konfigurasi ini membantu menganalisis trade-off antara kualitas sirkuit dan waktu transpilasi.
Parameter Utama​
max_iterations: Jumlah iterasi routing maju-mundur untuk menyempurnakan layout dan mengurangi biaya routing.layout_trials: Jumlah layout awal acak yang diuji, memilih yang meminimalkan gate SWAP.swap_trials: Jumlah uji routing untuk setiap layout, menyempurnakan penempatan gate untuk routing yang lebih baik.
Tingkatkan layout_trials dan swap_trials untuk melakukan optimasi yang lebih menyeluruh, dengan biaya peningkatan waktu transpilasi.
Konfigurasi dalam Tutorial Ini​
-
pm_1: Pengaturan default denganoptimization_level=3.max_iterations=4layout_trials=20swap_trials=20
-
pm_2: Meningkatkan jumlah uji untuk eksplorasi yang lebih baik.max_iterations=4layout_trials=200swap_trials=200
-
pm_3: Memperluaspm_2dengan meningkatkan jumlah iterasi untuk penyempurnaan lebih lanjut.max_iterations=8layout_trials=200swap_trials=200
Dengan membandingkan hasil konfigurasi ini, kita bertujuan menentukan mana yang mencapai keseimbangan terbaik antara kualitas sirkuit (misalnya, ukuran dan kedalaman) dan biaya komputasi.
# Get the coupling map from the backend
cmap = CouplingMap(backend().configuration().coupling_map)
# Create the SabreLayout passes for the custom configurations
sl_2 = SabreLayout(
coupling_map=cmap,
seed=seed,
max_iterations=4,
layout_trials=200,
swap_trials=200,
)
sl_3 = SabreLayout(
coupling_map=cmap,
seed=seed,
max_iterations=8,
layout_trials=200,
swap_trials=200,
)
# Create the pass managers, need to first create then configure the SabreLayout passes
pm_1 = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
pm_2 = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
pm_3 = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
Sekarang kita bisa mengkonfigurasi pass SabreLayout di pass manager kustom. Untuk melakukan ini, kita tahu bahwa untuk generate_preset_pass_manager default pada optimization_level=3, pass SabreLayout berada di indeks 2, karena SabreLayout terjadi setelah pass SetLayout dan VF2Layout. Kita bisa mengakses pass ini dan memodifikasi parameternya.
pm_2.layout.replace(index=2, passes=sl_2)
pm_3.layout.replace(index=2, passes=sl_3)
Dengan setiap pass manager dikonfigurasi, kita sekarang akan menjalankan proses transpilasi untuk masing-masing. Untuk membandingkan hasil, kita akan melacak metrik kunci, termasuk waktu transpilasi, kedalaman sirkuit (diukur sebagai kedalaman gate dua qubit), dan jumlah total gate dalam sirkuit yang ditranspilasi.
# Transpile the circuit with each pass manager and measure the time
t0 = time.time()
tqc_1 = pm_1.run(qc)
t1 = time.time() - t0
t0 = time.time()
tqc_2 = pm_2.run(qc)
t2 = time.time() - t0
t0 = time.time()
tqc_3 = pm_3.run(qc)
t3 = time.time() - t0
# Obtain the depths and the total number of gates (circuit size)
depth_1 = tqc_1.depth(lambda x: x.operation.num_qubits == 2)
depth_2 = tqc_2.depth(lambda x: x.operation.num_qubits == 2)
depth_3 = tqc_3.depth(lambda x: x.operation.num_qubits == 2)
size_1 = tqc_1.size()
size_2 = tqc_2.size()
size_3 = tqc_3.size()
# Transform the observables to match the backend's ISA
operators_list_1 = [op.apply_layout(tqc_1.layout) for op in operators]
operators_list_2 = [op.apply_layout(tqc_2.layout) for op in operators]
operators_list_3 = [op.apply_layout(tqc_3.layout) for op in operators]
# Compute improvements compared to pass manager 1 (default)
depth_improvement_2 = ((depth_1 - depth_2) / depth_1) * 100
depth_improvement_3 = ((depth_1 - depth_3) / depth_1) * 100
size_improvement_2 = ((size_1 - size_2) / size_1) * 100
size_improvement_3 = ((size_1 - size_3) / size_1) * 100
time_increase_2 = ((t2 - t1) / t1) * 100
time_increase_3 = ((t3 - t1) / t1) * 100
print(
f"Pass manager 1 (4,20,20) : Depth {depth_1}, Size {size_1}, Time {t1:.4f} s"
)
print(
f"Pass manager 2 (4,200,200): Depth {depth_2}, Size {size_2}, Time {t2:.4f} s"
)
print(f" - Depth improvement: {depth_improvement_2:.2f}%")
print(f" - Size improvement: {size_improvement_2:.2f}%")
print(f" - Time increase: {time_increase_2:.2f}%")
print(
f"Pass manager 3 (8,200,200): Depth {depth_3}, Size {size_3}, Time {t3:.4f} s"
)
print(f" - Depth improvement: {depth_improvement_3:.2f}%")
print(f" - Size improvement: {size_improvement_3:.2f}%")
print(f" - Time increase: {time_increase_3:.2f}%")
Pass manager 1 (4,20,20) : Depth 439, Size 2346, Time 0.5775 s
Pass manager 2 (4,200,200): Depth 395, Size 2070, Time 3.9927 s
- Depth improvement: 10.02%
- Size improvement: 11.76%
- Time increase: 591.43%
Pass manager 3 (8,200,200): Depth 375, Size 1873, Time 2.3079 s
- Depth improvement: 14.58%
- Size improvement: 20.16%
- Time increase: 299.67%
Hasil ini menunjukkan bahwa meningkatkan jumlah uji (layout_trials dan swap_trials) dapat secara signifikan meningkatkan kualitas sirkuit dengan mengurangi kedalaman dan ukuran. Namun, peningkatan ini sering datang dengan biaya peningkatan runtime karena komputasi tambahan yang diperlukan untuk mengeksplorasi lebih banyak layout potensial dan jalur routing.
Meningkatkan max_iterations dapat semakin meningkatkan optimasi dengan menyempurnakan layout melalui lebih banyak siklus routing maju-mundur. Dalam kasus ini, meningkatkan max_iterations menghasilkan pengurangan paling signifikan dalam kedalaman dan ukuran sirkuit, bahkan mengurangi runtime dibandingkan pm_2, kemungkinan dengan menyederhanakan tahap optimasi berikutnya. Penting untuk dicatat, bagaimanapun, bahwa efektivitas meningkatkan max_iterations dapat bervariasi secara signifikan tergantung pada sirkuit. Meskipun lebih banyak iterasi dapat menghasilkan pilihan layout dan routing yang lebih baik, mereka tidak memberikan jaminan dan sangat bergantung pada struktur sirkuit dan kompleksitas kendala konektivitas.
# Plot the results of the metrics
times = [t1, t2, t3]
depths = [depth_1, depth_2, depth_3]
sizes = [size_1, size_2, size_3]
pm_names = [
"pm_1 (4 iter, 20 trials)",
"pm_2 (4 iter, 200 trials)",
"pm_3 (8 iter, 200 trials)",
]
colors = plt.cm.viridis(np.linspace(0.2, 0.8, len(pm_names)))
# Create a figure with three subplots
fig, axs = plt.subplots(3, 1, figsize=(6, 9), sharex=True)
axs[0].bar(pm_names, times, color=colors)
axs[0].set_ylabel("Time (s)", fontsize=12)
axs[0].set_title("Transpilation Time", fontsize=14)
axs[0].grid(axis="y", linestyle="--", alpha=0.7)
axs[1].bar(pm_names, depths, color=colors)
axs[1].set_ylabel("Depth", fontsize=12)
axs[1].set_title("Circuit Depth", fontsize=14)
axs[1].grid(axis="y", linestyle="--", alpha=0.7)
axs[2].bar(pm_names, sizes, color=colors)
axs[2].set_ylabel("Size", fontsize=12)
axs[2].set_title("Circuit Size", fontsize=14)
axs[2].set_xticks(range(len(pm_names)))
axs[2].set_xticklabels(pm_names, fontsize=10, rotation=15)
axs[2].grid(axis="y", linestyle="--", alpha=0.7)
# Add some spacing between subplots
plt.tight_layout()
plt.show()
Langkah 3: Eksekusi Menggunakan Primitif Qiskit​
Pada langkah ini, kita menggunakan primitif Estimator untuk menghitung nilai ekspektasi untuk operator ZZ, mengevaluasi jeratan dan kualitas eksekusi Circuit yang ditranspilasi. Untuk selaras dengan alur kerja pengguna yang umum, kita mengirimkan job untuk eksekusi dan menerapkan penekanan kesalahan menggunakan dynamical decoupling, sebuah teknik yang memitigasi dekoherensi dengan menyisipkan urutan gate untuk mempertahankan keadaan qubit. Selain itu, kita menentukan tingkat resiliensi untuk mengatasi noise, dengan tingkat yang lebih tinggi memberikan hasil yang lebih akurat dengan biaya peningkatan waktu pemrosesan. Pendekatan ini menilai performa setiap konfigurasi pass manager dalam kondisi eksekusi yang realistis.
options = EstimatorOptions()
options.resilience_level = 2
options.dynamical_decoupling.enable = True
options.dynamical_decoupling.sequence_type = "XY4"
# Create an Estimator object
estimator = Estimator(backend, options=options)
# Submit the circuit to Estimator
job_1 = estimator.run([(tqc_1, operators_list_1)])
job_1_id = job_1.job_id()
print(job_1_id)
job_2 = estimator.run([(tqc_2, operators_list_2)])
job_2_id = job_2.job_id()
print(job_2_id)
job_3 = estimator.run([(tqc_3, operators_list_3)])
job_3_id = job_3.job_id()
print(job_3_id)
d5k0qs7853es738dab6g
d5k0qsf853es738dab70
d5k0qsf853es738dab7g
# Run the jobs
result_1 = job_1.result()[0]
print("Job 1 done")
result_2 = job_2.result()[0]
print("Job 2 done")
result_3 = job_3.result()[0]
print("Job 3 done")
Job 1 done
Job 2 done
Job 3 done
Langkah 4: Pasca-Proses dan Kembalikan Hasil dalam Format Klasik yang Diinginkan​
Setelah job selesai, kita menganalisis hasil dengan memplot nilai ekspektasi untuk setiap qubit. Dalam simulasi ideal, semua nilai seharusnya bernilai 1, mencerminkan jeratan sempurna di seluruh qubit. Namun, karena noise dan kendala perangkat keras, nilai ekspektasi biasanya menurun seiring peningkatan i, mengungkapkan bagaimana jeratan menurun seiring jarak.
Pada langkah ini, kita membandingkan hasil dari setiap konfigurasi pass manager dengan simulasi ideal. Dengan memeriksa penyimpangan dari 1 untuk setiap konfigurasi, kita dapat mengukur seberapa baik setiap pass manager mempertahankan jeratan dan memitigasi efek noise. Analisis ini secara langsung menilai dampak optimasi SABRE pada fidelitas eksekusi dan menyoroti konfigurasi mana yang terbaik dalam menyeimbangkan kualitas optimasi dan performa eksekusi.
Hasil akan divisualisasikan untuk menyoroti perbedaan di seluruh pass manager, menampilkan bagaimana peningkatan dalam layout dan routing memengaruhi eksekusi sirkuit akhir pada perangkat keras kuantum yang berisik.
data = list(range(1, len(operators) + 1)) # Distance between the Z operators
values_1 = list(result_1.data.evs)
values_2 = list(result_2.data.evs)
values_3 = list(result_3.data.evs)
plt.plot(
data,
values_1,
marker="o",
label="pm_1 (iters=4, swap_trials=20, layout_trials=20)",
)
plt.plot(
data,
values_2,
marker="s",
label="pm_2 (iters=4, swap_trials=200, layout_trials=200)",
)
plt.plot(
data,
values_3,
marker="^",
label="pm_3 (iters=8, swap_trials=200, layout_trials=200)",
)
plt.xlabel("Distance between qubits $i$")
plt.ylabel(r"$\langle Z_i Z_0 \rangle / \langle Z_1 Z_0 \rangle $")
plt.legend()
plt.show()

Analisis Hasil​
Plot menunjukkan nilai ekspektasi sebagai fungsi jarak antar qubit untuk tiga konfigurasi pass manager dengan tingkat optimasi yang meningkat. Dalam kasus ideal, nilai-nilai ini tetap mendekati 1, menunjukkan korelasi yang kuat di seluruh sirkuit. Seiring peningkatan jarak, noise dan kesalahan yang terakumulasi menyebabkan penurunan korelasi, mengungkapkan seberapa baik setiap strategi transpilasi mempertahankan struktur yang mendasari keadaan tersebut.
Di antara ketiga konfigurasi, pm_1 jelas berkinerja paling buruk. Nilai korelasinya menurun dengan cepat seiring peningkatan jarak dan mendekati nol jauh lebih awal dari dua konfigurasi lainnya. Perilaku ini konsisten dengan kedalaman sirkuit dan jumlah gate yang lebih besar, di mana noise yang terakumulasi dengan cepat menurunkan korelasi jarak jauh.
Baik pm_2 maupun pm_3 mewakili peningkatan signifikan dibandingkan pm_1 di hampir semua jarak. Secara rata-rata, pm_3 menunjukkan performa keseluruhan yang paling kuat, mempertahankan nilai korelasi yang lebih tinggi dalam jarak yang lebih jauh dan menunjukkan penurunan yang lebih bertahap. Ini selaras dengan optimasinya yang lebih agresif, yang menghasilkan sirkuit yang lebih dangkal dan umumnya lebih tahan terhadap akumulasi noise.
Namun demikian, pm_2 menunjukkan akurasi yang jauh lebih baik pada jarak pendek dibandingkan pm_3, meskipun memiliki kedalaman dan jumlah gate yang sedikit lebih besar. Ini menunjukkan bahwa kedalaman sirkuit saja tidak sepenuhnya menentukan performa; struktur spesifik yang dihasilkan oleh transpilasi, termasuk bagaimana gate yang saling menjerat diatur dan bagaimana kesalahan merambat melalui sirkuit, juga memainkan peran penting. Dalam beberapa kasus, transformasi yang diterapkan oleh pm_2 tampaknya lebih baik dalam mempertahankan korelasi lokal, meskipun tidak berskala sebaik untuk jarak yang lebih jauh.
Secara keseluruhan, hasil ini menyoroti trade-off antara kekompakan sirkuit dan struktur sirkuit. Meskipun peningkatan optimasi umumnya meningkatkan stabilitas jarak jauh, performa terbaik untuk observable tertentu bergantung pada pengurangan kedalaman sirkuit sekaligus menghasilkan struktur yang cocok dengan karakteristik noise perangkat keras.
Part II. Mengonfigurasi Heuristik di SABRE dan Menggunakan Serverless​
Selain menyesuaikan jumlah percobaan, SABRE mendukung kustomisasi heuristik routing yang digunakan selama transpilasi. Secara default, SabreLayout menggunakan heuristik decay, yang secara dinamis memboboti qubit berdasarkan kemungkinan mereka di-swap. Untuk menggunakan heuristik berbeda (seperti heuristik lookahead), kamu bisa membuat pass SabreSwap kustom dan menghubungkannya ke SabreLayout dengan menjalankan PassManager bersama FullAncillaAllocation, EnlargeWithAncilla, dan ApplyLayout. Saat menggunakan SabreSwap sebagai parameter untuk SabreLayout, hanya satu percobaan layout yang dilakukan secara default. Untuk menjalankan beberapa percobaan layout secara efisien, kita memanfaatkan runtime serverless untuk paralelisasi. Untuk informasi lebih lanjut tentang serverless, lihat dokumentasi Serverless.
Cara Mengubah Heuristik Routing​
- Buat pass
SabreSwapkustom dengan heuristik yang diinginkan. - Gunakan
SabreSwapkustom ini sebagai metode routing untuk passSabreLayout.
Meskipun memungkinkan untuk menjalankan beberapa percobaan layout menggunakan loop, runtime serverless adalah pilihan yang lebih baik untuk eksperimen berskala besar dan lebih intensif. Serverless mendukung eksekusi paralel dari percobaan layout, yang secara signifikan mempercepat optimasi sirkuit yang lebih besar dan sweep eksperimen yang luas. Hal ini membuatnya sangat berharga saat bekerja dengan tugas-tugas yang intensif sumber daya atau ketika efisiensi waktu sangat penting.
Bagian ini berfokus hanya pada langkah 2 optimasi: meminimalkan ukuran dan kedalaman sirkuit untuk mendapatkan sirkuit hasil transpilasi terbaik. Berdasarkan hasil sebelumnya, kita kini menjelajahi bagaimana kustomisasi heuristik dan paralelisasi serverless dapat lebih meningkatkan performa optimasi, menjadikannya cocok untuk transpilasi sirkuit kuantum berskala besar.
Hasil tanpa runtime serverless (1 percobaan layout):​
swap_trials = 1000
# Default PassManager with `SabreLayout` and `SabreSwap`, using heuristic "decay"
sr_default = SabreSwap(
coupling_map=cmap, heuristic="decay", trials=swap_trials, seed=seed
)
sl_default = SabreLayout(
coupling_map=cmap, routing_pass=sr_default, seed=seed
)
pm_default = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
pm_default.layout.replace(index=2, passes=sl_default)
pm_default.routing.replace(index=1, passes=sr_default)
t0 = time.time()
tqc_default = pm_default.run(qc)
t_default = time.time() - t0
size_default = tqc_default.size()
depth_default = tqc_default.depth(lambda x: x.operation.num_qubits == 2)
# Custom PassManager with `SabreLayout` and `SabreSwap`, using heuristic "lookahead"
sr_custom = SabreSwap(
coupling_map=cmap, heuristic="lookahead", trials=swap_trials, seed=seed
)
sl_custom = SabreLayout(coupling_map=cmap, routing_pass=sr_custom, seed=seed)
pm_custom = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
pm_custom.layout.replace(index=2, passes=sl_custom)
pm_custom.routing.replace(index=1, passes=sr_custom)
t0 = time.time()
tqc_custom = pm_custom.run(qc)
t_custom = time.time() - t0
size_custom = tqc_custom.size()
depth_custom = tqc_custom.depth(lambda x: x.operation.num_qubits == 2)
print(
f"Default (heuristic='decay') : Depth {depth_default}, Size {size_default}, Time {t_default}"
)
print(
f"Custom (heuristic='lookahead'): Depth {depth_custom}, Size {size_custom}, Time {t_custom}"
)
Default (heuristic='decay') : Depth 443, Size 3115, Time 1.034372091293335
Custom (heuristic='lookahead'): Depth 432, Size 2856, Time 0.6669301986694336
Di sini kita melihat bahwa heuristik lookahead berkinerja lebih baik daripada heuristik decay dalam hal kedalaman sirkuit, ukuran, dan waktu. Peningkatan ini menunjukkan bagaimana kita bisa meningkatkan SABRE melampaui sekadar percobaan dan iterasi untuk sirkuit dan batasan perangkat keras tertentu. Perlu dicatat bahwa hasil ini didasarkan pada satu percobaan layout. Untuk mendapatkan hasil yang lebih akurat, kami merekomendasikan menjalankan beberapa percobaan layout, yang dapat dilakukan secara efisien menggunakan runtime serverless.
Hasil dengan runtime serverless (beberapa percobaan layout)​
Qiskit Serverless mengharuskan pengaturan file .py workload ke dalam direktori khusus. Sel kode berikut adalah file Python di direktori source_files bernama transpile_remote.py. File ini berisi fungsi yang menjalankan proses transpilasi.
# This cell is hidden from users, it makes sure the `source_files` directory exists
from pathlib import Path
Path("source_files").mkdir(exist_ok=True)
%%writefile source_files/transpile_remote.py
import time
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes import SabreLayout, SabreSwap
from qiskit.transpiler import CouplingMap
from qiskit_serverless import get_arguments, save_result, distribute_task, get
from qiskit_ibm_runtime import QiskitRuntimeService
@distribute_task(target={
"cpu": 1,
"mem": 1024 * 1024 * 1024
})
def transpile_remote(qc, optimization_level, backend_name, seed, swap_trials, heuristic):
"""Transpiles an abstract circuit into an ISA circuit for a given backend."""
service = QiskitRuntimeService()
backend = service.backend(backend_name)
pm = generate_preset_pass_manager(
optimization_level=optimization_level,
backend=backend,
seed_transpiler=seed
)
# Changing the `SabreLayout` and `SabreSwap` passes to use the custom configurations
cmap = CouplingMap(backend().configuration().coupling_map)
sr = SabreSwap(coupling_map=cmap, heuristic=heuristic, trials=swap_trials, seed=seed)
sl = SabreLayout(coupling_map=cmap, routing_pass=sr, seed=seed)
pm.layout.replace(index=2, passes=sl)
pm.routing.replace(index=1, passes=sr)
# Measure the transpile time
start_time = time.time() # Start timer
tqc = pm.run(qc) # Transpile the circuit
end_time = time.time() # End timer
transpile_time = end_time - start_time # Calculate the elapsed time
return tqc, transpile_time # Return both the transpiled circuit and the transpile time
# Get program arguments
arguments = get_arguments()
circuit = arguments.get("circuit")
backend_name = arguments.get("backend_name")
optimization_level = arguments.get("optimization_level")
seed_list = arguments.get("seed_list")
swap_trials = arguments.get("swap_trials")
heuristic = arguments.get("heuristic")
# Transpile the circuits
transpile_worker_references = [
transpile_remote(circuit, optimization_level, backend_name, seed, swap_trials, heuristic)
for seed in seed_list
]
results_with_times = get(transpile_worker_references)
# Separate the transpiled circuits and their transpile times
transpiled_circuits = [result[0] for result in results_with_times]
transpile_times = [result[1] for result in results_with_times]
# Save both results and transpile times
save_result({"transpiled_circuits": transpiled_circuits, "transpile_times": transpile_times})
Overwriting source_files/transpile_remote.py
Sel berikut mengunggah file transpile_remote.py sebagai program Qiskit Serverless dengan nama transpile_remote_serverless.
serverless = QiskitServerless()
transpile_remote_demo = QiskitFunction(
title="transpile_remote_serverless",
entrypoint="transpile_remote.py",
working_dir="./source_files/",
)
serverless.upload(transpile_remote_demo)
transpile_remote_serverless = serverless.load("transpile_remote_serverless")
Buat 20 seed berbeda untuk mewakili 20 percobaan layout yang berbeda.
num_seeds = 20 # represents the different layout trials
seed_list = [seed + i for i in range(num_seeds)]
Jalankan program yang telah diunggah dan berikan input untuk heuristik lookahead.
job_lookahead = transpile_remote_serverless.run(
circuit=qc,
backend_name=backend.name,
optimization_level=3,
seed_list=seed_list,
swap_trials=swap_trials,
heuristic="lookahead",
)
job_lookahead.job_id
'15767dfc-e71d-4720-94d6-9212f72334c2'
job_lookahead.status()
'QUEUED'
Terima log dan hasil dari runtime serverless.
logs_lookahead = job_lookahead.logs()
print(logs_lookahead)
No logs yet.
Setelah program berstatus DONE, kamu bisa menggunakan job.results() untuk mengambil hasil yang tersimpan di save_result().
# Run the job with lookahead heuristic
start_time = time.time()
results_lookahead = job_lookahead.result()
end_time = time.time()
job_lookahead_time = end_time - start_time
Sekarang lakukan hal yang sama untuk heuristik decay.
job_decay = transpile_remote_serverless.run(
circuit=qc,
backend_name=backend.name,
optimization_level=3,
seed_list=seed_list,
swap_trials=swap_trials,
heuristic="decay",
)
job_decay.job_id
'00418c76-d6ec-4bd8-9f70-05d0fa14d4eb'
logs_decay = job_decay.logs()
print(logs_decay)
No logs yet.
# Run the job with the decay heuristic
start_time = time.time()
results_decay = job_decay.result()
end_time = time.time()
job_decay_time = end_time - start_time
# Extract transpilation times
transpile_times_decay = results_decay["transpile_times"]
transpile_times_lookahead = results_lookahead["transpile_times"]
# Calculate total transpilation time for serial execution
total_transpile_time_decay = sum(transpile_times_decay)
total_transpile_time_lookahead = sum(transpile_times_lookahead)
# Print total transpilation time
print("=== Total Transpilation Time (Serial Execution) ===")
print(f"Decay Heuristic : {total_transpile_time_decay:.2f} seconds")
print(f"Lookahead Heuristic: {total_transpile_time_lookahead:.2f} seconds")
# Print serverless job time (parallel execution)
print("\n=== Serverless Job Time (Parallel Execution) ===")
print(f"Decay Heuristic : {job_decay_time:.2f} seconds")
print(f"Lookahead Heuristic: {job_lookahead_time:.2f} seconds")
# Calculate and print average runtime per transpilation
avg_transpile_time_decay = total_transpile_time_decay / num_seeds
avg_transpile_time_lookahead = total_transpile_time_lookahead / num_seeds
avg_job_time_decay = job_decay_time / num_seeds
avg_job_time_lookahead = job_lookahead_time / num_seeds
print("\n=== Average Time Per Transpilation ===")
print(f"Decay Heuristic (Serial) : {avg_transpile_time_decay:.2f} seconds")
print(f"Decay Heuristic (Serverless): {avg_job_time_decay:.2f} seconds")
print(
f"Lookahead Heuristic (Serial) : {avg_transpile_time_lookahead:.2f} seconds"
)
print(
f"Lookahead Heuristic (Serverless): {avg_job_time_lookahead:.2f} seconds"
)
# Calculate and print serverless improvement percentage
decay_improvement_percentage = (
(total_transpile_time_decay - job_decay_time) / total_transpile_time_decay
) * 100
lookahead_improvement_percentage = (
(total_transpile_time_lookahead - job_lookahead_time)
/ total_transpile_time_lookahead
) * 100
print("\n=== Serverless Improvement ===")
print(f"Decay Heuristic : {decay_improvement_percentage:.2f}%")
print(f"Lookahead Heuristic: {lookahead_improvement_percentage:.2f}%")
=== Total Transpilation Time (Serial Execution) ===
Decay Heuristic : 112.37 seconds
Lookahead Heuristic: 85.37 seconds
=== Serverless Job Time (Parallel Execution) ===
Decay Heuristic : 5.72 seconds
Lookahead Heuristic: 5.85 seconds
=== Average Time Per Transpilation ===
Decay Heuristic (Serial) : 5.62 seconds
Decay Heuristic (Serverless): 0.29 seconds
Lookahead Heuristic (Serial) : 4.27 seconds
Lookahead Heuristic (Serverless): 0.29 seconds
=== Serverless Improvement ===
Decay Heuristic : 94.91%
Lookahead Heuristic: 93.14%
Hasil ini menunjukkan keuntungan efisiensi yang substansial dari penggunaan eksekusi serverless untuk transpilasi sirkuit kuantum. Dibandingkan dengan eksekusi serial, eksekusi serverless secara dramatis mengurangi total waktu eksekusi untuk heuristik decay maupun lookahead dengan memparalelkan percobaan transpilasi yang independen. Sementara eksekusi serial mencerminkan biaya kumulatif penuh dari penjelajahan beberapa percobaan layout, waktu job serverless menunjukkan bagaimana eksekusi paralel dapat memadatkan biaya ini menjadi waktu clock yang jauh lebih singkat. Hasilnya, waktu efektif per transpilasi berkurang menjadi sebagian kecil dari yang diperlukan dalam pengaturan serial, terlepas dari heuristik yang digunakan. Kemampuan ini sangat penting untuk mengoptimalkan SABRE hingga potensi penuhnya. Banyak peningkatan performa terkuat SABRE berasal dari meningkatkan jumlah percobaan layout dan routing, yang bisa sangat mahal jika dieksekusi secara berurutan. Eksekusi serverless menghilangkan bottleneck ini, memungkinkan sweep parameter berskala besar dan eksplorasi konfigurasi heuristik yang lebih mendalam dengan overhead minimal.
Secara keseluruhan, temuan ini menunjukkan bahwa eksekusi serverless adalah kunci untuk menskalakan optimasi SABRE, membuat eksperimentasi agresif dan penyempurnaan menjadi praktis dibandingkan eksekusi serial.
Ambil hasil dari runtime serverless dan bandingkan hasil heuristik lookahead dan decay. Kita akan membandingkan ukuran dan kedalamannya.
# Extract sizes and depths
sizes_lookahead = [
circuit.size() for circuit in results_lookahead["transpiled_circuits"]
]
depths_lookahead = [
circuit.depth(lambda x: x.operation.num_qubits == 2)
for circuit in results_lookahead["transpiled_circuits"]
]
sizes_decay = [
circuit.size() for circuit in results_decay["transpiled_circuits"]
]
depths_decay = [
circuit.depth(lambda x: x.operation.num_qubits == 2)
for circuit in results_decay["transpiled_circuits"]
]
def create_scatterplot(x, y1, y2, xlabel, ylabel, title, labels, colors):
plt.figure(figsize=(8, 5))
plt.scatter(
x, y1, label=labels[0], color=colors[0], alpha=0.8, edgecolor="k"
)
plt.scatter(
x, y2, label=labels[1], color=colors[1], alpha=0.8, edgecolor="k"
)
plt.xlabel(xlabel, fontsize=12)
plt.ylabel(ylabel, fontsize=12)
plt.title(title, fontsize=14)
plt.legend(fontsize=10)
plt.grid(axis="y", linestyle="--", alpha=0.7)
plt.tight_layout()
plt.show()
create_scatterplot(
seed_list,
sizes_lookahead,
sizes_decay,
"Seed",
"Size",
"Circuit Size",
["lookahead", "Decay"],
["blue", "red"],
)
create_scatterplot(
seed_list,
depths_lookahead,
depths_decay,
"Seed",
"Depth",
"Circuit Depth",
["lookahead", "Decay"],
["blue", "red"],
)


Setiap titik dalam scatter plot di atas mewakili satu percobaan layout, dengan sumbu x menunjukkan kedalaman sirkuit dan sumbu y menunjukkan ukuran sirkuit. Hasil menunjukkan bahwa heuristik lookahead umumnya mengungguli heuristik decay dalam meminimalkan kedalaman dan ukuran sirkuit. Dalam aplikasi praktis, tujuannya adalah mengidentifikasi percobaan layout optimal untuk heuristik yang dipilih, baik dengan memprioritaskan kedalaman maupun ukuran. Hal ini dapat dicapai dengan memilih percobaan dengan nilai terendah untuk metrik yang diinginkan. Yang penting, meningkatkan jumlah percobaan layout meningkatkan peluang untuk mencapai hasil yang lebih baik dalam hal ukuran atau kedalaman, tetapi dengan biaya overhead komputasi yang lebih tinggi.
min_depth_lookahead = min(depths_lookahead)
min_depth_decay = min(depths_decay)
min_size_lookahead = min(sizes_lookahead)
min_size_decay = min(sizes_decay)
print(
"Lookahead: Min Depth",
min_depth_lookahead,
"Min Size",
min_size_lookahead,
)
print("Decay: Min Depth", min_depth_decay, "Min Size", min_size_decay)
Lookahead: Min Depth 399 Min Size 2452
Decay: Min Depth 415 Min Size 2611
Dalam perbandingan awal kami menggunakan satu percobaan layout, heuristik lookahead menunjukkan performa yang sedikit lebih baik baik dalam kedalaman maupun ukuran sirkuit. Dengan memperluas studi ini ke beberapa percobaan layout menggunakan QiskitServerless, kami dapat mengeksplorasi ruang inisialisasi SABRE yang jauh lebih luas, memungkinkan perbandingan yang lebih representatif antara heuristik.
Dari scatter plot dan hasil terbaik yang diamati, jelas bahwa performa bervariasi secara signifikan dengan seed acak yang digunakan oleh SABRE. Kedua heuristik menunjukkan sebaran yang luas dalam kedalaman dan ukuran sirkuit di berbagai seed, menunjukkan bahwa satu run seringkali tidak cukup untuk menangkap hasil mendekati optimal. Variabilitas ini menekankan pentingnya menjalankan banyak percobaan dengan seed berbeda saat bertujuan meminimalkan kedalaman dan/atau jumlah gate. Di seluruh set percobaan, baik heuristik lookahead maupun decay mampu menghasilkan hasil yang kompetitif. Dalam beberapa kasus, heuristik decay mampu menyamai atau bahkan mengungguli lookahead untuk seed tertentu. Namun, untuk sirkuit tertentu ini, hasil keseluruhan terbaik diperoleh menggunakan heuristik lookahead, meskipun dengan selisih yang tipis. Ini menunjukkan bahwa meskipun lookahead memberikan hasil terkuat di sini, keunggulannya atas decay tidak mutlak.
Secara keseluruhan, hasil ini memperkuat dua poin kunci. Pertama, memanfaatkan banyak seed sangat penting untuk mengekstrak performa terbaik yang mungkin dari SABRE, terlepas dari heuristik yang digunakan. Kedua, meskipun pilihan heuristik penting, struktur sirkuit memainkan peran dominan, dan performa relatif lookahead dan decay mungkin berbeda untuk sirkuit lain. Oleh karena itu, eksperimentasi multi-seed berskala besar sangat penting untuk transpilasi sirkuit kuantum yang kuat dan efektif.
# This cell is hidden from users, it cleans up the `source_files` directory
from pathlib import Path
Path("source_files/transpile_remote.py").unlink()
Path("source_files").rmdir()
Kesimpulan​
Dalam tutorial ini, kita menjelajahi cara mengoptimalkan sirkuit besar menggunakan SABRE di Qiskit. Kita mendemonstrasikan cara mengonfigurasi pass SabreLayout dengan berbagai parameter untuk menyeimbangkan kualitas sirkuit dan waktu transpilasi. Kita juga menunjukkan cara menyesuaikan heuristik routing di SABRE dan menggunakan runtime QiskitServerless untuk memparalelkan percobaan layout secara efisien ketika SabreSwap terlibat. Dengan menyesuaikan parameter dan heuristik ini, kamu dapat mengoptimalkan layout dan routing sirkuit besar, memastikan eksekusinya berjalan efisien di perangkat keras kuantum.
Survei tutorial​
Silakan isi survei singkat ini untuk memberikan masukan tentang tutorial ini. Wawasanmu 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.