Note

This page was generated from docs/tutorials/vqe_with_estimator.ipynb.

# Variational Quantum Eigensolver with Estimator primitive¶

## Overview¶

The Variational Quantum Eigensolver (VQE) is an optimization routine for finding the ground state energy (the lowest eigenvalue) of a Hamiltonian and is a considered to be a viable candidate for near-term hardware. In this tutorial, you will learn how to use Qiskit Runtime to submit variational jobs using the `Estimator`

primitive. Specifically, you will calculate the ground state energy of the \(H_2\) molecule.

## Set up your local development environment¶

This tutorial requires a Qiskit Runtime service instance. If you haven’t done so already, follow these steps to set one up.

## Generate molecular Hamiltonians¶

This tutorial uses Qiskit Nature to generate and handle molecular Hamiltonians. If you haven’t already, you can install Qiskit Nature (and the PySCF addon) using the following commands. For more information about Qiskit Nature, see the Getting started guide.

```
pip install qiskit-nature
pip install 'qiskit-nature[pyscf]'
```

Next, we will generate the Hamiltonians that we want to find the ground state energy of. The first step is to use the `PySCFDriver`

to convert a string representing our molecule to an `ElectronicStructureProblem`

. The next step is to use the `ParityMapper`

to convert this problem into a qubit Hamiltonian that can run on a quantum computer.

```
[1]:
```

```
from qiskit_nature.second_q.drivers import PySCFDriver
driver = PySCFDriver(
atom="H 0 0 0; H 0 0 0.72" # Two Hydrogen atoms, 0.72 Angstrom apart
)
molecule = driver.run()
from qiskit_nature.second_q.mappers import QubitConverter, ParityMapper
qubit_converter = QubitConverter(ParityMapper())
hamiltonian = qubit_converter.convert(molecule.second_q_ops()[0])
```

## Solve classically¶

Since this problem is very small, we can solve it exactly using classical methods. The following code uses the minimum eigensolver from the `NumPy`

package to find the electronic ground state energy (in Hartree units), which we will use to assess the performance of the VQE.

```
[2]:
```

```
from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver
sol = NumPyMinimumEigensolver().compute_minimum_eigenvalue(hamiltonian)
real_solution = molecule.interpret(sol)
real_solution.groundenergy
```

```
[2]:
```

```
-1.8720800636154613
```

## Solve with VQE¶

Next, we will create our service instance and specify our backend. In this example we will use a simulator to avoid queue times, but you can use the following code to run on a real device by simply changing the backend.

```
[3]:
```

```
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Session, Options
service = QiskitRuntimeService()
backend = "ibmq_qasm_simulator"
```

The next code cell specifies how we want to run the VQE. This includes

the type of circuit (ansatz) used to create our trial state,

the classical algorithm that decides how to adjust our trial state to achieve better solutions, and

the starting parameters.

We will also create a simple object to log our intermediate results for plotting later.

```
[4]:
```

```
from qiskit.algorithms.minimum_eigensolvers import VQE
# Use RealAmplitudes circuit to create trial states
from qiskit.circuit.library import RealAmplitudes
ansatz = RealAmplitudes(num_qubits=2, reps=2)
# Search for better states using SPSA algorithm
from qiskit.algorithms.optimizers import SPSA
optimizer = SPSA(150)
# Set a starting point for reproduceability
import numpy as np
np.random.seed(6)
initial_point = np.random.uniform(-np.pi, np.pi, 12)
# Create an object to store intermediate results
from dataclasses import dataclass
@dataclass
class VQELog:
values: list
parameters: list
def update(self, count, parameters, mean, _metadata):
self.values.append(mean)
self.parameters.append(parameters)
print(f"Running circuit {count} of ~350", end="\r", flush=True)
log = VQELog([], [])
```

The next code cell runs the VQE algorithm. If you chose to run on a real device, the code runs zero-noise extrapolation on the final result to estimate the effects of noise, and guess what the result would be from a noiseless device.

```
[5]:
```

```
# Main calculation
with Session(service=service, backend=backend) as session:
options = Options()
options.optimization_level = 3
vqe = VQE(
Estimator(session=session, options=options),
ansatz,
optimizer,
callback=log.update,
initial_point=initial_point,
)
result = vqe.compute_minimum_eigenvalue(hamiltonian)
print("Experiment complete.".ljust(30))
print(f"Raw result: {result.optimal_value}")
if "simulator" not in backend:
# Run once with ZNE error mitigation
options.resilience_level = 2
vqe = VQE(
Estimator(session=session, options=options),
ansatz,
SPSA(1),
initial_point=result.optimal_point,
)
result = vqe.compute_minimum_eigenvalue(hamiltonian)
print(f"Mitigated result: {result.optimal_value}")
```

```
Experiment complete.
Raw result: -1.867238744921776
```

Finally, the following code cell plots the intermediate results from the optimization process. The optimization algorithm tweaks the parameters to gradually home in on values that produce lower energies. Provided the algorithm does not get caught in a local minima, this graph will plateau at the electronic ground state energy of the molecule.

```
[6]:
```

```
import matplotlib.pyplot as plt
plt.rcParams["font.size"] = 14
# Plot energy and reference value
plt.figure(figsize=(12, 6))
plt.plot(log.values, label="Estimator VQE")
plt.axhline(y=real_solution.groundenergy, color="tab:red", ls="--", label="Target")
plt.legend(loc="best")
plt.xlabel("Iteration")
plt.ylabel("Energy [H]")
plt.title("VQE energy")
plt.show()
```

```
[7]:
```

```
import qiskit_ibm_runtime
qiskit_ibm_runtime.version.get_version_info()
```

```
[7]:
```

```
'0.8.0'
```

```
[10]:
```

```
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
```

### Version Information

Qiskit Software | Version |
---|---|

`qiskit-terra` | 0.23.1 |

`qiskit-aer` | 0.11.2 |

`qiskit-ibmq-provider` | 0.20.0 |

`qiskit` | 0.41.0 |

`qiskit-nature` | 0.5.2 |

System information | |

Python version | 3.10.6 |

Python compiler | Clang 13.1.6 (clang-1316.0.21.2.5) |

Python build | main, Aug 11 2022 13:49:25 |

OS | Darwin |

CPUs | 8 |

Memory (Gb) | 32.0 |

Mon Feb 20 12:12:03 2023 GMT |

### This code is a part of Qiskit

© Copyright IBM 2017, 2023.

This code is licensed under the Apache License, Version 2.0. You may

obtain a copy of this license in the LICENSE.txt file in the root directory

of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this

copyright notice, and modified files need to carry a notice indicating

that they have been altered from the originals.