Skip to content

chemistry

eigenkit.chemistry

Quantum chemistry with the core of the library.

Build a fermionic Hamiltonian (FermionOperator), map it to a qubit Observable (jordan_wigner), and find its ground-state energy with the Variational Quantum Eigensolver (VQE), which uses the variational optimisation tools of the core. The package uses only NumPy and SciPy, needs no PyTorch, and works with any backend. For small systems, exact_ground_state_energy gives the classical reference value.

Example
from eigenkit.chemistry import (
    fermi_hubbard_dimer, jordan_wigner, VQE, exact_ground_state_energy,
)

hamiltonian, offset = jordan_wigner(fermi_hubbard_dimer(t=1.0, u=2.0))
result = VQE(layers=3, restarts=5).solve(hamiltonian, n_qubits=4, offset=offset)
exact = exact_ground_state_energy(hamiltonian, n_qubits=4, offset=offset)
print(result.energy, exact)

FermionOperator

A complex linear combination of fermionic terms, stored as {term: coeff}.

__init__(terms=None)

Build an operator from a mapping of terms to coefficients.

Parameters:

Name Type Description Default
terms dict[Term, complex] | None

Maps each term to its coefficient. A term is a tuple of (mode, action) pairs, where action is 1 for creation and 0 for annihilation, applied from left to right. The empty tuple is the identity. The coefficients of repeated terms are added together. Leave it out for the zero operator. The default is None.

None

annihilation(mode) classmethod

The annihilation operator a_mode.

Parameters:

Name Type Description Default
mode int

The index of the spin-orbital from which an electron is removed.

required

Returns:

Type Description
'FermionOperator'

The operator, as a FermionOperator.

creation(mode) classmethod

The creation operator a†_mode.

Parameters:

Name Type Description Default
mode int

The index of the spin-orbital in which an electron is created.

required

Returns:

Type Description
'FermionOperator'

The operator, as a FermionOperator.

hermitian_conjugate()

The adjoint of the operator.

The order of each term is reversed, creation and annihilation are swapped, and each coefficient is replaced by its complex conjugate.

Returns:

Type Description
'FermionOperator'

The adjoint, as a FermionOperator.

identity(coefficient=1.0) classmethod

The identity operator, optionally scaled.

Parameters:

Name Type Description Default
coefficient Scalar

The factor that multiplies the identity. The default is 1.0.

1.0

Returns:

Type Description
'FermionOperator'

The scaled identity, as a FermionOperator.

number(mode) classmethod

The number operator a†_mode a_mode.

It counts the electrons in one spin-orbital.

Parameters:

Name Type Description Default
mode int

The index of the spin-orbital.

required

Returns:

Type Description
'FermionOperator'

The operator, as a FermionOperator.

zero() classmethod

The zero operator, which has no terms.

Returns:

Type Description
'FermionOperator'

The zero FermionOperator.

Molecule dataclass

A molecular Hamiltonian in second quantisation.

fermion_operator already includes the constant term (the nuclear repulsion), so jordan_wigner(fermion_operator) returns it as the offset. hf_energy and fci_energy, when computed, are the reference energies from PySCF, which are useful targets for the Variational Quantum Eigensolver (VQE).

Attributes:

Name Type Description
fermion_operator FermionOperator

The Hamiltonian in second quantisation, including the constant term.

n_qubits int

The number of qubits needed after the mapping, one per spin-orbital with Jordan-Wigner.

n_electrons int

The number of electrons, which sets the Hartree-Fock reference state and the excitations that a unitary coupled-cluster singles and doubles (UCCSD) ansatz can use.

nuclear_repulsion float

The constant nuclear term, in Hartree. It is already included in fermion_operator, and it is kept separately so that it can be reported.

hf_energy float

The Hartree-Fock energy from PySCF, in Hartree. A VQE run should reach a lower energy.

fci_energy float | None

The full configuration interaction (FCI) energy, in Hartree, which is the exact answer in this basis set. It is None when it was not computed. The difference from hf_energy is the correlation energy that a VQE run tries to recover.

VQE

Bases: BaseQuantumSolver

Variational Quantum Eigensolver (VQE).

Parameters:

Name Type Description Default
layers int

The depth of the default hardware-efficient ansatz. The default is 2.

2
provider ProviderSpec

The backend to use. The default is "numpy", the built-in reference simulator.

'numpy'
optimizer Optimizer

