Lewati ke konten utama
Proyek ini masih dalam tahap beta. Menemukan bug? Buat isu GitHub. Punya pertanyaan atau ide? Tanya di Discussions — kami sangat menghargai masukan kamu!
Bagaimana kualitas terjemahan di halaman ini?

Manfaatkan trim SQD untuk pemilihan konfigurasi yang lebih baik

Perilaku default diagonalize_fermionic_hamiltonian adalah mendiagonalisasi setiap batch hasil subsampling dan menyimpan hasil terbaik. Trim SQD sebaliknya memperlakukan batch sebagai kandidat yang disaring: masing-masing didiagonalisasi, di-trim hingga tersisa konfigurasi dengan bobot terbesar, lalu sisa dari semua batch digabung dan didiagonalisasi bersama. Diagonalisasi gabungan itulah yang energinya dilaporkan oleh iterasi, dan output hasil trim-nya menjadi benih untuk iterasi berikutnya.

Implementasi trim SQD didasarkan pada riset bersama dari Cleveland Clinic Foundation, RIKEN, dan IBM®. Jika kamu memakai fitur ini dalam riset kamu, kutip juga makalahnya. Kutipannya ada di berkas CITATION.bib, dengan citation key merz2026crossing.

Untuk detail lebih lanjut tentang kode SQD yang dipakai di contoh ini, lihat tutorial Hamiltonian kimia.

Siapkan molekulnya​

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "pyscf": "pyscf", "qiskit_addon_sqd": "qiskit-addon-sqd"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
import pyscf
import pyscf.mcscf
from qiskit_addon_sqd.counts import generate_bit_array_uniform
from qiskit_addon_sqd.fermion import diagonalize_fermionic_hamiltonian
from qiskit_addon_sqd.trim import TrimPolicy

# Build N2 molecule
mol = pyscf.gto.Mole()
mol.build(
atom=[["N", (0, 0, 0)], ["N", (1.0, 0, 0)]],
basis="6-31g",
symmetry="Dooh",
)

# Define active space
n_frozen = 2
active_space = range(n_frozen, mol.nao_nr())

# Get molecular integrals
scf = pyscf.scf.RHF(mol).run()
num_orbitals = len(active_space)
n_electrons = int(sum(scf.mo_occ[active_space]))
num_elec_a = (n_electrons + mol.spin) // 2
num_elec_b = (n_electrons - mol.spin) // 2
cas = pyscf.mcscf.CASCI(scf, num_orbitals, (num_elec_a, num_elec_b))
mo = cas.sort_mo(active_space, base=0)
hcore, nuclear_repulsion_energy = cas.get_h1cas(mo)
eri = pyscf.ao2mo.restore(1, cas.get_h2cas(mo), num_orbitals)

# Compute exact energy
exact_energy = cas.run().e_tot

# Create a seed to control randomness throughout this workflow
rng = np.random.default_rng(24)

# Generate random samples
bit_array = generate_bit_array_uniform(
10_000, num_orbitals * 2, rand_seed=rng
)
WARN: Unable to to identify input symmetry using original axes.
Different symmetry axes will be used.

converged SCF energy = -108.835236570774
CASCI E = -109.046671778080 E(CI) = -32.8155692383188 S^2 = 0.0000000

Jalankan loop-nya​

Satu iterasi trim SQD melakukan hal berikut:

  1. Putaran penyaringan. Bagi bitstring menjadi batch. Diagonalisasi setiap batch dan simpan sebagian trim_ratio dari string CI-nya, per sektor spin, berdasarkan peringkat bobot.

  2. Putaran gabungan. Diagonalisasi sisa gabungan itu sekali. Ini adalah hasil yang dilaporkan iterasi, dan string hasil trim-nya menjadi benih untuk iterasi berikutnya.

sci_solver milik loop menjalankan kedua putaran, dan secara default memakai solver PySCF dari paket ini.

Aktifkan trim SQD dengan memberikan TrimPolicy seperti berikut:

result = diagonalize_fermionic_hamiltonian(
hcore,
eri,
bit_array,
samples_per_batch=300,
norb=num_orbitals,
nelec=(num_elec_a, num_elec_b),
num_batches=5,
max_iterations=5,
policy=TrimPolicy(trim_ratio=0.5, max_strings_per_trim=250),
symmetrize_spin=True,
max_dim=250,
seed=rng,
)
sci_state = result.sci_state
print(
f"Merged subspace: {len(sci_state.ci_strs_a)} x {len(sci_state.ci_strs_b)} CI strings"
)
print(f"Exact energy: {exact_energy}")
print(f"Estimated energy: {result.energy + nuclear_repulsion_energy}")
Merged subspace: 148 x 148 CI strings
Exact energy: -109.04667177808024
Estimated energy: -109.034369147063

Periksa apakah penyaringan membantu​

