Circuit cutting untuk pengurangan kedalaman
Perkiraan penggunaan: Delapan menit pada prosesor Eagle (CATATAN: Ini hanya perkiraan. Waktu eksekusi kamu mungkin berbeda.)
Latar Belakangβ
Tutorial ini menunjukkan cara membangun Qiskit pattern untuk memotong gate dalam quantum circuit guna mengurangi kedalaman circuit. Untuk diskusi lebih mendalam tentang circuit cutting, kunjungi dokumentasi circuit cutting Qiskit addon.
Persyaratanβ
Sebelum memulai tutorial ini, pastikan kamu sudah menginstal hal-hal berikut:
- Qiskit SDK v2.0 atau lebih baru, dengan dukungan visualisasi
- Qiskit Runtime v0.22 atau lebih baru (
pip install qiskit-ibm-runtime) - Circuit cutting Qiskit addon v0.9.0 atau lebih baru (
pip install qiskit-addon-cutting)
Setupβ
# Added by doQumentation β required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-ibm-runtime
import numpy as np
from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import PauliList, Statevector, SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_addon_cutting import (
cut_gates,
generate_cutting_experiments,
reconstruct_expectation_values,
)
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
Langkah 1: Petakan input klasik ke masalah kuantumβ
Kita akan mengimplementasikan pola Qiskit menggunakan empat langkah yang diuraikan dalam dokumentasi. Dalam hal ini, kita akan menyimulasikan nilai ekspektasi pada circuit dengan kedalaman tertentu dengan cara memotong gate yang menghasilkan swap gate dan menjalankan subeksperimen pada circuit yang lebih dangkal. Gate cutting relevan untuk Langkah 2 (mengoptimalkan circuit untuk eksekusi kuantum dengan mengurai gate yang berjauhan) dan Langkah 4 (pasca-pemrosesan untuk merekonstruksi nilai ekspektasi pada circuit asli). Pada langkah pertama, kita akan membuat circuit dari library circuit Qiskit dan mendefinisikan beberapa observable.
- Input: Parameter klasik untuk mendefinisikan sebuah circuit
- Output: Circuit abstrak dan observable
circuit = EfficientSU2(num_qubits=4, entanglement="circular").decompose()
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
observables = PauliList(["ZZII", "IZZI", "IIZZ", "XIXI", "ZIZZ", "IXIX"])
circuit.draw("mpl", scale=0.8, style="iqp")
Langkah 2: Optimalkan masalah untuk eksekusi pada perangkat keras kuantumβ
- Input: Circuit abstrak dan observable
- Output: Circuit target dan observable yang dihasilkan dengan memotong gate yang berjauhan untuk mengurangi kedalaman circuit setelah transpile
Kita memilih tata letak awal yang membutuhkan dua swap untuk menjalankan gate antara Qubit 3 dan 0, serta dua swap lagi untuk mengembalikan qubit ke posisi awalnya. Kita memilih optimization_level=3, yaitu tingkat optimasi tertinggi yang tersedia dengan preset pass manager.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=circuit.num_qubits, simulator=False
)
pm = generate_preset_pass_manager(
optimization_level=3, initial_layout=[0, 1, 2, 3], backend=backend
)
transpiled_qc = pm.run(circuit)

