Gamitin ang trim SQD para sa mas pinahusay na pagpili ng configuration
Ang default na gawi ng diagonalize_fermionic_hamiltonian ay i-diagonalize ang bawat na-subsample na batch at panatilihin ang pinakamahusay na resulta. Sa halip, tinatrato ng Trim SQD ang mga batch bilang mga kandidatong sasalain: bawat isa ay dinadiagonalize, tinatrim hanggang sa mga configuration na may pinakamalaking weight, at ang mga nakaligtas mula sa lahat ng batch ay pinagsasama at dinadiagonalize nang sama-sama. Ang pinagsamang diagonalization na iyon ang may energy na iuulat ng iteration, at ang sarili nitong trimmed na output ang nagiging binhi ng susunod na iteration.
Ang trim SQD na implementasyon ay batay sa magkasanib na pananaliksik mula sa
Cleveland Clinic Foundation, RIKEN, at IBM®. Kung gagamitin mo ang feature na ito sa
iyong pananaliksik, banggitin din ang papel. Makikita mo ang citation sa
file na CITATION.bib, na may citation key na merz2026crossing.
Para sa higit pang detalye tungkol sa SQD code na ginamit sa halimbawang ito, tingnan ang tutorial ng chemistry Hamiltonian.
I-set up ang molecule
# 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
Patakbuhin ang loop
Ganito ang ginagawa ng isang trim SQD iteration:
-
Screening round. Hatiin ang mga bitstring sa mga batch. I-diagonalize ang bawat batch at panatilihin ang fraction na
trim_rationg mga CI string nito, bawat spin sector, na niraranggo ayon sa weight. -
Merged round. I-diagonalize nang isang beses ang pinagsamang mga nakaligtas. Ito ang resultang iuulat ng iteration, at ang sarili nitong trimmed na mga string ang nagiging binhi ng susunod na iteration.
Ang sci_solver ng loop ang gumagawa ng parehong round, at ang default nito ay ang PySCF solver ng package na ito.
I-enable ang trim SQD sa pamamagitan ng pagpasa ng TrimPolicy tulad ng sumusunod:
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
Tingnan kung nakakatulong ang screening
Pinakamalaki ang naitutulong ng screening kapag mas marami nang malaki ang mga na-sample na configuration kaysa sa kayang i-diagonalize nang sabay-sabay, kaya ang pagraranggo sa mas malaking pool ay talagang nakakahanap ng mga configuration na hindi mapapansin ng isang batch lang. Pinakamaliit naman ang naitutulong nito kapag ang subspace na may abot-kayang laki ay nakukuha na ang karamihan ng wavefunction.
Nakadepende ang screening sa pagkakaiba ng mga batch sa isa't isa. Pinamamahalaan ito ng TrimPolicy sa pamamagitan ng pagbabago sa gawi ng diagonalize_fermionic_hamiltonian para kumuha ng isang pool ng samples_per_batch * num_batches na mga bitstring at hatiin ito sa mga batch, kaya walang bitstring na lumalabas sa higit sa isang batch.
Limitahan ang subspace
Ang isang subspace dito ay binubuo ng Cartesian product ng isang spin-alpha at isang spin-beta na CI string array.
Niraranggo ng trimming ang mga configuration, pero ang carryover ay dalawang listahan ng string bawat spin. Ang pagpapanatili sa 150 configuration na may pinakamataas na weight ng isang subspace ay karaniwang nangangailangan ng malapit sa 150 natatanging alpha string at 150 natatanging beta string, na ang product ay sumasaklaw sa humigit-kumulang 22,500 configuration, hindi 150. Kaya ang subspace na ipinapasa sa susunod na iteration ay karaniwang mas malaki nang husto kaysa sa set na niraranggo, at lumalaki ito nang quadratic sa dami ng pinapanatili mo.
Magkahiwalay ang limitasyon ng trimming at carryover, dahil nangyayari ang mga ito sa magkaibang punto: pinaliliit ng trimming ang bawat batch ng screening round, habang ang carryover ang tumatawid papunta sa susunod na iteration.
Apat na argument ang naglilimita rito, at kapaki-pakinabang na mag-set ng kahit isa:
-
Ang
trim_ratioay ang fraction ng mga string ng bawat batch, bawat spin sector, na nakakaligtas sa screening. Pinaliliit ng mas mababang value ang pinagsamang subspace pero itinatapon nito ang mga configuration na kailangang matuklasang muli ng susunod na iteration sa pamamagitan ng sampling. -
Nililimitahan ng
max_strings_per_trimang mga string na naiaambag ng bawat batch, bawat sector, anuman ang ratio. Kapaki-pakinabang ito kasama angsymmetrize_spin, na pinagsasama ang parehong spin sector sa isang listahan kaya halos nadodoble ang iniaalok ng bawat batch. Ang limitasyong ito ay bawat batch: ang pinagsamang subspace ay maaaring maglaman ng hanggangnum_batchesbeses na mas maraming string, bawas ang anumang pinagsaluhan ng mga batch, na sa praktika ay hindi gaanong marami. -
Nililimitahan ng
carryover_threshold,carryover_ratio, atmax_carryoverang mga string na nagiging binhi ng susunod na iteration, na inilalapat sa pinagsamang subspace sa kabuuan sa halip na bawat batch. Angcarryover_thresholday ang amplitude cutoff na ginagamit ngStandardPolicy, na may parehong default; ang dalawa pa ay naglilimita sa bilang, na hindi nagagawa ng cutoff lang. -
Nililimitahan ng
max_dim, sa mismongdiagonalize_fermionic_hamiltonian, ang bawat spin sector ng bawat subspace na dinadiagonalize ng loop, kasama ang pinagsama. Gumaganap itong backstop at inilalapat sa anumang ibinabalik ng policy, pagkatapos pagsamahin ang carryover sa mga bagong sample.
Itinatakda ng run sa itaas ang max_strings_per_trim=250 at max_dim=250 nang magkasama, kaya hindi lalampas sa hangganan ang naiaambag ng bawat batch ni ang subspace na binuo mula rito.
Gumamit ng external na eigensolver
Magagamit mo ang trim SQD kasama ang isang external na eigensolver sa pamamagitan ng pagpasa ng argument na 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,
)
Kailangang naka-install mula sa PyPI ang package na sbd-eigensolver para sa naunang snippet.
Ipamahagi ang gawain
Sa TrimPolicy, dalawang beses tinatawag ng loop ang sci_solver bawat iteration: minsan kasama ang lahat ng batch, at minsan kasama ang pinagsamang subspace. Parehong dumadaan ang dalawang tawag sa karaniwang interface ng sci_solver, na kolektibong tinatawag ng multi-process support ng package na ito sa bawat MPI rank.
Dalawang antas ng parallelism ang posibleng magamit, at hiwalay ang mga ito sa isa't isa:
-
Sa loob ng isang diagonalization. Ang isang solver tulad ng SBD ay maaaring ipamahagi ang isang diagonalization sa mga rank.
-
Sa iba't ibang batch. Ang isang solver ay maaari, sa prinsipyo, na i-diagonalize nang sabay-sabay ang mga batch.
Kapag may set ng mga batch, ang solver ang magpapasya kung paano ipapasa ang gawain sa mga worker process nito.