PennyLane provides a differentiable Hartree-Fock solver module
hf and a quantum chemistry
qchem to perform quantum simulations of the electronic structure of molecules. These
modules contain tools to construct the electronic Hamiltonian of molecules that can be used to
implement the Variational Quantum Eigensolver (VQE) algorithm.
To access the
qchem module, the
PennyLane-QChem plugin must be installed separately:
pip install pennylane-qchem
Building the electronic Hamiltonian¶
qchem module provides access to a driver function
to generate the electronic Hamiltonian in a single call. For example,
from pennylane import qchem import numpy as np symbols, coordinates = (['H', 'H'], np.array([0., 0., -0.66140414, 0., 0., 0.66140414])) h, qubits = qchem.molecular_hamiltonian( symbols, coordinates, charge=0, mult=1, basis='sto-3g', active_electrons=2, active_orbitals=2 )
his the qubit Hamiltonian of the molecule represented as a PennyLane Hamiltonian, and
qubitsis the number of qubits needed to perform the quantum simulation.
molecular_hamiltonian() calls the following functions in order
to generate the qubit Hamiltonian:
Reads the structure of the polyatomic system from a file and returns a list with the symbols of the atoms in the molecule and a 1D array with their positions \([x_1, y_1, z_1, x_2, y_2, z_2, \dots]\) in atomic units (Bohr radius = 1).
Generates a file from which the mean field electronic structure of the molecule can be retrieved.
Builds the active space for a given number of active electrons and active orbitals.
Decomposes the molecular Hamiltonian into a linear combination of Pauli operators using OpenFermion tools.
For more fine-grained control, these functions may be called independently as required.
Importing molecular structure data¶
The atomic structure of a molecule can be imported from an external file using the
>>> symbols, coordinates = qchem.read_structure('h2.xyz') >>> print(symbols, coordinates) ['H', 'H'] [0. 0. -0.66140414 0. 0. 0.66140414]
The geometry of the molecule is returned as a list containing the symbol and the Cartesian coordinates of each atomic species.
Solving the Hartree-Fock equations¶
meanfield() function uses the OpenFermion-PySCF and OpenFermion-Psi4 plugins to solve the Hartree-Fock equations for the molecule
using the electronic structure packages PySCF and Psi4, respectively.
symbols, coordinates = qchem.read_structure('h2o.xyz') hf_file = qchem.meanfield( symbols, coordinates, name='water', charge=-1, mult=2, basis='6-31g', package='pyscf' )
hf_file is the absolute path to the file containing
the Hartree-Fock electronic structure of the water molecule.
Mapping the Hamiltonian to the Pauli basis¶
active_space() is used to create an active space by classifying the Hartree-Fock molecular orbitals as
core, active, and external orbitals. Within this approximation, a certain number of active electrons can populate the active orbitals.
from openfermion import MolecularData water = MolecularData(filename=hf_file) core, active = qchem.active_space( water.n_electrons, water.n_orbitals, mult=2, active_electrons=3, active_orbitals=4 )
Once we have defined the active space,
OpenFermion functionalities to generate the second-quantized fermionic Hamiltonian
and map it to a linear combination of Pauli operators via the Jordan-Wigner or Bravyi-Kitaev transformation. For example,
qubit_hamiltonian = qchem.decompose( hf_file, mapping='jordan_wigner', core=core, active=active )
qubit_hamiltonian is an instance of the QubitOperator class of OpenFermion.
The Variational Quantum Eigensolver (VQE) is a hybrid quantum-classical computational scheme, where a quantum computer is used to prepare the trial wave function of a molecule and to measure the expectation value of the electronic Hamiltonian, while a classical optimizer is used to find its ground state.
PennyLane supports treating Hamiltonians just like any other observable, and the
expectation value of a Hamiltonian can be calculated using
import pennylane as qml dev = qml.device('default.qubit', wires=4) hamiltonian = 2.0 * qml.PauliZ(0) @ qml.PauliZ(1) @qml.qnode(dev) def circuit(params): qml.BasisState(np.array([1, 1, 0, 0]), wires=[0,1,2,3]) for i in range(4): qml.Rot(*params[i], wires=i) qml.CNOT(wires=[2, 3]) qml.CNOT(wires=[2, 0]) qml.CNOT(wires=[3, 1]) return qml.expval(hamiltonian) rng = np.random.default_rng(seed=42) params = rng.random([4, 3]) circuit(params)
The rotation angles can be optimized using the machine learning interface of choice until the energy difference between two consecutive iterations has converged to near zero.
For more details on VQE and the quantum chemistry functionality available in
check out the PennyLane quantum chemistry tutorials.