Note

Run interactively in the IBM Quantum lab.

# Ground state solvers¶

## Introduction¶

In this tutorial we are going to discuss the ground state calculation interface of Qiskit Chemistry. The goal is to compute the ground state of a molecular Hamiltonian. This Hamiltonian can be electronic or vibronic. To know more about the preparation of the Hamiltonian, check out the Electronic structure and Vibronic structure tutorials.

The first step is to define the molecular system. In the following we ask for the electronic part of a hydrogen molecule.

[1]:
from qiskit.chemistry.drivers import PySCFDriver, UnitsType, Molecule
from qiskit.chemistry.transformations import FermionicTransformation, FermionicQubitMappingType

molecule = Molecule(geometry=[['H', [0., 0., 0.]],
['H', [0., 0., 0.735]]],
charge=0, multiplicity=1)
driver = PySCFDriver(molecule = molecule, unit=UnitsType.ANGSTROM, basis='sto3g')
transformation = FermionicTransformation(qubit_mapping=FermionicQubitMappingType.JORDAN_WIGNER)

## The Solver¶

Then we need to define a solver. The solver is the algorithm through which the ground state is computed.

Let’s first start with a purely classical example: the NumPy minimum eigensolver. This algorithm exactly diagonalizes the Hamiltonian. Although it scales badely, it can be used on small systems to check the results of the quantum algorithms.

[2]:
from qiskit.aqua.algorithms import NumPyMinimumEigensolver

numpy_solver = NumPyMinimumEigensolver()

To find the ground state we coul also use the Variational Quantum Eigensolver (VQE) algorithm. The VQE algorithms works by exchanging information between a classical and a quantum computer as depicted in the following figure.

Let’s initialize a VQE solver.

[3]:
from qiskit import BasicAer
from qiskit.aqua import QuantumInstance
from qiskit.chemistry.algorithms.ground_state_solvers.minimum_eigensolver_factories import VQEUCCSDFactory

vqe_solver = VQEUCCSDFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator')))

To define the VQE solver one needs two essential elements:

1. A variational form: here we use the Unitary Coupled Cluster (UCC) ansatz (see for instance [Physical Review A 98.2 (2018): 022322]). Since it is a chemistry standard, a factory is already available allowing a fast initialization of a VQE with UCC. The default is to use all single and double excitations. However, the excitation type (S, D, SD) as well as other parameters can be selected.

