Lumaktaw sa pangunahing nilalaman
Ang proyektong ito ay nasa beta. Nakakita ng bug? Mag-bukas ng GitHub issue. May tanong o ideya? Magtanong sa Discussions — gusto naming marinig ang iyong feedback!
Gaano kaganda ang kalidad ng pagsasalin sa pahinang ito?

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:

  1. Screening round. Hatiin ang mga bitstring sa mga batch. I-diagonalize ang bawat batch at panatilihin ang fraction na trim_ratio ng mga CI string nito, bawat spin sector, na niraranggo ayon sa weight.

  2. 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_ratio ay 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_trim ang mga string na naiaambag ng bawat batch, bawat sector, anuman ang ratio. Kapaki-pakinabang ito kasama ang symmetrize_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 hanggang num_batches beses na mas maraming string, bawas ang anumang pinagsaluhan ng mga batch, na sa praktika ay hindi gaanong marami.

  • Nililimitahan ng carryover_threshold, carryover_ratio, at max_carryover ang mga string na nagiging binhi ng susunod na iteration, na inilalapat sa pinagsamang subspace sa kabuuan sa halip na bawat batch. Ang carryover_threshold ay ang amplitude cutoff na ginagamit ng StandardPolicy, na may parehong default; ang dalawa pa ay naglilimita sa bilang, na hindi nagagawa ng cutoff lang.

  • Nililimitahan ng max_dim, sa mismong diagonalize_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.