Mula dengan pemotongan Circuit menggunakan pemotongan Gate
Versi pakej
Kod pada halaman ini dibangunkan menggunakan keperluan berikut. Kami mengesyorkan menggunakan versi ini atau yang lebih baharu.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
qiskit-aer~=0.17
qiskit-addon-cutting~=0.10.0
Panduan ini menunjukkan dua contoh kerja pemotongan Gate dengan pakej qiskit-addon-cutting. Contoh pertama menunjukkan cara mengurangkan kedalaman Circuit (bilangan arahan Circuit) dengan memotong Gate pembelit pada Qubit yang tidak bersebelahan yang sebaliknya akan menanggung overhed SWAP apabila ditranspil ke perkakasan. Contoh kedua merangkumi cara menggunakan pemotongan Gate untuk mengurangkan lebar Circuit (bilangan Qubit) dengan membahagikan Circuit kepada beberapa Circuit dengan lebih sedikit Qubit.
Kedua-dua contoh akan menggunakan ansatz efficient_su2 dan merekonstruksi observable yang sama.
Pemotongan Gate untuk mengurangkan kedalaman Circuitβ
Aliran kerja berikut mengurangkan kedalaman Circuit dengan memotong Gate yang jauh, mengelakkan siri Gate SWAP yang besar yang sebaliknya akan diperkenalkan.
Mulakan dengan ansatz efficient_su2, dengan pembelit "bulatan" untuk memperkenalkan Gate yang jauh.
# Added by doQumentation β required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-aer qiskit-ibm-runtime
import numpy as np
from qiskit.circuit.library import efficient_su2
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
from qiskit_ibm_runtime import SamplerV2, Batch
from qiskit_aer.primitives import EstimatorV2
from qiskit_addon_cutting import (
cut_gates,
partition_problem,
generate_cutting_experiments,
reconstruct_expectation_values,
)
circuit = efficient_su2(num_qubits=4, entanglement="circular")
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])
print(f"Observable: {observable}")
circuit.draw("mpl", scale=0.8)
Observable: SparsePauliOp(['ZZII', 'IZZI', 'IIZZ', 'XIXI', 'ZIZZ', 'IXIX'],
coeffs=[ 1.+0.j, 1.+0.j, -1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])
Setiap Gate CNOT antara Qubit dan memperkenalkan dua Gate SWAP selepas transpilasi (dengan andaian Qubit disambungkan dalam satu garis lurus). Untuk mengelakkan peningkatan kedalaman ini, anda boleh menggantikan Gate yang jauh ini dengan objek TwoQubitQPDGate menggunakan kaedah cut_gates(). Fungsi ini juga mengembalikan senarai instance QPDBasis β satu untuk setiap penguraian.
# 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)
Setelah arahan Gate yang dipotong ditambah, subeksperimen akan mempunyai kedalaman yang lebih kecil selepas transpilasi berbanding Circuit asal. Coretan kod di bawah menjana subeksperimen menggunakan generate_cutting_experiments, yang menerima Circuit dan observable untuk direkonstruksi.
Argumen num_samples menentukan berapa banyak sampel yang diambil dari taburan quasi-kebarangkalian dan menentukan ketepatan pekali yang digunakan untuk rekonstruksi. Menghantar infiniti (np.inf) akan memastikan semua pekali dikira dengan tepat. Baca dokumentasi API tentang menjana pemberat dan menjana eksperimen pemotongan untuk maklumat lanjut.
Setelah subeksperimen dijana, anda boleh mentranspilnya dan menggunakan primitif Sampler untuk mengambil sampel taburan dan merekonstruksi nilai jangkaan yang dianggarkan. Blok kod berikut menjana, mentranspil, dan melaksanakan subeksperimen. Kemudian ia merekonstruksi keputusan dan membandingkannya dengan nilai jangkaan tepat.
# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observable.paulis, num_samples=np.inf
)
# Set a backend to use and transpile the subexperiments
backend = FakeManilaV2()
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend
)
isa_subexperiments = pass_manager.run(subexperiments)
# Set up the Qiskit Runtime Sampler primitive, submit the subexperiments, and retrieve the results
sampler = SamplerV2(backend)
job = sampler.run(isa_subexperiments, shots=4096 * 3)
results = job.result()
# Reconstruct the results
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
observable.paulis,
)
# Apply the coefficients of the original observable
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)
estimator = EstimatorV2()
exact_expval = (
estimator.run([(circuit, observable, [0.4] * len(circuit.parameters))])
.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.49812826
Exact expectation value: 0.50497603
Error in estimation: -0.00684778
Relative error in estimation: -0.0135606
Untuk merekonstruksi nilai jangkaan dengan tepat, pekali observable asal (yang berbeza daripada pekali dalam output generate_cutting_experiments()) mesti digunakan pada output rekonstruksi, kerana maklumat ini hilang semasa eksperimen pemotongan dijana atau semasa observable dikembangkan.
Biasanya pekali ini boleh digunakan melalui numpy.dot() seperti yang ditunjukkan di atas.
Pemotongan Gate untuk mengurangkan lebar Circuitβ
Bahagian ini menunjukkan penggunaan pemotongan Gate untuk mengurangkan lebar Circuit. Mulakan dengan efficient_su2 yang sama tetapi gunakan pembelit "linear".
qc = efficient_su2(4, entanglement="linear", reps=2)
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)
observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])
print(f"Observable: {observable}")
qc.draw("mpl", scale=0.8)
Observable: SparsePauliOp(['ZZII', 'IZZI', 'IIZZ', 'XIXI', 'ZIZZ', 'IXIX'],
coeffs=[ 1.+0.j, 1.+0.j, -1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])
Kemudian jana subCircuit dan subobservable yang akan dilaksanakan menggunakan fungsi partition_problem(). Fungsi ini menerima Circuit, observable, dan skim pembahagian pilihan serta mengembalikan Circuit dan observable yang dipotong dalam bentuk kamus.
Pembahagian ditakrifkan oleh rentetan label berbentuk "AABB" di mana setiap label dalam rentetan ini sepadan dengan Qubit pada indeks yang sama bagi argumen circuit. Qubit yang berkongsi label partition yang sama dikumpulkan bersama, dan mana-mana Gate bukan tempatan yang merentasi lebih daripada satu partition akan dipotong.
Argumen kata kunci observables kepada partition_problem adalah jenis PauliList. Pekali dan fasa sebutan observable diabaikan semasa penguraian masalah dan pelaksanaan subeksperimen. Ia boleh digunakan semula semasa rekonstruksi nilai jangkaan.
partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=observable.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
print(f"Subobservables: {subobservables}")
subcircuits["A"].draw("mpl", scale=0.8)
Sampling overhead: 81.0
Subobservables: {'A': PauliList(['II', 'ZI', 'ZZ', 'XI', 'ZZ', 'IX']), 'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}
subcircuits["B"].draw("mpl", scale=0.8)
Langkah seterusnya adalah menggunakan subCircuit dan subobservable untuk menjana subeksperimen yang akan dilaksanakan pada QPU menggunakan kaedah generate_cutting_experiments.
Untuk menganggarkan nilai jangkaan Circuit bersaiz penuh, banyak subeksperimen dijana dari taburan quasi-kebarangkalian bersama Gate yang diuraikan kemudian dilaksanakan pada satu atau lebih QPU. Bilangan sampel yang diambil dari taburan ini dikawal oleh argumen num_samples.
Blok kod berikut menjana subeksperimen dan melaksanakannya menggunakan primitif Sampler pada simulator tempatan. (Untuk menjalankannya pada QPU, tukar backend kepada sumber QPU pilihan anda.)
subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)
# Set a backend to use and transpile the subexperiments
backend = FakeManilaV2()
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()
}
# 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=4096 * 3)
for label, subsystem_subexpts in isa_subexperiments.items()
}
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}
Akhir sekali, nilai jangkaan Circuit penuh direkonstruksi menggunakan kaedah reconstruct_expectation_values.
Blok kod di bawah merekonstruksi keputusan dan membandingkannya dengan nilai jangkaan tepat.
# 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)
estimator = EstimatorV2()
exact_expval = (
estimator.run([(qc, observable, [0.4] * len(qc.parameters))])
.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.53571896
Exact expectation value: 0.56254612
Error in estimation: -0.02682716
Relative error in estimation: -0.04768882
Langkah seterusnyaβ
- Baca panduan Mula dengan pemotongan Circuit menggunakan pemotongan wayar.
- Baca kertas arXiv tentang pemotongan Circuit dengan komunikasi klasik.