Using QAOA with PennyLane¶
In this Jupyter Note Book, we will go through how to run a QAOA problem via PennyLane step by step. PennyLane provides a couple of handy ways to define a QAOA problem that can save our time, let's explore PennyLane's potential together!
First, we are going to learn how to set up a Hamiltonian via PennyLane. You should already know that we can use @
as a tensor product in PennyLane to help us represent the circuit more easiler. Please run the following code to construct a Hamiltonian:
import pennylane as qml
from pennylane import PauliZ
# setting Hamiltonian's coefficients & PauliZ
coefficients = [2, -1, 3.5]
Paulis = [PauliZ(0)@PauliZ(1), PauliZ(0)@PauliZ(2), PauliZ(2)@PauliZ(1)]
H = qml.Hamiltonian(coefficients, Paulis)
# Print out our problem
print(H)
# Print out matrix form of our Hamiltonian
print(qml.matrix(H))
2 * (Z(0) @ Z(1)) + -1 * (Z(0) @ Z(2)) + 3.5 * (Z(2) @ Z(1)) [[ 4.5+0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j] [ 0. +0.j -0.5+0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j] [ 0. +0.j 0. +0.j -6.5+0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j] [ 0. +0.j 0. +0.j 0. +0.j 2.5+0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j] [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j 2.5+0.j 0. +0.j 0. +0.j 0. +0.j] [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j -6.5+0.j 0. +0.j 0. +0.j] [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j -0.5+0.j 0. +0.j] [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 4.5+0.j]]
You should see a matrix representation of our Hamiltonian.
Now we know how to define Hamiltonian, we can use them to create QAOA circuits with PennyLane. Let's import qaoa
module, which will give us access to the cost_layer
and mixer_layer
functions. There are two kinds of layers that we will be going to define:
- The
cost_layer
: for encoding our problem. - The
mixer_layr
: for $\sum_{j} X_{j}$ = $H_{0}$, which is sometimes called the mixer Hamiltonian in QAOA structure.
By combining these two layers, we can construct our QAOA problem and calculate its energy of the state wrt $H_1$. This can be done esaily in Pennylane through expval
function. Please see the following code for defining our QAOA problem.
The following code consist of these elements:
- Defining our $H_{0}$ as $X_{0} + X_{1}$ with
qml.PauliX(0) + qml.PauliX(1)
. - Defining $H_1$ by using
1.0*qml.PauliZ(0) @ qml.PauliZ(1)
.- 1.0 coefficient must be included to complete the tensor product to convert to Hamiltonian object.
- The
energy
function only receives as parameters the angles for the rotation in the QAOA curcuit. - We declared
p
as a glabal variable since we want to optimizaenergy
wrt its parameters andp
is not something we want to optimize. - The exponentials for $H_1$ and $H_0$ receive their parameters from the
angles
list. - If
angles
is[1.0, 2.0, 3.0, 4.0]
, then we would have $\beta_{1} = 1.0$, $\gamma_{2} = 2.0$, $\beta_{2} = 3.0$, and $\gamma_{2} = 4.0$.
from pennylane import qaoa
# Define H0 and H1
H0 = qml.PauliX(0) + qml.PauliX(1)
H1 = 1.0*qml.PauliZ(0) @ qml.PauliZ(1) # 1.0 coefficient must be included to complete the tensor product to convert to Hamiltonian object.
wires = range(2)
dev = qml.device("default.qubit", wires = wires)
# set p = 2.
p = 2
@qml.qnode(dev)
def energy(angles):
for w in wires:
qml.Hadamard(wires=w)
for i in range(p):
# Both H0 and H1 receive their parameters from the `angle` list.
qaoa.cost_layer(angles[2*i+1], H1)
qaoa.mixer_layer(angles[2*i], H0)
return qml.expval(H1)
Now, let's run the optimization via the following code:
from pennylane import numpy as np
# Choose a optimizer
optimzer = qml.GradientDescentOptimizer()
# Define
steps = 20
# Initial angles
angles = np.array([1.0,1.0,1.0,1.0], requires_grad = True)
for i in range(steps):
angles = optimzer.step(energy, angles)
print("Optimal angles", angles)
Optimal angles [0.78884013 0.71892439 1.17959579 1.28138806]
The result shows that the optimal parameters [$\beta_{1}$, $\gamma_{1}$, $\beta_{2}$, $\gamma_{2}$].
One of the useful function that PennyLane provides is it ability to automatically calculate the deritative of the object function. To use this, we need to ser requires_grad = TRUE
when defining the initail angles.
We can now sample from the QAOA circuit with the parameters that we have found to obtain condidate to our problem. Let's run the following code:
@qml.qnode(dev)
def sample_solutions(angles):
for w in wires:
qml.Hadamard(wires=w)
for i in range(p):
# Both H0 and H1 receive their parameters from the `angle` list.
qaoa.cost_layer(angles[2*i+1], H1)
qaoa.mixer_layer(angles[2*i], H0)
return qml.sample()
print(sample_solutions(angles, shots = 5))
[[0 1] [0 1] [1 0] [0 1] [0 1]]
You can get a list of state results show the ground states of $Z_{0}Z_{1}$.
Summary¶
You know how to run a QAOA problem on PennyLane and here are what you have learned so far:
- How to set up Hamiltonian in PennyLane.
- You know that PennyLane takes
angles
as input for Hamiltonian parameters. - You can choose different classical optimizer that fit the best to your model.
- You know that PennyLane can do differentiation automatically by setting the correct code.