Hi all,
I’m having troubles with the lightning.qubit object of Pennylane. From my understanding, it should behave pretty much like the default.qubit object, but with a C++ backend. However, this code works with the default.qubit object and not the lightning.qubit, and furthermore I get a weird error message.
To explain exactly what I’m trying to do, I just want to define a circuit that we can apply some layers to, and then, with an optimizer, find the weights that minimize a given Hamiltonian. The problem arrises when I use an arbitrary unitary matrix for the transformation in my layer instead of a rotation. I also want to point out that the circuit with layerXX works fine if it is not executing in the optimizer.
import pennylane as qml
from pennylane import numpy as np
# Define layers
def layerR(W):
    qml.Rot(W[0, 0], W[0, 1], W[0, 2], wires=0)
    qml.Rot(W[1, 0], W[1, 1], W[1, 2], wires=1)
    qml.Rot(W[2, 0], W[2, 1], W[2, 2], wires=2)
    qml.Rot(W[3, 0], W[3, 1], W[3, 2], wires=3)
    qml.CNOT(wires=[0, 1])
    qml.CNOT(wires=[1, 2])
    qml.CNOT(wires=[2, 3])
    qml.CNOT(wires=[3, 0])
def layerXX(W):
    # circX() is a function that returns a unitary matrix as a 4x4 numpy array
    qml.QubitUnitary(circX(W[0, 0], W[0, 1], W[0, 2]), wires=[0, 1])
    qml.QubitUnitary(circX(W[0, 0], W[0, 1], W[0, 2]), wires=[2, 3])
    qml.SQISW(wires=[1, 2])
    qml.SQISW(wires=[0, 3])
# Define quantum circuits
def circuit(layer, hamiltonian, weights):
    qml.BasisState([0, 0, 0, 0], wires=[0, 1, 2, 3])
    for w in weights:
        layer(w)
    return qml.expval(hamiltonian)
ham4terms = qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliZ(2) @ qml.PauliZ(3)
tfield = 1.0 * (qml.PauliX(0) + qml.PauliX(1) + qml.PauliX(2) + qml.PauliX(3))
H = -ham4terms + tfield
def experience(label, layer, H, num_qubits, num_layers, scale, *args):
    print(label + ":")
    # Replace by dev = qml.device("default.qubit", wires=4) if you want it to work
    dev = qml.device("lightning.qubit", wires=4)
    @qml.qnode(dev, interface="autograd")
    def current_circuit(weights):
        return circuit(layer, H, weights)
    # Initialize weights
    np.random.seed(0)
    weights_init = scale * np.random.randn(
        num_layers, num_qubits, 3, requires_grad=True
    )
    # bias_init = np.array(0.0, requires_grad=True)
    opt = qml.NesterovMomentumOptimizer(args[0], args[1])
    weights = weights_init
    for it in range(40):
        weights = opt.step(current_circuit, weights)
        if (it + 1) % 10 == 0:
            print(
                "Iter: {:5d} | Energy: {:0.7f}".format(it + 1, current_circuit(weights))
            )
    print("")
if __name__ == "__main__":
    experience("Circuit R", layerR, H, 4, 1, 0.5, 0.2, 0.1)
    experience("Circuit XX", layerXX, H, 2, 2, 0.5, 0.2, 0.1)
The error stack is:
Traceback (most recent call last):
  File "autograd\core.py", line 31, in __init__
    vjpmaker = primitive_vjps[fun]
