Transpilasikan ansatz LUCJ
Konsep dalam panduan ini hanya tersedia dalam API Python.
Ansatz Jastrow kluster uniter setempat (LUCJ) ialah parametrisasi padat yang cekap perkakasan bagi fungsi gelombang elektronik berkorelasi. Ia merupakan ahli keluarga Jastrow kluster uniter (UCJ) yang lebih umum dan mengambil bentuk
dengan ialah keadaan rujukan (lazimnya Hartree-Fock), setiap ialah putaran orbital, dan setiap ialah operator Coulomb pepenjuru
dengan ialah operator nombor pada orbital ruang dengan spin .
ffsim membina operator ansatz; pakej ini menukarkannya menjadi litar dan menurunkan litar itu ke atas qubit. Panduan ini adalah mengenai separuh kedua ayat tersebut. Sebab untuk membuat perjalanan ini ialah penurunan itu sendiri: gate Qiskit ffsim sendiri khusus untuk transformasi Jordan-Wigner, manakala FermionicCircuit tidak membawa andaian tentang pengekodan fermion-ke-qubitnya, jadi ansatz yang sama boleh disintesis melalui apa jua pengekodan yang sesuai dengan peranti sasaran.
Oleh itu, operator ansatz tiba di sini dalam keadaan siap, dan segala yang berikut ialah apa yang berlaku kepadanya selepas itu: apa yang diuraikan oleh gate, bagaimana ia diturunkan melalui Jordan-Wigner, bagaimana ia dipadankan dengan peta gandingan peranti, dan apa yang masih diperlukan oleh penurunan bukan Jordan-Wigner. Untuk membina, memparametrikan, atau mensimulasikan ansatz UCJ pada mulanya, lihat panduan sendiri ffsim.
Panduan hubungan ffsim tentang cara kedua-dua pakej membahagikan kerja, dan panduan transpilasi untuk peringkat saluran paip yang digunakan di bawah.
1. Dapatkan operator LUCJ daripada ffsim
Ansatz dimulakan daripada amplitud pengiraan kluster berganding singles dan doubles (CCSD). Jalankan Hartree-Fock terhad diikuti CCSD untuk molekul hidrogen dalam asas 6-31g, menggunakan PySCF untuk kimia kuantum, kemudian serahkan amplitud kepada from_t_amplitudes() milik ffsim. Ia melakukan pemfaktoran berganda ke atas amplitud untuk mendapatkan matriks Coulomb pepenjuru dan putaran orbital bagi setiap lapisan, dan menerbitkan putaran orbital akhir pilihan daripada amplitud . Bilangan pengulangan ialah apa sahaja yang dihasilkan oleh pemfaktoran itu; n_reps memotongnya, menukar ketepatan dengan litar yang lebih cetek.
>>> import ffsim
>>> import pyscf
>>> import pyscf.cc
>>>
>>> # build the molecule and run Hartree-Fock
>>> mol = pyscf.gto.Mole()
>>> mol.build(
... atom=[["H", (0, 0, 0)], ["H", (0, 0, 0.74)]],
... basis="6-31g",
... symmetry="Dooh",
... verbose=0,
... )
<pyscf.gto.mole.Mole object at ...>
>>> scf = pyscf.scf.RHF(mol).run()
>>>
>>> norb = scf.mo_coeff.shape[1]
>>> nelec = (mol.nelec[0], mol.nelec[1])
>>>
>>> # run CCSD for the t-amplitudes, then factorize them into an ansatz operator
>>> ccsd = pyscf.cc.CCSD(scf).run()
>>> t1, t2 = ccsd.t1, ccsd.t2
>>>
>>> ucj_op = ffsim.UCJOpSpinBalanced.from_t_amplitudes(t2, t1=t1, n_reps=2)
Di sinilah ansatz tidak lagi menjadi urusan ffsim. ffsim menawarkan pilihan di sini yang tidak dilihat atau perlu diketahui oleh pakej ini, seperti pemfaktoran (“termampat”) yang dioptimumkan secara variasi di sebalik optimize=True, atau pembungkusan vektor parameter yang dipacu oleh pengoptimum variasi. Kesemuanya menghasilkan jenis operator yang sama, dan segala yang berikut berfungsi tanpa perubahan pada mana-mana daripadanya.
2. Tukarkan operator menjadi litar fermionik
Gate UCJ membungkus operator dan menyatakannya sebagai litar ke atas mod fermionik. Gate ini ialah uniter tulen yang tidak membawa rujukan sendiri, jadi letakkan gate InitializeModes (dibina dengan from_hartree_fock()) di hadapan untuk membekalkan rujukan Hartree-Fock yang dikenakan ansatz.
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import InitializeModes, UCJ
>>>
>>> ansatz = UCJ(ucj_op)
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(InitializeModes.from_hartree_fock(norb, nelec), circuit.modes)
>>> circuit.append(ansatz, circuit.modes)
Menguraikan litar mendedahkan anatominya, dan ini ialah perwakilan yang diusahakan oleh seluruh baki panduan. Gate InitializeModes menyediakan penentu rujukan, dan setiap lapisan ansatz menyumbang OrbitalRotation , kemudian (sebuah Evolution bagi operator Coulomb pepenjuru ), kemudian , dengan OrbitalRotation akhir di penghujung. Putaran orbital bertindak bagi setiap sektor spin, jadi setiap satu diletakkan pada mod alfa 0..norb dan mod beta norb..2*norb secara bebas.
>>> circuit.decompose().draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

