Getting started with Variational Quantum Eigensolving¶

Here, we show how to find a variational ground state to the following Hamiltonian:

$$ H = \vec{\sigma}_1\cdot \vec{\sigma}_2 = \sigma^X_1 \sigma^X_2 + \sigma^Y_1 \sigma^Y_2 + \sigma^Z_1 \sigma^Z_2 $$

We start by defining the Hamiltonian (in the form of an observable), and choose a variational circuit with two parameters:

In [1]:
from qat.core import Observable, Term
from qat.lang.AQASM import Program, CNOT, H, RX, RY, RZ
H_XY = Observable(2, 
                  pauli_terms=[Term(1., "XX", [0, 1]),
                               Term(1., "YY", [0, 1]),
                               Term(1., "ZZ", [0, 1])]
                  )
print("Hamiltonian:", H_XY)

prog = Program()
qbits = prog.qalloc(2)

alpha = prog.new_var(float, "\\alpha")
beta = prog.new_var(float, "\\beta")
gamma = prog.new_var(float, "\\gamma")
prog.apply(H, qbits[0])
prog.apply(RY(alpha), qbits[1])
prog.apply(CNOT, qbits)
prog.apply(RX(beta), qbits[0])
prog.apply(RY(gamma), qbits[1])

circuit = prog.to_circ()

circuit.display()
Hamiltonian: 1.0 * (XX|[0, 1]) +
1.0 * (YY|[0, 1]) +
1.0 * (ZZ|[0, 1])
No description has been provided for this image

Optimization¶

We now perform the optimization, using a Variational Plugin:

In [2]:
from qat.plugins import ScipyMinimizePlugin
from qat.qpus import LinAlg

linalg_qpu = LinAlg()
theta0 = [0.4, -0.3, 0.6]

optimizer_scipy = ScipyMinimizePlugin(method="COBYLA",
                                      x0=theta0,
                                      tol=1e-3,
                                      options={"maxiter": 2000})

qpu = optimizer_scipy | linalg_qpu

job = circuit.to_job(job_type="OBS", observable=H_XY)

result = qpu.submit(job)

print("Minimum energy =", result.value)
print("Optimal angles =", result.meta_data["parameters"])
#print("==========Optimization data=============\n", result.meta_data['optimization_trace'])

%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(eval(result.meta_data['optimization_trace']))
plt.xlabel("Steps")
plt.ylabel("Energy");
Minimum energy = -2.999999985437741
Optimal angles = [np.float64(-0.00010707754003805325), np.float64(-4.10250986041513e-05), np.float64(3.1415550557015255)]
No description has been provided for this image

True ground state¶

In this simple case, we can compute the ground state energy by diagonalizing the matrix corresponding to the Hamiltonian:

In [3]:
import numpy as np
from qat.fermion import SpinHamiltonian

H_XY_spin = SpinHamiltonian(nqbits=H_XY.nbqbits, terms=H_XY.terms)
H_XY_matrix = H_XY_spin.get_matrix()

eigvals, eigvecs = np.linalg.eigh(H_XY_matrix)
print("Exact ground state energy: ", min(eigvals))
Exact ground state energy:  -3.0

Going further:¶

  • play with the Hamiltonian
  • play with the ansatz
  • play with the QPU: try with a noisy QPU
  • play with the optimizer (change the method)