Keterikatan jarak jauh dengan litar dinamik
Anggaran penggunaan: 4 minit pada pemproses Heron r2. (NOTA: Ini adalah anggaran sahaja. Masa sebenar mungkin berbeza.)
Hasil pembelajaran
Setelah menyelesaikan tutorial ini, anda akan mempelajari perkara berikut:
- Cara melaksanakan gate CNOT jarak jauh menggunakan litar dinamik dengan pengukuran pertengahan litar (MCM) dan feedforward klasikal;
- Cara melaksanakan gate setara menggunakan pendekatan berasaskan SWAP uniter;
- Cara membandingkan kedua-dua pendekatan dengan mengukur kesetiaan gate sebagai fungsi jarak qubit.
Prasyarat
Kami cadangkan pengguna biasa dengan topik berikut sebelum melalui tutorial ini:
- Konsep pengkomputeran kuantum asas, termasuk keadaan Bell, keterikatan, dan gate kuantum;
- Kebiasaan dengan litar dinamik (pengukuran pertengahan litar dan feedforward klasikal);
- Pengetahuan asas Qiskit SDK dan Qiskit Runtime, serta akses kepada akaun IBM Quantum®.
Latar belakang
Keterikatan jarak jauh antara qubit yang berjauhan adalah sukar pada peranti dengan sambungan terhad. Tutorial ini menunjukkan bagaimana litar dinamik boleh menjana keterikatan tersebut dengan melaksanakan gate kawalan-X jarak jauh (LRCX) menggunakan protokol berasaskan pengukuran.
Mengikut pendekatan Elisa Bäumer et al. dalam 1, kaedah ini menggunakan pengukuran pertengahan litar dan feedforward untuk mencapai gate kedalaman tetap tanpa mengira jarak pemisahan qubit. Ia mencipta pasangan Bell perantara, mengukur satu qubit dari setiap pasangan, dan menggunakan gate bersyarat secara klasik untuk menyebarkan keterikatan merentasi peranti. Ini mengelakkan rantaian SWAP yang panjang, mengurangkan kedalaman litar dan pendedahan kepada ralat gate dua qubit.
Dalam buku nota ini, kami menyesuaikan protokol untuk perkakasan IBM Quantum dan membuat penanda aras prestasinya sebagai fungsi pemisahan kawalan–sasaran, membandingkannya dengan garis dasar berasaskan SWAP uniter.
Keperluan
Sebelum memulakan tutorial ini, pastikan anda telah memasang perkara berikut:
- Qiskit SDK v2.0 atau lebih baharu, dengan sokongan visualisasi
- Qiskit Runtime v0.37 atau lebih baharu (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 atau lebih baharu (
pip install qiskit-aer)
Persediaan
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.visualization import plot_circuit_layout
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Batch,
SamplerV2 as Sampler,
)
import matplotlib.pyplot as plt
import numpy as np
Contoh simulator skala kecil
Sebelum dijalankan pada QPU sebenar, kita sahkan bahawa kedua-dua litar dinamik dan uniter menghasilkan keadaan Bell yang ideal pada simulator tanpa hingar. Kita gunakan Qiskit Runtime Sampler dengan AerSimulator sebagai mod backend, pada jarak kecil iaitu 6.
Langkah 1: Petakan input klasik kepada masalah kuantum
Kini kami melaksanakan gate CNOT jarak jauh antara dua qubit yang berjauhan, mengikut pembinaan litar dinamik yang ditunjukkan di bawah (disesuaikan daripada Rajah 1a dalam Ref. 1). Idea utamanya adalah menggunakan "bas" Qubit ancilla, yang dimulakan kepada , untuk menjadi perantara teleportasi gate jarak jauh.