The optimiser: the name of a scipy.optimize.minimize method, "spsa", or a custom callable (see minimize_expectation). The default is "L-BFGS-B".

'L-BFGS-B'
restarts int

The number of runs from random starting points. The lowest energy is kept, because variational landscapes have local minima. The default is 1.

1
random_state int | None

The base seed. Restart r uses random_state + r, and None leaves every restart unseeded. The default is 42.

42

solve(hamiltonian, n_qubits, *, offset=0.0, ansatz=None)

Minimise the expectation value of the Hamiltonian over the ansatz.

It runs restarts independent optimisations from different random starting points and keeps the lowest energy, because a variational landscape has local minima.

Parameters:

Name Type Description Default
hamiltonian Observable

The Hamiltonian to minimise, as a qubit Observable, usually the one returned by jordan_wigner.

required
n_qubits int

The number of qubits of the circuit. It must match the Hamiltonian.

required
offset float

The constant added to the minimised value. This is where the identity term returned by the mapping goes, which for a molecule includes the nuclear repulsion, in Hartree. If it is left out, the energy is wrong by exactly that constant. The default is 0.0.

0.0
ansatz CircuitSpec | None

The circuit to optimise. The default, None, uses the built-in hardware-efficient ansatz with layers layers.

None

Returns:

Type Description
VQEResult

A VQEResult with the best energy, its parameters, and whether that restart converged.

VQEResult dataclass

Bases: ValueEquality

Outcome of a run of the Variational Quantum Eigensolver (VQE).

The result is read-only. Assigning to a field raises FrozenInstanceError, and writing into an array field raises ValueError. This prevents a mistyped = (instead of ==) or an in-place edit from leaving a result whose scalar fields describe a different run from the array it holds. To get a writable copy of the array, use np.array(result.field).

Results compare by value, including their arrays. They are not hashable, because a result is a collection of numbers and not a key, and a correct hash of a float array is expensive to compute.

Attributes:

Name Type Description
energy float

The lowest energy found, with the offset added back. For a molecule, it is in Hartree.

optimal_parameters ndarray

The ansatz weights that produced this energy.

n_iterations int

The number of optimiser iterations in the best restart. It is not summed over restarts.

success bool

Whether the optimiser of that restart reported convergence.

__post_init__()

Make the array field read-only.

Freezing the dataclass prevents a field from being reassigned, but it does not prevent writing into the array that the field holds, and a result that has been written into still reports the scalar values of the original run. The result therefore keeps its own copy, so the array it was built from can still be changed by the caller. To get a writable copy, use np.array(result.optimal_parameters).

apply_hartree_fock(circuit, n_electrons)

Prepare the Hartree-Fock reference state on an existing builder.

It applies an X gate to each of the lowest n_electrons spin-orbitals, which marks them as occupied (|1⟩).

The convention is the one of the Jordan-Wigner mapping: mode j is qubit j, and the spin-orbitals are ordered so that the lowest n_electrons of them are occupied in the reference state, for example |1…1 0…0⟩.

Parameters:

Name Type Description Default
circuit CircuitBuilder

The builder to add the gates to.

required
n_electrons int

The number of electrons, which sets the Hartree-Fock reference state.

required

Returns:

Type Description
CircuitBuilder

The same builder, so that calls can be chained.

bravyi_kitaev(operator, n_qubits=None)

Map a FermionOperator to qubits with the Bravyi-Kitaev transformation.

The transformation itself is done by OpenFermion (the chemistry extra), and the result is converted to an eigenkit Observable. The Jordan-Wigner mapping, in contrast, is implemented in eigenkit. n_qubits defaults to the largest mode index plus one.

Parameters:

Name Type Description Default
operator FermionOperator

The fermionic operator to map.

required
n_qubits int

The number of qubits.

None

Returns:

Name Type Description
observable Observable

The operator on qubits, without its identity part.

offset float

The coefficient of the identity part, which the Observable does not contain.

dense_hamiltonian(observable, n_qubits, offset=0.0)

The 2**n_qubits × 2**n_qubits matrix of observable + offset * I.

Qubit 0 is the most significant factor of the tensor product, which matches the ordering of basis states in the simulators.

Parameters:

Name Type Description Default
observable Observable

The qubit operator.

required
n_qubits int

The number of qubits.

required
offset float

The constant (identity) term that the mapping returned separately, added back to the energy. For a molecule, it includes the nuclear repulsion, in Hartree.

