This notebook is a short example of how to use the Ising solver implemented using the QAOA algorithm. We start by declaring the import of the ising function.


In [ ]:
from mock import patch, Mock
from pyquil.api import WavefunctionSimulator

from grove.ising.ising_qaoa import ising

This code finds the global minima of an Ising model with external fields of the form $$f(x)= \Sigma_i h_i x_i + \Sigma_{i,j} J_{i,j} x_i x_j.$$ Two adjacent sites $i,j$ have an interaction equal to $J_{i,j}$. There is also an external magnetic field $h_i$ that affects each individual spin. The discrete variables take the values $x_i \in \{+1,-1\}$.

In order to assert the correctness of the code we will find the minima of the following Ising model $$f(x)=x_0+x_1-x_2+x_3-2 x_0 x_1 +3 x_2 x_3.$$ Which corresponds to $x_{min}=[-1, -1, 1, -1]$ in numerical order, with a minimum value of $f(x_{min})=-9$.

This Ising code runs on quantum hardware, which means that we need to specify a connection to a QVM or QPU. Due to the absence of a real connection in this notebook, we will mock out the response to correspond to the expected value. In order to run this notebook on a QVM or QPU, replace cxn with a valid PyQuil connection object.

The input for the code in the default mode corresponds simply to the parameters $h_i$ and $J_{i,j}$, that we specify as a list in numerical order and a dictionary. The code returns the bitstring of the minima, the minimum value, and the QAOA quantum circuit used to obtain that result.


In [ ]:
with patch("pyquil.api.QuantumComputer") as qc, \
        patch("grove.pyvqe.vqe.WavefunctionSimulator") as wfs:
        qc.run.return_value = [[1,1,0,1]]
        
        fake_wfs = Mock(WavefunctionSimulator)
        fake_wfs.expectation.return_value = [-0.4893891813015294,
                                             0.8876822987380573,
                                             -0.4893891813015292,
                                             -0.9333372094534063,
                                             -0.9859245403423198,
                                             0.9333372094534065]
        wfs.return_value = fake_wfs
        
        J = {(0, 1): -2, (2, 3): 3}
        h = [1, 1, -1, 1]

        solution, min_energy, circuit = ising(h, J, connection=qc)

It is also possible to specify the Trotterization order for the QAOA algorithm used to implement the Ising model. By default this value is equal to double the number of variables. It is also possible to change the verbosity of the function, which is True by default. There are more advanced parameters that can be specified and are not described here.


In [ ]:
with patch("pyquil.api.QuantumComputer") as qc, \
        patch("grove.pyvqe.vqe.WavefunctionSimulator") as wfs:
        qc.run.return_value = [[1,1,0,1]]
        
        fake_wfs = Mock(WavefunctionSimulator)
        fake_wfs.expectation.return_value = [-0.4893891813015294,
                                             0.8876822987380573,
                                             -0.4893891813015292,
                                             -0.9333372094534063,
                                             -0.9859245403423198,
                                             0.9333372094534065]
        wfs.return_value = fake_wfs

        solution_2, min_energy_2, circuit_2 = ising(h, J, num_steps=9, verbose=False, connection=qc)

For large Ising problems, or those with many and close suboptimal minima, it is possible for the code to not return the global minima. Increasing the number of steps can solve this problem.

Finally, we will check if the correct bitstring was found, corresponding to the global minima, in both runs.


In [ ]:
assert solution == [-1, -1, 1, -1], "Found bitstring for first run does not correspond to global minima"
print("Energy for first run solution:", min_energy)
assert min_energy == -9
assert solution_2 == [-1, -1, 1, -1], "Found bitstring for second run does not correspond to global minima"
print("Energy for second run solution:", min_energy_2)
assert min_energy_2 == -9

If the assertions succeeded, and the energy was equal to $-9$, we have found the correct solution for both runs.