Seperti yang digambarkan dalam rajah, prosesnya berjalan seperti berikut:
- Sediakan rantaian pasangan Bell yang menghubungkan qubit kawalan dan sasaran melalui ancilla perantara.
- Lakukan pengukuran Bell antara qubit jiran yang tidak terikat, menukar keterikatan langkah demi langkah sehingga kawalan dan sasaran berkongsi pasangan Bell.
- Gunakan pasangan Bell ini untuk teleportasi gate, mengubah CNOT setempat menjadi CNOT jarak jauh yang deterministik pada kedalaman tetap.
Pendekatan ini menggantikan rantaian SWAP yang panjang dengan protokol kedalaman tetap, mengurangkan pendedahan kepada ralat gate dua qubit dan menjadikan operasi boleh berskala dengan saiz peranti.
Dalam bahagian berikut, kita akan melalui pelaksanaan litar dinamik bagi litar LRCX. Di akhir tutorial, kami juga akan menyediakan pelaksanaan berasaskan uniter untuk perbandingan, bagi menyerlahkan kelebihan litar dinamik dalam konteks ini.
Mulakan litar
Kita mulakan dengan masalah kuantum mudah yang akan menjadi asas perbandingan. Secara khusus, kita memulakan litar dengan qubit kawalan pada indeks 0 dan menggunakan gate Hadamard padanya. Ini menghasilkan keadaan superposisi yang, apabila diikuti dengan operasi kawalan-X, menghasilkan keadaan Bell antara qubit kawalan dan sasaran.
Pada tahap ini, kita belum lagi membina gate kawalan-X jarak jauh (LRCX) itu sendiri. Sebaliknya, matlamat kita adalah untuk mentakrifkan litar permulaan yang jelas dan ringkas yang menonjolkan peranan LRCX. Dalam Langkah 2, kita akan menunjukkan bagaimana LRCX boleh dilaksanakan sebagai pengoptimuman menggunakan litar dinamik, dan membandingkan prestasinya dengan setara uniter. Penting untuk diingat, protokol LRCX boleh digunakan pada mana-mana litar permulaan. Di sini kita gunakan persediaan Hadamard mudah ini untuk kejelasan demonstrasi.
distance = 6 # The distance of the CNOT gate, with the convention that a distance of zero is a nearest-neighbor CNOT.
def initialize_circuit(distance):
assert distance >= 0
control = 0 # control qubit
n = distance # number of qubits between target and control
qr = QuantumRegister(
n + 2, name="q"
) # Circuit with n qubits between control and target
cr = ClassicalRegister(
2, name="cr"
) # Classical register for measuring control and target qubits
k = int(n / 2) # Number of Bell States to be used
allcr = [cr]
if (
distance > 1
): # This classical register will be used to store ZZ measurements.
# It is only used for long-range CX gates with distance > 1
c1 = ClassicalRegister(
k, name="c1"
) # Classical register needed for post processing
allcr.append(c1)
if (
distance > 0
): # This classical register will be used to store XX measurements.
# It is only used if distance > 0
c2 = ClassicalRegister(
n - k, name="c2"
) # Classical register needed for post processing
allcr.append(c2)
qc = QuantumCircuit(qr, *allcr, name="CNOT")
# Apply a Hadamard gate to the control qubit such that the
# long-range CNOT gate will prepare a
# Bell state (|00> + |11>)/sqrt(2)
qc.h(control)
return qc
qc = initialize_circuit(distance)
qc.draw(fold=-1, output="mpl", scale=0.5)
Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantum
Dalam langkah ini, kita tunjukkan cara membina litar LRCX menggunakan litar dinamik. Matlamatnya adalah untuk mengoptimumkan litar bagi pelaksanaan pada perkakasan dengan mengurangkan kedalaman berbanding pelaksanaan uniter semata-mata. Untuk menggambarkan manfaatnya, kita akan memaparkan kedua-dua pembinaan LRCX dinamik dan setara uniternya, serta kemudian membandingkan prestasinya selepas transpilasi. Penting untuk diingat, walaupun di sini kita menggunakan LRCX pada masalah yang dimulakan dengan Hadamard yang mudah, protokol ini boleh digunakan pada mana-mana litar yang memerlukan CNOT jarak jauh.
Sediakan pasangan Bell
Kita mulakan dengan mencipta rantaian pasangan Bell di sepanjang laluan antara qubit kawalan dan sasaran. Jika jaraknya ganjil, kita mula-mula menggunakan CNOT dari kawalan ke jirannya, iaitu CNOT yang akan diteleportkan. Bagi jarak genap, CNOT ini akan digunakan selepas langkah penyediaan pasangan Bell. Rantaian pasangan Bell kemudiannya mengikat pasangan qubit yang berturutan, mewujudkan sumber yang diperlukan untuk membawa maklumat kawalan merentasi peranti.
# Determine where to start the Bell pair chain and add an extra CNOT when n is odd
def check_even(n: int) -> int:
"""Return 1 if n is even, else 2."""
return 1 if n % 2 == 0 else 2
def prepare_bell_pairs(qc, add_barriers=True):
n = qc.num_qubits - 2 # number of qubits between target and control
k = int(n / 2)
if add_barriers:
qc.barrier()
x0 = check_even(n)
if n % 2 != 0:
qc.cx(0, 1)
# Create k Bell pairs
for i in range(k):
qc.h(x0 + 2 * i)
qc.cx(x0 + 2 * i, x0 + 2 * i + 1)
return qc
qc = prepare_bell_pairs(qc)
qc.draw(output="mpl", fold=-1, scale=0.5)
Ukur pasangan qubit jiran dalam asas Bell
Seterusnya, kita ukur qubit jiran yang tidak terikat dalam asas Bell (pengukuran dua qubit bagi dan ). Ini mewujudkan pasangan Bell jarak jauh antara qubit sasaran dan qubit bersebelahan dengan kawalan (tertakluk kepada pembetulan Pauli, yang akan dilaksanakan melalui feedforward dalam langkah berikut). Secara selari, kita melaksanakan pengukuran pengikat yang menteleportkan gate CNOT untuk bertindak pada qubit sasaran yang dimaksudkan.
def measure_bell_basis(qc, add_barriers=True):
n = qc.num_qubits - 2 # number of qubits between target and control
k = int(n / 2)
if n > 1:
_, c1, c2 = qc.cregs
elif n > 0:
_, c2 = qc.cregs
# Determine where to start the Bell pair chain and add an extra CNOT
# when n is odd
x0 = 1 if n % 2 == 0 else 2
# Entangling layer that implements the Bell measurement
# (and additionally adds the CNOT to be
# teleported, if n is even)
for i in range(k + 1):
qc.cx(x0 - 1 + 2 * i, x0 + 2 * i)
for i in range(1, k + x0):
if i == 1:
qc.h(2 * i + 1 - x0)
else:
qc.h(2 * i + 1 - x0)
if add_barriers:
qc.barrier()
# Map the ZZ measurements onto classical register c1
for i in range(k):
if i == 0:
qc.measure(2 * i + x0, c1[i])
else:
qc.measure(2 * i + x0, c1[i])
# Map the XX measurements onto classical register c2
for i in range(1, k + x0):
if i == 1:
qc.measure(2 * i + 1 - x0, c2[i - 1])
else:
qc.measure(2 * i + 1 - x0, c2[i - 1])
return qc
qc = measure_bell_basis(qc)
qc.draw(output="mpl", fold=-1, scale=0.5)
Gunakan pembetulan feedforward untuk membetulkan operator sampingan Pauli
Pengukuran asas Bell memperkenalkan produk sampingan Pauli yang perlu diperbetulkan menggunakan hasil ukuran yang direkodkan. Ini dilakukan dalam dua langkah. Pertama, kita perlu mengira pariti semua pengukuran , yang kemudian digunakan untuk menggunakan gate secara bersyarat pada qubit sasaran. Begitu juga, pariti pengukuran dikira dan digunakan untuk menggunakan gate secara bersyarat pada qubit kawalan.
Dengan rangka kerja ungkapan klasik baharu dalam Qiskit, pariti-pariti ini boleh dikira terus dalam lapisan pemprosesan klasik litar. Daripada menggunakan urutan gate bersyarat individu untuk setiap bit ukuran, kita boleh membina satu ungkapan klasik tunggal yang mewakili XOR (pariti) semua hasil ukuran yang berkaitan. Ungkapan ini kemudian digunakan sebagai syarat dalam satu blok if_test, membolehkan gate pembetulan digunakan pada kedalaman tetap. Pendekatan ini bukan sahaja memudahkan litar, malah memastikan pembetulan feedforward tidak menambah latensi tambahan yang tidak perlu.
def apply_ffwd_corrections(qc):
control = 0 # control qubit
target = qc.num_qubits - 1 # target qubit
n = qc.num_qubits - 2 # number of qubits between target and control
k = int(n / 2)
x0 = check_even(n)
if n > 1:
_, c1, c2 = qc.cregs
elif n > 0:
_, c2 = qc.cregs
# First, let's compute the parity of all ZZ measurements
for i in range(k):
if i == 0:
parity_ZZ = expr.lift(
c1[i]
) # Store the value of the first ZZ measurement in parity_ZZ
else:
parity_ZZ = expr.bit_xor(
c1[i], parity_ZZ
) # Successively compute the parity via XOR operations
for i in range(1, k + x0):
if i == 1:
parity_XX = expr.lift(
c2[i - 1]
) # Store the value of the first XX measurement in parity_XX
else:
parity_XX = expr.bit_xor(
c2[i - 1], parity_XX
) # Successively compute the parity via XOR operations
if n > 0:
with qc.if_test(parity_XX):
qc.z(control)
if n > 1:
with qc.if_test(parity_ZZ):
qc.x(target)
return qc
qc = apply_ffwd_corrections(qc)
qc.draw(output="mpl", fold=-1, scale=0.5)
Ukur qubit kawalan dan sasaran
Kita takrifkan fungsi pembantu yang membolehkan pengukuran qubit kawalan dan sasaran dalam asas , , atau . Untuk mengesahkan keadaan Bell , nilai jangkaan dan sepatutnya kedua-duanya , kerana ia adalah penstabil bagi keadaan tersebut. Pengukuran juga disokong di sini dan akan digunakan di bawah semasa mengira kesetiaan.
def measure_in_basis(qc, basis="XX", add_barrier=True):
control = 0 # control qubit
target = qc.num_qubits - 1 # target qubit
assert basis in ["XX", "YY", "ZZ"]
qc = (
qc.copy()
) # We copy the circuit because we want to measure in different bases
cr = qc.cregs[0]
if add_barrier:
qc.barrier()
if basis == "XX":
qc.h(control)
qc.h(target)
elif basis == "YY":
qc.sdg(control)
qc.sdg(target)
qc.h(control)
qc.h(target)
qc.measure(control, cr[0])
qc.measure(target, cr[1])
return qc
qc_YY = measure_in_basis(qc.copy(), basis="YY")
qc_YY.draw(
output="mpl", fold=-1, scale=0.5
) # Circuit for measuring in the YY basis
Gabungkan semuanya
Kita gabungkan pelbagai langkah yang ditakrifkan di atas untuk mencipta gate CX jarak jauh di dua hujung garisan satu dimensi (1D). Langkah-langkahnya adalah seperti berikut:
- Memulakan qubit kawalan dalam
- Menyediakan pasangan Bell
- Mengukur pasangan qubit jiran
- Menggunakan pembetulan feedforward bergantung pada MCM
def lrcx(distance, prep_barrier=True, pre_measure_barrier=True):
qc = initialize_circuit(distance)
qc = prepare_bell_pairs(qc, prep_barrier)
qc = measure_bell_basis(qc, pre_measure_barrier)
qc = apply_ffwd_corrections(qc)
return qc
qc = lrcx(distance)
# Apply the measurement in the XX, YY, and ZZ bases
qc_XX, qc_YY, qc_ZZ = [
measure_in_basis(qc, basis=basis) for basis in ["XX", "YY", "ZZ"]
]
qc_YY.draw(
output="mpl", fold=-1, scale=0.5
) # Circuit for measuring in the YY basis
Pelaksanaan berasaskan unitari dengan menukar qubit ke tengah
Untuk perbandingan, kita periksa dulu kes di mana gate CNOT jarak jauh dilaksanakan menggunakan sambungan jadi-jiran terdekat dan gate unitari. Dalam rajah berikut, sebelah kiri adalah Circuit untuk gate CNOT jarak jauh yang merentangi rantaian 1D sebanyak n-Qubit yang tertakluk kepada sambungan jadi-jiran terdekat sahaja. Di tengah pula adalah penguraian unitari yang setara yang boleh dilaksanakan dengan gate CNOT setempat, dengan kedalaman Circuit .