Setiap gate dalam penguraian itu masih fermionik: OrbitalRotation dan Evolution ditakrifkan pada mod, dan tiada operator qubit atau Pauli yang muncul lagi. Itulah yang membiarkan pengekodan terbuka, dan ia ialah keadaan yang kekal pada ansatz sehingga peringkat sintesis memilih satu.
Setiap lapisan berakhir dengan dan yang berikutnya bermula dengan , jadi gate OrbitalRotation bersebelahan boleh digabungkan menjadi satu putaran. Pas transpilasi yang melakukan pelakuran ini merupakan pembangunan masa depan yang dirancang.
3. Pilih pengekodan fermion-ke-qubit
Litar masih fermionik, dan itulah titik di mana pakej ini membuktikan tempatnya dalam aliran kerja. FermionicCircuit tidak membawa andaian tentang cara mod menjadi qubit, jadi pengekodan ialah pilihan peringkat sintesis dan bukan sesuatu yang terterap dalam ansatz. Itulah yang ditambah oleh pakej ini berbanding gate Qiskit ffsim sendiri, yang khusus untuk transformasi Jordan-Wigner.
Untuk Jordan-Wigner sahaja anda tidak memerlukan lencongan ini: ffsim menyertakan UCJOpSpinBalancedJW dan saudara-maranya, yang membawa operator UCJ ke litar qubit dengan sendirinya. Sebab untuk menyalurkan ansatz melalui litar fermionik ialah segala yang lain yang boleh diberikan oleh pengekodan. Pengekodan setempat, sebagai contoh, membelanjakan qubit tambahan untuk mengikat berat Pauli bagi setiap sebutan, yang digunakan oleh panduan set aliran 1D dan 2D untuk menjadikan kedalaman dua-qubit bagi satu langkah Trotter tidak bergantung pada saiz sistem.
Khusus untuk ansatz UCJ, peringkat sintesis perlu meliputi dua jenis gate:
-
Evolusi Coulomb pepenjuru.
Evolutionsudah pun tidak bergantung pada pengekodan:MapperFnEvolutionSynthesismengambil fungsi pemeta, jadi lapisan diturunkan melalui mana-mana pengekodan yang boleh anda ungkapkan sebagai satu. Panduan set aliran menunjukkan cara menulisnya. -
Putaran orbital dan penyediaan penentu Slater. Tidak
OrbitalRotationmahupunPrepareSlaterDeterminantyang digabungkan olehInitializeModesutama dan putaran (lihat di bawah) dipetakan ke qubit sebagaimana adanya. PasF2FSynthesisterlebih dahulu memecahkannya, dalam ruang fermionik, menjadi gateEvolutionpada satu atau dua mod setiap satu (dan, untuk penyediaan, sebuahInitializeModesbagi rujukan), jadi mana-mana pengekodan yang boleh memetakanEvolutiondapat mengendalikannya. Di bawah Jordan-Wigner, faktor antara mod bersebelahan menjadi objekXXPlusYYGatepada peringkat qubit. -
Pemulaan. Pemalam untuk
InitializeModestidak diparametrikan oleh pengekodan: ia mendokumenkan andaiannya tentang pengekodan asas penghunian dengan pemetaan mod-ke-qubit 1-ke-1, dan mengeluarkan gate terus pada asas itu. Pengekodan yang berbeza memerlukan pemalamnya sendiri, dan belum ada yang disertakan.
Cara mentranspilasikan litar UCJ di bawah pengekodan bukan Jordan-Wigner ialah persoalan penyelidikan terbuka dan pakej ini menyediakan rangka kerja untuk membangunkan saluran paip sedemikian. Baki panduan ini membina saluran paip transpiler untuk pengekodan Jordan-Wigner, setara dengan yang dihasilkan oleh generate_preset_jw_pass_manager(), sebagai contoh.
4. Turunkan melalui Jordan-Wigner
Penurunan berlaku dalam F2QSynthesis, yang berfungsi seperti HighLevelSynthesis Qiskit: ia melalui arahan fermionik dan menyerahkan setiap satu kepada pemalam yang didaftarkan untuk nama gate tersebut. Atribut F2QSynthesis.methods memegang satu F2QSynthesisPlugin bagi setiap nama gate, jadi membina peringkat ini bermaksud memilih pemalam untuk setiap gate fermionik yang terkandung dalam litar:
>>> from qiskit_fermions.mappers.library import jordan_wigner
>>> from qiskit_fermions.transpiler.passes import F2QSynthesis
>>> from qiskit_fermions.transpiler.passes.synthesis import (
... MapperFnEvolutionSynthesis,
... TrivialOccupationInitializeModesSynthesis,
... )
>>>
>>> synthesis = F2QSynthesis()
>>> synthesis.methods["Evolution"] = MapperFnEvolutionSynthesis(jordan_wigner)
>>> synthesis.methods["InitializeModes"] = TrivialOccupationInitializeModesSynthesis()
Menetapkan tika seperti ini juga merupakan cara pemalam yang anda tulis sendiri memasuki saluran paip, tanpa perlu mendaftarkannya di mana-mana terlebih dahulu.
Di sinilah pengekodan ditetapkan, dalam dua cara yang diterangkan dalam bahagian 3: secara eksplisit, dengan menyerahkan jordan_wigner() kepada MapperFnEvolutionSynthesis, dan secara tersirat, oleh pemalam lain yang sudah mengandaikannya.
Peringkat itu kemudian dimasukkan ke dalam MultiStagePassManager yang peringkatnya berjalan dalam urutan tetap:
>>> from qiskit.passmanager import MultiStagePassManager
>>> from qiskit.transpiler import generate_preset_pass_manager
>>> from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
>>>
>>> from qiskit_fermions.transpiler import (
... FermionicCircuitToDAG,
... FermionicPassManager,
... QuantumDAGToCircuit,
... )
>>> from qiskit_fermions.transpiler.passes import (
... F2FSynthesis,
... HopEvolutionSynthesis,
... MergeOrbitalRotations,
... MergeSlaterDeterminantPreparation,
... TrivialF2QLayout,
... )
>>>
>>> pm = MultiStagePassManager(
... input=FermionicCircuitToDAG(),
... optimization=FermionicPassManager(
... [
... MergeOrbitalRotations(),
... MergeSlaterDeterminantPreparation(),
... F2FSynthesis(
... {"OrbitalRotation": "Givens", "PrepareSlaterDeterminant": "Givens"}
... ),
... ]
... ),
... layout=FermionicPassManager(TrivialF2QLayout()),
... synthesis=synthesis,
... qubit=generate_preset_pass_manager(
... hls_config=HLSConfig(PauliEvolution=[HopEvolutionSynthesis(), "default"])
... ),
... output=QuantumDAGToCircuit(),
... )
Peringkat pengoptimuman berjalan sebelum sintesis, pada litar fermionik, yang menjadikannya bernilai: ia menulis semula gate semasa masih fermionik dan tidak bergantung pada pengekodan, jadi penjimatan dibawa kepada apa jua pengekodan yang menyusul. MergeOrbitalRotations meruntuhkan setiap rentetan gate OrbitalRotation berturutan menjadi satu, yang penting untuk ansatz UCJ kerana setiap lapisan berakhir dengan dan yang berikutnya bermula dengan . MergeSlaterDeterminantPreparation kemudian menggabungkan InitializeModes utama dan putaran yang mengikutinya menjadi satu PrepareSlaterDeterminant, yang diturunkan oleh sintesis melalui penguraian Slater terturun yang lebih murah dan bukannya putaran segi empat sama penuh. Urutan penting: menggabungkan putaran terlebih dahulu mendedahkan putaran tunggal sejurus selepas pemulaan, yang kemudian dikecutkan ke dalamnya oleh pelakuran Slater. F2FSynthesis datang terakhir, kerana ia memecahkan apa sahaja putaran yang tinggal, dan berbuat demikian lebih awal akan meninggalkan kedua-dua pas penggabungan tanpa apa-apa untuk digabungkan.
Peringkat yang tinggal ialah kerja paip. input dan output menukar antara litar dan DAG, layout menetapkan mod fermionik kepada qubit (TrivialF2QLayout memetakan mod i kepada qubit i), dan qubit ialah pass manager Qiskit biasa yang mengambil alih apabila tiada lagi yang fermionik.
Menjalankannya memerlukan satu langkah persediaan: gate komposit UCJ perlu diuraikan terlebih dahulu kepada gate primitifnya, supaya peringkat pengoptimuman dapat melihat putaran dan evolusi individu.
>>> transpiled = pm.run(circuit.decompose())
>>> print(dict(sorted(transpiled.count_ops().items())))
{'rz': 14, 'rzz': 12, 'x': 2, 'xx_plus_yy': 28}
Tanpa peranti sasaran, ini dipetakan ke 2 * norb qubit dengan kesambungan semua-ke-semua diandaikan; putaran orbital disintesis menjadi objek XXPlusYYGatedan evolusi Coulomb pepenjuru menjadi objek RZZGate:
>>> transpiled.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
Saluran paip ini tepat seperti yang dihimpunkan oleh generate_preset_jw_pass_manager(), jadi gunakan pratetap dalam amalan dan bina peringkat secara manual apabila anda perlu mengubah salah satu daripadanya:
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> preset = generate_preset_jw_pass_manager()
>>> preset.run(circuit.decompose()).count_ops() == transpiled.count_ops()
True
5. Padankan topologi peranti
Peranti sebenar mempunyai peta gandingan qubit yang terhad, dan ansatz LUCJ direka untuk memadankannya. Interaksi spin sama (pairs_aa) membentuk dua rantai linear dan interaksi alfa-beta (pairs_ab) menjambatani keduanya. generate_lucj_pass_manager() milik ffsim membina saluran paip qubit sedar-peranti untuk struktur ini, dan mengembalikan subset pairs_ab yang sebenarnya boleh ditampung oleh perkakasan. Masukkan saluran paip itu ke dalam peringkat qubit pratetap sambil mengekalkan sintesis fermion-ke-qubit pakej itu sendiri:
>>> from ffsim.qiskit import generate_lucj_pass_manager
>>> from qiskit.providers.fake_provider import GenericBackendV2
>>> from qiskit.transpiler import CouplingMap
>>>
>>> # a heavy-hex device coupling map (any BackendV2 works, e.g. a real fake_provider backend)
>>> coupling_map = CouplingMap.from_heavy_hex(5)
>>> backend = GenericBackendV2(
... num_qubits=coupling_map.size(),
... basis_gates=["cp", "xx_plus_yy", "p", "x", "swap"],
... coupling_map=coupling_map,
... )
>>>
>>> # nearest-neighbor same-spin chain; let the pass manager choose the alpha-beta pairs
>>> pairs_aa = [(p, p + 1) for p in range(norb - 1)]
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> hls_config = HLSConfig(PauliEvolution=[HopEvolutionSynthesis(), "default"])
>>> pm.qubit, allowed_pairs_ab = generate_lucj_pass_manager(
... backend,
... norb,
... "heavy-hex",
... (pairs_aa, None),
... optimization_level=3,
... seed_transpiler=0,
... hls_config=hls_config,
... )
>>>
>>> # the alpha-beta interactions the heavy-hex connectivity can implement
>>> print(allowed_pairs_ab)
[(0, 0)]
Gubahan itulah intinya: peringkat qubit sedar-peranti, manakala peringkat sintesis fermion-ke-qubit di hadapannya kekal milik pakej ini sendiri, dan oleh itu kekal boleh diganti. Menggantikan peringkat qubit memang menggugurkan apa yang didaftarkan oleh pratetap di sana, iaitu HopEvolutionSynthesis yang menukarkan faktor Givens bagi putaran orbital menjadi objek XXPlusYYGate. Salurkannya melalui hls_config seperti di atas, atau asas peranti perlu dicapai tanpanya.
Dengan pm.qubit kini ditetapkan kepada saluran paip sedar-peranti, menjalankan pass manager meletakkan litar pada qubit backend dan menghalakannya ke peta gandingan. Bagi ansatz tidak terhad daripada langkah 1, yang operator Coulomb pepenjurunya masih mengandungi sebutan alfa-beta yang tidak dapat dicapai secara langsung oleh perkakasan, penghala mesti menyisipkan banyak gate SWAP untuk menjambatani:
>>> naive = pm.run(circuit.decompose())
>>> naive.num_qubits # laid out on the full heavy-hex device register
57
>>> naive_swaps = naive.count_ops()["swap"]
>>> naive_swaps # many SWAPs to bridge the unreachable alpha-beta interactions
33
Hadkan ansatz kepada interaksi yang boleh dilaksanakan oleh perkakasan
Penyelesaiannya ialah menyuapkan allowed_pairs_ab kembali ke dalam pembinaan ansatz, melalui argumen interaction_pairs bagi from_t_amplitudes(), supaya operator Coulomb pepenjuru hanya mengandungi sebutan alfa-beta yang boleh dilaksanakan secara langsung oleh peta gandingan. Ansatz kemudian memadankan topologi peranti dan penghala hampir tidak perlu menyentuhnya:
>>> restricted = UCJ(
... ffsim.UCJOpSpinBalanced.from_t_amplitudes(
... t2, t1=t1, n_reps=2, interaction_pairs=(pairs_aa, allowed_pairs_ab)
... )
... )
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(InitializeModes.from_hartree_fock(norb, nelec), circuit.modes)
>>> circuit.append(restricted, circuit.modes)
>>>
>>> transpiled = pm.run(circuit.decompose())
>>> restricted_swaps = transpiled.count_ops()["swap"]
>>> restricted_swaps # far fewer routing SWAPs than the unrestricted ansatz
4
Melukis hanya qubit aktif (idle_wires=False) menunjukkan litar terhad kepada dua rantai spin dan jambatan alfa-beta, dinyatakan dalam gate asas peranti. Reka letak dan penghalaan menyerakkan mod logik merentasi qubit fizikal peranti, jadi hantarkan wire_order yang diambil daripada reka letak akhir litar (final_index_layout() menyenaraikan qubit fizikal tempat setiap qubit input berakhir, mengikut urutan qubit input) untuk melukis semula wayar dalam urutan mod asal:
>>> wire_order = transpiled.layout.final_index_layout(filter_ancillas=False)
>>> transpiled.draw("mpl", idle_wires=False, fold=-1, wire_order=wire_order)
<Figure size ... with 1 Axes>

