Pemotongan Circuit untuk pengurangan kedalaman
Anggaran penggunaan: Lapan minit pada pemproses Eagle (NOTA: Ini hanyalah anggaran sahaja. Masa larian anda mungkin berbeza.)
Latar Belakangβ
Tutorial ini menunjukkan cara membina Qiskit pattern untuk memotong gate dalam Circuit kuantum bagi mengurangkan kedalaman Circuit. Untuk perbincangan lebih mendalam tentang pemotongan Circuit, lawati dokumentasi addon Qiskit pemotongan Circuit.
Keperluanβ
Sebelum memulakan tutorial ini, pastikan anda telah memasang perkara berikut:
- Qiskit SDK v2.0 atau lebih baharu, dengan sokongan visualisasi
- Qiskit Runtime v0.22 atau lebih baharu (
pip install qiskit-ibm-runtime) - Addon Qiskit pemotongan Circuit v0.9.0 atau lebih baharu (
pip install qiskit-addon-cutting)
Persediaanβ
# 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 kepada masalah kuantumβ
Kita akan melaksanakan corak Qiskit menggunakan empat langkah yang digariskan dalam dokumentasi. Dalam kes ini, kita akan mensimulasikan nilai jangkaan pada Circuit dengan kedalaman tertentu dengan memotong gate yang menghasilkan swap gate dan melaksanakan subeksperimen pada Circuit yang lebih cetek. Pemotongan Gate berkaitan untuk Langkah 2 (optimumkan Circuit untuk pelaksanaan kuantum dengan menguraikan gate yang jauh) dan 4 (pasca-pemprosesan untuk merekonstruksi nilai jangkaan pada Circuit asal). Pada langkah pertama, kita akan menjana Circuit dari pustaka Circuit Qiskit dan mentakrifkan beberapa observable.
- Input: Parameter klasik untuk mentakrifkan 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: Optimumkan masalah untuk pelaksanaan perkakasan kuantumβ
- Input: Circuit abstrak dan observable
- Output: Circuit sasaran dan observable yang dihasilkan dengan memotong gate yang jauh untuk mengurangkan kedalaman Circuit yang ditranspil
Kita memilih susun atur awal yang memerlukan dua swap untuk melaksanakan gate antara Qubit 3 dan 0, serta dua swap lagi untuk memulangkan Qubit ke kedudukan asal mereka. Kita memilih optimization_level=3, yang merupakan tahap pengoptimuman tertinggi yang tersedia dengan pengurus laluan preset.
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
Cari dan potong gate yang jauh: Kita akan menggantikan gate yang jauh (gate yang menghubungkan Qubit bukan setempat, 0 dan 3) dengan objek TwoQubitQPDGate dengan menyatakan indeks mereka. cut_gates akan menggantikan gate pada indeks yang ditentukan dengan objek TwoQubitQPDGate dan juga mengembalikan senarai contoh QPDBasis -- satu untuk setiap penguraian gate. Objek QPDBasis mengandungi maklumat tentang cara menguraikan gate yang dipotong kepada operasi satu-Qubit.
# 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)
Jana subeksperimen untuk dijalankan pada Backend: generate_cutting_experiments menerima Circuit yang mengandungi contoh TwoQubitQPDGate dan observable sebagai PauliList.
Untuk mensimulasikan nilai jangkaan Circuit bersaiz penuh, banyak subeksperimen dijana daripada taburan quasikemungkinan bersama gate yang diuraikan dan kemudian dilaksanakan pada satu atau lebih Backend. Bilangan sampel yang diambil dari taburan dikawal oleh num_samples, dan satu pekali gabungan diberikan untuk setiap sampel unik. Untuk maklumat lanjut tentang cara pekali dikira, rujuk bahan penjelasan.
# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observables, num_samples=np.inf
)
Sebagai perbandingan, kita lihat bahawa subeksperimen QPD akan lebih cetek selepas memotong gate yang jauh: Berikut adalah contoh subeksperimen yang dipilih secara rawak yang dijana daripada Circuit QPD. Kedalamannya telah dikurangkan lebih daripada separuh. Banyak subeksperimen berkebarangkalian ini perlu dijana dan dinilai untuk merekonstruksi nilai jangkaan 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
Sebaliknya, pemotongan mengakibatkan keperluan pensampelan tambahan. Di sini kita memotong tiga gate CNOT, menghasilkan overhead pensampelan sebesar . Untuk maklumat lanjut tentang overhead pensampelan yang ditanggung oleh pemotongan Circuit, rujuk dokumentasi Circuit Knitting Toolbox.
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 729.0
Langkah 3: Laksanakan menggunakan primitif Qiskitβ
Laksanakan Circuit sasaran ("subeksperimen") dengan Primitif Sampler.
- Input: Circuit sasaran
- Output: Taburan kuasi-kebarangkalian
# 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 dikehendakiβ
Gunakan hasil subeksperimen, subobservable, dan pekali pensampelan untuk merekonstruksi nilai jangkaan Circuit asal.
Input: Taburan kuasi-kebarangkalian Output: Nilai jangkaan yang 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
Tinjauan tutorialβ
Sila ambil tinjauan singkat ini untuk memberikan maklum balas tentang tutorial ini. Pandangan anda akan membantu kami menambah baik tawaran kandungan 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.