Litar di tengah boleh dilaksanakan seperti berikut:
def cnot_unitary(distance):
"""Generate a long range CNOT gate using local CNOTs on a 1D
chain of qubits subject to n
nearest-neighbor connections only.
Args:
distance (int) : The distance of the CNOT gate,
with the convention that
a distance of 0 is a nearest-neighbor CNOT.
Returns:
QuantumCircuit: A Quantum Circuit implementing a
long-range CNOT gate
between qubit 0 and qubit distance+1
"""
assert distance >= 0
n = distance # number of qubits between target and control
qr = QuantumRegister(
n + 2, name="q"
) # Circuit with n qubits between control and target
cr = ClassicalRegister(
2, name="cr"
) # Classical register for measuring control and target qubits
qc = QuantumCircuit(qr, cr, name="CNOT_unitary")
control_qubit = 0
qc.h(control_qubit) # Prepare the control qubit in the |+> state
k = int(n / 2)
qc.barrier()
for i in range(control_qubit, control_qubit + k):
qc.cx(i, i + 1)
qc.cx(i + 1, i)
qc.cx(-i - 1, -i - 2)
qc.cx(-i - 2, -i - 1)
if n % 2 == 1:
qc.cx(k + 2, k + 1)
qc.cx(k + 1, k + 2)
qc.barrier()
qc.cx(k, k + 1)
for i in range(control_qubit, control_qubit + k):
qc.cx(k - i, k - 1 - i)
qc.cx(k - 1 - i, k - i)
qc.cx(k + i + 1, k + i + 2)
qc.cx(k + i + 2, k + i + 1)
if n % 2 == 1:
qc.cx(-2, -1)
qc.cx(-1, -2)
return qc
qc_uni = cnot_unitary(distance)
Sekarang bina Circuit yang mengukur dalam asas , , dan , sama seperti yang kita buat untuk Circuit dinamik di atas.
# Apply the measurement in the XX, YY, and ZZ bases
qc_uni_XX, qc_uni_YY, qc_uni_ZZ = [
measure_in_basis(qc_uni, basis=basis) for basis in ["XX", "YY", "ZZ"]
]
qc_uni_YY.draw(
output="mpl", fold=-1, scale=0.5
) # Circuit for measuring in the YY basis
Sekarang kita telah membina kedua-dua litar dinamik dan litar uniter untuk contoh skala kecil dengan distance=6, kita kemudian transpilkan untuk dijalankan dahulu pada simulator tanpa hingar.
from qiskit_aer import AerSimulator
aer_backend = AerSimulator()
pm_sim = generate_preset_pass_manager(
optimization_level=0, backend=aer_backend
)
# Dynamic circuits
isa_sim_dyn = pm_sim.run([qc_XX, qc_YY, qc_ZZ])
# Unitary circuits
isa_sim_uni = pm_sim.run([qc_uni_XX, qc_uni_YY, qc_uni_ZZ])
Langkah 3: Laksanakan menggunakan primitif Qiskit
Kita kini boleh menjalankan eksperimen pada backend simulator tanpa hingar. Kita gunakan Qiskit Runtime Sampler dengan AerSimulator sebagai mod backend untuk melaksanakan litar.
sampler_sim = Sampler(mode=aer_backend)
sim_job = sampler_sim.run(isa_sim_dyn + isa_sim_uni)
sim_results = sim_job.result()
Langkah 4: Proses selepas dan kembalikan keputusan dalam format klasikal yang dikehendaki
Setelah eksperimen berjaya dilaksanakan, kita kini memproses kiraan pengukuran untuk mengekstrak metrik yang bermakna. Dalam langkah ini, kita lakukan perkara berikut:
- Takrifkan metrik kualiti untuk menilai prestasi CX jarak jauh.
- Kira nilai jangkaan operator Pauli daripada hasil pengukuran mentah.
- Gunakan nilai-nilai ini untuk mengira kesetiaan keadaan Bell yang dijana.
Dalam simulasi tanpa hingar, kita akan sahkan bahawa metrik kesetiaan adalah untuk litar yang dibina. Dalam eksperimen pada QPU sebenar, analisis ini akan memberi gambaran jelas tentang seberapa baik Circuit dinamik berprestasi berbanding pelaksanaan garis dasar uniter.
Metrik kualiti
Untuk menilai kejayaan protokol CX jarak jauh, kita ukur sejauh mana keadaan output menghampiri keadaan Bell yang ideal. Cara yang mudah untuk mengukur ini ialah dengan mengira kesetiaan keadaan menggunakan nilai jangkaan operator Pauli. Kita boleh mengira kesetiaan untuk keadaan Bell pada keadaan kawalan dan sasaran selepas mengetahui , , dan . Khususnya,
Untuk mengira nilai jangkaan ini daripada data pengukuran mentah, kita takrifkan satu set fungsi pembantu:
compute_ZZ_expectation: Diberi kiraan pengukuran, mengira nilai jangkaan operator Pauli dua-Qubit dalam asas .compute_fidelity: Menggabungkan nilai jangkaan , , dan ke dalam ungkapan kesetiaan di atas.get_counts_from_bitarray: Utiliti untuk mengekstrak kiraan daripada objek keputusan Backend.
def compute_ZZ_expectation(counts):
total = sum(counts.values())
expectation = 0
for bitstring, count in counts.items():
# Ensure bitstring is 2 bits
z1 = (-1) ** (int(bitstring[-1]))
z2 = (-1) ** (int(bitstring[-2]))
expectation += z1 * z2 * count
return expectation / total
def compute_fidelity(counts_xx, counts_yy, counts_zz):
xx, yy, zz = [
compute_ZZ_expectation(c) for c in [counts_xx, counts_yy, counts_zz]
]
return 1 / 4 * (1 + xx - yy + zz)
# Dynamic fidelity
counts_xx = sim_results[0].data.cr.get_counts()
counts_yy = sim_results[1].data.cr.get_counts()
counts_zz = sim_results[2].data.cr.get_counts()
fidelity_dyn = compute_fidelity(counts_xx, counts_yy, counts_zz)
# Unitary fidelity
counts_xx = sim_results[3].data.cr.get_counts()
counts_yy = sim_results[4].data.cr.get_counts()
counts_zz = sim_results[5].data.cr.get_counts()
fidelity_uni = compute_fidelity(counts_xx, counts_yy, counts_zz)
print(f"Dynamic fidelity (distance={distance}): {fidelity_dyn:.4f}")
print(f"Unitary fidelity (distance={distance}): {fidelity_uni:.4f}")
Dynamic fidelity (distance=6): 1.0000
Unitary fidelity (distance=6): 1.0000
Seperti yang dijangkakan dalam simulasi tanpa hingar, kesetiaan dalam kedua-dua litar dinamik dan litar uniter adalah .
Contoh perkakasan skala besar
Di sini kita gabungkan semua butiran ini ke dalam satu aliran kerja berskala lebih besar, yang kemudian dijalankan pada perkakasan kuantum sebenar.
Jana Circuit untuk Jarak Berbeza
Kita sekarang akan jana Circuit CX jarak jauh untuk pelbagai jarak pemisahan qubit sehingga 60 qubit jaraknya. Untuk setiap jarak, kita bina Circuit yang mengukur dalam asas , , dan , yang akan digunakan kemudian untuk mengira fideliti.
Senarai jarak ini merangkumi pemisahan jarak dekat dan jarak jauh, dengan distance = 0 bersamaan dengan CX jadi-jiran terdekat. Jarak yang sama ini juga akan digunakan untuk menjana Circuit unitari yang sepadan kemudian bagi tujuan perbandingan.
# -------------------------Step 1-------------------------
distances = [
0,
1,
2,
3,
6,
11,
16,
21,
28,
35,
44,
55,
60,
] # Distances for long range CX. distance of 0 is a nearest-neighbor CX
distances.sort()
assert min(distances) >= 0
basis_list = ["XX", "YY", "ZZ"]
# Dynamic circuits
circuits_dyn = []
for distance in distances:
for basis in basis_list:
circuits_dyn.append(
measure_in_basis(lrcx(distance, prep_barrier=False), basis=basis)
)
print(f"Number of circuits: {len(circuits_dyn)}")
# Unitary circuits
circuits_uni = []
for distance in distances:
for basis in basis_list:
circuits_uni.append(
measure_in_basis(cnot_unitary(distance), basis=basis)
)
print(f"Number of circuits: {len(circuits_uni)}")
Sekarang kita dah ada Circuit dinamik dan unitari untuk pelbagai jarak, kita dah bersedia untuk transpilasi. Kita perlu pilih peranti Backend dahulu.
# -------------------------Step 2-------------------------
# Set up access to IBM Quantum devices
from qiskit.circuit import IfElseOp
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=156
)
if "if_else" not in backend.target.operation_names:
backend.target.add_instruction(IfElseOp, name="if_else")
Gunakan rentetan Ketepatan Lapisan untuk memilih rantaian 1D
Memandangkan kita ingin membandingkan prestasi Circuit dinamik dan uniter pada rantaian 1D, kita gunakan rentetan Ketepatan Lapisan untuk memilih topologi linear rantaian qubit terbaik dari peranti tersebut. Ini memastikan kedua-dua jenis Circuit ditranspilkan di bawah kekangan sambungan yang sama, membolehkan perbandingan prestasi yang adil.
# This selects best qubits for longest distance and uses
# the same control for all lengths
lf_qubits = backend.properties().to_dict()[
"general_qlists"
] # best linear chain qubits
chosen_layouts = {
distance: [
val["qubits"]
for val in lf_qubits
if val["name"] == f"lf_{distances[-1] + 2}"
][0][: distance + 2]
for distance in distances
}
print(chosen_layouts[max(distances)]) # best qubits at each distance
[11, 12, 13, 14, 15, 19, 35, 34, 33, 39, 53, 54, 55, 59, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 76, 81, 82, 83, 84, 85, 86, 87, 97, 107, 108, 109, 110, 111, 98, 91, 92, 93, 94, 95, 99, 115, 114, 113, 119, 133, 132, 131, 138, 151, 150, 149, 148]
isa_circuits_dyn = []
isa_circuits_uni = []
# Using the same initial layouts for both circuits for better
# apples to apples comparison
for qc in circuits_dyn:
pm = generate_preset_pass_manager(
optimization_level=1,
backend=backend,
initial_layout=chosen_layouts[qc.num_qubits - 2],
)
isa_circuits_dyn.append(pm.run(qc))
for qc in circuits_uni:
pm = generate_preset_pass_manager(
optimization_level=1,
backend=backend,
initial_layout=chosen_layouts[qc.num_qubits - 2],
)
isa_circuits_uni.append(pm.run(qc))
print(
f"2Q depth: "
f"{isa_circuits_dyn[14].depth(lambda x: x.operation.num_qubits == 2)}"
)
isa_circuits_dyn[14].draw("mpl", fold=-1, idle_wires=0)
2Q depth: 2

