Note

This page was generated from tutorials/algorithms/04_vqd.ipynb.

# Variational Quantum Deflation (VQD) Algorithm¶

This notebook demostrates how to use Qiskit’s implementation of the Variational Quantum Deflation (VQD) algorithm for computing higher energy states of a Hamiltonian, as introduced in this reference paper.

## Introduction¶

VQD is a quantum algorithm that uses a variational technique to find the *k* eigenvalues of the Hamiltonian *H* of a given system.

The algorithm computes excited state energies of generalized hamiltonians by optimizing over a modified cost function. Each successive eigenvalue is calculated iteratively by introducing an overlap term with all the previously computed eigenstates that must be minimized. This ensures that higher energy eigenstates are found.

## Complete working example for VQD¶

The first step of the VQD workflow is to create a qubit operator, ansatz and optimizer. For this example, you can use the H2 molecule, which should already look familiar if you have completed the previous VQE tutorials:

```
[1]:
```

```
from qiskit.quantum_info import SparsePauliOp
H2_op = SparsePauliOp.from_list(
[
("II", -1.052373245772859),
("IZ", 0.39793742484318045),
("ZI", -0.39793742484318045),
("ZZ", -0.01128010425623538),
("XX", 0.18093119978423156),
]
)
```

You can set up, for example, a `TwoLocal`

ansatz with three qubits, and choose `SLSQP`

as the optimization method.

```
[2]:
```

```
from qiskit.circuit.library import TwoLocal
from qiskit.algorithms.optimizers import SLSQP
ansatz = TwoLocal(3, rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1)
optimizer = SLSQP()
ansatz.decompose().draw('mpl')
```

```
[2]:
```

The next step of the workflow is to define the required primitives for running `VQD`

. This algorithm requires two different primitive instances: one `Estimator`

for computing the expectation values for the “VQE part” of the algorithm, and one `Sampler`

. The sampler will be passed along to the `StateFidelity`

subroutine that will be used to compute the cost for higher energy states. There are several methods that you can use to compute state fidelities, but to keep things simple, you can
use the `ComputeUncompute`

method already available in `qiskit.algorithm.state_fidelities`

.

```
[3]:
```

```
from qiskit.primitives import Sampler, Estimator
from qiskit.algorithms.state_fidelities import ComputeUncompute
estimator = Estimator()
sampler = Sampler()
fidelity = ComputeUncompute(sampler)
```

In order to set up the VQD algorithm, it is important to define two additional inputs: the number of energy states to compute (`k`

) and the `betas`

defined in the original VQD paper. In this example, the number of states (`k`

) will be set to three, which indicates that two excited states will be computed in addition to the ground state.

The `betas`

balance the contribution of each overlap term to the cost function, and they are an optional argument in the `VQD`

construction. If not set by the user, they can be autoevaluated for input operators of type `SparsePauliOp`

. Please note that if you want to set your own `betas`

, you should provide a list of values of length `k`

.

```
[4]:
```

```
k = 3
betas = [33, 33, 33]
```

You are almost ready to run the VQD algorithm, but let’s define a callback first to store intermediate values:

```
[5]:
```

```
counts = []
values = []
steps = []
def callback(eval_count, params, value, meta, step):
counts.append(eval_count)
values.append(value)
steps.append(step)
```

You can finally instantiate `VQD`

and compute the eigenvalues for the chosen operator.

```
[6]:
```

```
from qiskit.algorithms.eigensolvers import VQD
vqd = VQD(estimator, fidelity, ansatz, optimizer, k=k, betas=betas, callback=callback)
result = vqd.compute_eigenvalues(operator = H2_op)
vqd_values = result.optimal_values
```

You can see the three state energies as part of the `VQD`

result:

```
[7]:
```

```
print(vqd_values)
```

