.. role:: html(raw)
:format: html
.. _intro_vcircuits:
Quantum Circuits
================
.. image:: ../_static/qnode.png
:align: right
:width: 180px
:target: javascript:void(0);
In PennyLane, variational quantum circuits are represented as *quantum node* objects. A quantum node
is a combination of a :ref:`quantum function ` that composes the circuit,
and a :ref:`device ` that runs the computation. One can conveniently create quantum nodes using
the quantum node :ref:`decorator `.
Each classical :ref:`interface ` uses a different version of a quantum node,
and we will introduce the standard QNode to use with the NumPy interface here.
NumPy-interfacing quantum nodes take NumPy datastructures,
such as floats and arrays, and return Numpy data structures.
They can be optimized using NumPy-based :ref:`optimization methods `.
Quantum nodes for other PennyLane interfaces like :ref:`PyTorch ` and
:ref:`TensorFlow's Eager mode ` are introduced in the section on :ref:`interfaces `.
.. _intro_vcirc_qfunc:
Quantum functions
-----------------
A quantum circuit is constructed as a special Python function, a *quantum circuit function*, or *quantum function* in short.
For example:
.. code-block:: python
import pennylane as qml
def my_quantum_function(x, y):
qml.RZ(x, wires=0)
qml.CNOT(wires=[0,1])
qml.RY(y, wires=1)
return qml.expval(qml.PauliZ(1))
Quantum functions are a restricted subset of Python functions, adhering to the following
constraints:
* The body of the function must consist of only supported PennyLane
:ref:`operations ` or sequences of operations called :ref:`templates `,
using one instruction per line.
* The function must always return either a single or a tuple of
*measured observable values*, by applying a :ref:`measurement function `
to a :ref:`qubit ` or :ref:`continuous-value observable `.
* Classical processing of function arguments, either by arithmetic operations
or external functions, is not allowed. One current exception is simple scalar
multiplication.
.. note::
The quantum operations cannot be used outside of a quantum circuit function, as all
:class:`Operations ` require a QNode in order to perform queuing on initialization.
.. note::
Measured observables **must** come after all other operations at the end
of the circuit function as part of the return statement, and cannot appear in the middle.
.. _intro_vcirc_device:
Defining a device
-----------------
To run - and later optimize - a quantum circuit, one needs to first specify a *computational device*.
The device is an instance of the :class:`~_device.Device`
class, and can represent either a simulator or hardware device. They can be
instantiated using the :func:`device ` loader.
.. code-block:: python
dev = qml.device('default.qubit', wires=2)
PennyLane offers some basic devices such as the ``'default.qubit'`` simulator; additional devices can be installed
as plugins (see :ref:`plugins ` for more details). Note that the choice of a device significantly
determines the speed of your computation.
.. _intro_vcirc_qnode:
Creating a quantum node
-----------------------
Together, a quantum function and a device are used to create a *quantum node* or
:class:`QNode ` object, which wraps the quantum function and binds it to the device.
A `QNode` can be explicitly created as follows:
.. code-block:: python
qnode = qml.QNode(my_quantum_function, dev)
The `QNode` can be used to compute the result of a quantum circuit as if it was a standard Python
function. It takes the same arguments as the original quantum function:
>>> qnode(np.pi/4, 0.7)
0.7648421872844883
.. _intro_vcirc_decorator:
The QNode decorator
-------------------
A more convenient - and in fact the recommended - way for creating `QNodes` is the provided
quantum node decorator. This decorator converts a quantum function containing PennyLane quantum
operations to a :class:`QNode ` that will run on a quantum device.
.. note::
The decorator completely replaces the Python-based quantum function with
a :mod:`QNode ` of the same name - as such, the original
function is no longer accessible (but is accessible via the ``func`` attribute).
For example:
.. code-block:: python
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def qfunc(x):
qml.RZ(x, wires=0)
qml.CNOT(wires=[0,1])
qml.RY(x, wires=1)
return qml.expval(qml.PauliZ(0))
result = qfunc(0.543)