Lewati ke konten utama

Gate Cutting untuk Mengurangi Lebar Circuit

Dalam notebook ini, kita akan melalui langkah-langkah pola Qiskit sambil menggunakan circuit cutting untuk mengurangi jumlah Qubit dalam sebuah Circuit. Kita akan memotong Gate agar bisa merekonstruksi nilai ekspektasi dari sebuah Circuit empat Qubit hanya menggunakan eksperimen dua Qubit.

Berikut adalah langkah-langkah yang akan kita lakukan:

  • Langkah 1: Petakan masalah ke circuit kuantum dan operator:
    • Petakan hamiltonan ke sebuah Circuit kuantum.
  • Langkah 2: Optimalkan untuk hardware target [Menggunakan cutting addon]:
    • Potong Circuit dan observable.
    • Transpile subeksperimen untuk hardware.
  • Langkah 3: Jalankan pada hardware target:
    • Jalankan subeksperimen yang diperoleh di Langkah 2 menggunakan primitif Sampler.
  • Langkah 4: Pasca-proses hasil [Menggunakan cutting addon]:
    • Gabungkan hasil Langkah 3 untuk merekonstruksi nilai ekspektasi observable yang dimaksud.

Langkah 1: Petakan​

Buat Circuit yang akan dipotong​

# Added by doQumentation β€” required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-aer qiskit-ibm-runtime
from qiskit.circuit.library import efficient_su2

qc = efficient_su2(4, entanglement="linear", reps=2)
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)

qc.draw("mpl", scale=0.8)

Diagram Circuit kuantum

Tentukan sebuah observable​

from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])

Langkah 2: Optimalkan​

Pisahkan Circuit dan observable sesuai partisi Qubit yang ditentukan​

Setiap label dalam partition_labels sesuai dengan Qubit circuit pada indeks yang sama. Qubit yang berbagi label partisi yang sama akan dikelompokkan bersama, dan Gate non-lokal yang mencakup lebih dari satu partisi akan dipotong.

Catatan: Argumen observables pada partition_problem bertipe PauliList. Koefisien dan fase suku observable diabaikan selama dekomposisi masalah dan eksekusi subeksperimen. Keduanya bisa diterapkan kembali saat rekonstruksi nilai ekspektasi.

from qiskit_addon_cutting import partition_problem

partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=observable.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

Visualisasikan masalah yang telah didekomposisi​

subobservables
{'A': PauliList(['II', 'ZI', 'ZZ', 'XI', 'ZZ', 'IX']),
'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}
subcircuits["A"].draw("mpl", scale=0.8)

Diagram Circuit kuantum

subcircuits["B"].draw("mpl", scale=0.8)

Diagram Circuit kuantum

Hitung overhead sampling untuk potongan yang dipilih​

Di sini kita memotong dua Gate CNOT, menghasilkan overhead sampling sebesar 929^2.

Untuk lebih lanjut tentang overhead sampling yang ditimbulkan oleh circuit cutting, lihat materi penjelasan.

import numpy as np

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 81.0

Buat subeksperimen untuk dijalankan pada Backend​

generate_cutting_experiments menerima argumen circuits/observables sebagai dictionary yang memetakan label partisi Qubit ke subcircuit/subobservables masing-masing.

Untuk mensimulasikan nilai ekspektasi dari Circuit berukuran penuh, banyak subeksperimen dihasilkan dari distribusi kuasiprobabilitas gabungan Gate yang telah didekomposisi lalu dijalankan pada satu atau lebih Backend. Jumlah sampel yang diambil dari distribusi dikendalikan oleh num_samples, dan satu koefisien gabungan diberikan untuk setiap sampel unik. Untuk informasi lebih lanjut tentang cara koefisien dihitung, lihat materi penjelasan.

from qiskit_addon_cutting import generate_cutting_experiments

subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)

Pilih sebuah Backend​

Di sini kita menggunakan Backend palsu, yang akan membuat Qiskit Runtime berjalan dalam mode lokal (yaitu, pada simulator lokal).

from qiskit_ibm_runtime.fake_provider import FakeManilaV2

backend = FakeManilaV2()

Siapkan subeksperimen untuk Backend​

Kita harus men-transpile Circuit dengan Backend kita sebagai target sebelum mengirimkannya ke Qiskit Runtime.

from qiskit.transpiler import generate_preset_pass_manager

# Transpile the subexperiments to ISA circuits
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_subexperiments = {
label: pass_manager.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}

Langkah 3: Jalankan​

Jalankan subeksperimen menggunakan primitif Sampler Qiskit Runtime​

from qiskit_ibm_runtime import SamplerV2, Batch

# Submit each partition's subexperiments to the Qiskit Runtime Sampler
# primitive, in a single batch so that the jobs will run back-to-back.
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
/home/garrison/Qiskit/qiskit-ibm-runtime/qiskit_ibm_runtime/session.py:157: UserWarning: Session is not supported in local testing mode or when using a simulator.
warnings.warn(
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}

Langkah 4: Pasca-proses​

Rekonstruksi nilai ekspektasi​

Rekonstruksi nilai ekspektasi untuk setiap suku observable dan gabungkan untuk merekonstruksi nilai ekspektasi dari observable asli.

from qiskit_addon_cutting import reconstruct_expectation_values

# Get expectation values for each observable term
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)

# Reconstruct final expectation value
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)

Bandingkan nilai ekspektasi yang direkonstruksi dengan nilai ekspektasi eksak dari Circuit dan observable asli​

from qiskit_aer.primitives import EstimatorV2

estimator = EstimatorV2()
exact_expval = estimator.run([(qc, observable)]).result()[0].data.evs
print(f"Reconstructed expectation value: {np.real(np.round(reconstructed_expval, 8))}")
print(f"Exact expectation value: {np.round(exact_expval, 8)}")
print(f"Error in estimation: {np.real(np.round(reconstructed_expval-exact_expval, 8))}")
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expval-exact_expval) / exact_expval, 8))}"
)
Reconstructed expectation value: 0.6991539
Exact expectation value: 0.56254612
Error in estimation: 0.13660778
Relative error in estimation: 0.24283836