Classical feedforward dan control flow
Versi paket
Kode di halaman ini dikembangkan menggunakan persyaratan berikut. Kami merekomendasikan menggunakan versi ini atau yang lebih baru.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Versi baru dynamic circuits kini tersedia untuk semua pengguna di semua backend. Kamu sekarang bisa menjalankan dynamic circuits dalam skala utilitas. Lihat pengumumannya untuk detail lebih lanjut.
Dynamic circuits adalah alat yang powerful yang memungkinkan kamu mengukur qubit di tengah eksekusi quantum circuit, lalu melakukan operasi logika klasik di dalam circuit berdasarkan hasil pengukuran mid-circuit tersebut. Proses ini juga dikenal sebagai classical feedforward. Meskipun masih tahap awal dalam memahami cara terbaik memanfaatkan dynamic circuits, komunitas riset kuantum sudah mengidentifikasi sejumlah kasus penggunaan, seperti berikut:
- Persiapan quantum state yang efisien, seperti GHZ state, W-state, (untuk informasi lebih lanjut tentang W-state, lihat juga "State preparation by shallow circuits using feed forward") dan berbagai kelas matrix product states
- Long-range entanglement yang efisien antar qubit di chip yang sama menggunakan shallow circuits
- Sampling IQP-like circuits yang efisien
Namun, peningkatan yang dibawa dynamic circuits ini datang dengan trade-off. Pengukuran mid-circuit dan operasi klasik biasanya memiliki waktu eksekusi yang lebih lama dibanding two-qubit gates, dan peningkatan waktu ini bisa meniadakan keuntungan dari pengurangan kedalaman circuit. Oleh karena itu, pengurangan durasi pengukuran mid-circuit menjadi area fokus perbaikan saat IBM Quantum® merilis versi baru dynamic circuits.
Spesifikasi OpenQASM 3 mendefinisikan sejumlah struktur control-flow, tetapi Qiskit Runtime saat ini hanya mendukung pernyataan kondisional if. Di Qiskit SDK, ini sesuai dengan metode if_test pada QuantumCircuit. Metode ini mengembalikan sebuah context manager dan biasanya digunakan dalam pernyataan with. Panduan ini menjelaskan cara menggunakan pernyataan kondisional tersebut.
Contoh kode dalam panduan ini menggunakan instruksi measure standar untuk pengukuran mid-circuit. Namun, disarankan untuk menggunakan instruksi MidCircuitMeasure sebagai gantinya, jika backend mendukungnya. Lihat dokumentasi Mid-circuit measurements untuk detailnya.
Pernyataan if​
Pernyataan if digunakan untuk melakukan operasi secara kondisional berdasarkan nilai sebuah classical bit atau register.
Pada contoh di bawah, kita menerapkan Hadamard gate pada sebuah qubit dan mengukurnya. Jika hasilnya adalah 1, maka kita menerapkan X gate pada qubit tersebut, yang efeknya adalah membaliknya kembali ke state 0. Kita kemudian mengukur qubit itu lagi. Hasil pengukuran yang dihasilkan seharusnya 0 dengan probabilitas 100%.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
circuit = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
circuit.h(q0)
# Use MidCircuitMeasure() if it's supported by the backend.
# circuit.append(MidCircuitMeasure(), [q0], [c0])
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)):
circuit.x(q0)
circuit.measure(q0, c0)
circuit.draw("mpl")
# example output counts: {'0': 1024}
Pernyataan with bisa diberi target penugasan yang berupa context manager itu sendiri, yang bisa disimpan dan kemudian digunakan untuk membuat blok else, yang dieksekusi setiap kali isi blok if tidak dieksekusi.
Pada contoh di bawah, kita menginisialisasi register dengan dua qubit dan dua classical bit. Kita menerapkan Hadamard gate pada qubit pertama dan mengukurnya. Jika hasilnya adalah 1, maka kita menerapkan Hadamard gate pada qubit kedua; jika tidak, kita menerapkan X gate pada qubit kedua. Terakhir, kita juga mengukur qubit kedua.
qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q1)
with else_:
circuit.x(q1)
circuit.measure(q1, c1)
circuit.draw("mpl")
# example output counts: {'01': 260, '11': 272, '10': 492}
Selain mengondisikan pada satu classical bit, kamu juga bisa mengondisikan pada nilai sebuah classical register yang terdiri dari beberapa bit.
Pada contoh di bawah, kita menerapkan Hadamard gates pada dua qubit dan mengukurnya. Jika hasilnya adalah 01, yaitu qubit pertama adalah 1 dan qubit kedua adalah 0, maka kita menerapkan X gate pada qubit ketiga. Terakhir, kita mengukur qubit ketiga. Perlu dicatat bahwa demi kejelasan, kita memilih untuk menentukan state classical bit ketiga, yaitu 0, dalam kondisi if. Dalam gambar circuit, kondisi ditunjukkan oleh lingkaran pada classical bit yang dijadikan kondisi. Lingkaran hitam menunjukkan pengondisian pada 1, sedangkan lingkaran putih menunjukkan pengondisian pada 0.
qubits = QuantumRegister(3)
clbits = ClassicalRegister(3)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1, q2) = qubits
(c0, c1, c2) = clbits
circuit.h([q0, q1])
circuit.measure(q0, c0)
circuit.measure(q1, c1)
with circuit.if_test((clbits, 0b001)):
circuit.x(q2)
circuit.measure(q2, c2)
circuit.draw("mpl")
# example output counts: {'101': 269, '011': 260, '000': 252, '010': 243}
Ekspresi klasik​
Modul ekspresi klasik Qiskit qiskit.circuit.classical berisi representasi eksploratif dari operasi runtime pada nilai klasik selama eksekusi circuit. Karena keterbatasan hardware, hanya kondisi QuantumCircuit.if_test() yang saat ini didukung.
Contoh berikut menunjukkan bahwa kamu bisa menggunakan perhitungan paritas untuk membuat n-qubit GHZ state menggunakan dynamic circuits. Pertama, buat pasangan Bell pada qubit yang berdekatan. Kemudian, gabungkan pasangan-pasangan ini menggunakan satu lapisan CNOT gates di antara pasangan. Kamu kemudian mengukur target qubit dari semua CNOT gates sebelumnya dan me-reset setiap qubit yang diukur ke state . Kamu menerapkan ke setiap situs yang tidak diukur di mana paritas dari semua bit sebelumnya adalah ganjil. Terakhir, CNOT gates diterapkan pada qubit yang diukur untuk memulihkan entanglement yang hilang saat pengukuran.
Dalam perhitungan paritas, elemen pertama dari ekspresi yang dibangun melibatkan pengangkatan objek Python mr[0] ke sebuah node Value (lift digunakan untuk mengubah objek sembarang menjadi ekspresi klasik). Ini tidak diperlukan untuk mr[1] dan kemungkinan classical register berikutnya, karena keduanya adalah input untuk expr.bit_xor, dan pengangkatan yang diperlukan dilakukan secara otomatis dalam kasus tersebut. Ekspresi semacam itu bisa dibangun dalam loop dan konstruk lainnya.
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr
num_qubits = 8
if num_qubits % 2 or num_qubits < 4:
raise ValueError("num_qubits must be an even integer ≥ 4")
meas_qubits = list(range(2, num_qubits, 2)) # qubits to measure and reset
qr = QuantumRegister(num_qubits, "qr")
mr = ClassicalRegister(len(meas_qubits), "m")
qc = QuantumCircuit(qr, mr)
# Create local Bell pairs
qc.reset(qr)
qc.h(qr[::2])
for ctrl in range(0, num_qubits, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])
# Glue neighboring pairs
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])
# Measure boundary qubits between pairs,reset to 0
for k, q in enumerate(meas_qubits):
qc.measure(qr[q], mr[k])
qc.reset(qr[q])
# Parity-conditioned X corrections
# Each non-measured qubit gets flipped iff the parity (XOR) of all
# preceding measurement bits is 1
for tgt in range(num_qubits):
if tgt in meas_qubits: # skip measured qubits
continue
# all measurement registers whose physical qubit index < tgt
left_bits = [k for k, q in enumerate(meas_qubits) if q < tgt]
if not left_bits: # skip if list empty
continue
# build XOR-parity expression
parity = expr.lift(
mr[left_bits[0]]
) # lift the first bit to Value so it will be treated like a boolean.
for k in left_bits[1:]:
parity = expr.bit_xor(
mr[k], parity
) # calculate parity with all other bits
with qc.if_test(parity): # Add X if parity is 1
qc.x(qr[tgt])
# Re-entangle measured qubits
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])
qc.draw(output="mpl", style="iqp", idle_wires=False, fold=-1)
Temukan backend yang mendukung dynamic circuits​
Untuk menemukan semua backend yang bisa diakses oleh akunmu dan mendukung dynamic circuits, jalankan kode seperti berikut. Contoh ini mengasumsikan bahwa kamu sudah menyimpan kredensial login. Kamu juga bisa menentukan kredensial secara eksplisit saat menginisialisasi akun layanan Qiskit Runtime. Ini memungkinkan kamu melihat backend yang tersedia pada instansi atau jenis paket tertentu, misalnya.
- Backend yang tersedia untuk akun bergantung pada instansi yang ditentukan dalam kredensial.
- Versi baru dynamic circuits kini tersedia untuk semua pengguna di semua backend. Lihat pengumumannya untuk detail lebih lanjut.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_miami')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_torino')>, <IBMBackend('ibm_kingston')>]
Keterbatasan Qiskit Runtime​
Perhatikan batasan berikut saat menjalankan dynamic circuits di Qiskit Runtime.
-
Karena keterbatasan memori fisik pada elektronik kontrol, ada juga batas pada jumlah pernyataan
ifdan ukuran operannya. Batas ini merupakan fungsi dari jumlah broadcast dan jumlah bit yang di-broadcast dalam sebuah job (bukan circuit).Saat memproses kondisi
if, data pengukuran perlu ditransfer ke logika kontrol untuk melakukan evaluasi tersebut. Broadcast adalah transfer data klasik yang unik, dan broadcasted bits adalah jumlah classical bit yang ditransfer. Perhatikan hal berikut:c0 = ClassicalRegister(3)
c1 = ClassicalRegister(5)
...
with circuit.if_test((c0, 1)) ...
with circuit.if_test((c0, 3)) ...
with circuit.if_test((c1[2], 1)) ...Dalam contoh kode sebelumnya, dua objek
if_testpertama padac0dianggap satu broadcast karena isic0tidak berubah, sehingga tidak perlu di-broadcast ulang.if_testpadac1adalah broadcast kedua. Yang pertama mem-broadcast semua tiga bit dic0dan yang kedua mem-broadcast hanya satu bit, sehingga total ada empat broadcasted bits.Saat ini, jika kamu mem-broadcast 60 bit setiap kali, maka job bisa memiliki sekitar 300 broadcast. Namun jika kamu mem-broadcast hanya satu bit setiap kali, maka job bisa memiliki 2400 broadcast.
-
Operand yang digunakan dalam pernyataan
if_testharus 32 bit atau kurang. Jadi, jika kamu membandingkan seluruhClassicalRegister, ukuranClassicalRegistertersebut harus 32 bit atau kurang. Namun jika kamu hanya membandingkan satu bit dari sebuahClassicalRegister,ClassicalRegistertersebut bisa berukuran berapa saja (karena operandnya hanya satu bit).Misalnya, blok kode "Tidak valid" tidak berfungsi karena
crlebih dari 32 bit. Namun, kamu bisa menggunakan classical register yang lebih lebar dari 32 bit jika hanya menguji satu bit, seperti yang ditunjukkan dalam blok kode "Valid".- Tidak valid
- Valid
cr = ClassicalRegister(50)
qr = QuantumRegister(50)
circuit = QuantumCircuit(qr, cr)
...
circ.measure(qr, cr)
with circ.if_test((cr, 15)):
...cr = ClassicalRegister(50)
qr = QuantumRegister(50)
circuit = QuantumCircuit(qr, cr)
...
circ.measure(qr, cr)
with circ.if_test((cr[5], 1)):
... -
Kondisional bersarang tidak diperbolehkan. Misalnya, blok kode berikut tidak akan berfungsi karena ada
if_testdi dalamif_testlainnya:- Tidak valid
- Valid
c1 = ClassicalRegister(1, "c1")
c2 = ClassicalRegister(2, "c2")
...
with circ.if_test((c1, 1)):
with circ.if_test(c2, 1)):
...cr = ClassicalRegister(2)
...
with circuit.if_test((cr, 0b11)):
... -
Penggunaan
resetatau pengukuran di dalam kondisional tidak didukung. -
Operasi aritmatika tidak didukung.
-
Lihat tabel fitur OpenQASM 3 untuk menentukan fitur OpenQASM 3 mana yang didukung di Qiskit dan Qiskit Runtime.
-
Ketika OpenQASM 3 (bukan
QuantumCircuit) digunakan sebagai format input untuk meneruskan circuits ke Qiskit Runtime primitives, hanya instruksi yang bisa dimuat ke Qiskit yang didukung. Operasi klasik, misalnya, tidak didukung karena tidak bisa dimuat ke Qiskit. Lihat Import program OpenQASM 3 ke Qiskit untuk informasi lebih lanjut. -
Instruksi
for,while, danswitchtidak didukung.
Gunakan dynamic circuits dengan Estimator​
Karena Estimator tidak mendukung dynamic circuits, kamu bisa menggunakan Sampler dan membangun measurement circuit sendiri. Sebagai alternatif, kamu bisa menggunakan Executor primitive, yang mendukung dynamic circuits.
Untuk mereplikasi perilaku Estimator, ikuti proses ini:
- Kelompokkan suku-suku dari semua observabel ke dalam sebuah partisi. Ini bisa dilakukan dengan menggunakan API
PauliList, misalnya.catatanKamu bisa menggunakan atribut primitif
BitArrayuntuk menghitung nilai ekspektasi dari observabel yang diberikan. - Eksekusi satu circuit perubahan basis per partisi (perubahan basis apa pun yang perlu dilakukan untuk setiap partisi). Lihat modul utilitas addon Measurement bases
measurement_basesmodule untuk informasi lebih lanjut. Mulai dengan utilities. - Gabungkan kembali hasil untuk setiap partisi.
Langkah selanjutnya​
- Pelajari cara mengimplementasikan dynamic decoupling yang akurat menggunakan stretch.
- Pelajari tentang pengukuran mid-circuit yang lebih singkat untuk mengurangi waktu circuit.
- Gunakan visualisasi jadwal circuit untuk men-debug dan mengoptimalkan dynamic circuits kamu.