Bilangan gate dan kedalaman tepat selepas reka letak bergantung pada pas penghalaan/pengoptimuman dan peranti yang dipilih, jadi ia tidak dihasilkan semula di sini. Perkara utamanya ialah reka bentuk bersama; menyatakan ansatz dengan rantai pairs_aa jiran terdekat dan jambatan pairs_ab yang ditapis mengikut perkakasan mengekalkan litar tersintesis dekat dengan topologi peranti, meminimumkan overhed penghalaan (gate SWAP yang disisipkan). Lihat FermionicSlaterGivensDecomposition untuk pilihan sintesis berkaitan (minimize_2q_gate_count), yang menukar bilangan gate dua-qubit dengan kedalaman terhalakan.
Langkah seterusnya
-
Ketahui cara gate individu berfungsi dalam dokumentasi
qiskit_fermions.circuit.librarydan panduan litar fermionik. -
Terokai panduan penerangan operator untuk memahami cara membina operator fermionik dan Hamiltonian secara langsung.
-
Lihat bagaimana litar fermionik dipetakan ke qubit dalam panduan transpilasi.
-
Baca dokumentasi
F2QSynthesisuntuk cara lain mengkonfigurasi peringkat sintesis: kamusconfigyang memilih pemalam mengikut nama pendek yang didaftarkan di bawah titik masukqiskit_fermions.transpiler.synthesismereka, dan bukannya mengikut tika. -
Baca panduan hubungan ffsim untuk memahami cara kedua-dua pakej membahagikan kerja, dan protokol mana yang membolehkan ffsim mensimulasikan litar pakej ini.