```
[[ 6.50666726e+00 1.57092278e+00 -4.42002213e+00 6.28301704e+00
3.14186318e+00 4.71259441e+00 2.53642130e+00 -2.46763103e+00]
[ 3.14177580e+00 3.14158705e+00 -4.73432158e+00 4.84912617e+00
3.14189116e+00 3.14153735e+00 2.45706137e+00 -1.84790579e+00]
[-9.59481229e-04 3.14200056e+00 -3.43129600e+00 1.04023754e+01
3.14272052e+00 3.49113195e-04 2.33552038e+00 -1.74856210e+00]
[-9.59481229e-04 3.14200056e+00 -3.43129600e+00 1.04023754e+01
3.14272052e+00 3.49113195e-04 2.33552038e+00 -1.74856210e+00]]
```

And we can use the values stored by the callback to plot the energy convergence for each state:

```
[8]:
```

```
import numpy as np
import pylab
pylab.rcParams["figure.figsize"] = (12, 8)
steps = np.asarray(steps)
counts = np.asarray(counts)
values = np.asarray(values)
for i in range(1,4):
_counts = counts[np.where(steps == i)]
_values = values[np.where(steps == i)]
pylab.plot(_counts, _values, label=f"State {i-1}")
pylab.xlabel("Eval count")
pylab.ylabel("Energy")
pylab.title("Energy convergence for each computed state")
pylab.legend(loc="upper right");
```

This molecule can be solved exactly using the `NumPyEigensolver`

class, which will give a reference value that you can compare with the `VQD`

result:

```
[9]:
```

```
from qiskit.algorithms.eigensolvers import NumPyEigensolver
from qiskit.opflow import PauliSumOp
exact_solver = NumPyEigensolver(k=3)
exact_result = exact_solver.compute_eigenvalues(PauliSumOp(H2_op))
ref_values = exact_result.eigenvalues
```

```
/tmp/ipykernel_3949/257437797.py:5: DeprecationWarning: The class ``qiskit.opflow.primitive_ops.pauli_sum_op.PauliSumOp`` is deprecated as of qiskit-terra 0.24.0. It will be removed no earlier than 3 months after the release date. For code migration guidelines, visit https://qisk.it/opflow_migration.
exact_result = exact_solver.compute_eigenvalues(PauliSumOp(H2_op))
```

Let’s see a comparison of the exact result with the previously computed `VQD`

eigenvalues:

```
[10]:
```

```
print(f"Reference values: {ref_values}")
print(f"VQD values: {vqd_values}")
```

```
Reference values: [-1.85727503 -1.24458455 -0.88272215]
VQD values: [[ 6.50666726e+00 1.57092278e+00 -4.42002213e+00 6.28301704e+00
3.14186318e+00 4.71259441e+00 2.53642130e+00 -2.46763103e+00]
[ 3.14177580e+00 3.14158705e+00 -4.73432158e+00 4.84912617e+00
3.14189116e+00 3.14153735e+00 2.45706137e+00 -1.84790579e+00]
[-9.59481229e-04 3.14200056e+00 -3.43129600e+00 1.04023754e+01
3.14272052e+00 3.49113195e-04 2.33552038e+00 -1.74856210e+00]
[-9.59481229e-04 3.14200056e+00 -3.43129600e+00 1.04023754e+01
3.14272052e+00 3.49113195e-04 2.33552038e+00 -1.74856210e+00]]
```

As you can see, the result from VQD matches the values from the exact solution, and extends VQE to also compute excited states.

```
[11]:
```

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

### Version Information

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

`qiskit-terra` | 0.24.1 |

`qiskit-aer` | 0.12.0 |

`qiskit-ibmq-provider` | 0.20.2 |

`qiskit` | 0.43.1 |

`qiskit-nature` | 0.6.2 |

`qiskit-finance` | 0.3.4 |

`qiskit-optimization` | 0.5.0 |

`qiskit-machine-learning` | 0.6.1 |

System information | |

Python version | 3.8.16 |

Python compiler | GCC 11.3.0 |

Python build | default, Jan 11 2023 00:28:51 |

OS | Linux |

CPUs | 2 |

Memory (Gb) | 6.7812042236328125 |

Fri Jun 09 12:47:08 2023 UTC |

### 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.