Quantum circuits

QNodes form part of the core structure of PennyLane — they are used to encapsulate a quantum function that runs on a quantum hardware device.

By defining QNodes, either via the QNode decorator or the QNode class, dispatching them to devices, and combining them with classical processing, it is easy to create arbitrary classical-quantum hybrid computations.

The QNode decorator

Module name: pennylane.decorator

The standard way for creating ‘quantum nodes’ or QNodes is the provided qnode decorator. This decorator converts a quantum circuit function containing PennyLane quantum operations to a QNode that will run on a quantum device.

This decorator is provided for convenience, and allows a quantum circuit function to be converted to a QNode implicitly, avoiding the need to manually instantiate a QNode object.

Note that the decorator completely replaces the Python-defined function with a QNode of the same name - as such, the original function is no longer accessible (but is accessible via the func attribute).

dev1 = qml.device('default.qubit', wires=2)

def qfunc1(x):
    qml.RZ(x, wires=0)
    qml.RY(x, wires=1)
    return qml.expval(qml.PauliZ(0))

result = qfunc1(0.543)

Once defined, the QNode can then be used like any other function in Python. This includes combining it with other QNodes and classical functions to build a hybrid computation. For example,

dev2 = qml.device('default.gaussian', wires=2)

def qfunc2(x, y):
    qml.Displacement(x, 0, wires=0)
    qml.Beamsplitter(y, 0, wires=[0, 1])
    return qml.expval(qml.NumberOperator(0))

def hybrid_computation(x, y):
    return np.sin(qfunc1(y))*np.exp(-qfunc2(x+y, x)**2)


Applying the qnode() decorator to a user-defined function is equivalent to instantiating the QNode object manually. For example, the above example can also be written as follows:

def qfunc1(x):
    qml.RZ(x, wires=0)
    qml.RY(x, wires=1)
    return qml.expval(qml.PauliZ(0))

qnode1 = qml.QNode(qfunc1, dev1)
result = qnode1(0.543)

Machine learning interfaces

PennyLane provides support for various classical machine learning interfaces, including Autograd/NumPy, PyTorch, and TensorFlow. The interfaces have access to gradients of a QNode, and can therefore integrate quantum computations into a larger machine learning or optimization pipeline.

Depending on the classical machine learning interface chosen, you may be able to offload the classical portion of your hybrid model onto an accelerator, such as a GPU or TPU.

By default, QNodes make use of the wrapped version of NumPy provided by PennyLane (via autograd). By importing NumPy from PennyLane,

from pennylane import numpy as np

any classical computation in the model can then make use of arbitrary NumPy functions, while retaining support for automatic differentiation. For an example, see the hybrid computation tutorial.

However, PennyLane has the ability to contruct quantum nodes that can also be used in conjunction with other classical machine learning libraries. Such QNodes will accept and return the correct object types expected by the machine learning library (i.e., Python default types and NumPy array for the PennyLane-provided wrapped NumPy, torch.tensor for PyTorch, and tf.Tensor or tfe.Variable for TensorFlow). Furthermore, PennyLane will correctly pass the quantum analytic gradient to the machine learning library during backpropagation.

Code details

qnode(device, interface='numpy', cache=False)[source]

QNode decorator.

  • device (Device) – a PennyLane-compatible device
  • interface (str) –

    the interface that will be used for automatic differentiation and classical processing. This affects the types of objects that can be passed to/returned from the QNode:

    • interface='numpy': The QNode accepts default Python types (floats, ints, lists) as well as NumPy array arguments, and returns NumPy arrays.
    • interface='torch': The QNode accepts and returns Torch tensors.
    • interface='tfe': The QNode accepts and returns eager execution TensorFlow tfe.Variable objects.
  • cache (bool) – If True, the quantum function used to generate the QNode will only be called to construct the quantum circuit once, on first execution, and this circuit structure (i.e., the placement of templates, gates, measurements, etc.) will be cached for all further executions. The circuit parameters can still change with every call. Only activate this feature if your quantum circuit structure will never change.