print(
f"2Q depth: "
f"{isa_circuits_uni[14].depth(lambda x: x.operation.num_qubits == 2)}"
)
isa_circuits_uni[14].draw("mpl", fold=-1, idle_wires=False)
2Q depth: 13

Visualisasikan qubit yang digunakan untuk Circuit LRCX
Dalam bahagian ini, kita periksa bagaimana Circuit LRCX dipetakan ke perkakasan. Kita mulakan dengan memvisualisasikan qubit fizikal yang digunakan dalam Circuit, kemudian kaji bagaimana jarak kawalan–sasaran dalam susun atur mempengaruhi bilangan operasi.
Seterusnya, kita jalankan eksperimen pada backend sebenar. Kita juga guna batching untuk menjalankan eksperimen secara cekap merentas beberapa percubaan. Menjalankan percubaan berulang membolehkan kita mengira purata untuk perbandingan yang lebih tepat antara kaedah uniter dan dinamik, serta untuk mengukur kebolehubahan dengan membandingkan sisihan merentas setiap cubaan.
# Note: the qubit coordinates must be hard-coded.
# The backend API does not currently provide this information directly.
# If using a different backend, you will need to
# adjust the coordinates accordingly,
# or set the qubit_coordinates = None to use the default layout coordinates.
def _heron_coords_r2():
"""Generate coordinates for the Heron layout in R2. Note"""
cord_map = np.array(
[
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
3,
7,
11,
15,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
1,
5,
9,
13,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
3,
7,
11,
15,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
1,
5,
9,
13,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
3,
7,
11,
15,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
1,
5,
9,
13,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
3,
7,
11,
15,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
],
-1
* np.array([j for i in range(15) for j in [i] * [16, 4][i % 2]]),
],
dtype=int,
)
hcords = []
ycords = cord_map[0]
xcords = cord_map[1]
for i in range(156):
hcords.append([xcords[i] + 1, np.abs(ycords[i]) + 1])
return hcords
# Visualize the active qubits in the circuit layout
plot_circuit_layout(
circuit=isa_circuits_uni[-1],
backend=backend,
view="physical",
qubit_coordinates=_heron_coords_r2(),
)

