Optimumkan penyediaan penentu Slater
Konsep dalam panduan ini kini hanya tersedia dalam API Python. Fungsi setara akan disediakan dalam API C dalam keluaran akan datang.
Gate InitializeModes mengisytiharkan penghunian mod rujukan; gate OrbitalRotation memutarkan asas zarah tunggal. Apabila diletakkan berturutan, kedua-dua gate menyediakan penentu Slater; mod bermula dalam penentu rujukan dan kemudian diputarkan ke orbital sasaran. Gate PrepareSlaterDeterminant menangkap gubahan itu, dan kerana ia membawa penghunian rujukan, transpilasinya boleh menggunakan givens_decomposition_slater() segi empat tepat, yang hanya merealisasikan orbital terhuni, dan bukannya penguraian segi empat sama penuh yang diperlukan oleh OrbitalRotation sahaja. Itu ialah sintesis yang jauh lebih murah (lihat pulangannya di akhir panduan ini).
Pas transpiler MergeSlaterDeterminantPreparation mengesan corak InitializeModes-kemudian-OrbitalRotation dalam FermionicCircuit dan menulisnya semula menjadi gate PrepareSlaterDeterminant, supaya peringkat sintesis kemudian mengambil penguraian terkurang secara automatik. Dalam simulasi, penulisan semula itu tidak mengubah keadaan: PrepareSlaterDeterminant ialah sahkan-kemudian-putar (ia mengesahkan penghunian rujukan dan kemudian menerapkan putaran, sama seperti kedua-dua gate berasingan), jadi gabungan itu membuka sintesis yang lebih murah tanpa mengubah keadaan yang disediakan.
Sepanjang panduan ini, setiap litar dilukis sebelum dan selepas pas, bersebelahan: input di sebelah kiri, dan hasil menjalankan pas padanya di sebelah kanan. Dua pembantu melakukannya. merge menjalankan pas pada salinan litar (melalui FermionicDAGCircuit nya) dan menukar hasilnya kembali kepada FermionicCircuit yang boleh dilukis, dan draw_merge melukis kedua-dua separuh ke dalam satu rajah sebelum/selepas:
>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import InitializeModes, OrbitalRotation
>>> from qiskit_fermions.transpiler import FermionicCircuitToDAG
>>> from qiskit_fermions.transpiler.converters import FermionicDAGToCircuit
>>> from qiskit_fermions.transpiler.passes import MergeSlaterDeterminantPreparation
>>>
>>> def merge(circuit):
... dag = FermionicCircuitToDAG().run(circuit)
... merged = MergeSlaterDeterminantPreparation().run(dag)
... return FermionicDAGToCircuit().run(merged)
>>>
>>> def natural_size(circuit):
... # the figure size Qiskit picks for a circuit on its own (discard the probe figure)
... probe = circuit.draw("mpl")
... size = probe.get_size_inches()
... plt.close(probe)
... return size
>>>
>>> def draw_merge(circuit):
... merged = merge(circuit)
... # let Qiskit size each half naturally, then lay them out side by side
... (bw, bh), (aw, ah) = natural_size(circuit), natural_size(merged)
... fig, (before, after) = plt.subplots(1, 2, figsize=(bw + aw, max(bh, ah)))
... circuit.draw("mpl", ax=before)
... merged.draw("mpl", ax=after)
... before.set_title("before")
... after.set_title("after")
... return fig
Apa yang digabungkan
Pas ini mengenali tiga corak, semuanya bergantung pada konvensyen mod spin blok yang digunakan oleh InitializeModes dan OrbitalRotation. Bagi sistem dengan norb orbital ruang, mod 0..norb ialah sektor spin-alfa, dan norb..2*norb ialah sektor spin-beta. Penyediaan penentu Slater dilakukan bagi setiap sektor spin kerana setiap sektor mempunyai bentuk (elektron, orbital) tersendiri.
Daftar penuh (atau tanpa spin)
Corak paling mudah ialah menggunakan InitializeModes, diikuti serta-merta oleh OrbitalRotation pada mod yang sama. Ini ialah kes tanpa spin (satu penentu ke atas semua mod) dan juga litar berspin yang putarannya merentangi kedua-dua sektor serentak. Kedua-dua gate bercantum menjadi satu PrepareSlaterDeterminant:
>>> circuit = FermionicCircuit(4)
>>> circuit.append(InitializeModes([1, 1, 0, 0]), circuit.modes)
>>> circuit.append(OrbitalRotation(np.eye(4)), circuit.modes)
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Bagi setiap sektor spin
Ini ialah bentuk yang sama, tetapi terhad kepada satu separuh spin. Di sini, dua pasangan inisialisasi-kemudian-putar yang bebas, satu bagi setiap sektor, masing-masing bercantum sendiri menjadi PrepareSlaterDeterminant:
>>> circuit = FermionicCircuit(6) # norb = 3: alpha modes 0..3, beta modes 3..6
>>> circuit.append(InitializeModes([1, 1, 0]), circuit.modes[:3])
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[:3])
>>> circuit.append(InitializeModes([1, 0, 0]), circuit.modes[3:])
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[3:])
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Inisialisasi global, putaran bagi setiap spin
Ini melibatkan satu InitializeModes daftar penuh (2 * norb) diikuti oleh dua tindakan OrbitalRotation, satu pada setiap separuh spin yang bersebelahan. Pas membahagikan penghunian global pada sempadan sektor dan menghasilkan dua gate PrepareSlaterDeterminant. Kedua-dua putaran mungkin muncul dalam mana-mana susunan.
Ini ialah bentuk yang dihasilkan oleh aliran kerja kluster Jastrow unitari setempat (LUCJ) (lihat panduan LUCJ); pengguna meletakkan InitializeModes (lazimnya rujukan Hartree-Fock dengan menggunakan from_hartree_fock()) di hadapan litar dan menambah ansatz UCJ, yang dua putaran orbital per-spin pertamanya terus mengikuti inisialisasi sebaik sahaja ansatz diuraikan.
>>> circuit = FermionicCircuit(6) # norb = 3, nelec = (2, 1)
>>> circuit.append(InitializeModes.from_hartree_fock(3, (2, 1)), circuit.modes)
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[:3])
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[3:])
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Corak ini juga berlaku apabila hanya satu separuh spin diputarkan oleh gate yang terus mengikuti inisialisasi, iaitu bentuk yang dihasilkan apabila putaran orbital satu sektor spin sahaja kebetulan berada di hadapan litar. Separuh yang diputarkan menjadi PrepareSlaterDeterminant dengan putarannya, dan separuh lagi disediakan dengan putaran identiti. Penyediaan identiti disintesis kepada gate X rujukan yang akan dikeluarkan oleh InitializeModes untuk separuh itu juga, jadi mengisinya tidak menelan gate tambahan sambil tetap membuka sintesis Slater terkurang pada separuh yang diputarkan:
>>> circuit = FermionicCircuit(6)
>>> circuit.append(InitializeModes.from_hartree_fock(3, (2, 1)), circuit.modes)
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[:3])
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Apa yang dibiarkan tidak disentuh
Pas ini sengaja berhati-hati. Ia hanya menggabungkan apabila kedua-dua gate benar-benar tergubah menjadi penyediaan penentu Slater, dan menyalin segala yang lain tanpa perubahan. “Diikuti serta-merta” difahami ke atas graf aliran data litar. OrbitalRotation hanya bercantum apabila InitializeModes ialah pendahulunya yang tunggal merentasi semua modnya. Dalam rajah di bawah, sebelum dan selepas adalah serupa: tiada apa yang bercantum.
Operasi di antaranya
Jika sebarang gate menyentuh mod di antara inisialisasi dan putaran, kedua-duanya tidak lagi tergubah menjadi penyediaan yang ringkas, jadi tiada apa yang digabungkan:
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> circuit = FermionicCircuit(4)
>>> circuit.append(InitializeModes([1, 1, 0, 0]), circuit.modes)
>>> number_op = FermionOperator.from_dict({(cre(0), ann(0)): 1.0})
>>> circuit.append(Evolution(4, number_op, time=0.5), circuit.modes)
>>> circuit.append(OrbitalRotation(np.eye(4)), circuit.modes)
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Putaran separa yang bukan separuh spin
Putaran yang meliputi tepat satu separuh spin bersebelahan bagi inisialisasi daftar penuh memang bercantum (lihat bahagian sebelumnya). Tetapi putaran pada set mod separa lain (lebih sedikit mod daripada inisialisasi dan bukan salah satu daripada dua separuh spinnya, seperti sub-julat yang melintasi sempadan sektor) bukan penyediaan bagi setiap sektor. Menggabungkannya akan secara senyap menggugurkan peranan inisialisasi pada mod yang ditinggalkannya, jadi pas membiarkan kedua-dua gate di tempatnya:
>>> circuit = FermionicCircuit(4) # norb = 2: the only spin halves are modes [0, 1] and [2, 3]
>>> circuit.append(InitializeModes([1, 1, 0, 0]), circuit.modes)
>>> circuit.append(OrbitalRotation(np.eye(3)), circuit.modes[:3])
>>> draw_merge(circuit)
<Figure size ... with 2 Axes>
Mengapa ia penting: pulangan sintesis
Gabungan itu berbaloi kerana PrepareSlaterDeterminant disintesis kepada jauh lebih sedikit gate daripada OrbitalRotation yang diserapnya. Penentu -elektron ke atas orbital memerlukan paling banyak putaran dua-qubit dan tiada gate fasa pepenjuru, berbanding putaran ditambah fasa bagi putaran orbital segi empat sama penuh.
Pengurus pas Jordan-Wigner pratetap menjalankan MergeSlaterDeterminantPreparation dalam peringkat pengoptimumannya, jadi pengurangan ini berlaku secara automatik. Transpilkan penyediaan dua-elektron, enam-orbital sehingga ke QuantumCircuit dan kira gate-nya:
Pratetap menjalankan MergeOrbitalRotations sebelum MergeSlaterDeterminantPreparation serta-merta. Ini penting apabila satu larian gate OrbitalRotation berturutan mengikuti inisialisasi. Pas terdahulu mula-mula meruntuhkan larian itu menjadi satu putaran, yang kemudian dikontrak oleh MergeSlaterDeterminantPreparation dengan inisialisasi menjadi satu PrepareSlaterDeterminant. Tanpa susunan itu, hanya putaran pertama dalam larian akan diserap dan selebihnya akan disintesis dengan penguraian segi empat sama penuh.
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> # a reproducible random 6 x 6 orbital rotation
>>> rng = np.random.default_rng(1)
>>> z = rng.standard_normal((6, 6)) + 1j * rng.standard_normal((6, 6))
>>> q, r = np.linalg.qr(z)
>>> rotation = q * (np.diagonal(r) / np.abs(np.diagonal(r)))
>>>
>>> circuit = FermionicCircuit(6)
>>> circuit.append(InitializeModes([1, 1, 0, 0, 0, 0]), circuit.modes)
>>> circuit.append(OrbitalRotation(rotation), circuit.modes)
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> prepared = pm.run(circuit)
>>> print(dict(sorted(prepared.count_ops().items())))
{'x': 2, 'xx_plus_yy': 8}
>>> prepared.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
Bandingkan itu dengan mensintesis putaran orbital yang sama secara bersendirian. Tanpa inisialisasi terdahulu, tiada apa untuk digabungkan, jadi pratetap kembali kepada penguraian segi empat sama penuh, yang lebih dalam dan membawa gate fasa pepenjuru:
>>> reference = FermionicCircuit(6)
>>> reference.append(OrbitalRotation(rotation), reference.modes)
>>> reference_prepared = pm.run(reference)
>>> print(dict(sorted(reference_prepared.count_ops().items())))
{'rz': 6, 'xx_plus_yy': 15}
>>> reference_prepared.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

