Langkau ke kandungan utama

Gate Cutting untuk Mengurangkan Kedalaman Circuit

Dalam tutorial ini, kita akan mengurangkan kedalaman Circuit dengan memotong Gate yang berjauhan, mengelakkan swap gates yang akan diperkenalkan semasa routing.

Berikut adalah langkah-langkah yang akan kita ambil dalam corak Qiskit ini:

  • Langkah 1: Peta masalah kepada Circuit dan operator kuantum:
    • Petakan hamiltonian ke dalam Circuit kuantum.
  • Langkah 2: Optimumkan untuk perkakasan sasaran [Menggunakan cutting addon]:
    • Potong Circuit dan observable.
    • Transpile subeksperimen untuk perkakasan.
  • Langkah 3: Laksanakan pada perkakasan sasaran:
    • Jalankan subeksperimen yang diperoleh dalam Langkah 2 menggunakan primitif Sampler.
  • Langkah 4: Proses pasca keputusan [Menggunakan cutting addon]:
    • Gabungkan keputusan Langkah 3 untuk membina semula nilai jangkaan observable yang berkenaan.

Langkah 1: Peta​

Cipta Circuit untuk dijalankan pada Backend​

# 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

circuit = efficient_su2(num_qubits=4, entanglement="circular")
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
circuit.draw("mpl", scale=0.8)

Rajah Circuit kuantum

Tentukan observable​

from qiskit.quantum_info import SparsePauliOp

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

Langkah 2: Optimumkan​

Tentukan Backend​

Anda boleh menyediakan sama ada Backend palsu atau Backend perkakasan daripada Qiskit Runtime.

from qiskit_ibm_runtime.fake_provider import FakeManilaV2

backend = FakeManilaV2()

Transpile Circuit, visualisasikan swap, dan catat kedalaman​

Kita pilih susun atur yang memerlukan dua swap untuk melaksanakan Gate antara Qubit 3 dan 0, serta dua swap lagi untuk memulangkan Qubit ke kedudukan asal mereka.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, initial_layout=[0, 1, 2, 3]
)

transpiled_qc = pass_manager.run(circuit)
print(f"Transpiled circuit depth: {transpiled_qc.depth(lambda x: len(x.qubits) >= 2)}")
Transpiled circuit depth: 30
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, fold=-1)

Rajah Circuit kuantum

Gantikan Gate yang berjauhan dengan TwoQubitQPDGate dengan menentukan indeksnya​

cut_gates akan menggantikan Gate pada indeks yang ditentukan dengan TwoQubitQPDGate dan juga mengembalikan senarai contoh QPDBasis β€” satu untuk setiap penguraian Gate.

from qiskit_addon_cutting import cut_gates

# 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)

Rajah Circuit kuantum

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 kuasiprobabiliti bersama Gate yang didekomposkan, kemudian dilaksanakan pada satu atau lebih Backend. Bilangan sampel yang diambil daripada taburan dikawal oleh num_samples, dan satu pekali gabungan diberikan untuk setiap sampel unik. Untuk maklumat lanjut tentang cara pekali dikira, rujuk bahan penerangan.

Nota: Argumen observables kwarg kepada generate_cutting_experiments adalah jenis PauliList. Pekali dan fasa terma observable diabaikan semasa penguraian masalah dan pelaksanaan subeksperimen. Ia boleh digunakan semula semasa pembinaan semula nilai jangkaan.

import numpy as np
from qiskit_addon_cutting import generate_cutting_experiments

# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observable.paulis, num_samples=np.inf
)

Kira overhed pensampelan untuk potongan yang dipilih​

Di sini kita memotong tiga Gate CNOT, menghasilkan overhed pensampelan sebesar 939^3.

Untuk maklumat lanjut tentang overhed pensampelan yang ditanggung oleh circuit cutting, rujuk bahan penerangan.

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

Tunjukkan bahawa subeksperimen QPD akan lebih cetek selepas memotong Gate yang berjauhan​

Berikut adalah contoh subeksperimen yang dipilih secara rawak yang dijana daripada Circuit QPD. Kedalamannya telah dikurangkan lebih daripada separuh. Banyak subeksperimen probabilistik ini perlu dijana dan dinilai untuk membina semula nilai jangkaan Circuit yang lebih dalam.

# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pass_manager.run(subexperiments[100])

print(
f"Original circuit depth after transpile: {transpiled_qc.depth(lambda x: len(x.qubits) >= 2)}"
)
print(
f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth(lambda x: len(x.qubits) >= 2)}"
)
transpiled_qpd_circuit.draw("mpl", scale=0.8, idle_wires=False, fold=-1)
Original circuit depth after transpile: 30
QPD subexperiment depth after transpile: 7

Rajah Circuit kuantum

Sediakan subeksperimen untuk Backend​

# Transpile the subeperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pass_manager.run(subexperiments)

Langkah 3: Laksanakan​

Jalankan subeksperimen menggunakan primitif Qiskit Runtime Sampler​

from qiskit_ibm_runtime import SamplerV2

# 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()

Langkah 4: Proses Pasca​

Bina semula nilai jangkaan​

Bina semula nilai jangkaan untuk setiap terma observable dan gabungkannya untuk membina semula nilai jangkaan bagi observable asal.

from qiskit_addon_cutting import reconstruct_expectation_values

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

Bandingkan nilai jangkaan yang dibina semula dengan nilai jangkaan tepat daripada Circuit dan observable asal​

from qiskit_aer.primitives import EstimatorV2

estimator = EstimatorV2()
exact_expval = estimator.run([(circuit, 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.44018555
Exact expectation value: 0.50497603
Error in estimation: -0.06479049
Relative error in estimation: -0.12830408