Langkau ke kandungan utama

Pemotongan wayar untuk anggaran nilai jangkaan

Anggaran penggunaan: 22 saat pada pemproses Heron (NOTA: Ini adalah anggaran sahaja. Masa jalan anda mungkin berbeza.)

Hasil pembelajaran

Selepas melalui tutorial ini, pengguna sepatutnya memahami:

  • Cara menggunakan qiskit-addon-cutting untuk mempartisi litar yang besar kepada subLitar yang lebih kecil, dengan itu mengurangkan kesan hingar

Prasyarat

Kami mencadangkan agar pengguna biasa dengan topik berikut sebelum melalui tutorial ini:

  • Menggunakan primitif Sampler, yang digunakan dalam aliran kerja ini

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 atau qubit. Setiap subLitar boleh dilaksanakan secara bebas, dan keputusan akhir diperoleh melalui pemprosesan klasik ke atas hasil setiap subLitar. Teknik ini boleh diakses melalui Circuit cutting Qiskit addon; lihat dokumentasi berserta bahan pengenalan lain untuk penjelasan terperinci tentang teknik ini.

Tutorial ini menumpukan pada 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 basis yang lengkap secara tomografi, seperti basis Pauli [3], [4]) dan disediakan pula dalam keadaan eigenstatenya yang sepadan. Rajah di bawah (ihsan: [7]) menunjukkan contoh pemotongan wayar untuk keadaan GHZ empat-Qubit menjadi tiga subLitar. Di sini MjM_j merujuk kepada set basis (biasanya Pauli X, Y dan Z), dan PiP_i merujuk kepada set eigenstate (biasanya 0|0\rangle, 1|1\rangle, +|+\rangle dan +i|+i\rangle).

wc-1.png wc-2.png

Memandangkan setiap subLitar mempunyai lebih sedikit qubit dan gerbang, ia dijangka lebih tahan terhadap hingar. Tutorial 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.10.0 atau lebih baharu (pip install qiskit-addon-cutting)
  • Qiskit addon utils 0.3 atau lebih baharu (pip install qiskit-addon-utils)
  • Qiskit Aer (pip install qiskit-aer )

Persediaan

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-cutting qiskit-aer 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_aer import AerSimulator
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

Contoh simulator skala kecil

Tutorial ini melaksanakan corak Qiskit untuk mensimulasikan litar Many-Body Localization (MBL) satu dimensi (1D). Litar MBL ialah litar yang cekap dari segi perkakasan dan diparameterkan oleh dua parameter θ\theta dan ϕ\vec{\phi}. Apabila θ\theta ditetapkan kepada 00 dan keadaan awal disediakan dalam 0|0\rangle untuk semua qubit, nilai jangkaan ideal bagi Zi\langle Z_i \rangle ialah +1+1 untuk setiap tapak qubit ii tanpa mengira nilai ϕ\vec{\phi}. Butiran lanjut tentang litar ini tersedia dalam artikel ini.

Perlu diingat bahawa dalam simulator tanpa hingar, nilai jangkaan yang diperoleh dengan dan tanpa pemotongan litar adalah sama.

Langkah 1: Petakan input klasik kepada masalah kuantum

Bina litar MBL 1D

Pertama, kita kemukakan fungsi untuk membina litar MBL 1D.

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)
num_qubits = 10
depth = 2
mbl = MBLChainCircuit(num_qubits, depth)
mbl.draw("mpl", fold=-1)

Output of the previous code cell

Kita mengira nilai jangkaan purata O=1niZiO = \frac{1}{n} \sum_i Z_i ke atas semua qubit untuk θ=0\theta = 0. Oleh kerana nilai jangkaan ideal bagi Zi=1\langle Z_i \rangle = 1 \forall ii, nilai jangkaan ideal bagi OO juga ialah 11. Parameter ϕ\phi dipilih secara rawak.