0.0

Returns:

Type Description
ndarray

The matrix, as a complex NumPy array.

exact_ground_state_energy(observable, n_qubits, offset=0.0)

The lowest eigenvalue of observable + offset * I, by dense diagonalisation.

Parameters:

Name Type Description Default
observable Observable

The qubit operator.

required
n_qubits int

The number of qubits.

required
offset float

The constant (identity) term that the mapping returned separately, added back to the energy. For a molecule, it includes the nuclear repulsion, in Hartree.

0.0

Returns:

Type Description
float

The ground-state energy.

fermi_hubbard_dimer(t, u)

The two-site Fermi-Hubbard model with spin 1/2.

It has four spin-orbital modes, indexed by mode = 2 * site + spin, with spin 0 for up and 1 for down. Site 0 has modes 0 and 1, and site 1 has modes 2 and 3. The Hamiltonian is:

H = -t Σ_σ (a†_{0σ} a_{1σ} + a†_{1σ} a_{0σ})
    + U (n_{0↑} n_{0↓} + n_{1↑} n_{1↓})

The ground-state energy at half filling has the closed form fermi_hubbard_dimer_ground_energy(). This makes the model an exact check of the fermion-to-qubit mapping and of VQE, with no external dependency.

Parameters:

Name Type Description Default
t float

The hopping amplitude between the two sites.

required
u float

The on-site Coulomb repulsion.

required

Returns:

Type Description
FermionOperator

The Hamiltonian, as a FermionOperator.

fermi_hubbard_dimer_ground_energy(t, u)

The ground-state energy of the Fermi-Hubbard dimer at half filling.

The energy of fermi_hubbard_dimer() with two electrons in a singlet state is (U - sqrt(U² + 16t²)) / 2. This value is the ground state over all particle numbers only when U < 3t. For a larger U, double occupancy costs so much energy that the state with a single electron, of energy -t, is lower, and the ground state over all particle numbers is min(-t, (U - sqrt(U² + 16t²)) / 2). An ansatz that conserves the number of particles, such as UCCSD, targets the half-filling sector directly. The hardware-efficient ansatz explores all sectors, so use it only where the half-filling state is the overall ground state.

Parameters:

Name Type Description Default
t float

The hopping amplitude, as in the model.

required
u float

The on-site repulsion, as in the model.

required

Returns:

Type Description
float

The ground-state energy at half filling, from the closed form.

fermion_operator_from_openfermion(operator)

Convert an openfermion.FermionOperator to an eigenkit FermionOperator.

Parameters:

Name Type Description Default
operator FermionOperator

The fermionic operator to convert.

required

Returns:

Type Description
FermionOperator

The same operator, as an eigenkit FermionOperator.

hardware_efficient_ansatz(n_qubits, layers)

A standard hardware-efficient ansatz.

It starts with a layer of RY rotations, then repeats layers times a linear chain of CNOT gates followed by an RY and an RZ rotation on each qubit. It has n_qubits + 2 * layers * n_qubits trainable weights.

Parameters:

Name Type Description Default
n_qubits int

The number of qubits.

required
layers int

The number of repetitions.

required

Returns:

Type Description
CircuitSpec

The ansatz, as a CircuitSpec.

hartree_fock_state(n_qubits, n_electrons)

A circuit that prepares the Hartree-Fock reference state.

The state is |1…1 0…0⟩ on n_qubits qubits, with n_electrons occupied spin-orbitals.

Parameters:

Name Type Description Default
n_qubits int

The number of qubits.

required
n_electrons int

The number of electrons, which sets the Hartree-Fock reference state.

required

Returns:

Type Description
CircuitSpec

The circuit, as a CircuitSpec with no trainable weights.

hydrogen_molecule(bond_length=0.7414, *, basis='sto-3g', run_fci=False)

The hydrogen molecule H₂ at the given bond length, in angstroms.

In the minimal STO-3G basis set, this is the standard 4-qubit benchmark for VQE. Its FCI ground-state energy is about -1.137 Hartree at equilibrium.

Parameters:

Name Type Description Default
bond_length float

The distance between the nuclei, in angstroms. The default, 0.7414, is close to equilibrium.

0.7414
basis str

The name of the PySCF basis set.

'sto-3g'
run_fci bool

Whether to also compute the exact FCI energy, the target against which a VQE run is measured.

False

Returns:

