Przejdź do głównej treści
Ten projekt jest w wersji beta. Znalazłeś błąd? Otwórz zgłoszenie na GitHub. Masz pytanie lub pomysł? Zapytaj w Discussions — chętnie poznamy Twoją opinię!
Jak oceniasz jakość tłumaczenia tej strony?

Skalowanie przepływów pracy chemii SQD za pomocą Fulqrum

Fulqrum to pakiet oprogramowania, który oblicza wartości własne i wektory własne hamiltonianów zrzutowanych na podprzestrzeń. Tworzy przenośną reprezentację zrzutowanego hamiltonianu, którą możesz przekazać do wybranego solwera wartości własnych, w tym do standardowych, gotowych solwerów. Solwery te mogą być znacznie szybszą alternatywą dla domyślnego solwera PySCF, którego dodatek SQD używa do diagonalizacji. Informacje o instalacji i użyciu Fulqrum znajdziesz w dokumentacji Fulqrum.

Moduł addon_sqd_support w Fulqrum buduje solwer, który diagonalize_fermionic_hamiltonian przyjmuje bezpośrednio, więc przekazujesz do obu te same całki, a Fulqrum zajmuje się projekcją i diagonalizacją.

Więcej szczegółów o kodzie SQD użytym w tym przykładzie znajdziesz w samouczku o hamiltonianie chemicznym.

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

_needed = {"fulqrum": "fulqrum", "numpy": "numpy", "primme": "primme", "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.cc
import pyscf.mcscf
from fulqrum.addon_sqd_support import sci_solver_from_integrals
from qiskit_addon_sqd.counts import generate_bit_array_uniform
from qiskit_addon_sqd.fermion import diagonalize_fermionic_hamiltonian

# 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
)

# Build a solver that diagonalizes with Fulqrum. It converts the integrals to a
# Fulqrum operator once, then projects onto each subspace the SQD loop requests.
sci_solver = sci_solver_from_integrals(hcore, eri, tol=1e-12)

# Run SQD
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,
sci_solver=sci_solver,
symmetrize_spin=True,
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
print(f"Exact energy: {exact_energy}")
print(f"Estimated energy: {result.energy + nuclear_repulsion_energy}")
Exact energy: -109.04667177808024
Estimated energy: -109.03402667559365

Użyj innego solwera wartości własnych​

Ponieważ Fulqrum udostępnia zrzutowany hamiltonian jako standardowy scipy.sparse.linalg.LinearOperator, możesz go zdiagonalizować dowolnym wybranym solwerem wartości własnych, zamiast być związanym z scipy.sparse.linalg.eigsh. Dzięki temu łatwo zastąpić go solwerem lepiej dopasowanym do rozmiaru problemu lub sprzętu.

Przekaż wybrany solwer wartości własnych jako argument eigensolver. Jako przykład ten przewodnik pokazuje PRIMME, wydajną bibliotekę solwerów wartości własnych. Jej interfejs Pythona, primme.eigsh, ma konwencję wywołania podobną do scipy.sparse.linalg.eigsh, więc możesz go użyć jako bezpośredniego zamiennika.

import primme

# Build a solver that diagonalizes with PRIMME instead of the default,
# scipy.sparse.linalg.eigsh
sci_solver = sci_solver_from_integrals(
hcore, eri, eigensolver=primme.eigsh, tol=1e-12
)

# Run SQD using the PRIMME-based 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,
max_iterations=5,
sci_solver=sci_solver,
symmetrize_spin=True,
seed=rng,
)
print(f"Exact energy: {exact_energy}")
print(f"Estimated energy: {result.energy + nuclear_repulsion_energy}")
Exact energy: -109.04667177808024
Estimated energy: -109.03937429196168