Hi everyone, I would like to make this code work but in PennyLane:
from docplex.mp.model import Model
from qiskit_optimization.problems import QuadraticProgram
from qiskit_optimization.translators import from_docplex_mp
import matplotlib.pyplot as plt
import networkx as nx
#QAOA
from qiskit.algorithms.minimum_eigensolvers import QAOA
from qiskit.algorithms.optimizers import COBYLA
from qiskit.primitives import Sampler
#VQE
from qiskit.algorithms.optimizers import SPSA
from qiskit.circuit.library import TwoLocal
from qiskit.primitives import Sampler
from qiskit.algorithms.minimum_eigensolvers import SamplingVQE
edges = [(0, 1), (1, 2), (2, 0), (2, 3)]
G = nx.Graph(edges)
nx.draw(G, with_labels=True)
# Parameters of the problem.
a = 4.0
b = 1.0
N = G.number_of_nodes()
# Optimizer
optimizerQAOA = COBYLA()
optimizerVQE = SPSA(maxiter=300)
mdl = Model()
# Here, we define the binary variable X_i.
x = {i: mdl.binary_var(name=f'x_{i}') for i in range(N)}
# For the sake of readability, we have subdivided H_a into three distinct equations,
# with each equation mirroring the one previously explained, partitioned by the addition operator (+).
one = a * mdl.sum((1 - x[u]) * (1 - x[v]) for u in range(N) for v in range(N) if v in G[u])
two = b * mdl.sum(x[v] for v in range(N))
# Here we combine the two equations to form the entire Hamiltonian.
objective = one + two
# We decide to minimize the problem.
mdl.minimize(objective)
# We transform the Hamiltonian equation into a Qubo for Qiskit.
qp = from_docplex_mp(mdl)
# Finally, we create the Ising model with the Qubo for Qiskit.
H, offset = QuadraticProgram.to_ising(qp)
print('Offset:', offset)
print('Ising Hamiltonian:')
print(H)
The two problems are:
- If I extract the Pauli-String and give it to PennyLane, the result is not the same and not correct.
- The second one is if I use the method implemented by PennyLane for the vertex cover, I don’t obtain the same result. I also saw that if I change the coefficients before
cost_h = 3 * edge_driver(graph, ["11", "10", "01"]) + bit_driver(graph_nodes, 0)
for another one than 3, the result is completely false. However, with my comprehension of Hamiltonian, the behavior should not be like that.
So, I want to know if it’s me who doesn’t understand something specific or if the way Hamiltonian works is different between Qiskit and PennyLane or something else.
Furthermore, for additional information, I have the same number of operators, but the coefficients differ, and based on my understanding, PennyLane seems to be quite sensitive to coefficients.
Here is my code in PennyLane:
# G = nx.circular_ladder_graph(5)
edges = [(0, 1), (1, 2), (2, 0), (2, 3)]
G = nx.Graph(edges)
nx.draw(G, with_labels=True)
def test1():
coeffs = [-1 for _ in G.nodes()]
ops = [qml.PauliZ(w) for w in G.nodes()]
return qml.Hamiltonian(coeffs, ops)
def test2():
coeffs = []
ops = []
for e in G.edges:
sign = 1
coeffs.extend([0.25, 0.25, 0.25])
ops.extend(
[
qml.PauliZ(e[0]) @ qml.PauliZ(e[1]),
qml.PauliZ(e[0]),
qml.PauliZ(e[1]),
]
)
return qml.Hamiltonian(coeffs, ops)
wires = range(len(G.nodes()))
depth = 2
# This is in case you want to try the Pauli string that I got from Qiskit
coeffs = [3.5, 3.5, 5.5, 1.5, 2.0, 2.0, 2.0, 2.0]
ops = [
qml.PauliZ(0),
qml.PauliZ(1),
qml.PauliZ(2),
qml.PauliZ(3),
qml.PauliZ(0) @ qml.PauliZ(1),
qml.PauliZ(0) @ qml.PauliZ(2),
qml.PauliZ(1) @ qml.PauliZ(2),
qml.PauliZ(2) @ qml.PauliZ(3),
]
cost_h = (3 * test2()) + test1()
mixer_h = qaoa.x_mixer(G.nodes)
def qaoa_layer(gamma, alpha):
qaoa.cost_layer(gamma, cost_h)
qaoa.mixer_layer(alpha, mixer_h)
def circuit(params, **kwargs):
for w in wires:
qml.Hadamard(wires=w)
qml.layer(qaoa_layer, depth, params[0], params[1])
dev = qml.device("default.qubit", wires=wires)
@qml.qnode(dev)
def cost_function(params):
circuit(params)
return qml.expval(cost_h)
optimizer = qml.GradientDescentOptimizer()
steps = 70
params = np.array([[0.5, 0.5], [0.5, 0.5]], requires_grad=True)
for i in range(steps):
params = optimizer.step(cost_function, params)
print("Optimal Parameters")
print(params)
@qml.qnode(dev)
def probability_circuit(gamma, alpha):
circuit([gamma, alpha])
return qml.probs(wires=wires)
probs = probability_circuit(params[0], params[1])
plt.style.use("seaborn")
plt.bar(range(2 ** len(wires)), probs)
plt.show()
Thank you in advance for your response.
Name: PennyLane Version: 0.33.0 Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc. Home-page: GitHub - PennyLaneAI/pennylane: PennyLane is a cross-platform Python library for differentiable programming of quantum computers. Train a quantum computer the same way as a neural network. Author: Author-email: License: Apache License 2.0 Location: /opt/homebrew/lib/python3.11/site-packages Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions Required-by: PennyLane-Lightning Platform info: macOS-13.0-arm64-arm-64bit Python version: 3.11.2 Numpy version: 1.23.5 Scipy version: 1.10.1 Installed devices: - lightning.qubit (PennyLane-Lightning-0.33.1) - default.gaussian (PennyLane-0.33.0) - default.mixed (PennyLane-0.33.0) - default.qubit (PennyLane-0.33.0) - default.qubit.autograd (PennyLane-0.33.0) - default.qubit.jax (PennyLane-0.33.0) - default.qubit.legacy (PennyLane-0.33.0) - default.qubit.tf (PennyLane-0.33.0) - default.qubit.torch (PennyLane-0.33.0) - default.qutrit (PennyLane-0.33.0) - null.qubit (PennyLane-0.33.0)