Penyaringan paling bermanfaat saat konfigurasi yang disampel jauh lebih banyak daripada yang bisa didiagonalisasi sekaligus, sehingga meranking kumpulan yang lebih besar benar-benar menemukan konfigurasi yang akan terlewat oleh satu batch. Manfaatnya paling kecil saat subruang dengan ukuran yang terjangkau sudah menangkap sebagian besar fungsi gelombang.

Penyaringan bergantung pada batch yang berbeda satu sama lain. TrimPolicy mengelola ini dengan mengubah perilaku diagonalize_fermionic_hamiltonian agar menarik satu kumpulan berisi samples_per_batch * num_batches bitstring dan membaginya ke antar batch, sehingga tidak ada bitstring yang muncul di lebih dari satu batch.

Batasi subruangnya​

Subruang di sini direntang oleh hasil kali Kartesius dari array string CI spin-alpha dan spin-beta.

Trimming meranking konfigurasi, tetapi yang dibawa ke iterasi berikutnya adalah dua daftar string per spin. Mempertahankan 150 konfigurasi berbobot tertinggi dari sebuah subruang biasanya melibatkan sekitar 150 string alpha yang berbeda dan 150 string beta yang berbeda, yang hasil kalinya merentang sekitar 22.500 konfigurasi, bukan 150. Jadi subruang yang diteruskan ke iterasi berikutnya umumnya jauh lebih besar daripada himpunan yang diranking, dan tumbuh secara kuadratik terhadap jumlah yang kamu pertahankan.

Trimming dan carryover dibatasi secara terpisah, karena keduanya terjadi di titik yang berbeda: trimming mengecilkan setiap batch pada putaran penyaringan, sedangkan carryover adalah yang berpindah ke iterasi berikutnya.

Ada empat argumen yang membatasinya, dan sebaiknya atur setidaknya satu:

  • trim_ratio adalah fraksi string setiap batch, per sektor spin, yang lolos penyaringan. Nilai yang lebih rendah mengecilkan subruang gabungan tetapi membuang konfigurasi yang harus ditemukan ulang lewat sampling oleh iterasi berikutnya.

  • max_strings_per_trim membatasi jumlah string yang disumbangkan setiap batch, per sektor, apa pun rasionya. Berguna bersama symmetrize_spin, yang menggabungkan kedua sektor spin ke dalam satu daftar sehingga kira-kira menggandakan apa yang ditawarkan setiap batch. Batas ini berlaku per batch: subruang gabungan bisa memuat hingga num_batches kali lipat string, dikurangi apa pun yang sama antar batch, yang dalam praktiknya tidak banyak.

  • carryover_threshold, carryover_ratio, dan max_carryover membatasi string yang menjadi benih iterasi berikutnya, diterapkan ke subruang gabungan secara keseluruhan, bukan per batch. carryover_threshold adalah batas amplitudo yang dipakai StandardPolicy, dengan nilai default yang sama; dua lainnya membatasi jumlahnya, yang tidak bisa dicapai oleh batas amplitudo saja.

  • max_dim, pada diagonalize_fermionic_hamiltonian itu sendiri, membatasi setiap sektor spin dari setiap subruang yang didiagonalisasi loop, termasuk yang gabungan. Ini bertindak sebagai pengaman cadangan dan berlaku untuk apa pun yang dikembalikan policy, setelah carryover digabung dengan sampel baru.

Run di atas menetapkan max_strings_per_trim=250 dan max_dim=250 sekaligus, sehingga baik kontribusi setiap batch maupun subruang yang dibangun darinya tidak bisa membengkak tak terkendali.

Pakai eigensolver eksternal​

Kamu bisa memakai trim SQD dengan eigensolver eksternal dengan memberikan argumen sci_solver:

from sbd.sbd_solver import create_sbd_solver

result = diagonalize_fermionic_hamiltonian(
hcore,
eri,
bit_array,
samples_per_batch=300,
norb=num_orbitals,
nelec=(num_elec_a, num_elec_b),
num_batches=5,
policy=TrimPolicy(trim_ratio=0.1),
sci_solver=create_sbd_solver(sbd_config={"method": 0, "eps": 1e-10}),
seed=rng,
)

Snippet sebelumnya mengharuskan paket sbd-eigensolver terpasang dari PyPI.

Distribusikan pekerjaannya​

Dengan TrimPolicy, loop memanggil sci_solver dua kali per iterasi: sekali dengan semua batch, dan sekali dengan subruang gabungan. Kedua panggilan lewat antarmuka sci_solver biasa, yang dipanggil secara kolektif di setiap rank MPI oleh dukungan multi-proses paket ini.

Ada dua tingkat paralelisme yang mungkin tersedia, dan keduanya independen:

  • Dalam satu diagonalisasi. Solver seperti SBD bisa menyebar satu diagonalisasi ke beberapa rank.

  • Antar batch. Sebuah solver, pada prinsipnya, bisa mendiagonalisasi batch secara bersamaan.

Diberi sekumpulan batch, solver menentukan cara mendelegasikan pekerjaan ke proses worker-nya.