KeyError: <function primitive.<locals>.f_wrapped at 0x000002114435A040>
During handling of the above exception, another exception occurred:
  [...]
  File "pennylane\optimize\gradient_descent.py", line 93, in step
    g, _ = self.compute_grad(objective_fn, args, kwargs, grad_fn=grad_fn)
  File "pennylane\optimize\nesterov_momentum.py", line 76, in compute_grad
    grad = g(*shifted_args, **kwargs)
  File "pennylane\_grad.py", line 165, in __call__
    grad_value, ans = grad_fn(*args, **kwargs)  # pylint: disable=not-callable
  File "autograd\wrap_util.py", line 20, in nary_f
    return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
  File "pennylane\_grad.py", line 183, in _grad_with_forward
    vjp, ans = _make_vjp(fun, x)  # pylint: disable=redefined-outer-name
  File "autograd\core.py", line 10, in make_vjp
    end_value, end_node =  trace(start_node, fun, x)
  File "autograd\tracer.py", line 10, in trace
    end_box = fun(start_box)
  File "autograd\wrap_util.py", line 15, in unary_f
    return fun(*subargs, **kwargs)
  File "pennylane\workflow\qnode.py", line 1095, in __call__
    self._update_gradient_fn(shots=override_shots, tape=self._tape)
  File "pennylane\workflow\qnode.py", line 604, in _update_gradient_fn
    self.gradient_fn, self.gradient_kwargs, self.device = self.get_gradient_fn(
  File "pennylane\workflow\qnode.py", line 650, in get_gradient_fn
    if device.supports_derivatives(config, circuit=tape):
  File "pennylane_lightning\lightning_qubit\lightning_qubit.py", line 627, in supports_derivatives
    return _supports_adjoint(circuit=circuit)
  File "pennylane_lightning\lightning_qubit\lightning_qubit.py", line 363, in _supports_adjoint
    prog((circuit,))
  File "pennylane\transforms\core\transform_program.py", line 509, in __call__
    new_tapes, fn = transform(tape, *targs, **tkwargs)
  File "pennylane\devices\preprocess.py", line 340, in decompose
    new_ops = [
  File "pennylane\devices\preprocess.py", line 343, in <listcomp>
    for final_op in _operator_decomposition_gen(
  File "pennylane\devices\preprocess.py", line 62, in _operator_decomposition_gen
    decomp = decomposer(op)
  File "pennylane\devices\preprocess.py", line 328, in decomposer
    return op.decomposition()
  File "pennylane\operation.py", line 1285, in decomposition
    return self.compute_decomposition(
  File "pennylane\ops\qubit\matrix_ops.py", line 223, in compute_decomposition
    return qml.ops.two_qubit_decomposition(U, Wires(wires))
  File "pennylane\ops\op_math\decompositions\two_qubit_unitary.py", line 615, in two_qubit_decomposition
    num_cnots = _compute_num_cnots(U)
  File "pennylane\ops\op_math\decompositions\two_qubit_unitary.py", line 126, in _compute_num_cnots
    evs = math.linalg.eigvals(gammaU)
  File "autoray.py", line 81, in do
    return func(*args, **kwargs)
  File "pennylane\numpy\wrapper.py", line 117, in _wrapped
    res = obj(*args, **kwargs)
  File "autograd\tracer.py", line 45, in f_wrapped
    node = node_constructor(ans, f_wrapped, argvals, kwargs, argnums, parents)
  File "autograd\core.py", line 34, in __init__
    raise NotImplementedError("VJP of {} wrt argnums {} not defined"
NotImplementedError: VJP of eigvals wrt argnums (0,) not defined
Here is the full package version:
Name: PennyLane
Version: 0.36.0
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: ###
Platform info:           Windows-10-10.0.19045-SP0
Python version:          3.9.19
Numpy version:           1.21.5
Scipy version:           1.10.1
Installed devices:
- default.clifford (PennyLane-0.36.0)
- default.gaussian (PennyLane-0.36.0)
- default.mixed (PennyLane-0.36.0)
- default.qubit (PennyLane-0.36.0)
- default.qubit.autograd (PennyLane-0.36.0)
- default.qubit.jax (PennyLane-0.36.0)
- default.qubit.legacy (PennyLane-0.36.0)
- default.qubit.tf (PennyLane-0.36.0)
- default.qubit.torch (PennyLane-0.36.0)
- default.qutrit (PennyLane-0.36.0)
- default.qutrit.mixed (PennyLane-0.36.0)
- null.qubit (PennyLane-0.36.0)
- lightning.qubit (PennyLane-Lightning-0.36.0)