Pemotongan wayar untuk anggaran nilai jangkaan
Anggaran penggunaan: satu minit pada pemproses Eagle (NOTA: Ini adalah anggaran sahaja. Masa jalan anda mungkin berbeza.)
Latar Belakangβ
Circuit-knitting ialah istilah umum yang merangkumi pelbagai kaedah untuk mempartisi sebuah litar kepada beberapa subLitar yang lebih kecil, melibatkan lebih sedikit gerbang dan/atau Qubit. Setiap subLitar boleh dilaksanakan secara bebas dan keputusan akhir diperoleh melalui pemprosesan klasik selepas daripada hasil setiap subLitar. Teknik ini boleh diakses melalui circuit cutting Qiskit addon, dan penjelasan terperinci tentang teknik ini diberikan dalam dokumen rasmi berserta bahan pengenalan lain.
Notebook ini membincangkan kaedah yang dipanggil pemotongan wayar di mana litar dipartisi mengikut wayar [1], [2]. Perlu diingat bahawa pemotongan dalam litar klasik adalah mudah kerana hasil pada titik pemotongan boleh ditentukan secara deterministik, sama ada 0 atau 1. Walau bagaimanapun, keadaan Qubit pada titik pemotongan adalah, secara umumnya, keadaan campuran. Oleh itu, setiap subLitar perlu diukur beberapa kali dalam basis yang berbeza (biasanya set basis yang lengkap secara tomografi seperti basis Pauli [3], [4]) dan disediakan pula dalam keadaan eigenstatenya yang sepadan. Rajah di bawah (ihsan: Tesis PhD, Ritajit Majumdar) menunjukkan contoh pemotongan wayar untuk keadaan GHZ 4-Qubit menjadi tiga subLitar. Di sini merujuk kepada set basis (biasanya Pauli X, Y dan Z) dan merujuk kepada set eigenstate (biasanya , , dan ).
Memandangkan setiap subLitar mempunyai lebih sedikit Qubit dan/atau gerbang, ia dijangka lebih tahan terhadap hingar. Notebook ini menunjukkan contoh bagaimana kaedah ini boleh digunakan untuk menyekat hingar dalam sistem secara berkesan.
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) - Circuit cutting Qiskit addon v0.9.0 atau lebih baharu (
pip install qiskit-addon-cutting)
Kita akan menggunakan litar Many Body Localization (MBL) dalam notebook ini. Litar MBL ialah litar yang cekap dari segi perkakasan dan diparameterkan oleh dua parameter dan . Apabila ditetapkan kepada dan keadaan awal disediakan dalam untuk semua Qubit, nilai jangkaan ideal bagi ialah untuk setiap tapak Qubit tanpa mengira nilai . Anda boleh menyemak butiran lanjut tentang litar MBL dalam kertas kerja ini.
Persediaanβ
# Added by doQumentation β required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-cutting qiskit-ibm-runtime
import numpy as np
import matplotlib.pyplot as plt
from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit
from qiskit.quantum_info import PauliList, SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.result import sampled_expectation_value
from qiskit_addon_cutting.instructions import CutWire
from qiskit_addon_cutting import (
cut_wires,
expand_observables,
partition_problem,
generate_cutting_experiments,
reconstruct_expectation_values,
)
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2, Batch
class MBLChainCircuit(QuantumCircuit):
def __init__(
self, num_qubits: int, depth: int, use_cut: bool = False
) -> None:
super().__init__(
num_qubits, name=f"MBLChainCircuit<{num_qubits}, {depth}>"
)
evolution = MBLChainEvolution(num_qubits, depth, use_cut)
self.compose(evolution, inplace=True)
class MBLChainEvolution(QuantumCircuit):
def __init__(self, num_qubits: int, depth: int, use_cut) -> None:
super().__init__(
num_qubits, name=f"MBLChainEvolution<{num_qubits}, {depth}>"
)
theta = Parameter("ΞΈ")
phis = ParameterVector("Ο", num_qubits)
for layer in range(depth):
layer_parity = layer % 2
# print("layer parity", layer_parity)
for qubit in range(layer_parity, num_qubits - 1, 2):
# print(qubit)
self.cz(qubit, qubit + 1)
self.u(theta, 0, np.pi, qubit)
self.u(theta, 0, np.pi, qubit + 1)
if (
use_cut
and layer_parity == 0
and (
qubit == num_qubits // 2 - 1
or qubit == num_qubits // 2
)
):
self.append(CutWire(), [num_qubits // 2])
if use_cut and layer < depth - 1 and layer_parity == 1:
if qubit == num_qubits // 2:
self.append(CutWire(), [qubit])
for qubit in range(num_qubits):
self.p(phis[qubit], qubit)
Bahagian I. Contoh skala kecilβ
Langkah 1: Petakan input klasik kepada masalah kuantumβ
Pertama sekali kita bina litar templat tanpa sebarang nilai parameter tertentu. Kita juga menyediakan pemegang tempat yang dipanggil CutWire untuk menandakan kedudukan pemotongan. Bagi contoh skala kecil ini, kita menggunakan litar MBL 10-Qubit.
num_qubits = 10
depth = 2
mbl = MBLChainCircuit(num_qubits, depth)
mbl.draw("mpl", fold=-1)
Ingat bahawa kita ingin mencari nilai jangkaan bagi pemerhatian apabila . Kita akan menetapkan beberapa nilai rawak untuk parameter .
phis = list(np.random.rand(mbl.num_parameters - 1))
theta = [0]
params = theta + phis
params
[0,
0.2376615174332788,
0.28244289857682414,
0.019248960591717768,
0.46140600996102477,
0.31408025180068433,
0.718184005135733,
0.991153920182475,
0.09289485768301442,
0.8857848280067783,
0.6177529765767047]
Sekarang kita tandakan litar untuk pemotongan dengan memasukkan CutWire yang sesuai bagi mencipta dua pemotongan yang kira-kira sama besar. Kita tetapkan use_cut=True dalam fungsi, dan benarkan ia menandakan selepas Qubit, dengan ialah bilangan Qubit dalam litar asal.
mbl_cut = MBLChainCircuit(num_qubits, depth, use_cut=True)
mbl_cut.assign_parameters(params, inplace=True)
mbl_cut.draw("mpl", fold=-1)
Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantumβ
Seterusnya kita potong litar kepada dua subLitar yang lebih kecil. Untuk contoh ini, kita hadkan kepada 2 subLitar sahaja. Untuk itu, kita menggunakan Qiskit Addon: Circuit Cutting.
Potong litar kepada subLitar yang lebih kecilβ
Memotong wayar pada satu titik meningkatkan bilangan Qubit sebanyak satu. Selain Qubit asal, terdapat satu Qubit tambahan sebagai pemegang tempat kepada litar selepas pemotongan. Imej berikut memberikan gambaran ini:
Addon ini menggunakan fungsi cut_wires untuk mengambil kira Qubit tambahan yang timbul akibat pemotongan.
mbl_move = cut_wires(mbl_cut)
Cipta dan kembangkan pemerhatianβ
Sekarang kita bina pemerhatian . Memandangkan hasil ideal bagi untuk setiap ialah , hasil ideal bagi juga ialah .
observable = PauliList(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)]
)
observable
PauliList(['ZIIIIIIIII', 'IZIIIIIIII', 'IIZIIIIIII', 'IIIZIIIIII',
'IIIIZIIIII', 'IIIIIZIIII', 'IIIIIIZIII', 'IIIIIIIZII',
'IIIIIIIIZI', 'IIIIIIIIIZ'])
Walau bagaimanapun, perlu diperhatikan bahawa bilangan Qubit dalam litar telah bertambah selepas memasukkan operasi Move maya 2-Qubit selepas pemotongan. Oleh itu, kita perlu mengembangkan pemerhatian juga dengan memasukkan identiti untuk menyesuaikan dengan litar semasa.
new_obs = expand_observables(observable, mbl, mbl_move)
new_obs
PauliList(['ZIIIIIIIIII', 'IZIIIIIIIII', 'IIZIIIIIIII', 'IIIZIIIIIII',
'IIIIZIIIIII', 'IIIIIIZIIII', 'IIIIIIIZIII', 'IIIIIIIIZII',
'IIIIIIIIIZI', 'IIIIIIIIIIZ'])
Perhatikan bahawa setiap pemerhatian kini telah dikembangkan untuk menampung tujuh Qubit, seperti dalam litar dengan operasi Move, berbanding enam Qubit asal. Seterusnya, partisi litar kepada dua subLitar.
partitioned_problem = partition_problem(circuit=mbl_move, observables=new_obs)
Mari kita visualisasikan subLitar tersebut
subcircuits = partitioned_problem.subcircuits
subcircuits[0].draw("mpl", fold=-1)
subcircuits[1].draw("mpl", fold=-1)
Pemerhatian turut dipartisi untuk disesuaikan dengan subLitar
subobservables = partitioned_problem.subobservables
subobservables
{0: PauliList(['IIIIII', 'IIIIII', 'IIIIII', 'IIIIII', 'IIIIII', 'IZIIII',
'IIZIII', 'IIIZII', 'IIIIZI', 'IIIIIZ']),
1: PauliList(['ZIIII', 'IZIII', 'IIZII', 'IIIZI', 'IIIIZ', 'IIIII', 'IIIII',
'IIIII', 'IIIII', 'IIIII'])}
Perlu diingat bahawa setiap subLitar menghasilkan beberapa sampel. Rekonstruksi mengambil kira hasil setiap sampel ini. Setiap sampel ini dipanggil subexperiment.
Mengembangkan pemerhatian menggunakan operasi Move memerlukan struktur data PauliList. Kita juga boleh mencipta pemerhatian dalam struktur data SparsePauliOp yang lebih umum, yang akan berguna kemudian semasa rekonstruksi subeksperimen.
M_z = SparsePauliOp(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)],
coeffs=[1 / num_qubits] * num_qubits,
)
M_z
SparsePauliOp(['ZIIIIIIIII', 'IZIIIIIIII', 'IIZIIIIIII', 'IIIZIIIIII', 'IIIIZIIIII', 'IIIIIZIIII', 'IIIIIIZIII', 'IIIIIIIZII', 'IIIIIIIIZI', 'IIIIIIIIIZ'],
coeffs=[0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j, 0.1+0.j,
0.1+0.j, 0.1+0.j])
subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits,
observables=subobservables,
num_samples=np.inf,
)
Mari kita lihat dua contoh di mana Qubit yang dipotong diukur dalam dua basis yang berbeza. Pertama, ia diukur dalam basis Z biasa, dan seterusnya diukur dalam basis X.
subexperiments[0][6].draw("mpl", fold=-1)
subexperiments[0][2].draw("mpl", fold=-1)
Transpilkan setiap subeksperimenβ
Pada masa ini kita perlu Transpilkan litar kita sebelum menghantarnya untuk pelaksanaan. Oleh itu, kita akan Transpilkan setiap litar dalam subeksperimen terlebih dahulu.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
Sekarang kita perlu Transpilkan setiap litar dalam subeksperimen. Untuk itu, kita mula-mula mencipta pengurus laluan, kemudian menggunakannya untuk Transpilkan setiap litar.
pm = generate_preset_pass_manager(optimization_level=2, backend=backend)
isa_subexperiments = {
label: pm.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}
isa_subexperiments[0][0].draw("mpl", fold=-1, idle_wires=False)
Langkah 3: Laksanakan menggunakan primitif Qiskitβ
Sekarang kita akan melaksanakan setiap litar dalam subeksperimen. Qiskit-addon-cutting menggunakan SamplerV2 untuk melaksanakan subeksperimen.
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()
}
Langkah 4: Proses selepas dan kembalikan keputusan dalam format klasik yang dikehendakiβ
Setelah litar dilaksanakan, kita perlu mendapatkan semula keputusan dan merekonstruksi nilai jangkaan untuk litar yang tidak dipotong dan pemerhatian asal.
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)
reconstructed_expval = np.dot(reconstructed_expval_terms, M_z.coeffs).real
reconstructed_expval
0.9674376845359803
Pengesahan silangβ
Mari kita laksanakan litar tanpa pemotongan dan semak hasilnya. Perlu diingat bahawa untuk pelaksanaan litar yang tidak dipotong, kita boleh terus menggunakan EstimatorV2 untuk mengira nilai jangkaan. Namun kita akan menggunakan Primitive yang sama sepanjang masa. Jadi kita akan menggunakan SamplerV2 untuk mendapatkan taburan kebarangkalian dan mengira nilai jangkaan menggunakan fungsi sampled_expectation_value.
Pertama kita perlu Transpilkan litar mbl yang tidak dipotong.
sampler = SamplerV2(mode=backend)
if mbl.num_clbits == 0:
mbl.measure_all()
isa_mbl = pm.run(mbl)
Seterusnya kita bina pub dan jalankan litar yang tidak dipotong.
pub = (isa_mbl, params)
uncut_job = sampler.run([pub])
uncut_counts = uncut_job.result()[0].data.meas.get_counts()
uncut_expval = sampled_expectation_value(uncut_counts, M_z)
uncut_expval
0.9498046875000001
Kita perhatikan bahawa nilai jangkaan yang diperoleh melalui pemotongan wayar lebih hampir kepada nilai ideal berbanding yang tidak dipotong. Mari kita tingkatkan skala masalah sekarang.
Bahagian II. Tingkatkan skalanya!β
Sebelum ini, kita menunjukkan keputusan untuk litar MBL 10-Qubit. Seterusnya, kita tunjukkan bahawa peningkatan dalam nilai jangkaan juga diperoleh untuk litar yang lebih besar. Untuk itu, kita ulangi proses ini untuk litar MBL 60-Qubit.
Langkah 1: Petakan input klasik kepada masalah kuantumβ
num_qubits = 60
depth = 2
mbl = MBLChainCircuit(num_qubits, depth)
Kita cipta satu set nilai rawak untuk
phis = list(np.random.rand(mbl.num_parameters - 1))
theta = [0]
params = theta + phis
Seterusnya kita bina litar yang dipotong
mbl_cut = MBLChainCircuit(num_qubits, depth, use_cut=True)
mbl_cut.assign_parameters(params, inplace=True)
mbl_cut.draw("mpl", fold=-1)
Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantumβ
Seperti yang ditunjukkan dalam contoh skala kecil, kita partisi litar dan pemerhatian untuk eksperimen pemotongan.
mbl_move = cut_wires(mbl_cut)
# Define observable
observable = PauliList(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)]
)
new_obs = expand_observables(observable, mbl, mbl_move)
# Partition the circuit into subcircuits
partitioned_problem = partition_problem(circuit=mbl_move, observables=new_obs)
# Get subcircuits
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
Kita juga mencipta objek SparsePauliOp untuk pemerhatian dengan pekali yang betul.
M_z = SparsePauliOp(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)],
coeffs=[1 / num_qubits] * num_qubits,
)
Seterusnya kita janakan subeksperimen dan Transpilkan setiap litar dalam subeksperimen.
subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits,
observables=subobservables,
num_samples=np.inf,
)
isa_subexperiments = {
label: pm.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}
Langkah 3: Laksanakan menggunakan primitif Qiskitβ
Kita menggunakan mod Batch untuk melaksanakan semua litar dalam subeksperimen.
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()
}
Langkah 4: Proses selepas dan kembalikan keputusan dalam format klasik yang dikehendakiβ
Mari kita dapatkan semula keputusan untuk setiap litar dalam subeksperimen dan rekonstruksi nilai jangkaan yang sepadan dengan litar yang tidak dipotong dan pemerhatian asal.
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)
reconstructed_expval = np.dot(reconstructed_expval_terms, M_z.coeffs).real
reconstructed_expval
0.9631355921427409
Pengesahan silangβ
Seperti dalam contoh skala kecil, kita akan sekali lagi mendapatkan nilai jangkaan dengan melaksanakan litar yang tidak dipotong, dan membandingkan hasilnya dengan pemotongan litar. Kita akan menggunakan SamplerV2 untuk mengekalkan keseragaman dalam penggunaan Primitif.
sampler = SamplerV2(mode=backend)
if mbl.num_clbits == 0:
mbl.measure_all()
isa_mbl = pm.run(mbl)
pub = (isa_mbl, params)
uncut_job = sampler.run([pub])
uncut_counts = uncut_job.result()[0].data.meas.get_counts()
uncut_expval = sampled_expectation_value(uncut_counts, M_z)
uncut_expval
0.9426757812499998
Visualisasiβ
Mari kita visualisasikan peningkatan dalam nilai jangkaan yang diperoleh dengan menggunakan pemotongan wayar.
ax = plt.gca()
methods = ["cut", "uncut"]
values = [reconstructed_expval, uncut_expval]
plt.bar(methods, values, color="#a56eff", width=0.4, edgecolor="#8a3ffc")
plt.axhline(y=1, color="k", linestyle="--")
ax.set_ylim([0.85, 1.02])
plt.text(0.3, 0.99, "Exact result")
plt.show()
Inferensβ
Kita perhatikan bahawa dalam kedua-dua masalah skala kecil dan besar, pemotongan wayar menghasilkan keputusan yang lebih baik berbanding yang tidak dipotong. Perlu diingat bahawa tiada teknik pengurangan ralat digunakan dalam eksperimen ini. Oleh itu, peningkatan dalam keputusan yang diperoleh adalah semata-mata kerana pemotongan wayar. Ada kemungkinan untuk meningkatkan lagi keputusan menggunakan kaedah pengurangan yang berbeza bersama-sama dengan pemotongan litar.
Selain itu, dalam notebook ini, kita mengira kedua-dua subLitar pada perkakasan yang sama. Dalam [5], [6], para pengarang menunjukkan kaedah untuk mengedarkan subLitar pada perkakasan yang berbeza menggunakan maklumat hingar bagi memaksimumkan penindasan hingar dan memparalelkan proses tersebut.
Lampiran: pertimbangan penskalaan sumberβ
Bilangan litar yang perlu dilaksanakan meningkat dengan bilangan pemotongan. Oleh itu, walaupun banyak pemotongan boleh menghasilkan subLitar yang kecil sehingga meningkatkan lagi prestasi, ia juga membawa kepada bilangan pelaksanaan litar yang amat tinggi, yang mungkin tidak praktikal bagi kebanyakan kes. Di bawah, kita tunjukkan contoh bilangan subLitar yang sepadan dengan bilangan pemotongan untuk litar 50-Qubit.
Perlu diingat bahawa walaupun untuk lima pemotongan, bilangan subeksperimen adalah sekitar 200k. Oleh itu, pemotongan litar hanya patut digunakan apabila bilangan pemotongan adalah kecil.
Satu contoh litar mesra-potong dan tidak mesra-potongβ
Litar mesra-potongβ
Seperti yang dinyatakan sebelum ini, sebuah litar adalah mesra-potong apabila litar itu boleh dipartisi kepada subLitar berasingan yang lebih kecil dengan bilangan pemotongan yang sedikit. Mana-mana litar yang cekap dari segi perkakasan, iaitu litar yang memerlukan sedikit atau tiada gerbang SWAP apabila dipetakan ke peta gandingan perkakasan, adalah secara umumnya mesra-potong. Di bawah, kita tunjukkan contoh ansatz pemuliharaan pengujaan yang digunakan dalam Kimia Kuantum. Perhatikan bahawa litar sedemikian boleh dipartisi kepada dua subLitar dengan satu pemotongan sahaja tanpa mengira bilangan Qubit.

