Langkau ke kandungan utama

Mula dengan pemotongan Circuit menggunakan pemotongan wayar

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 contoh kerja pemotongan wayar dengan pakej qiskit-addon-cutting. Ia merangkumi rekonstruksi nilai jangkaan Circuit tujuh-Qubit menggunakan pemotongan wayar.

Pemotongan wayar diwakili dalam pakej ini sebagai arahan dua-Qubit Move, yang ditakrifkan sebagai tetapan semula Qubit kedua yang diarahkan, diikuti dengan pertukaran kedua-dua Qubit. Operasi ini bersamaan dengan memindahkan keadaan Qubit pertama ke Qubit kedua, sambil membuang keadaan masuk Qubit kedua secara serentak.

Pakej ini direka untuk konsisten dengan cara anda perlu merawat pemotongan wayar apabila bertindak pada Qubit fizikal. Sebagai contoh, pemotongan wayar mungkin mengambil keadaan Qubit fizikal nn dan meneruskannya sebagai Qubit fizikal mm selepas pemotongan. Anda boleh fikirkan "pemotongan arahan" sebagai kerangka bersatu untuk mempertimbangkan pemotongan wayar dan Gate dalam formalisme yang sama (kerana pemotongan wayar hanyalah arahan Move yang dipotong). Menggunakan kerangka ini untuk pemotongan wayar juga membolehkan penggunaan semula Qubit, yang dijelaskan dalam bahagian tentang pemotongan wayar secara manual.

Arahan satu-Qubit CutWire berfungsi sebagai antara muka yang lebih abstrak dan mudah untuk bekerja dengan pemotongan wayar. Ia membolehkan anda menandakan di mana dalam Circuit wayar perlu dipotong pada peringkat tinggi dan membiarkan addon pemotongan Circuit memasukkan arahan Move yang sesuai untuk anda.

Contoh berikut menunjukkan rekonstruksi nilai jangkaan selepas pemotongan wayar. Anda akan mencipta Circuit dengan beberapa Gate bukan tempatan dan mentakrifkan observable untuk dianggarkan.

# 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 import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
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.instructions import Move, CutWire
from qiskit_addon_cutting import (
partition_problem,
generate_cutting_experiments,
cut_wires,
expand_observables,
reconstruct_expectation_values,
)

qc_0 = QuantumCircuit(7)
for i in range(7):
qc_0.rx(np.pi / 4, i)
qc_0.cx(0, 3)
qc_0.cx(1, 3)
qc_0.cx(2, 3)
qc_0.cx(3, 4)
qc_0.cx(3, 5)
qc_0.cx(3, 6)
qc_0.cx(0, 3)
qc_0.cx(1, 3)
qc_0.cx(2, 3)

# Define observable
observable = SparsePauliOp(["ZIIIIII", "IIIZIII", "IIIIIIZ"])

# Draw circuit
qc_0.draw("mpl")

Output of the previous code cell

Potong wayar menggunakan arahan CutWire peringkat tinggi​

Seterusnya, buat pemotongan wayar menggunakan arahan satu-Qubit CutWire pada Qubit q3q_3. Setelah subeksperimen bersedia untuk dilaksanakan, gunakan fungsi cut_wires() untuk menukar CutWire kepada arahan Move pada Qubit yang baru diperuntukkan.

qc_1 = QuantumCircuit(7)
for i in range(7):
qc_1.rx(np.pi / 4, i)
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)
qc_1.append(CutWire(), [3])
qc_1.cx(3, 4)
qc_1.cx(3, 5)
qc_1.cx(3, 6)
qc_1.append(CutWire(), [3])
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)

qc_1.draw("mpl")

Output of the previous code cell

Nota tentang pengembangan observable

Apabila Circuit dikembangkan melalui satu atau lebih pemotongan wayar, observable perlu dikemaskini untuk mengambil kira Qubit tambahan yang diperkenalkan. Pakej qiskit-addon-cutting mempunyai fungsi kemudahan expand_observables(), yang mengambil objek PauliList serta Circuit asal dan yang dikembangkan sebagai argumen, dan mengembalikan PauliList baharu.

PauliList yang dikembalikan ini tidak akan mengandungi sebarang maklumat tentang pekali observable asal, tetapi ini boleh diabaikan sehingga rekonstruksi nilai jangkaan akhir.

# Transform CutWire instructions to Move instructions
qc_2 = cut_wires(qc_1)

# Expand the observable to match the new circuit size
expanded_observable = expand_observables(observable.paulis, qc_0, qc_2)
print(f"Expanded Observable: {expanded_observable}")
qc_2.draw("mpl")
Expanded Observable: ['ZIIIIIIII', 'IIIZIIIII', 'IIIIIIIIZ']

Output of the previous code cell

Bahagikan Circuit dan observable​

Kini masalah boleh dipisahkan kepada partition. Ini dilakukan menggunakan fungsi partition_problem() dengan set label partition pilihan untuk menentukan cara memisahkan Circuit. Qubit yang berkongsi label partition yang sama dikumpulkan bersama, dan mana-mana Gate bukan tempatan yang merentasi lebih daripada satu partition dipotong.

Jika tiada label partition disediakan, maka pembahagian akan ditentukan secara automatik berdasarkan kesambungan Circuit. Baca bahagian seterusnya tentang pemotongan wayar secara manual untuk maklumat lanjut tentang memasukkan label partition.

