Hi!
I am new to Pennylane, and have some questions regarding how to gain some speedups with some of the code that I have. My goal is to see how QAOA performs with both increasing graph sizes and depth. In order to get some data, I need to run the simulations multiple times, however, my code quickly becomes inefficient as I increase the number of qubits or the depth of the QAOA circuit. So I’m curious about 3 things:
Which qubit device is recommended to use to get increased speed? (I am currently using default.qubit)
Is there any efficient way to run the optimization? (possibly jit-ing the computations?)
I calculate the expectation-value of the hamiltonian using the ExpVal function. Is there an argument that can be passed to increase the speed of these evaluations?
Currently, running a 6 qubit system on a regular 3-degree graph requires around 15 minutes to run.
Here is some of the code that I have written. Note that the “edges” structure in my case is essentially just a list with tuples (i,j,w) that describe the edges with their corresponding weights, while graph is a networkx class. Out of these classes, it is QAOA complete in particular I think that is the slowest part of the code, so any help in speeding that part of the code would be incredibly helpful. Thanks in advance for any tips
Here is the python file if it is easier to read off that: QAOA-MaxcutAttempt.py (10.5 KB)
def ProblemUnitary(edge1,edge2,t,weight):
"""Creates the problem unitary which is specific to MaxCut. Applies e^{-i t H_c}
Args:
edge1 ([int]): [The control qubit]
edge2 ([int]): [The target qubit]
t ([type]): [The t in the expression]
weight ([float]): [weight of the edge between the nodes in the graph]
"""
qml.CNOT(wires = [edge1,edge2])
qml.RZ(2*t*weight,wires = edge2)
qml.CNOT(wires = [edge1,edge2])
def MixerUnitary(edge1,t):
"""Creates the mixer unitary given by e^{-i t\sum_i X_i}. In this function, it is decomposed into a Rz rotation
Args:
edge1 ([int]): [The edge to apply the circuit on]
t ([float]): [The t in the expression]
"""
qml.Hadamard(wires = edge1)
qml.RZ(2*t,wires = edge1)
qml.Hadamard(wires = edge1)
def OneLayer(gamma,beta):
"""Create the one layer of the QAOA algorithm
Args:
gamma ([float]): [The k'th value of gamma]
beta ([float]): [The k'th value of beta]
"""
for i,j,w in edges:
ProblemUnitary(i,j,gamma,w)
for i in graph.nodes():
MixerUnitary(i,beta)
def QAOAMaxCutAnsatz(parameters,**kwargs):
#This creates the QAOA ansatz
if len(np.shape(parameters))== 2:
p = len(parameters[0])
else:
p = len(parameters)//2
for i in range(len(graph.nodes())):
qml.Hadamard(wires = i)
for i in range(p):
if len(np.shape(parameters))== 2:
OneLayer(parameters[0][i],parameters[1][i])
else:
OneLayer(parameters[0:p][i],parameters[p:][i])
#return [qml.sample(qml.PauliZ(i)) for i in range(len(graph.nodes()))]
def QAOAcomplete(p,init_parameters, Hamiltonian, dev, graph, steps = 200):
params = init_parameters
cost_function = qml.ExpvalCost(QAOAMaxCutAnsatz, Hamiltonian,dev, graph = graph) #diff_method = autograd currently
opt = qml.AdamOptimizer()
for i in range(steps):
params = opt.step(cost_function,params)
if (i+1)%steps == 0:
print(f'objective after step {i+1}: {cost_function(params)}')
return params,cost_function(params)