print(f"Transpiled circuit depth: {transpiled_qc.depth()}")
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, style="iqp", fold=-1)
Transpiled circuit depth: 103
Temukan dan potong gate yang berjauhan: Kita akan mengganti gate yang berjauhan (gate yang menghubungkan qubit non-lokal, 0 dan 3) dengan objek TwoQubitQPDGate dengan menentukan indeksnya. cut_gates akan mengganti gate pada indeks yang ditentukan dengan objek TwoQubitQPDGate dan juga mengembalikan daftar instansi QPDBasis β satu untuk setiap dekomposisi gate. Objek QPDBasis berisi informasi tentang cara mengurai gate yang dipotong menjadi operasi qubit tunggal.
# Find the indices of the distant gates
cut_indices = [
i
for i, instruction in enumerate(circuit.data)
if {circuit.find_bit(q)[0] for q in instruction.qubits} == {0, 3}
]
# Decompose distant CNOTs into TwoQubitQPDGate instances
qpd_circuit, bases = cut_gates(circuit, cut_indices)
qpd_circuit.draw("mpl", scale=0.8)
Buat subeksperimen untuk dijalankan pada Backend: generate_cutting_experiments menerima circuit yang mengandung instansi TwoQubitQPDGate dan observable berupa PauliList.
Untuk menyimulasikan nilai ekspektasi dari circuit berukuran penuh, banyak subeksperimen dibuat dari distribusi kuasiprobabilitas gabungan gate yang diurai, lalu dieksekusi pada satu atau lebih backend. Jumlah sampel yang diambil dari distribusi dikontrol oleh num_samples, dan satu koefisien gabungan diberikan untuk setiap sampel unik. Untuk informasi lebih lanjut tentang cara koefisien dihitung, lihat materi penjelasan.
# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observables, num_samples=np.inf
)
Sebagai perbandingan, kita melihat bahwa subeksperimen QPD akan lebih dangkal setelah memotong gate yang berjauhan: Berikut ini adalah contoh subeksperimen yang dipilih secara acak dari circuit QPD. Kedalamannya telah berkurang lebih dari setengahnya. Banyak subeksperimen probabilistik seperti ini harus dibuat dan dievaluasi untuk merekonstruksi nilai ekspektasi dari circuit yang lebih dalam.
# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pm.run(subexperiments[100])
print(f"Original circuit depth after transpile: {transpiled_qc.depth()}")
print(
f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth()}"
)
transpiled_qpd_circuit.draw(
"mpl", scale=0.6, style="iqp", idle_wires=False, fold=-1
)
Original circuit depth after transpile: 103
QPD subexperiment depth after transpile: 46
Di sisi lain, pemotongan mengakibatkan kebutuhan sampling tambahan. Di sini kita memotong tiga gate CNOT, sehingga menghasilkan overhead sampling sebesar . Untuk lebih lanjut tentang overhead sampling yang ditimbulkan oleh circuit cutting, lihat dokumentasi Circuit Knitting Toolbox.
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 729.0
Langkah 3: Jalankan menggunakan Qiskit primitivesβ
Jalankan circuit target ("subeksperimen") dengan Sampler Primitive.
- Input: Circuit target
- Output: Distribusi kuasiprobabilitas
# Transpile the subexperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pm.run(subexperiments)
# Set up the Qiskit Runtime Sampler primitive. For a fake backend, this will use a local simulator.
sampler = SamplerV2(backend)
# Submit the subexperiments
job = sampler.run(isa_subexperiments)
# Retrieve the results
results = job.result()
print(job.job_id())
czypg1r6rr3g008mgp6g
Langkah 4: Pasca-proses dan kembalikan hasil dalam format klasik yang diinginkanβ
Gunakan hasil subeksperimen, subobservable, dan koefisien sampling untuk merekonstruksi nilai ekspektasi dari circuit asli.
Input: Distribusi kuasiprobabilitas Output: Nilai ekspektasi yang telah direkonstruksi
reconstructed_expvals = reconstruct_expectation_values(
results,
coefficients,
observables,
)
# Reconstruct final expectation value
final_expval = np.dot(reconstructed_expvals, [1] * len(observables))
print("Final reconstructed expectation value")
print(final_expval)
Final reconstructed expectation value
1.0751342773437473
ideal_expvals = [
Statevector(circuit).expectation_value(SparsePauliOp(observable))
for observable in observables
]
print("Ideal expectation value")
print(np.dot(ideal_expvals, [1] * len(observables)).real)
Ideal expectation value
1.2283177520039992
Survei tutorialβ
Silakan isi survei singkat ini untuk memberikan masukan tentang tutorial ini. Pendapatmu akan membantu kami meningkatkan konten dan pengalaman pengguna.
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.