partitioned_problem = partition_problem(
circuit=qc_2,
observables=expanded_observable,
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

print(f"Subobservables to measure: \n{subobservables}\n")
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
subcircuits[0].draw("mpl")
Subobservables to measure:
{0: PauliList(['IIIII', 'ZIIII', 'IIIIZ']), 1: PauliList(['ZIII', 'IIII', 'IIII'])}

Sampling overhead: 256.0

Output of the previous code cell

subcircuits[1].draw("mpl")

Output of the previous code cell

Dalam skim pembahagian ini, anda telah memotong dua wayar, menghasilkan overhed pensampelan sebesar 444^4.

Jana subeksperimen untuk dilaksanakan dan pasca-proses keputusan​

Untuk menganggarkan nilai jangkaan Circuit bersaiz penuh, beberapa subeksperimen dijana dari taburan quasi-kebarangkalian bersama Gate yang diuraikan kemudian dilaksanakan pada satu (atau lebih) QPU. Kaedah generate_cutting_experiments melakukan ini dengan menerima argumen untuk kamus subcircuits dan subobservables yang anda cipta di atas, serta bilangan sampel yang diambil dari taburan.

Nota tentang bilangan sampel

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) memastikan semua pekali dikira dengan tepat. Baca dokumentasi API tentang menjana pemberat dan menjana eksperimen pemotongan untuk maklumat lanjut.

# Generate subexperiments
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=2**12)
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 boleh direkonstruksi menggunakan kaedah reconstruct_expectation_values().

Blok kod di bawah merekonstruksi keputusan dan membandingkannya dengan nilai jangkaan tepat.

reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)
# Apply the coefficients of the original observable
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)

# Compute the exact expectation value using the `qiskit_aer` package.
estimator = EstimatorV2()
exact_expval = estimator.run([(qc_0, 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: 1.45965266
Exact expectation value: 1.59099026
Error in estimation: -0.1313376
Relative error in estimation: -0.08255085
Nota tentang pekali observable

Untuk merekonstruksi nilai jangkaan dengan tepat, pekali observable asal (yang berbeza daripada 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 sebelum ini.

Potong wayar menggunakan arahan Move peringkat rendah​

Satu had penggunaan arahan CutWire peringkat tinggi adalah ia tidak membenarkan penggunaan semula Qubit. Jika ini dikehendaki untuk eksperimen pemotongan, anda boleh meletakkan arahan Move secara manual. Walau bagaimanapun, kerana arahan Move membuang keadaan Qubit destinasi, adalah penting bahawa Qubit ini tidak berkongsi sebarang pembelitan dengan baki sistem. Jika tidak, operasi tetapan semula akan menyebabkan keadaan Circuit runtuh sebahagiannya selepas pemotongan wayar.

Blok kod di bawah melakukan pemotongan wayar pada Qubit q3q_3 untuk Circuit contoh yang sama seperti yang ditunjukkan sebelum ini. Perbezaannya di sini adalah anda boleh menggunakan semula Qubit dengan membalikkan operasi Move di mana pemotongan wayar kedua dibuat (walau bagaimanapun, ini tidak sentiasa mungkin dan bergantung kepada Circuit yang dipotong).

qc_1 = QuantumCircuit(8)
for i in [*range(4), *range(5, 8)]:
qc_1.rx(np.pi / 4, i)
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)
qc_1.append(Move(), [3, 4])
qc_1.cx(4, 5)
qc_1.cx(4, 6)
qc_1.cx(4, 7)
qc_1.append(Move(), [4, 3])
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)

# Expand observable
observable_expanded = SparsePauliOp(["ZIIIIIII", "IIIIZIII", "IIIIIIIZ"])
qc_1.draw("mpl")

Output of the previous code cell

Circuit di atas kini boleh dibahagikan dan eksperimen pemotongan dijana. Untuk menentukan secara eksplisit cara Circuit perlu dibahagikan, anda boleh menambah label partition ke fungsi partition_problem(). Qubit yang berkongsi label partition yang sama dikumpulkan bersama, dan mana-mana Gate bukan tempatan yang merentasi lebih daripada satu partition dipotong. Kunci kamus output oleh partition_problem() akan sepadan dengan yang dinyatakan dalam rentetan label.

partitioned_problem = partition_problem(
circuit=qc_1,
partition_labels="AAAABBBB",
observables=observable_expanded.paulis,
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

print(f"Subobservables to measure: \n{subobservables}\n")
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
subcircuits["A"].draw("mpl")
Subobservables to measure:
{'A': PauliList(['IIII', 'ZIII', 'IIIZ']), 'B': PauliList(['ZIII', 'IIII', 'IIII'])}

Sampling overhead: 256.0

Output of the previous code cell

subcircuits["B"].draw("mpl")

Output of the previous code cell

Kini eksperimen pemotongan boleh dijana dan nilai jangkaan direkonstruksi dengan cara yang sama seperti bahagian sebelumnya.

Langkah seterusnya​

Cadangan
Source: IBM Quantum docs β€” updated 13 Feb 2026
English version on doQumentation β€” updated 7 Mei 2026
This translation based on the English version of 11 Mac 2026