Penguraian terkurang menggugurkan kesemua enam gate fasa dan hampir separuhkan bilangan putaran dua-qubit. Penentu yang disediakan adalah betul sehingga fasa global (tidak relevan secara fizikal untuk penyediaan keadaan), iaitu perkara yang akan dibetulkan oleh gate fasa.
Dua cara untuk menguraikan gate
PrepareSlaterDeterminant boleh diuraikan dalam dua cara berbeza, dan kedua-duanya tidak boleh ditukar ganti:
decompose()
Mengembangkan gate kepada takrifannya: InitializeModes bagi rujukan diikuti oleh OrbitalRotation penuh. Ini setara dengan gate sebagai operator, untuk sebarang keadaan input.
PrepareSlaterDeterminant.synthesis, diterapkan oleh F2FSynthesis
Menggantikan gate dengan penguraian terkurang dalam panduan ini. Ini setara dengan gate hanya sebagai penyediaan keadaan: ia menghasilkan penentu yang sama, sehingga fasa global, apabila mod bermula dalam vakum. Ia lebih murah tepat kerana ia menganggap perkara itu.
Gunakan sintesis apabila gate menyediakan keadaan pada vakum, iaitu tujuan gate itu dan apa yang transpiler lakukan untuk anda. Gunakan decompose() apabila gate perlu terus bertindak sebagai operator, contohnya kerana gate lain mendahuluinya pada mod yang sama, atau apabila anda ingin memeriksa atau mensimulasikan gate biasa. Pas F2FSynthesis tidak dapat mengetahui kes mana yang sedang dilihatnya, jadi litar yang anda berikan yang bertanggungjawab menyediakan penentu daripada vakum.
Mensimulasikan litar dengan ffsim tidak memerlukan kedua-duanya: setiap gate menerapkan seluruh unitarinya, jadi litar yang mengandungi PrepareSlaterDeterminant disimulasikan seadanya, dan kekal pada laluan pantas untuk gate OrbitalRotation di sekelilingnya. Menguraikan gate Slater sahaja dengan circuit.decompose("PrepareSlaterDeterminant") juga membiarkan putaran tersebut utuh.
PrepareSlaterDeterminant, InitializeModes, OrbitalRotation, MergeOrbitalRotations, F2FSynthesis, FermionicSlaterGivensDecomposition, dan panduan LUCJ untuk aliran kerja yang menghasilkan corak inisialisasi global.
