Train parameters on a Hamiltonian

Hi, I hope you are doing well!

I am trying to retrieve a target state introducing an input Hamiltonian with two trainable parameters and using the infidelity as cost function. Here is a snippet of the code

import numpy as np
import pennylane as qml
from pennylane import numpy as qnp

# Target state
target = np.array([0,0,0,1])

# Circuit + cost function definition
@qml.qnode(device=qml.device('default.qubit', wires=2), interface='autograd')
def circuit(params):
    H = sum([params[i]*(qml.PauliX(i) + qml.PauliZ(i)) for i in range(2)])
    qml.exp(H, coeff=-0.5j)
    return qml.state()
def cost_fn(params):
    return 1-abs(np.dot(circuit(params), target))**2 # infidelity

# Select optimizer + trainable parameters initialization
opt = qml.GradientDescentOptimizer()
theta = qnp.array([0.0, 0.0], requires_grad=True)

# Store infidelities to track convergence
infidelity = [cost_fn(theta)]

max_iterations = 100
conv_tol = 1e-03

for n in range(max_iterations):
    theta, prev_infid = opt.step_and_cost(cost_fn, theta)

    infidelity.append(cost_fn(theta))

    conv = np.abs(infidelity[-1] - prev_infid)
    if n % 2 == 0:
        print(f"Step = {n}, Infidelity = {infidelity[-1]:.8f}")
    if conv <= conv_tol:
        break

print("\n" f"Final infidelity = {infidelity[-1]:.8f}")

The error shown is

TypeError: Can't differentiate w.r.t. type <class 'pennylane.ops.qubit.hamiltonian.Hamiltonian'>

Since I am new using PennyLane, probably I am not coding it properly. I have tried but I did not find references regarding this error.

Thanks in advance for your time and have a nice day.

Hi @sebastianvromero

The issue is happening because you’re trying to create a parametrized hamiltonian and differentiate with respect to that. Unfortunately PennyLane doesn’t allow this the way you have it coded. You can try however using the JAX interface and using qml.evolve() to evolve your hamiltonian as needed. Below is a code example that can help you. Notice how we make the hamiltonian evolve within a timeframe specified by t.

import jax
import pennylane as qml

coeffs = [lambda p, t: p * t for _ in range(4)]
ops = [qml.PauliX(i) for i in range(4)]

# ParametrizedHamiltonian
H = qml.dot(coeffs, ops)

# ParametrizedEvolution
ev = qml.evolve(H)

dev = qml.device("default.qubit.jax", wires=4)

@qml.qnode(dev, interface="jax")
def circuit(params):
    qml.evolve(H)(params, t=[0, 0.5])
    return qml.expval(qml.PauliZ(0))

params = [1., 2., 3., 4.]
circuit(params)

Please let me know if this helps or if you have any further questions about this!