Quick-start guide

On this page we give a quick example of running a quantum computational chemistry calculation using InQuanto. This example evaluates the H2 electronic wave function in the minimal basis using the Unitary Coupled Cluster Singles Doubles Ansatz and finding parameters using the variational quantum eigensolver and a state vector (noiseless) backend.

Express database

Most quantum chemical calculations on a quantum computer start with a classical computation of molecular integrals. In general this is achieved in InQuanto via separate extensions, which interface to external classical quantum chemistry packages (for example inquanto-pyscf). However, InQuanto also has a small internal database as part of its express module. This database contains molecular Hamiltonians, as well as other useful information, for a variety of small systems. These examples can be easily loaded and provide a simple way to start exploring InQuanto’s functionality.

In the cell below, we import the load_h5() function which we then use to load the H2 STO-3G example data. We then inspect its Hamiltonian terms, and print its classically calculated CCSD energy, which is stored for easy comparison in the express database entry.

from inquanto.express import load_h5
h2_sto3g_data = load_h5("h2_sto3g.h5", as_tuple=True)
hamiltonian = h2_sto3g_data.hamiltonian_operator
print(hamiltonian.to_FermionOperator())
print(h2_sto3g_data.energy_ccsd)
(0.7430177069924179, ), (-1.270292724390438, F0^ F0 ), (-0.45680735030941033, F2^ F2 ), (-1.270292724390438, F1^ F1 ), (-0.45680735030941033, F3^ F3 ), (0.48890859745047327, F2^ F0^ F0  F2 ), (0.48890859745047327, F3^ F1^ F1  F3 ), (0.6800618575841273, F1^ F0^ F0  F1 ), (0.6685772770134888, F2^ F1^ F1  F2 ), (0.1796686795630157, F1^ F0^ F2  F3 ), (-0.17966867956301558, F2^ F1^ F0  F3 ), (-0.17966867956301558, F3^ F0^ F1  F2 ), (0.1796686795630155, F3^ F2^ F0  F1 ), (0.6685772770134888, F3^ F0^ F0  F3 ), (0.7028135332762804, F3^ F2^ F2  F3 )
-1.1368465754747636

VQE wrapper function

In the manual sections we demonstrate how a user can build a variety of tools for performing quantum chemistry using InQuanto, but here we want a simple intuitive example that “just runs”. To do this we will use the run_vqe() function from express to run a variational quantum eigensolver algorithm.

run_vqe() requires the user to provide: an ansatz, the Hamiltonian operator, and a pytket backend. Optionally, the user can also choose whether run_vqe() uses gradients, what flavor of classical minimizer strategy to use, and the starting parameters for the variational cycle. These are not required options, and when left undefined in the example below will default to i) using gradients, ii) using the Scipy L-BFGS-B minimizer, and iii) starting with symbol parameters all set to zero.

As stated, run_vqe() requires the Hamiltonian, an ansatz, and a backend. To construct these we take the stored Fermionic operator data and qubit encode it using the Jordan-Wigner mapping). Then we prepare a 4 qubit ansatz circuit (corresponding to the 4 spin-orbitals of H2 STO-3G ) by defining the FermionSpace and FermionState objects and feeding them into the FermionSpaceAnsatzUCCSD class (more here). Lastly we import and instantiate a pytket state vector backend from Qiskit.

from inquanto.express import run_vqe
from inquanto.states import FermionState
from inquanto.spaces import FermionSpace
from inquanto.ansatzes import FermionSpaceAnsatzUCCSD
from pytket.extensions.qiskit import AerStateBackend

hamiltonian = load_h5("h2_sto3g.h5", as_tuple=True).hamiltonian_operator.qubit_encode()

space = FermionSpace(4)
state = FermionState([1, 1, 0, 0])
ansatz = FermionSpaceAnsatzUCCSD(fermion_space=space, fermion_state=state)

backend = AerStateBackend()

vqe = run_vqe(ansatz, hamiltonian, backend)
print(round(vqe.final_value, 8))
print(vqe.final_parameters)
# TIMER BLOCK-0 BEGINS AT 2024-11-20 15:54:38.114317
# TIMER BLOCK-0 ENDS - DURATION (s):  0.2052297 [0:00:00.205230]
-1.13684658
{d0: np.float64(-0.10723347230091604), s0: np.float64(-5.945469082845105e-17), s1: np.float64(-1.0151376297669872e-16)}

After the VQE algorithm has converged we can inquire the total energy of the system usng final_value(). In UCCSD ansatz, this energy is equivalent to the CCSD energy printed above (~1.1368465 Ha). We can also examine the parameters of the ansatz terms by printing the final_parameters(). These show that the singly excited terms (s) have no contribution due to being symmetry forbidden but the doubly (d) excited term has significant weight in the optimized wave function.

The above is just a quick example of how a user can run meaningful quantum computational chemistry calculations easily using InQuanto. Whilst still using run_vqe() there are plenty of variables to explore. For example, you can try loading a different system with more electrons or orbitals from express, modify the FermionSpace and FermionState accordingly and run a bigger calculation. Alternatively, you could examine how setting with_gradient=False on run_vqe() or modifying its minimizer changes the time to converge. Or how about comparing the speed of different pytket state vector backends?

After you’re comfortable with this quick-start guide, we recommend diving into the manual or following further tutorials.

Note

The run_vqe() method is only recommended for testing purposes, not for production purposes. The method only permits state vector based pytket backends. For example one may use the AerStateBackend or QulacsBackend (see info here). As the run_vqe() method only permits state vector it streamlines the selection and generation of the computables and protocols. Specifically, under the hood, the Protocol, which provides instructions for circuit measurement and post-processing, is set to SparseStatevectorProtocol, and the Computable is ExpectationValue. Again, under the hood, the computables are built (using build()) and then ran (using run()). For non-state vector calculations, one must utilize a proper instance of AlgorithmVQE, which is much more flexible than run_vqe().