Device Error with self-written Template

Dear Pennylane-Team,

I have a question regarding a code-snippit I wrote about > year ago in pennylane 0.25.1.
I updated now my pennylane version to 0.35.1 and run into a problem that I don’t understand.

In the following I provide a minimal example where I try to implement my own template.
In this minimal example, the template should solely realize an RY-rotation to encode my input.
When I run the code I get the following error.

When using “default.qubit”:

DeviceError: Operator minimalExample(array([0.78539816]), wires=[0]) not supported on default.qubit and does not provide a decomposition.

When using “default.qubit.torch”:

DeviceError: Gate minimalExample not supported on device default.qubit.torch

I checked with this example ( How to add custom gates and templates to PennyLane | PennyLane Blog) and can’t find the error.

Here is the code:

  1. I define the minimal Template Example
import numpy as np
import torch
import pennylane as qml
from pennylane.operation import Operation, AnyWires

class minimalExample(Operation):
    r"""
    Template of minimal example
    """

    num_wires = AnyWires
    par_domain = "A"


    def __init__(self, features, wires, alpha="Y", varphi="arccos",
                 beta=1.0, id=None):
    

        super().__init__(features, wires=wires, id=id)

    @property
    def num_params(self):
        return 1

    def expand(self):
        r"""
        Implements the encoding of the input parameters.
        """

        num_weights = qml.math.shape(features)[0]

        with qml.tape.QuantumTape() as tape:
            for i in range(num_weights):
                qml.RY(features[0], wires=self.wires[i])
        return tape
  1. I tried to initiate the input values as numpy.array or torch.tensor. When using torch.tensor I used it with default.qubit.torch
inputNumpy = np.array([np.pi / 4])
#inputTorch = torch.tensor([np.pi / 4])
nqubit = 1

dev = qml.device("default.qubit", wires=nqubit)
#dev = qml.device("default.qubit.torch", wires=nqubit)

@qml.qnode(dev)
#@qml.qnode(dev, interface='torch', diff_method='backprop')
def qcFkt(inputs, wires):
    """ QC function that performs encoding via the Templates"""
    minimalExample(inputs, range(wires))
    return [qml.expval(qml.PauliZ(i)) for i in range(wires)]

Calling this circuit gives me the described errors.

qcFkt(inputTorch, nqubit)

Thank you very much and best regards,
Pia

Hi @Pia, thank you for your question. I’m looking into it.

Hi @Pia,

The blog that you were looking at was unfortunately outdated. We always update the documentation and the demos when we make a new release, but the blog content remains static to how it was when it was published.

Fortunately you can find all of the updated information here in the docs!

In your example the issue was that you needed the static method compute_decomposition. I’ve added a working code below. I hope this helps!

import numpy as np
import torch
import pennylane as qml
from pennylane.operation import Operation, AnyWires

class minimalExample(Operation):
    r"""
    Template of minimal example
    """

    num_wires = AnyWires
    grad_method = "A"


    def __init__(self, features, wires, alpha="Y", varphi="arccos",
                 beta=1.0, id=None):
    

        super().__init__(features, wires=wires, id=id)

    @property
    def num_params(self):
        return 1

    @staticmethod
    def compute_decomposition(features, wires):
        # Overwriting this method defines the decomposition of the new gate, as it is
        # called by Operator.decomposition().
        # The general signature of this function is (*parameters, wires, **hyperparameters).
        num_weights = qml.math.shape(features)[0]
        op_list = []
        for i in range(num_weights):
          op_list.append(qml.RY(features[0], wires=wires[i]))

        return op_list

# inputNumpy = np.array([np.pi / 4])
inputTorch = torch.tensor([np.pi / 4])
nqubit = 1

# dev = qml.device("default.qubit", wires=nqubit)
dev = qml.device("default.qubit.torch", wires=nqubit)

# @qml.qnode(dev)
@qml.qnode(dev, interface='torch', diff_method='backprop')
def qcFkt(inputs, wires):
    """ QC function that performs encoding via the Templates"""
    minimalExample(inputs, range(wires))
    return [qml.expval(qml.PauliZ(i)) for i in range(wires)]

qcFkt(inputTorch, nqubit)

qml.draw_mpl(qcFkt, expansion_strategy='device')(inputTorch, nqubit)
1 Like

Thanks, this helped :slight_smile:

1 Like