Skalakan aliran kerja kimia SQD dengan Fulqrum
Fulqrum ialah pakej perisian yang mengira nilai eigen dan vektor eigen bagi Hamiltonian yang diunjurkan ke dalam subruang. Ia membina perwakilan mudah alih bagi Hamiltonian yang diunjurkan yang boleh anda hantar kepada penyelesai nilai eigen pilihan anda, termasuk penyelesai piawai yang sedia ada. Penyelesai ini boleh menyediakan alternatif yang jauh lebih pantas berbanding penyelesai PySCF lalai yang digunakan oleh addon SQD untuk pepenjuruan. Untuk maklumat tentang cara memasang dan menggunakan Fulqrum, lihat dokumentasi Fulqrum.
Modul addon_sqd_support milik Fulqrum membina penyelesai yang diterima terus oleh diagonalize_fermionic_hamiltonian, jadi anda menghantar kamiran yang sama kepada kedua-duanya dan Fulqrum mengendalikan unjuran serta pepenjuruan.
Untuk butiran lanjut tentang kod SQD yang digunakan dalam contoh ini, lihat tutorial Hamilton kimia.
# 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
Gunakan penyelesai eigen yang berbeza
Oleh sebab Fulqrum mendedahkan Hamiltonian yang diunjurkan sebagai scipy.sparse.linalg.LinearOperator piawai, anda boleh mempepenjurukannya dengan sebarang penyelesai eigen pilihan anda dan bukannya terikat kepada scipy.sparse.linalg.eigsh. Ini memudahkan penggantian penyelesai yang lebih sesuai dengan saiz masalah atau perkakasan anda.
Hantar penyelesai eigen yang anda mahu sebagai argumen eigensolver. Sebagai contoh, panduan ini menunjukkan PRIMME, pustaka penyelesai eigen berprestasi tinggi. Antara muka Pythonnya, primme.eigsh, mengikut konvensyen panggilan yang serupa dengan scipy.sparse.linalg.eigsh, jadi anda boleh menggunakannya sebagai pengganti langsung.
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