Seterusnya, kita jalankan eksperimen pada backend sebenar. Kita juga guna batching untuk menjalankan eksperimen secara cekap merentas beberapa percubaan. Menjalankan percubaan berulang membolehkan kita mengira purata untuk perbandingan yang lebih tepat antara kaedah uniter dan dinamik, serta untuk mengukur kebolehubahan dengan membandingkan sisihan merentas setiap cubaan.
# -------------------------Step 3-------------------------
num_trials = 10
jobs_uni = []
jobs_dyn = []
with Batch(backend=backend) as batch:
sampler = Sampler(mode=batch)
sampler.options.environment.job_tags = ["TUT_LRE"]
for _ in range(num_trials):
jobs_uni.append(sampler.run(isa_circuits_uni, shots=1024))
jobs_dyn.append(sampler.run(isa_circuits_dyn, shots=1024))
Kita kira kesetiaan untuk Circuit CX jarak jauh dinamik. Bagi setiap jarak, kita ekstrak hasil pengukuran dalam asas , , dan . Keputusan-keputusan ini digabungkan menggunakan fungsi pembantu yang telah ditakrifkan sebelum ini untuk mengira kesetiaan mengikut . Ini memberikan kesetiaan yang diperhatikan bagi protokol yang dilaksanakan secara dinamik pada setiap jarak.
# -------------------------Step 4-------------------------
fidelities_dyn = []
# loop over trials
for job in jobs_dyn:
result_dyn = job.result()
trial_fidelities = []
# loop over all distances
for ind, dist in enumerate(distances):
counts_xx = result_dyn[ind * 3].data.cr.get_counts()
counts_yy = result_dyn[ind * 3 + 1].data.cr.get_counts()
counts_zz = result_dyn[ind * 3 + 2].data.cr.get_counts()
trial_fidelities.append(
compute_fidelity(counts_xx, counts_yy, counts_zz)
)
fidelities_dyn.append(trial_fidelities)
# average over trials for each distance
avg_fidelities_dyn = np.mean(fidelities_dyn, axis=0)
std_fidelities_dyn = np.std(fidelities_dyn, axis=0)
Kini kita kira kesetiaan untuk Circuit CX jarak jauh uniter, dengan cara yang sama seperti yang kita lakukan untuk Circuit dinamik di atas.
fidelities_uni = []
# loop over trials
for job in jobs_uni:
result_uni = job.result()
trial_fidelities = []
# loop over all distances
for ind, dist in enumerate(distances):
counts_xx = result_uni[ind * 3].data.cr.get_counts()
counts_yy = result_uni[ind * 3 + 1].data.cr.get_counts()
counts_zz = result_uni[ind * 3 + 2].data.cr.get_counts()
trial_fidelities.append(
compute_fidelity(counts_xx, counts_yy, counts_zz)
)
fidelities_uni.append(trial_fidelities)
# average over trials for each distance
avg_fidelities_uni = np.mean(fidelities_uni, axis=0)
std_fidelities_uni = np.std(fidelities_uni, axis=0)
Plot keputusan
Untuk menghayati keputusan secara visual, sel di bawah memplot kesetiaan gate yang dianggarkan diukur pada pelbagai jarak antara qubit yang terbelit bagi setiap kaedah.
fig, ax = plt.subplots()
# Unitary with error bars
ax.errorbar(
distances,
avg_fidelities_uni,
yerr=std_fidelities_uni,
fmt="o-.",
color="c",
ecolor="c",
elinewidth=1,
capsize=4,
label="Unitary",
)
# Dynamic with error bars
ax.errorbar(
distances,
avg_fidelities_dyn,
yerr=std_fidelities_dyn,
fmt="o-.",
color="m",
ecolor="m",
elinewidth=1,
capsize=4,
label="Dynamic",
)
# Random gate baseline
ax.axhline(y=1 / 4, linestyle="--", color="gray", label="Random gate")
legend = ax.legend(frameon=True)
for text in legend.get_texts():
text.set_color("black")
legend.get_frame().set_facecolor("white")
legend.get_frame().set_edgecolor("black")
ax.set_title(
"Bell State Fidelity vs Control–Target Separation", color="black"
)
ax.set_xlabel("Distance", color="black")
ax.set_ylabel("Bell state fidelity", color="black")
ax.grid(linestyle=":", linewidth=0.6, alpha=0.4, color="gray")
ax.set_ylim((0.2, 1))
ax.set_facecolor("white")
fig.patch.set_facecolor("white")
for spine in ax.spines.values():
spine.set_visible(True)
spine.set_color("black")
ax.tick_params(axis="x", colors="black")
ax.tick_params(axis="y", colors="black")
plt.show()

