ขยายเวิร์กโฟลว์เคมี SQD ด้วย Fulqrum
Fulqrum เป็นแพ็กเกจซอฟต์แวร์ที่คำนวณค่าไอเจนและเวกเตอร์ไอเจนของ Hamiltonian ที่โปรเจกต์ลงในซับสเปซ มันสร้างการแทนค่าแบบพกพาของ Hamiltonian ที่โปรเจกต์แล้ว ซึ่งคุณส่งให้ตัวแก้ไอเจนที่คุณเลือกได้ รวมถึงตัวแก้สำเร็จรูปมาตรฐาน ตัวแก้เหล่านี้เป็นทางเลือกที่เร็วกว่ามากเมื่อเทียบกับตัวแก้ PySCF เริ่มต้นที่แอดออน SQD ใช้ทำ diagonalization สำหรับข้อมูลเกี่ยวกับวิธีติดตั้งและใช้ Fulqrum ดูเอกสาร Fulqrum
โมดูล addon_sqd_support ของ Fulqrum สร้างตัวแก้ที่ diagonalize_fermionic_hamiltonian รับได้โดยตรง ดังนั้นคุณส่งอินทิกรัลชุดเดียวกันให้ทั้งสองฝั่ง แล้ว Fulqrum จัดการการโปรเจกต์และ diagonalization ให้
สำหรับรายละเอียดเพิ่มเติมของโค้ด SQD ที่ใช้ในตัวอย่างนี้ ดูบทแนะนำ Hamilton ทางเคมี
# 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
ใช้ eigensolver ตัวอื่น
เนื่องจาก Fulqrum เปิดเผย Hamiltonian ที่โปรเจกต์แล้วเป็น scipy.sparse.linalg.LinearOperator มาตรฐาน คุณจึงทำ diagonalization ด้วย eigensolver ใดก็ได้ที่คุณเลือก แทนที่จะผูกติดกับ scipy.sparse.linalg.eigsh ทำให้สลับไปใช้ตัวแก้ที่เหมาะกับขนาดปัญหาหรือฮาร์ดแวร์ของคุณมากกว่าได้อย่างตรงไปตรงมา
ส่ง eigensolver ที่คุณต้องการเป็นอาร์กิวเมนต์ eigensolver ตัวอย่างเช่น คู่มือนี้สาธิต PRIMME ไลบรารี eigensolver ประสิทธิภาพสูง อินเทอร์เฟซ Python ของมัน primme.eigsh ใช้รูปแบบการเรียกคล้ายกับ scipy.sparse.linalg.eigsh ดังนั้นคุณใช้แทนกันได้โดยตรง
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