Type Description
Molecule

The molecule, with its Hamiltonian and reference energies.

jordan_wigner(operator, *, atol=1e-10)

Map a FermionOperator to qubits with the Jordan-Wigner transformation.

The operator must be Hermitian, as a Hamiltonian is. If a resulting coefficient is not real, a ValueError is raised.

Parameters:

Name Type Description Default
operator FermionOperator

The fermionic operator to map.

required
atol float

Terms whose coefficient is smaller than this value in magnitude are dropped.

1e-10

Returns:

Name Type Description
observable Observable

The operator on qubits, without its identity part.

offset float

The coefficient of the identity part, which the Observable does not contain.

molecular_hamiltonian(geometry, *, basis='sto-3g', charge=0, multiplicity=1, run_fci=False)

Build a Molecule from a geometry, with PySCF and OpenFermion.

Parameters:

Name Type Description Default
geometry list[tuple[str, tuple[float, float, float]]]

A list of (element, (x, y, z)) entries, with the coordinates in angstroms.

required
basis str

The name of the PySCF basis set. The default is the minimal basis set "sto-3g".

'sto-3g'
charge int

The total charge of the molecule.

0
multiplicity int

The spin multiplicity, 2S + 1.

1
run_fci bool

Whether to also compute the FCI energy, which is exact in this basis set and a useful target for VQE. It needs an exact diagonalisation, so it is only possible for small systems.

False

Returns:

Type Description
Molecule

The Molecule, with its Hamiltonian and reference energies.

observable_from_openfermion(qubit_operator, *, atol=1e-10)

Convert an openfermion.QubitOperator to an (Observable, offset) pair.

The identity term becomes the real offset. The coefficients must be real, because the operator must be Hermitian, and a ValueError is raised otherwise.

Parameters:

Name Type Description Default
qubit_operator QubitOperator

The operator to convert.

required
atol float

Terms whose coefficient is smaller than this value in magnitude are dropped.

1e-10

Returns:

Name Type Description
observable Observable

The operator, without its identity term.

offset float

The coefficient of the identity term.

to_openfermion_fermion_operator(operator)

Convert an eigenkit FermionOperator to an openfermion.FermionOperator.

Parameters:

Name Type Description Default
operator FermionOperator

The fermionic operator to convert.

required

Returns:

Type Description
FermionOperator

The same operator, in OpenFermion.

uccsd_ansatz(n_qubits, n_electrons, reps=1)

The UCCSD ansatz on the Hartree-Fock reference, with a Trotter approximation.

UCCSD is the unitary coupled-cluster ansatz with single and double excitations. The circuit prepares (∏_k exp(θ_k (T_k − T_k†)))^reps |HF⟩, where |HF⟩ is the Hartree-Fock state.

Each generator G = T − T† is anti-Hermitian. The Jordan-Wigner mapping turns H = −iG into a Hermitian qubit operator, and exp(θG) = exp(iθH) is then a product of pauli_exponential gates. The Pauli terms of one generator commute, so that product is exact. The product over different generators is a first-order Trotter approximation. reps repeats the whole sequence with independent weights, which reduces the Trotter error: more repetitions bring the circuit closer to the exact UCCSD unitary. The ansatz has reps * n_excitations weights in total.

Parameters:

Name Type Description Default
n_qubits int

The number of qubits, one per spin-orbital.

required
n_electrons int

The number of electrons, which sets the Hartree-Fock reference and the possible excitations.

required
reps int

The number of Trotter repetitions of the product of excitations. The default is 1.

1

Returns:

Type Description
CircuitSpec

The ansatz as a CircuitSpec, with one trainable angle per generator and per repetition.

uccsd_excitation_generators(n_qubits, n_electrons)

The excitation generators T - T† of the UCCSD ansatz.

UCCSD is the unitary coupled-cluster ansatz with single and double excitations. The excitations go from the occupied spin-orbitals (the lowest n_electrons) to the unoccupied ones. Single and double excitations are taken over all choices of occupied and unoccupied indices, with no restriction from spin symmetry, which keeps the construction simple and correct. A variant restricted by spin symmetry, which would have fewer parameters, is not implemented.

Parameters:

Name Type Description Default
n_qubits int

The number of qubits.

required
n_electrons int

The number of electrons, which sets the Hartree-Fock reference state.

required

Returns:

Type Description
list[FermionOperator]

The generators, as a list of FermionOperator objects.