2. An initial state: the initial state of the qubits. In the factory used above, the qubits are initialized in the Hartree-Fock (see the electronic structure tutorial) initial state (the qubits corresponding to occupied MOs are $$|1\rangle$$ and those corresponding to virtual MOs are $$|0\rangle$$.

3. The backend: this is the quantum machine on which the right part of the figure above will be performed. Here we ask for the perfect quantum emulator (statevector_simulator).

One could also use any available variational form / initial state or even define one’s own. For instance,

[4]:
from qiskit.aqua.algorithms import VQE
from qiskit.circuit.library import TwoLocal

num_qubits = 4
tl_circuit = TwoLocal(num_qubits, ['h', 'rx'], 'cz',
entanglement='full', reps=3, parameter_prefix = 'y')

tl_circuit.draw(output = 'mpl')

another_solver = VQE(var_form = tl_circuit,
quantum_instance = QuantumInstance(BasicAer.get_backend('statevector_simulator')))

## The calculation and results¶

We are now ready to run the calculation.

[5]:
from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver

calc = GroundStateEigensolver(transformation, vqe_solver)
res = calc.solve(driver)

print(res)
=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030146
- computed part:      -1.857275030146
- frozen energy part: 0.0
- particle hole part: 0.0
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035697

=== MEASURED OBSERVABLES ===

0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: -0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

0:
* Electronic dipole moment (a.u.): [0.0  0.0  1.38894867]
- computed part:      [0.0  0.0  1.38894867]
- frozen energy part: [0.0  0.0  0.0]
- particle hole part: [0.0  0.0  0.0]
> Dipole moment (a.u.): [0.0  0.0  0.00000003]  Total: 0.00000003
(debye): [0.0  0.0  0.00000008]  Total: 0.00000008

We can compare the VQE results to the NumPy exact solver and see that they match.

[6]:
calc = GroundStateEigensolver(transformation, numpy_solver)
res = calc.solve(driver)
print(res)
=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030202
- computed part:      -1.857275030202
- frozen energy part: 0.0
- particle hole part: 0.0
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035753

=== MEASURED OBSERVABLES ===

0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

0:
* Electronic dipole moment (a.u.): [0.0  0.0  1.3889487]
- computed part:      [0.0  0.0  1.3889487]
- frozen energy part: [0.0  0.0  0.0]
- particle hole part: [0.0  0.0  0.0]
> Dipole moment (a.u.): [0.0  0.0  0.0]  Total: 0.
(debye): [0.0  0.0  0.0]  Total: 0.

## Using a filter function¶

Sometimes the true ground state of the Hamiltonian is not of interest because it lies in a different symmetry sector of the Hilbert space. In this case the NumPy eigensolver can take a filter function to return only the eigenstates with for example the correct number of particles. This is of particular importance in the case of vibronic structure calculations where the true ground state of the Hamiltonian is the vacuum state. A default filter function to check the number of particles is implemented in the different transformations and can be used as

[7]:
from qiskit.chemistry.drivers import GaussianForcesDriver
from qiskit.chemistry.algorithms.ground_state_solvers import NumPyMinimumEigensolverFactory
from qiskit.chemistry.transformations import (BosonicTransformation,
BosonicTransformationType,
BosonicQubitMappingType)

driver = GaussianForcesDriver(logfile='aux_files/CO2_freq_B3LYP_ccpVDZ.log')
bosonic_transformation = BosonicTransformation(qubit_mapping=BosonicQubitMappingType.DIRECT,
transformation_type=BosonicTransformationType.HARMONIC,
basis_size=2,
truncation=2)

solver_without_filter = NumPyMinimumEigensolverFactory(use_default_filter_criterion=False)
solver_with_filter = NumPyMinimumEigensolverFactory(use_default_filter_criterion=True)

gsc_wo = GroundStateEigensolver(bosonic_transformation, solver_without_filter)
result_wo = gsc_wo.solve(driver)

gsc_w = GroundStateEigensolver(bosonic_transformation, solver_with_filter)
result_w = gsc_w.solve(driver)

print(result_wo)
print('\n\n')
print(result_w)
=== GROUND STATE ENERGY ===

* Vibronic ground state energy (cm^-1): (1e-12+0j)
The number of occupied modals is
- Mode 0: [0.0, 0.0, 0.0, 0.0]

=== GROUND STATE ENERGY ===

* Vibronic ground state energy (cm^-1): (2536.487976362417+0j)
The number of occupied modals is
- Mode 0: [1.0000000000000002, 1.0000000000000002, 1.0000000000000002, 1.0000000000000002]
/home/runner/work/qiskit/qiskit/.tox/docs/lib/python3.8/site-packages/qiskit/chemistry/results/vibronic_structure_result.py:73: DeprecationWarning: The Python built-in round is deprecated for complex scalars, and will raise a TypeError in a future release. Use np.round or scalar.round instead.
format(round(self.computed_vibronic_energies[0], 12)))
/home/runner/work/qiskit/qiskit/.tox/docs/lib/python3.8/site-packages/qiskit/chemistry/results/vibronic_structure_result.py:73: DeprecationWarning: The Python built-in round is deprecated for complex scalars, and will raise a TypeError in a future release. Use np.round or scalar.round instead.
format(round(self.computed_vibronic_energies[0], 12)))
[8]:
import qiskit.tools.jupyter
%qiskit_version_table

### Version Information

Qiskit SoftwareVersion
Qiskit0.23.1
Terra0.16.1
Aer0.7.1
Ignis0.5.1
Aqua0.8.1
IBM Q Provider0.11.1
System information
Python3.8.6 (default, Oct 28 2020, 13:08:18) [GCC 7.5.0]
OSLinux
CPUs2
Memory (Gb)6.791393280029297
Mon Nov 30 18:47:49 2020 UTC