# Quantum circuits¶

In PennyLane, quantum computations are represented as *quantum node* objects. A quantum node is used to
declare the quantum circuit, and also ties the computation to a specific device that executes it.
Quantum nodes can be easily created by using the qnode decorator.

QNodes can interface with any of the supported numerical and machine learning libraries—NumPy,
PyTorch, and TensorFlow—indicated by providing an optional `interface`

argument when creating a QNode. Each interface allows the quantum circuit to integrate seamlessly with library-specific data
structures (e.g., NumPy arrays, or Pytorch/TensorFlow tensors) and optimizers.

By default, QNodes use the NumPy interface. The other PennyLane interfaces are introduced in more detail in the section on interfaces.

## Quantum functions¶

A quantum circuit is constructed as a special Python function, a
*quantum circuit function*, or *quantum function* in short.
For example:

```
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))
```

Note

PennyLane uses the term *wires* to refer to a quantum subsystem—for most
devices, this corresponds to a qubit. For continuous-variable
devices, a wire corresponds to a quantum mode.

Quantum functions are a restricted subset of Python functions, adhering to the following constraints:

- The quantum function accepts classical inputs, and consists of quantum operations or sequences of operations called Templates, using one instruction per line.
- The function can contain classical flow control structures such as
`for`

loops, but in general they must not depend on the parameters of the function. - The quantum function must always return either a single or a tuple of
*measured observable values*, by applying a measurement function to a qubit observable or continuous-value observable.

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.

Note

Quantum functions can only be evaluated on a device from within a QNode.

## 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 `Device`

class, and can represent either a simulator or hardware device. They can be
instantiated using the `device`

loader.

```
dev = qml.device('default.qubit', wires=2, shots=1000, analytic=False)
```

PennyLane offers some basic devices such as the `'default.qubit'`

and `'default.gaussian'`

simulators; additional devices can be installed as plugins (see
available plugins for more details). Note that the
choice of a device significantly determines the speed of your computation, as well as
the available options that can be passed to the device loader.

### Device options¶

When loading a device, the name of the device must always be specified.
Further options can then be passed as keyword arguments; these options can differ based
on the device. For the in-built `'default.qubit'`

and `'default.gaussian'`

devices, the options are:

`wires`

(*int*): The number of wires to initialize the device with.`analytic`

(*bool*): Indicates if the device should calculate expectations and variances analytically. Only possible with simulator devices. Defaults to`True`

.`shots`

(*int*): How many times the circuit should be evaluated (or sampled) to estimate the expectation values. Defaults to 1000 if not specified.

For a plugin device, refer to the plugin documentation for available device options.

## Creating a quantum node¶

Together, a quantum function and a device are used to create a *quantum node* or
`QNode`

object, which wraps the quantum function and binds it to the device.

A QNode can be explicitly created as follows:

```
circuit = 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:

```
>>> circuit(np.pi/4, 0.7)
0.7648421872844883
```

## The QNode decorator¶

A more convenient—and in fact the recommended—way for creating QNodes is the provided
`qnode`

decorator. This decorator converts a Python function containing PennyLane quantum
operations to a `QNode`

circuit that will run on a quantum device.

Note

The decorator completely replaces the Python-based quantum function with
a `QNode`

of the same name—as such, the original
function is no longer accessible.

For example:

```
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def circuit(x):
qml.RZ(x, wires=0)
qml.CNOT(wires=[0,1])
qml.RY(x, wires=1)
return qml.expval(qml.PauliZ(1))
result = circuit(0.543)
```

## Quantum circuits from other frameworks¶

PennyLane supports creating customized PennyLane templates imported from other
frameworks. By loading your existing quantum code as a PennyLane template, you
add the ability to perform analytic differentiation, and interface with machine
learning libraries such as PyTorch and TensorFlow. Currently, `QuantumCircuit`

objects from Qiskit, QASM strings or QASM files can be loaded by using the
following functions:

`from_qiskit` |
Loads Qiskit QuantumCircuit objects by using the converter in the PennyLane-Qiskit plugin. |

`from_qasm` |
Loads quantum circuits from a QASM string using the converter in the PennyLane-Qiskit plugin. |

`from_qasm_file` |
Loads quantum circuits from a QASM file using the converter in the PennyLane-Qiskit plugin. |

To use these conversion functions, the PennyLane-Qiskit plugin needs to be installed.

Objects for quantum circuits can be loaded outside or directly inside of a
`QNode`

. Circuits that contain unbound parameters are also
supported. Parameter binding may happen by passing a dictionary containing the
parameter-value pairs.

Once a PennyLane template has been created from such a quantum circuit, it can
be used similarly to other templates in PennyLane. One important thing to note
is that custom templates must always be executed
within a `QNode`

(similar to pre-defined templates).

Note

Certain instructions that are specific to the external frameworks might be ignored when loading an external quantum circuit. Warning messages will be emitted for ignored instructions.

The following is an example of loading and calling a parametrized Qiskit `QuantumCircuit`

object
while using the `QNode`

decorator:

```
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
import numpy as np
dev = qml.device('default.qubit', wires=2)
theta = Parameter('θ')
qc = QuantumCircuit(2)
qc.rz(theta, [0])
qc.rx(theta, [0])
qc.cx(0, 1)
@qml.qnode(dev)
def quantum_circuit_with_loaded_subcircuit(x):
qml.from_qiskit(qc)({theta: x})
return qml.expval(qml.PauliZ(0))
angle = np.pi/2
result = quantum_circuit_with_loaded_subcircuit(angle)
```

Furthermore, loaded templates can be used with any supported device, any number of times.
For instance, in the following example a template is loaded from a QASM string,
and then used multiple times on the `forest.qpu`

device provided by PennyLane-Forest:

```
import pennylane as qml
dev = qml.device('forest.qpu', wires=2)
hadamard_qasm = 'OPENQASM 2.0;' \
'include "qelib1.inc";' \
'qreg q[1];' \
'h q[0];'
apply_hadamard = qml.from_qasm(hadamard_qasm)
@qml.qnode(dev)
def circuit_with_hadamards():
apply_hadamard(wires=[0])
apply_hadamard(wires=[1])
qml.Hadamard(wires=[1])
return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))
result = circuit_with_hadamards()
```

## Contents

## Downloads