np.random.seed(42)
phis = list(np.random.rand(mbl.num_parameters - 1))
theta = [0]
params = theta + phis

Litar perlu ditandakan dengan memasukkan CutWire di lokasi yang dikehendaki untuk mempartisinya. Untuk tutorial ini, kita memilih partition yang sama rata. Litar MBL direka bentuk supaya menetapkan use_cut=True dalam fungsi akan memasukkan tanda dengan betul selepas n2\frac{n}{2} qubit, dengan nn ialah bilangan qubit dalam litar asal. Kita juga menetapkan parameter yang dijana secara rawak kepada litar tersebut.

mbl_cut = MBLChainCircuit(num_qubits, depth, use_cut=True)
mbl_cut.assign_parameters(params, inplace=True)
mbl_cut.draw("mpl", fold=-1)

Output of the previous code cell

Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantum

Potong litar kepada subLitar yang lebih kecil

Sekarang kita partisi litar kepada dua subLitar yang lebih kecil menggunakan qiskit-addon-cutting. qiskit-addon-cutting menambahkan gerbang Move maya untuk memisahkan lokasi pemotongan wayar dengan menyesuaikan bilangan qubit dengan sewajarnya. Sekarang kita cipta litar dengan gerbang maya ini. Oleh kerana terdapat satu pemotongan wayar, bilangan qubit yang berkaitan akan ditambah sebanyak 1.

mbl_move = cut_wires(mbl_cut)
mbl_move.draw("mpl", fold=-1)

Output of the previous code cell

Bina dan kembangkan pemerhatian

Pemerhatian, seperti yang ditakrifkan sebelum ini, ialah purata ZZ pada setiap qubit. Walau bagaimanapun, setelah memasukkan gerbang Move maya, bilangan qubit efektif dalam litar bertambah. Pemerhatian juga mesti dikembangkan mengikutnya untuk mengambil kira perubahan dalam bilangan qubit ini. Perlu diingat bahawa pemerhatian sentiasa bertindak secara trivial (seperti II) pada qubit tambahan yang ditambah untuk gerbang Move maya.

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'])
new_obs = expand_observables(observable, mbl, mbl_move)
new_obs
PauliList(['ZIIIIIIIIII', 'IZIIIIIIIII', 'IIZIIIIIIII', 'IIIZIIIIIII',
'IIIIZIIIIII', 'IIIIIIZIIII', 'IIIIIIIZIII', 'IIIIIIIIZII',
'IIIIIIIIIZI', 'IIIIIIIIIIZ'])
partitioned_problem = partition_problem(circuit=mbl_move, observables=new_obs)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables

Di sini kita visualisasikan dua subLitar:

subcircuits[0].draw("mpl", fold=-1)

Output of the previous code cell

subcircuits[1].draw("mpl", fold=-1)

Output of the previous code cell

Mengembangkan pemerhatian menggunakan operasi Move memerlukan struktur data PauliList. Untuk merekonstruksi nilai jangkaan litar asal, kita memerlukan pemerhatian dalam format SparsePauliOp.

M_z = SparsePauliOp(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)],
coeffs=[1 / num_qubits] * num_qubits,
)

Seperti yang dibincangkan sebelum ini, untuk setiap pemotongan litar upstream mesti diukur dalam basis Pauli, dan litar downstream mesti disediakan dalam eigenstate basis tersebut. Fungsi generate_cutting_experiments mencipta semua litar yang diperlukan ini beserta pekali yang berkaitan dengan setiap litar yang diperlukan untuk rekonstruksi. Cari butiran lanjut dalam kertas kerja ini.

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

Transpilkan litar ke atas backend

Bagi contoh pertama yang melibatkan simulasi sahaja, kita Transpilkan litar ke dalam set gerbang asas backend:

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=133
)

print(backend)
<IBMBackend('ibm_fez')>

Langkah 3: Laksanakan menggunakan primitif Qiskit

