Superfermion logo
Guides

Chemistry

Molecular Hamiltonians, fermion-to-qubit mappings, UCCSD ansatz, and PySCF integration.

Superfermion's chemistry module handles molecular electronic structure: building Hamiltonians, mapping fermions to qubits, and constructing chemistry-inspired ansatze.

Quick Start

from superfermion.chemistry.hamiltonians import get_molecular_hamiltonian
from superfermion.chemistry.ansatz import uccsd_ansatz
import superfermion as sf

# Get a pre-built molecular Hamiltonian
H = get_molecular_hamiltonian("H2", basis="sto-3g")
print(f"H2 Hamiltonian: {len(H.terms)} terms")

# Build a UCCSD ansatz (minimal 2-qubit H2 ansatz)
ansatz = uccsd_ansatz(n_qubits=2, n_electrons=2)
print(f"Ansatz: {ansatz.n_parameters} parameter, {ansatz.gate_count} gates")

# Run VQE
from superfermion.algorithms.variational import VQE
vqe = VQE(ansatz, H)
result = vqe.minimize(iterations=100)
print(f"H2 ground state energy: {result.optimal_value:.6f} Hartree")

Molecular Hamiltonians

Pre-built Library

from superfermion.chemistry.hamiltonians import get_molecular_hamiltonian

# Built-in molecules (pre-computed at equilibrium geometry)
h2 = get_molecular_hamiltonian("H2", basis="sto-3g")
print(f"H2: {len(h2.terms)} terms")

# Additional molecules (LiH, H2O, ...) require PySCF — install with:
#   pip install "superfermion[chemistry]"

PySCF Bridge — Custom Molecules

For any molecule, use the PySCF bridge:

from superfermion.chemistry.pyscf_bridge import molecule_from_geometry

# Define any molecule via an XYZ geometry string
mol = molecule_from_geometry("H 0 0 0; H 0 0 0.7414", basis="sto-3g", name="H2")

# With PySCF installed this computes HF + integrals; otherwise it falls
# back to the pre-computed molecule library
summary = mol.summary()
print(f"{summary['name']}: {summary['n_electrons']} electrons, "
      f"{summary['n_orbitals']} orbitals, {summary['n_qubits']} qubits, "
      f"pyscf={'available' if summary['pyscf_available'] else 'library fallback'}")

# Build the qubit Hamiltonian
H = mol.to_hamiltonian(active_space=(2, 2))
print(f"Qubit Hamiltonian: {len(H.terms)} terms")

Fermion-to-Qubit Mappings

from superfermion.chemistry.hamiltonians import FermionicOperator
import numpy as np

# One-body integrals h1 (spin-orbital basis) — a two-site model
h1 = np.zeros((2, 2))
h1[0, 0] = -1.0
h1[1, 1] = -0.5
h1[0, 1] = h1[1, 0] = 0.2

fermion_op = FermionicOperator.from_coeffs(h1)

# Jordan-Wigner transform
jw_qubit_op = fermion_op.jordan_wigner(n_qubits=2)
print(f"Jordan-Wigner: {len(jw_qubit_op.terms)} terms")

# Bravyi-Kitaev transform
bk_qubit_op = fermion_op.bravyi_kitaev(n_qubits=2)
print(f"Bravyi-Kitaev: {len(bk_qubit_op.terms)} terms")
MappingQubit ScalingLocalityBest For
Jordan-WignerO(N)O(N) weightSmall molecules
Bravyi-KitaevO(N)O(log N) weightLarger molecules

UCCSD Ansatz

The Unitary Coupled Cluster Singles and Doubles ansatz is the standard choice for molecular VQE:

from superfermion.chemistry.ansatz import uccsd_ansatz

# Minimal 2-qubit H2 ansatz (single parameter, O'Malley et al. 2016)
h2_ansatz = uccsd_ansatz(n_qubits=2, n_electrons=2)
print(f"H2 ansatz: {h2_ansatz.n_parameters} parameter, {h2_ansatz.gate_count} gates")

# Hardware-efficient UCC-style ansatz for larger active spaces
uccsd = uccsd_ansatz(n_qubits=4, n_electrons=2)
print(f"4-qubit ansatz: {uccsd.n_parameters} parameters, {uccsd.gate_count} gates")

Full VQE Workflow

End-to-end VQE with a custom molecule:

from superfermion.chemistry.hamiltonians import get_molecular_hamiltonian
from superfermion.chemistry.ansatz import uccsd_ansatz
from superfermion.algorithms.variational import VQE
import numpy as np

# 1. Build molecular Hamiltonian (pre-computed H2 library entry)
H = get_molecular_hamiltonian("H2", basis="sto-3g")

# 2. Build ansatz
ansatz = uccsd_ansatz(2, 2)

# 3. Initial parameters (array, ordered as ansatz.parameters)
init_params = np.zeros(ansatz.n_parameters)

# 4. Run VQE
vqe = VQE(ansatz, H)
result = vqe.minimize(initial_params=init_params, iterations=200)
print(f"Ground state energy: {result.optimal_value:.8f} Hartree")
print(f"Optimal parameters: {result.optimal_params}")

Performance Notes

  • Hamiltonian construction — runs in Python using PySCF's integral engine
  • Expectation values — computed in Rust via sf.State.expectation()
  • Gradients — adjoint method in Rust, O(1) scaling regardless of parameter count
  • Recommendation — for molecules < 20 qubits, combine UCCSD + adjoint gradient for fastest convergence

On this page