Daripada plot kesetiaan di atas, LRCX tidak secara konsisten mengatasi pelaksanaan uniter langsung. Malah, untuk pemisahan kawalan-sasaran yang pendek, Circuit uniter mencapai kesetiaan yang lebih tinggi. Namun, pada pemisahan yang lebih besar, Circuit dinamik mula mencapai kesetiaan yang lebih baik berbanding pelaksanaan uniter. Tingkah laku ini tidak mengejutkan pada perkakasan semasa: walaupun Circuit dinamik mengurangkan kedalaman Circuit dengan mengelakkan rantaian SWAP yang panjang, ia memperkenalkan masa Circuit tambahan daripada pengukuran pertengahan Circuit, maklum balas klasikal, dan kelewatan laluan kawalan. Kependaman tambahan ini meningkatkan dekoheren dan ralat pembacaan, yang boleh melebihi penjimatan kedalaman pada jarak yang pendek.
Namun begitu, kita perhatikan titik persimpangan di mana pendekatan dinamik mengatasi pendekatan uniter. Ini adalah hasil langsung daripada penskalaan yang berbeza: kedalaman Circuit uniter berkembang secara linear dengan jarak antara qubit, manakala kedalaman Circuit dinamik kekal malar.
Perkara utama:
- Faedah segera Circuit dinamik: Motivasi utama pada masa kini ialah pengurangan kedalaman dua-Qubit, bukan semestinya peningkatan kesetiaan.
- Mengapa kesetiaan boleh lebih buruk hari ini: Peningkatan masa Circuit daripada operasi pengukuran dan klasikal sering mendominasi, terutamanya apabila pemisahan kawalan-sasaran adalah kecil.
- Melihat ke hadapan: Apabila perkakasan bertambah baik, khususnya pembacaan yang lebih cepat, kependaman kawalan klasikal yang lebih pendek, dan overhead pertengahan Circuit yang berkurangan, kita sepatutnya menjangkakan pengurangan kedalaman dan tempoh ini diterjemahkan kepada keuntungan kesetiaan yang boleh diukur.
# Compute metrics for each distance, skipping the basis circuits since
# they are identical for each distance
depths_2q_dyn = [
c.depth(lambda x: x.operation.num_qubits == 2)
for c in isa_circuits_dyn[::3]
]
meas_dyn = [
sum(1 for instr in c.data if instr.operation.name == "measure")
for c in isa_circuits_dyn[::3]
]
depths_2q_uni = [
c.depth(lambda x: x.operation.num_qubits == 2)
for c in isa_circuits_uni[::3]
]
meas_uni = [
sum(1 for instr in c.data if instr.operation.name == "measure")
for c in isa_circuits_uni[::3]
]
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].plot(
distances, depths_2q_uni, "o-.", color="c", label="Unitary (2Q depth)"
)
axes[0].plot(
distances, depths_2q_dyn, "o-.", color="m", label="Dynamic (2Q depth)"
)
axes[0].set_xlabel("Number of qubits between control and target")
axes[0].set_ylabel("Two-qubit depth")
axes[0].grid(True, linestyle=":", linewidth=0.6, alpha=0.4)
axes[0].legend()
axes[1].plot(
distances, meas_uni, "o-.", color="c", label="Unitary (# measurements)"
)
axes[1].plot(
distances, meas_dyn, "o-.", color="m", label="Dynamic (# measurements)"
)
axes[1].set_xlabel("Number of qubits between control and target")
axes[1].set_ylabel("Number of measurements")
axes[1].grid(True, linestyle=":", linewidth=0.6, alpha=0.4)
axes[1].legend()
fig.suptitle("Scaling of Unitary vs Dynamic LRCX with Distance", fontsize=12)
plt.tight_layout()
plt.show()

