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)