Litar tidak mesra-potongβ
Sebuah litar adalah tidak mesra-potong jika, secara umumnya, bilangan pemotongan yang diperlukan untuk membentuk partition berasingan meningkat dengan ketara seiring dengan kedalaman atau bilangan Qubit. Ingat bahawa dengan setiap pemotongan, satu Qubit tambahan diperlukan. Jadi dengan bertambahnya bilangan pemotongan, bilangan Qubit efektif juga turut meningkat. Di bawah kita tunjukkan contoh litar Grover 3-Qubit dengan satu contoh pemotongan yang mungkin.
Kita perhatikan bahawa tiga pemotongan diperlukan, dan pemotongan itu lebih bersifat menegak daripada mendatar. Ini bermakna bilangan pemotongan dijangka berskala secara linear dengan bilangan Qubit, yang tidak sesuai untuk pemotongan.
Rujukanβ
[1] Peng, T., Harrow, A. W., Ozols, M., & Wu, X. (2020). Simulating large quantum circuits on a small quantum computer. Physical review letters, 125(15), 150504.
[2] Tang, W., Tomesh, T., Suchara, M., Larson, J., & Martonosi, M. (2021, April). Cutqc: using small quantum computers for large quantum circuit evaluations. In Proceedings of the 26th ACM International conference on architectural support for programming languages and operating systems (pp. 473-486).
[3] Perlin, M. A., Saleem, Z. H., Suchara, M., & Osborn, J. C. (2021). Quantum circuit cutting with maximum-likelihood tomography. npj Quantum Information, 7(1), 64.
[4] Majumdar, R., & Wood, C. J. (2022). Error mitigated quantum circuit cutting. arXiv preprint arXiv:2211.13431.
[5] Khare, T., Majumdar, R., Sangle, R., Ray, A., Seshadri, P. V., & Simmhan, Y. (2023). Parallelizing Quantum-Classical Workloads: Profiling the Impact of Splitting Techniques. In 2023 IEEE International Conference on Quantum Computing and Engineering (QCE) (Vol. 1, pp. 990-1000). IEEE.
[6] Bhoumik, D., Majumdar, R., Saha, A., & Sur-Kolay, S. (2023). Distributed Scheduling of Quantum Circuits with Noise and Time Optimization. arXiv preprint arXiv:2309.06005.
Tinjauan tutorialβ
Sila ambil tinjauan singkat ini untuk memberikan maklum balas tentang tutorial ini. Pandangan anda akan membantu kami meningkatkan 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.