Plot kedalaman dua-Qubit ini menyerlahkan kelebihan utama LRCX yang dilaksanakan dengan Circuit dinamik: prestasi kekal pada dasarnya malar apabila pemisahan antara qubit kawalan dan sasaran meningkat. Sebaliknya, pelaksanaan uniter berkembang secara linear dengan jarak akibat rantaian SWAP yang diperlukan. Kedalaman menangkap penskalaan logikal operasi dua-Qubit, manakala kiraan pengukuran mencerminkan overhead tambahan untuk Circuit dinamik. Pengukuran-pengukuran ini adalah cekap, kerana ia dilakukan secara selari, tetapi ia tetap memperkenalkan kos tetap pada perkakasan hari ini.
Mengapa kesetiaan boleh lebih buruk hari ini: Peningkatan masa Circuit daripada operasi pengukuran dan klasikal sering mendominasi, terutamanya apabila pemisahan kawalan-sasaran adalah kecil. Sebagai contoh, purata panjang pembacaan pada pemproses Heron r2 ialah 2,280 ns, sedangkan panjang gate 2Q-nya hanya 68 ns.
Apabila kependaman pengukuran dan klasikal bertambah baik, kita menjangkakan penskalaan kedalaman malar dan pengukuran malar bagi Circuit dinamik akan menghasilkan kelebihan kesetiaan dan masa jalan yang jelas pada Circuit yang lebih besar.
Langkah seterusnya
Jika anda mendapati karya ini menarik, anda mungkin berminat dengan bahan-bahan berikut:
Rujukan
[1] Efficient Long-Range Entanglement using Dynamic Circuits, by Elisa Bäumer, Vinay Tripathi, Derek S. Wang, Patrick Rall, Edward H. Chen, Swarnadeep Majumder, Alireza Seif, Zlatko K. Minev. IBM Quantum, (2023). https://arxiv.org/abs/2308.13065