Sekarang, laksanakan setiap subeksperimen:

pm_basis = generate_preset_pass_manager(
optimization_level=2, basis_gates=backend.configuration().basis_gates
)
basis_subexperiments = {
label: pm_basis.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}
sampler = SamplerV2(mode=AerSimulator())
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in basis_subexperiments.items()
}

Langkah 4: Proses selepas dan kembalikan keputusan dalam format klasik yang dikehendaki

Sekarang kita dapatkan semula keputusan setiap subeksperimen yang dijalankan dan rekonstruksi nilai jangkaan litar yang tidak dipotong:

# 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
np.float64(0.9953821063041687)
methods = [
"Uncut",
"Wire cut",
]
values = [
1,
reconstructed_expval,
] # since the ideal expectation value in noiseless simulation is +1

ax = plt.gca()
plt.bar(methods, values, color="#a56eff", width=0.4, edgecolor="#8a3ffc")
ax.set_ylabel(r"$M_Z$", fontsize=12)
Text(0, 0.5, '$M_Z$')

Output of the previous code cell

Contoh perkakasan berskala besar

Sekarang kita demonstrasikan pemotongan wayar untuk litar MBL 60-Qubit. Litar yang tidak dipotong, serta litar yang dipotong, akan dilaksanakan pada perkakasan IBM Quantum®:

num_qubits = 60
depth = 2

# construct the circuit
mbl = MBLChainCircuit(num_qubits, depth)

# create parameters
phis = list(np.random.rand(mbl.num_parameters - 1))
theta = [0]
params = theta + phis

# construct the cut circuit
mbl_cut = MBLChainCircuit(num_qubits, depth, use_cut=True)
mbl_cut.assign_parameters(params, inplace=True)
mbl_move = cut_wires(mbl_cut)

# Define observable and expand to account for the wire cut
observable = PauliList(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)]
)
new_obs = expand_observables(observable, mbl, mbl_move)

# Construct a SparsePauliOp version of the observable for later use in reconstruction
M_z = SparsePauliOp(
["I" * i + "Z" + "I" * (num_qubits - i - 1) for i in range(num_qubits)],
coeffs=[1 / num_qubits] * num_qubits,
)

# Partition the circuit and get subcircuits and subobservables
partitioned_problem = partition_problem(circuit=mbl_move, observables=new_obs)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables

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

# Transpile the subexperiments to the backend
pm = generate_preset_pass_manager(optimization_level=2, backend=backend)
isa_subexperiments = {
label: pm.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}

# Execute the subexperiments and retrieve results
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
sampler.options.environment.job_tags = ["TUT_WC"]
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
results = {label: job.result() for label, job in jobs.items()}

# Reconstruct the expectation value of the original observable
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)
reconstructed_expval = np.dot(reconstructed_expval_terms, M_z.coeffs).real

# Compute the uncut circuit to obtain the noisy expectation value for comparison
sampler = SamplerV2(mode=backend)
sampler.options.environment.job_tags = ["TUT_WC"]

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)

# visualize the results
ax = plt.gca()
methods = ["uncut", "cut"]
values = [uncut_expval, reconstructed_expval]

plt.bar(methods, values, color="#a56eff", width=0.4, edgecolor="#8a3ffc")
plt.axhline(y=1, color="k", linestyle="--")
plt.text(0.3, 0.95, "Exact result")
plt.show()

Output of the previous code cell

uncut_expval
0.9202473958333336

Langkah seterusnya

Cadangan

Jika anda mendapati karya ini menarik, anda mungkin berminat dengan bahan berikut:

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.

[7] Majumdar, R. (2024). Efficient Reduction of Resources and Noise in Discrete Quantum Computing Circuits (Doctoral dissertation, Indian Statistical Institute - Kolkata). https://www.proquest.com/openview/b481def90b1cc80e6b58a77c99e8385c/1?pq-origsite=gscholar&cbl=2026366&diss=y