# Templates¶

**Module name:** `pennylane.templates`

This module provides a growing library of templates of common quantum
machine learning circuit architectures that can be used to easily build,
evaluate, and train more complex quantum machine learning models. In the
quantum machine learning literature, such architectures are commonly known as an
**ansatz**.

Templates are used exactly as one would use a quantum gate, only that they invoke a sequence of quantum gates instead.

Note

Templates are constructed out of **structured combinations** of the `quantum operations`

provided by PennyLane. This means that **template functions can only be used within a valid** `pennylane.qnode`

.

PennyLane conceptually distinguishes two types of templates, **layer architectures** and **input embeddings**:

Layer architectures, found in

`pennylane.templates.layers`

, define sequences of gates that are repeated like the layers in a neural network. They usually contain only trainable parameters.Embeddings, found in

`pennylane.templates.embeddings`

, encode input features into the quantum state of the circuit. Hence, they take a feature vector as an argument. These embeddings can also depend on trainable parameters, in which case the embedding is learnable.

The following templates of each type are available:

Each trainable template has a dedicated function in `pennylane.init`

which generates a list of
**randomly initialized** arrays for the trainable **parameters**. To illustrate how these can be used, let us use a hypothetical parameter initialization function `my_init_fun()`

and its corresponding hypothetical template `MyTemplate()`

, which takes three parameter arrays. The two can be combined in the following two ways:

Dereference the list when feeding it into the template:

```
par_list = my_init_fun(...)
...
MyTemplate(*par_list, ...)
```

Unpack the list as the init function is called:

```
a, b, c = my_init_fun(...)
...
MyTemplate(a, b, c, ...)
```

The following parameter initialization methods are available:

## Examples¶

You can construct a circuit-centric quantum
classifier with the architecture from [R2] on an arbitrary
number of wires and with an arbitrary number of layers by using the
template `StronglyEntanglingLayers()`

in the following way:

```
import pennylane as qml
from pennylane.templates.layers import StronglyEntanglingLayers
from pennylane.init import strong_ent_layers_normal
from pennylane import numpy as np
n_wires = 4
n_layers = 3
dev = qml.device('default.qubit', wires=n_wires)
@qml.qnode(dev)
def circuit(pars, x=None):
qml.BasisState(x, wires=range(n_wires))
StronglyEntanglingLayers(*pars, wires=range(n_wires))
return qml.expval(qml.PauliZ(0))
pars = strong_ent_layers_normal(n_layers=n_layers, n_wires=n_wires, mean=0, std=0.1)
print(circuit(pars, x=np.array(np.random.randint(0, 1, n_wires))))
```

Note

`pars`

is a list of parameter arrays. In the case of the strongly entangling template, the list contains
exactly one such parameter array of shape `(n_layers, n_wires, 3)`

. One could alternatively create this
list of arrays by hand, replacing second-to-last line with

```
pars = [np.random.normal(loc=0, scale=0.1, size=(n_layers, n_wires, 3))]
```

Note

Most parameter generating methods have a ‘normal’ and a ‘uniform’ version, sampling the angle parameters of rotation gates either from a normal or uniform distribution.

Templates can contain each other. An example is the handy `Interferometer`

template. It constructs
arbitrary interferometers in terms of elementary `Beamsplitter`

operations, by providing lists of
transmittivity and phase angles. A `CVNeuralNetLayer()`

template — implementing the continuous-variable neural
network architecture from [R3] — contains two such interferometers. But it can also
be used (and optimized) independently:

```
import pennylane as qml
from pennylane.templates.layers import Interferometer
from pennylane import numpy as np
n_wires = 4
n_params = int(n_wires * (n_wires - 1) / 2)
dev = qml.device('default.gaussian', wires=n_wires)
# initial parameters
r = np.random.rand(n_wires, 2)
theta = np.random.uniform(0, 2 * np.pi, n_params)
phi = np.random.uniform(0, 2 * np.pi, n_params)
varphi = np.random.uniform(0, 2 * np.pi, n_wires)
@qml.qnode(dev)
def circuit(theta, phi, varphi):
for w in range(n_wires):
qml.Squeezing(r[w][0], r[w][1], wires=w)
Interferometer(theta=theta, phi=phi, varphi=varphi, wires=range(n_wires))
return [qml.expval(qml.NumberOperator(wires=w)) for w in range(n_wires)]
j = qml.jacobian(circuit, 0)
print(j(theta, phi, varphi))
```

Once more, instead of generating the arrays for `theta`

, `phi`

and `varphi`

by hand, one can use
the `interferometer_uniform()`

function.

```
from pennylane.init import interferometer_uniform
import pennylane as qml
from pennylane.templates.layers import Interferometer
from pennylane import numpy as np
n_wires = 4
n_params = int(n_wires * (n_wires - 1) / 2)
dev = qml.device('default.gaussian', wires=n_wires)
# initial parameters
r = np.random.rand(n_wires, 2)
pars = interferometer_uniform(n_wires)
@qml.qnode(dev)
def circuit(theta, phi, varphi):
for w in range(n_wires):
qml.Squeezing(r[w][0], r[w][1], wires=w)
Interferometer(theta=theta, phi=phi, varphi=varphi, wires=range(n_wires))
return [qml.expval(qml.NumberOperator(wires=w)) for w in range(n_wires)]
j = qml.jacobian(circuit, 0)
print(j(*pars))
```

By growing this library of templates, PennyLane allows easy access to variational models discussed in the quantum machine learning literature.