Introduction to the InQuanto Computational Chemistry Platform For Quantum Computers
Introduction
Quantum chemistry aims to accurately describe and predict the fundamental properties of matter and materials, and hence is a powerful tool in the design and development of new molecules and materials. Despite the success of current techniques, they have shortcomings of two broad types: (i) current techniques use approximations to reduce the computation complexity but then lack accuracy; or (ii) highly accurate techniques exist but impose heavy computation overhead to scale these calculations, making industrial relevant problems intractable with even today’s most powerful computing resources.
A highly utilized computational modeling method in quantum chemistry is called Density Functional Theory (DFT), with which the energetics of a molecule or solid is obtained from the electron density. This theory is now widely used in simulation as it is cheap and relatively accurate in many situations. However, there are many systems for which DFT is not accurate enough or it is qualitatively incorrect due to the necessary approximations to the exchange-correlation functional.
In principle, wavefunction methods are more accurate than DFT because they may be improved systematically, thus they capture electron correlation in a more precise way. However, scaling of these methods on traditional classical computers is prohibitive for all but the simplest systems. For example, the state-of-the-art wavefunction method CCSD(T), which scales as N⁷, is unable to adequately describe strong electron correlation.
Quantum computing promises to make correlated wavefunction methods affordable for the computational chemist. This technology maps a quantum system (a molecule or material) to a programmable quantum system (the quantum computer). In this way, wavefunction-based algorithms may be efficiently implemented thus being able to reach chemical accuracy at a cheaper cost in the future, when sizeable quantum computers are available.
So why start exploring chemistry on today’s devices now? The route to quantum advantage is an iterative process and improvements are required on both the hardware and software sides. The transition from variational ansatz optimisation to fault-tolerant algorithms such as Quantum Phase Estimation will be a gradual one, via variational and probabilistic approximations to Phase Estimation, which will soon become practical and will bring us closer to beating classical simulations. Thus, it is essential to start prototyping today with real-world use cases so that methods are tailored to solving industrially-relevant problems.
For this reason, we have created the InQuanto platform to enable users — anywhere from computational chemists to quantum developers — to easily experiment with the latest quantum algorithms and techniques on a range of quantum backends to help them understand the potential of quantum computing to significantly improve the accuracy of complex molecular and materials simulations in their fields.
InQuanto
InQuanto is a python based platform that allows users to program in their familiar Juypter environment. InQuanto uses our open source software development toolkit, TKET, to enable users to seamlessly transition their code onto actual quantum hardware or quantum simulation tools of their choosing. The InQuanto platform includes the main inquanto
package, various extension packages and TKET backends. The maininquanto
package has the latest and most relevant Noisy Intermediate Scale Quantum (NISQ) algorithms for quantum chemistry simulations. Among them, of course, we have the workhorse of variational algorithms for quantum chemistry: the Variational Quantum Eigensolver, also known as VQE. This algorithm finds the ground state energy of a molecule or material via the interplay between a quantum computer and a classical machine. The classical machine performs an optimization procedure on a function that outputs the energy of a molecule. This function depends on a parameterized quantum circuit, and the quantum computer handles the calculation of the energy for each parameter set proposed by the classical machine during the optimization process. The implementation of this basic algorithm in InQuanto is efficient, easy to run and serves as basis for a wide variety of methods.
The main package also includes other algorithms for ground state and excited state calculations, such as ADAPT-VQE, Quantum Subspace Expansion and penalty-driven VQE approaches, in addition to Quantinuum’s chemistry specific noise mitigation methods. InQuanto’s end-to-end workflow is outlined in Figure 1 that describes the logical steps from an industrially-relevant chemistry or material science problem to a solution. The steps include the problem “InQuantization” which refers to the standardization of traditional quantum chemistry quantities from various sources, the method selections and the actual quantum computation on any of the supported quantum devices or simulators. In the following sections we demonstrate InQuanto with a few examples.
Ground state of a simple molecule — H₂
Similarly to a traditional quantum chemistry code, the workflow starts with specifying the geometry of the molecule or the solid state system along with many other physical system-specific parameters, such as the charge, multiplicity, unit cell, symmetries, etc. In addition, many computational parameters also set by the user, out of which the most important is the basis set. A large basis set leads to accurate results, but also to a larger number of qubits and much deeper quantum circuits, which may make a calculation unfeasible on today’s quantum computer. As the quantum computing hardware evolves and as users experiment with different quantum hardware, researchers can easily scale their InQuanto code to take full advantage of the quantum device.
In order to perform a quantum calculation for a real physical system we usually need to run a relatively light-weight traditional quantum chemistry calculation first. This is typically a Hartree–Fock (HF) calculation that one needs to keep in mind when assessing how big system can be simulated. InQuanto has various extensions to third-party packages that enable smooth integrations between existing and well known traditional quantum chemistry packages such as PySCF or other libraries for visualization or quantum calculations. With the help of the inquanto-pyscf
package we can run a HF calculation and obtain the Hamiltonian operator in a second quantized form.
The typical next step is to transform the second quantized operators to qubit operators (operators that are acting on qubits) with a suitable encoding. InQuanto supports multiple encodings, such as, Jordan–Wigner (JW), Bravyi–Kitaev (BK). The default encoding is JW, and the method operator.qubit_encode()
can be used to transform the second quantized representation of the chemical Hamiltonian into a qubit operator.
To calculate the ground state energy of the chemical system, an ansatz also must be defined. InQuanto has many predefined ansätze available for the user to choose from. A typical chemistry ansatz, the UCCSD ansatz, is defined with a reference state and the exponents, that are the terms in the anti-hermitian UCCSD cluster operator. If the exponents are also in second quantized form then it must be transformed to the corresponding qubit operators. In the simplest case InQuanto’s FermionSpace
object can take care of many of the details and generate the single and double fermionic excitation operators.
Once the ansatz and the Hamiltonian operator are given we can run a simple VQE calculation very quickly using the black box function from the express
module. The express
module is useful to get started because it makes a number of loadable, precomputed Hamiltonians available instantly. In this example a Hamiltonian of the H₂ molecule is used which was precomputed with STO-3G basis set withinquanto-pyscf
. The example script for performing a VQE calculation for H₂:
from inquanto.express import load_h5, run_vqe
from inquanto.states import FermionState
from inquanto.spaces import FermionSpace
from inquanto.ansatzes import FermionSpaceAnsatzUCCSDfrom pytket.extensions.qiskit import AerStateBackend
backend = 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(space, state)vqe = run_vqe(ansatz, hamiltonian, backend)print("Ground state energy = ", vqe.final_value)
vqe.final_parameters.print_report()# Ground state energy = -1.1368465754720536
# 000: s0 = 0.0000000000
# 001: s1 = 0.0000000000
# 002: d0 = -0.1072334723
In this example to perform the actual quantum computation, we chose to use a statevector simulation provided in the standard Qiskit library, however, with the assistance of TKET users can seamlessly try out their codes and algorithms on any number of quantum computing hardware or simulator backends from Quantinuum, IBM, Google and many more..
Chemistry aware circuit optimization — H₃⁺
To help users make the most of today’s and the near futures hardware, InQuanto uses advanced techniques to optimize circuits. Some of them are based on TKET’s general circuit optimizations, while others are specific to circuits known to describe chemical systems.
If a molecular system exhibits certain geometrical symmetries then InQuanto can reduce the required quantum computational resources or perform some error mitigations. For example, the equilateral triangular trihydrogen cation molecule H₃⁺ has D₃ₕ point group symmetry and this information is used to omit excitation operators from the UCCSD ansatz and therefore reduces the number of variational parameters and circuit depth. The user can specify the symmetries manually, but the inquanto-pyscf
extension can be a great help because the chemistry driver can be instructed to infer the symmetry of any molecule. When the get_system()
method is called the space
variable retains the symmetry information and the excitation operators are generated by the space
take into account the symmetry group and consequently the quantum computational overhead for the UCCSD ansatz will be smaller:
from inquanto.extensions.pyscf import ChemistryDriverPyscfMolecularRHF
zmatrix = """
H
H 1 0.9
H 2 0.9 1 60
"""
driver = ChemistryDriverPyscfMolecularRHF(
zmatrix=zmatrix, charge=1, basis="STO-3G", point_group_symmetry=True
)
hamiltonian, space, state = driver.get_system()
from inquanto.ansatzes import FermionSpaceStateExpChemicallyAware
exponents = space.construct_single_ucc_operators(state)
exponents += space.construct_double_ucc_operators(state)
ansatz = FermionSpaceStateExpChemicallyAware(exponents, state)
from pytket.circuit import OpType
ansatz.state_circuit.depth_by_type(OpType.CX)# 12
In addition to the simplifications made from symmetry, built-in capabilities to InQuanto enable additional circuit simplifications. In the example above a specially designed chemistry aware ansatz is used that results in a circuit depth with 12 CX gates. Table 1 shows the circuit depths of optimized and unoptimized circuits for a few molecules. The combination of InQuanto’s chemistry aware optimizations with symmetries consistently give significantly shorter circuits than other optimizations.
Embedding methods — Aspirin
In order to test and run quantum algorithms in a realistic chemistry context and not only for model systems, InQuanto supports embedding methods based on Density Matrix Embedding Theory (DMET). Embedding methods are useful as they can reduce the qubit requirements for the simulation of a large molecule. The basic idea is that if a molecule’s properties cannot be computed due to its large size with a quantum computer, the molecule can be subdivided into small fragments, which can be individually simulated with traditional chemistry methods or via quantum algorithms. The properties of the whole molecule are computed from the results for the individual fragments.
Figure 2. Fragmentations of aspirin for DMET (left) and total energies (right) with different solvers. The MP2 method applied to the entire molecule, DMET-HF, DMET-CCSD and DMET-VQE-UCC used the fragmentation on the left. For the DMET-VQE-UCC calculation an active space with 12 spin-orbitals was selected.
As a demonstration, we run a DMET simulation of the aspirin molecule. Figure 2 shows a way of subdividing the molecule into fragments. Prior to the embedding method one needs to generate a Hamiltonian operator with a localized and orthonormal basis, in which spatial fragments can be specified. This is usually performed by a chemistry driver and the driver also runs a full HF calculation to compute the one-electron reduced density matrix (1-RDM) which is also necessary to perform an embedding calculation. With theinquanto-pyscf
extension installed you can use the PySCF drivers to generate the Hamiltonian and 1-RDM in the localized space by using the get_lowdin_system()
method:
from inquanto.geometries import GeometryMolecular
from inquanto.extensions.pyscf import ChemistryDriverPyscfMolecularRHF
geometry = GeometryMolecular.load_xyz("aspirin.xyz")
driver = ChemistryDriverPyscfMolecularRHF(basis="sto-3g", geometry=geometry.xyz, charge=0)
hamiltonian_operator, space, rdm1 = driver.get_lowdin_system()
The fragment definition is based on the spatial orbitals, but for ease of use InQuanto has a utility function get_fragment_orbital_masks(…)
that converts fragments defined by atoms into fragments defined by their spatial orbitals. The extension inquanto-nglview
can help by selecting and visualizing the molecule, the orbitals and the fragments. Once the fragments are defined, for each fragment we need to associate a quantum solver to finally run the DMET simulation:
from inquanto.embeddings import DMETRHF
from inquanto.extensions.pyscf import (
get_fragment_orbital_masks,
DMETRHFFragmentPyscfRHF,
DMETRHFFragmentPyscfActive,
DMETRHFFragmentPyscfFCI,
DMETRHFFragmentPyscfCCSD,
DMETRHFFragmentPyscfMP2,
)
atom_fragments = {"CH-1":[1,15], "CH-2":[3,17],
"CH-3":[2,16], "CH-4":[0,14],
"OCOH":[7,9,10,13], "CHHH":[4,18,19,20],
"OCO":[8,11,12], "CC":[5,6]}
orbsCH1, orbsCH2, orbsCH3, orbsCH4, orbsOCOH, orbsCHHH, orbsOCO, orbsCC = get_fragment_orbital_masks(driver, *atom_fragments.values() )
dmet = DMETRHF(hamiltonian_operator, rdm1)
frCH1 = DMETRHFFragmentPyscfFCI(dmet, orbsCH1)
frCH2 = DMETRHFFragmentPyscfCCSD(dmet, orbsCH2)
frCH3 = DMETRHFFragmentPyscfMP2(dmet, orbsCH3)
frCH4 = DMETRHFFragmentPyscfCCSD(dmet, orbsCH4)
frOCOH = DMETRHFFragmentPyscfCCSD(dmet, orbsOCOH)
frCHHH = DMETRHFFragmentPyscfCCSD(dmet, orbsCHHH)
frOCO = DMETRHFFragmentPyscfMP2(dmet, orbsOCO)
frCC = DMETRHFFragmentPyscfCCSD(dmet, orbsCC)
fragments = [frCH1, frCH2, frCH3, frCH4, frOCOH, frCHHH, frOCO, frCC]
result = dmet.run(fragments)
InQuanto supports various fragment solvers that are based on PySCF, and also different kinds of DMET flavors, such as single fragment DMET, single-shot DMET, or full DMET. Due to InQuanto’s mix & match philosophy we do not provide fragment solvers for many quantum algorithms as the possibilities are countless, however InQuanto allows the user to easily define their own fragment solver, therefore one can combine any ansatz, backend, error mitigation techniques and quantum algorithm with a DMET method:
class MyFragment(DMETRHFFragmentPyscfActive):
def solve_active(
self,
hamiltonian_operator,
fragment_energy_operator,
fermion_space,
fermion_state
):
... write here your quantum algorithm, for example VQE ...
return vqe_energy, fragment_energy, vqe_rdm1
Our documentation also provides detailed examples on how to construct these fragment solvers. Since DMET depends on localized Hamiltonians, the user has the option to experiment with model Hamiltonians for molecular or solid state systems as well, constructed independently from a chemistry driver.
Anatomy of the computation flow — Reduced Density Matrix
InQuanto offers full support for end-to-end simulations with optional access to the low level components of the computational flow down to the level of quantum circuits. In this way InQuanto not only helps to perform simulations of interesting chemistry systems with ready made methods, but also allows the user to mix and match various computational components and explore custom workflows. In this section we demonstrate a middle level computational example based on the so-called computables that provide an interface between traditional quantum chemistry and quantum computations for users with traditional quantum chemistry experience.
The computables represent high level quantities such as Reduced Density Matrices (RDM) or gradients that can be calculated with the help of a quantum device. However, they are simpler than a general quantum algorithm (like the VQE method) because for a computable all of the measurement circuits can be generated before any actual measurements performed. The measurement circuits then can be sent to a quantum device and when the probability distributions are retrieved from the quantum device the target quantity can be computed. This computational flow is sketched in Figure 3. In essence, the main responsibility of a computable is to prepare, manage and optimize internally the lower level subcomponents to calculate the represented quantity via quantum measurements.
Some of the main computables InQuanto supports:
- Basic computables:
ExpectationValue
calculates the expectation value of an operator with a state.
OverlapSquared
calculates the square of the overlap of two states. - Composite computables that combines multiple computables together:
Computables
is a tuple of any computables.
ComputableList
is a list of any computables.
ComputableArray
is an numpy ndarray of any computables.
+ - / *
arithmetic expressions of computables are also computables. - Derived high level computables based on
ExpectationValue
:ComputableRestrictedOneBodyRDM
computes the one-body RDM for spin restricted system.
ComputableUnrestrictedOneBodyRDM
computes the one-body RDM for spin unrestricted spin system.
ComputableSpinlessNBodyRDMTensor
computes the general n-body spatial RDM tensor.
ComputableQSEMatrices
computes the matrices for quantum subspace expansion.
ExpectationValueGradient
computes the gradient with respect to some ansatz parameters.
Many of these computables are essential components in higher level hybrid classical-quantum algorithms. For example in VQE the ground-state is calculated by minimizing an expectation value with respect to the ansatz parameters, where the expectation values and the derivatives that drive the minimization can be computed with computables at each iteration.
The most basic example of a computable object is the ExpectationValue
which represents the expectation value of a QubitOperator
with an Ansatz
:
from inquanto.express import load_h5
from inquanto.ansatzes import StateTrotter
from inquanto.operators import QubitOperatorList
from inquanto.states import QubitState
from pytket.extensions.qiskit import AerBackend
backend = AerBackend()
hamiltonian = load_h5("h2_sto3g.h5", as_tuple=True).hamiltonian_operator.qubit_encode()
exponents = QubitOperatorList.from_string("theta ,[(1j, Y0 X1 X2 X3)]")
ansatz = StateTrotter(exponents, QubitState([1, 1, 0, 0]))
from inquanto.computables import ExpectationValue
energy = ExpectationValue(ansatz, hamiltonian)
The energy
represents the expectation value of the hamiltonian
with respect to ansatz
. In order to generate the measurement circuits that are necessary to eventually compute the energy we need to provide further instructions to the computable on how the measurement circuits are to be generated. These instructions are called protocols and can be imported from inquanto.protocols
submodule. The expectation value of an operator can be obtained with different kinds of measurement circuits, therefore InQuanto provides a wide range of protocols. The protocol can be specified with the build(…)
method which allows the circuits to be generated. By calling the therun(…)
method the generated circuits will be sent to the quantum device and the distributions are retrieved when the measurements are completed:
from inquanto.protocols import ProtocolDirect
from inquanto.core import SymbolDictprotocol = ProtocolDirect()
energy.build(protocol, optimize=True)
energy.run(backend, SymbolDict(theta=0.1), n_shots = 8000)
value = energy.evaluate()
Once the run
method is finished, which means the distributions are retrieved from the quantum computer (or from the simulator), the computable object can be evaluated with evaluate()
to obtain its value.
The protocols can be also modified with error mitigation techniques, such as State Preparation and Measurement (SPAM) method or Partition Measurement Symmetry Verification (PMSV). The latter takes advantage of the chemical symmetries and in practice one can apply it on the protocol:
from inquanto.protocols.supporters import SupporterPMSV
symmetries = mapping.operator_map(
space.symmetry_operators_z2_in_sector(state)
)pmsv = SupporterPMSV(symmetries)
pmsv.calibrate()
protocol = ProtocolDirect().apply(pmsv)
InQuanto supports many more computables, such as overlaps, derivatives, arithmetic expressions of other computables, or composite computables such as Quantum Subspace Expansion (QSE) matrices or RDM-s built from more elementaries. To summarize a complete calculation, in the following example an n-body RDM (with n=2) is computed:
from inquanto.states import FermionState
from inquanto.spaces import FermionSpace
from inquanto.ansatzes import FermionSpaceAnsatzUCCSD
from inquanto.mappings import QubitMappingJordanWigner
from inquanto.computables import ComputableSpinlessNBodyRDMTensor
from inquanto.protocols import ProtocolDirect
from pytket.extensions.qiskit import AerBackend
backend = AerBackend()
space = FermionSpace(4)
state = FermionState([1, 1, 0, 0])
mapping = QubitMappingJordanWigner()
ansatz = FermionSpaceAnsatzUCCSD(space, state, mapping)
parameters = ansatz.state_symbols.construct_from_array(
[0.0, 0.0, -1.07233472e-01]
)
n_body_rdm_tensor_expr = ComputableSpinlessNBodyRDMTensor(
2, space, ansatz, mapping
)
n_body_rdm_tensor_expr.build(ProtocolDirect())
n_body_rdm_tensor_expr.run(
backend,
parameters,
n_shots = 8000
)
n_body_rdm_tensor = n_body_rdm_tensor_expr.evaluate()
Furthermore, the ProtocolDirect
supports the calculation of standard errors, therefore we can calculate the standard error for the n_body_rdm_tensor
as well:
n_body_rdm_tensor_std_err = n_body_rdm_tensor_expr.approximate_error()
which is useful to have an error-bar on the final result.
Further reading on applications
InQuanto has an end-to-end approach that supports both molecular and periodic systems. Thanks to the mix & match philosophy, the various algorithms, circuit synthesis and measurement reduction methods InQuanto ensures the simulation can be run on early stage devices, and with the supported embedding methods the simulations can be performed for applications with realistic sized molecules or solids. For further details on hardware calculations for realistic systems you can read our papers on Quantum Computational Quantification of Protein-Ligand Interactions and Quantum hardware calculations of periodic systems: hydrogen chain and iron crystals
How to Access InQuanto?
If you are interested in trying InQuanto please request a demo at inquanto@quantinuum.com or visit our website at https://www.quantinuum.com/products/inquanto
Join Our Showcase Event
Join us virtually on June 9 to meet early adopters of quantum computing and discuss the latest in quantum chemistry using quantum computers
Register here: https://www.quantinuum.com/computational-chemistry
Quantinuum Quantum Chemistry Team
In alphabetical order:
Andrew Tranter, Cono Di Paola, David Muñoz Ramo, David Zsolt Manrique, Duncan Gowland, Gabriel Greene-Diniz, Georgia Christopoulou, Iakov Polyak, Irfan Khan, Jerzy Pilipczuk, Josh Kirsopp, Kentaro Yamamoto, Maria Tudorovskaya, Michal Krompiec, Nathan Fitzpatrick