Bekerja dengan circuit fermionik
Konsep-konsep dalam panduan ini saat ini hanya tersedia di Python API. Fungsionalitas yang setara akan hadir di C API pada rilis mendatang.
Panduan ini menjelaskan cara memakai FermionicCircuit untuk menjalankan algoritma kuantum langsung di ruang fermionik, tanpa harus memetakannya ke qubit dulu.
Kenapa pakai circuit fermionik
Coba lihat alur kerja tradisional untuk mengimplementasikan evolusi waktu dari Hamiltonian fermionik di arsitektur berbasis qubit:
-
Definisikan Hamiltonian fermionik (misalnya, ).
-
Petakan ke operator qubit (misalnya, dengan pemetaan Jordan-Wigner).
-
Implementasikan evolusi waktu di ruang qubit (dengan Trotterization atau metode lain).
Pendekatan ini punya keterbatasan mendasar: pemetaan ke qubit di awal membuang pengetahuan yang sadar-masalah tentang struktur fermionik. Pass optimisasi standar tidak bisa memanfaatkan simetri fermionik atau penataan ulang suku yang diperbolehkan, sehingga circuit yang dihasilkan kurang optimal dengan depth dan jumlah gate yang tidak perlu.
FermionicCircuit memungkinkan alur kerja yang lebih baik:
-
Definisikan Hamiltonian fermionik (misalnya, ).
-
Implementasikan evolusi waktu langsung di ruang fermionik dengan gate fermionik.
-
Petakan ke ruang qubit sebagai bagian dari proses transpilasi.
Pendekatan ini mengatasi keterbatasan tadi dengan menjaga pengetahuan yang sadar-masalah tetap di ruang fermionik, tempat pass optimisasi bisa memanfaatkan struktur fermionik dan relasi komutasi untuk memangkas depth circuit. Circuit fermionik menjelaskan komputasi apa yang dilakukan, sedangkan transpilasi menangani cara memetakannya ke qubit, sehingga pemisahan tanggung jawabnya lebih bersih.
Pengindeksan mode generik
Baik modul operators maupun FermionicCircuit memakai pengindeksan berbasis mode yang generik dan tidak berasumsi apa pun soal sifat modenya. Mode hanyalah indeks abstrak yang memberi label pada satu derajat kebebasan fermionik, tanpa semantik bawaan. Pilihan desain ini meniru modul operators dan memastikan fleksibilitas maksimum. Misalnya, kamu bisa mengimplementasikan evolusi waktu untuk operator apa pun yang mengimplementasikan protokol OperatorTrait, apa pun representasi matematisnya.
Membangun circuit fermionik
Contoh di bawah ini mengimplementasikan evolusi waktu yang dijelaskan di bagian sebelumnya. Contoh ini membuat FermionicCircuit dengan menentukan jumlah mode fermionik, lalu menambahkan gate fermionik dari qiskit_fermions.circuit.library untuk mengimplementasikan evolusi waktu.
Contoh ini juga menunjukkan cara memasukkan pengetahuan domain ke dalam operator dengan pengelompokan suku operator. Dengan memberi indeks grup pada suku-suku Hamiltonian, kamu mempertahankan informasi struktural yang bisa dimanfaatkan pass optimisasi di seluruh stack transpilasi.
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, cre, ann
>>>
>>> # Create a circuit with 4 fermionic modes
>>> circuit = FermionicCircuit(4)
>>>
>>> # Define a simple fermionic Hamiltonian
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(2)], 0.5),
... ([cre(2), ann(0)], 0.5),
... ([cre(1), ann(3)], 0.5),
... ([cre(3), ann(1)], 0.5),
... ])
>>> # Add some problem structure by grouping our Hamiltonian terms
>>> hamiltonian.groups = [0, 0, 1, 1]
>>>
>>> # Add an evolution gate to implement exp(-i * t * H)
>>> evolution = Evolution(4, hamiltonian, time=1.0)
>>> circuit.append(evolution, circuit.register)
Perhatikan bahwa pengelompokan suku operator tetap terjaga bahkan pada operasi sederhana seperti dekomposisi. Ini menunjukkan bagaimana informasi struktural mengalir melalui stack circuit. Untuk memahami transpilasi lengkap ke qubit, lihat panduan Transpiling fermionic circuits.
Pisahkan gate dengan barrier
Pass optimisasi menggabungkan gate bertetangga kalau bisa. Misalnya, MergeOrbitalRotations menggabungkan rangkaian gate OrbitalRotation yang berurutan menjadi satu, dan MergeSlaterDeterminantPreparation melipat InitializeModes ke dalam rotasi yang mengikutinya.
Pakai FermionicCircuit.barrier() kalau kamu ingin mencegah hal itu. Barrier tidak punya efek uniter, jadi tidak mengubah state yang disiapkan circuit-mu; barrier hanya menandai titik yang tidak dilewati penggabungan oleh pass. Panggil tanpa argumen untuk mencakup semua mode, atau berikan mode-mode yang ingin dibatasi:
>>> from qiskit_fermions.circuit.library import OrbitalRotation
>>> import numpy as np
>>>
>>> rotations = FermionicCircuit(4)
>>> rotations.append(OrbitalRotation(np.eye(4, dtype=complex)), rotations.register)
>>> rotations.barrier()
>>> rotations.append(OrbitalRotation(np.eye(4, dtype=complex)), rotations.register)
Barrier tetap bertahan setelah transpilasi fermion-ke-qubit, jadi barrier juga membatasi optimisasi tingkat qubit yang menyusul. Panduan Transpile fermionic circuits membahas tahap itu.
Mengulang circuit
Banyak algoritma menerapkan blok gate yang sama berkali-kali. Evolusi waktu adalah kasus yang paling umum: satu langkah Trotter dibuat sekali, lalu diulang sampai mencapai waktu target. Pakai repeat() untuk membuat circuit berulang, dan compose() untuk menyambungkannya ke prefiks persiapan state.
Contoh di bawah ini membuat langkah Trotter orde kedua untuk model Fermi-Hubbard. Langkahnya simetris: suku hopping dipecah menjadi dua gate OrbitalRotation berdurasi setengah yang mengapit interaksi on-site.
>>> import scipy.linalg
>>> from qiskit_fermions.circuit.library import InitializeModes, OrbitalRotation
>>>
>>> norb, reps, time = 2, 3, 1.0
>>> num_modes = 2 * norb
>>> dt = time / reps
>>>
>>> hopping = np.zeros((norb, norb))
>>> hopping[0, 1] = hopping[1, 0] = -1.0
>>> interaction = FermionOperator.from_dict(
... {(cre(p), ann(p), cre(p + norb), ann(p + norb)): 2.0 for p in range(norb)}
... )
>>>
>>> def rotation(duration):
... propagator = scipy.linalg.expm(-1j * duration * hopping)
... # the same rotation acts on the alpha and beta halves of the register
... return scipy.linalg.block_diag(propagator, propagator)
>>>
>>> trotter_step = FermionicCircuit(num_modes)
>>> trotter_step.append(OrbitalRotation(rotation(dt / 2)), trotter_step.modes)
>>> trotter_step.append(
... Evolution(num_modes, interaction, dt, atomic=True), trotter_step.modes
... )
>>> trotter_step.append(OrbitalRotation(rotation(dt / 2)), trotter_step.modes)
Mengulang langkah itu dan menyusunnya di atas referensi Hartree-Fock menghasilkan evolusi penuh:
>>> evolution = FermionicCircuit(num_modes)
>>> evolution.append(InitializeModes([True, False, True, False]), evolution.modes)
>>> evolution.compose(trotter_step.repeat(reps), inplace=True)
>>> evolution.count_ops()["OrbitalRotation"]
6
Pengulangan diratakan ke dalam circuit yang dikembalikan, bukan dibungkus dalam satu gate, sehingga count_ops() menghitung dua rotasi per langkah. Perataan itulah yang membuat redundansi di batas antarlangkah terlihat oleh transpiler: rotasi berdurasi setengah di akhir satu langkah dan yang di awal langkah berikutnya saling bersebelahan, sehingga MergeOrbitalRotations menggabungkannya menjadi satu rotasi.
>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.passes import MergeOrbitalRotations
>>>
>>> merged = FermionicPassManager([MergeOrbitalRotations()]).run(evolution)
>>> merged.count_ops()["OrbitalRotation"]
4
Hasilnya membutuhkan satu rotasi per langkah ditambah satu, sama seperti kalau kamu menggabungkan setengah-langkah itu secara manual. Menulis langkah dalam bentuk simetris alaminya lalu mengulangnya menghasilkan circuit yang sama, jadi penggabungannya diserahkan ke tahap optimisasi.
Kalau kamu perlu pengulangan tetap terpisah, berikan insert_barriers=True untuk menempatkan barrier() di antaranya. Pass optimisasi tidak menggabungkan gate melintasi barrier, sehingga setiap rotasi tetap ada:
>>> separated = trotter_step.repeat(reps, insert_barriers=True)
>>> FermionicPassManager([MergeOrbitalRotations()]).run(separated).count_ops()[
... "OrbitalRotation"
... ]
6
Argumen reps dari FermionicSuzukiTrotter adalah konsep yang berbeda. Argumen itu membagi satu gate Evolution menjadi lebih banyak faktor yang lebih pendek, sedangkan repeat() menggandakan seluruh circuit. Mengulang circuit yang berisi satu Evolution hanya melipatgandakan total waktu evolusinya.
Mengukur mode fermionik
measure_all() membaca setiap mode ke bit klasiknya sendiri, dengan memasangkan mode i dengan bit i. Pakai measure() dengan ClassicalRegister milikmu sendiri untuk membaca sebagian mode saja.
>>> measured = trotter_step.measure_all(inplace=False)
>>> measured.count_ops()["measure"]
4
Memberikan inplace=False mengembalikan salinan yang sudah diukur dan membiarkan aslinya tidak berubah. Ini penting karena pengukuran tidak uniter: circuit yang memuat pengukuran tidak bisa lagi diterapkan ke state vector, jadi simpan circuit tanpa pengukuran kalau kamu juga ingin mensimulasikannya.
Mengukur di sini, bukan pada QuantumCircuit hasil transpilasi, membuat bitstring hasil sampling tetap mudah dibaca. Pengukuran fermionik menyebut mode yang dibacanya, sehingga setiap tahap yang memindahkan mode (RelabelModes di tingkat fermionik, layout dan routing di tingkat qubit) ikut membawa pengukurannya, dan bitstring tetap diindeks menurut mode yang kamu tanyakan.
Berbeda dengan measure_all(), tidak ada barrier() yang disisipkan sebelum pengukuran. Panggil barrier() sendiri lebih dulu kalau kamu menginginkannya di situ.
Apakah bit hasil ukur bermakna seperti yang kamu harapkan tergantung pada encoding fermion-ke-qubit, yang dipilih saat transpilasi, bukan di sini. Pada encoding basis okupasi seperti Jordan-Wigner, setiap mode dibawa oleh satu qubit dan bitnya adalah okupasi mode tersebut; lihat FermionicMeasure.
Transpilasi circuit fermionik
Untuk mengimplementasikan algoritma kuantum yang diwakili oleh FermionicCircuit milikmu, circuit itu harus ditranspilasi menjadi QuantumCircuit. Cara melakukannya ada di panduan Transpile fermionic circuits.
Langkah berikutnya
-
Pelajari gate fermionik yang tersedia di dokumentasi
qiskit_fermions.circuit.library. -
Jelajahi panduan penjelasan operators untuk memahami cara membangun Hamiltonian fermionik yang bisa dipakai dengan circuit fermionik.
-
Tinjau panduan memulai SQDRIFT untuk contoh end-to-end yang praktis.
-
Baca panduan hubungan dengan ffsim untuk memahami bagaimana
FermionicCircuitbisa disimulasikan secara langsung, dan bagaimana indeks mode generik ini baru mendapat semantik spin saat simulasi.

