PennyLane provides a growing library of pre-coded templates of common variational circuit architectures that can be used to easily build, evaluate, and train more complex models. In the literature, such architectures are commonly known as an ansatz.
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
Most templates are complemented by functions that provide an array of random initial parameters.
The following is a gallery of built-in templates provided by PennyLane.
Embeddings encode input features into the quantum state of the circuit. Hence, they take a feature vector as an argument. Embeddings can also depend on trainable parameters, and they may consist of repeated layers.
Layer architectures define sequences of trainable gates that are repeated like the layers in a
neural network. Note arbitrary templates or operations can also be layered using the
State preparation templates transform a given state into a sequence of gates preparing that state.
Subroutines are sequences of (possibly trainable) gates that do not fulfill the conditions of other templates.
PennyLane offers a broadcasting function to easily construct templates:
takes single quantum operations or other templates and applies them to wires in a specific pattern.
Each trainable template has dedicated functions in the
pennylane.init module, which generate
randomly initialized arrays for the trainable parameters. For example,
be used together with the template
import pennylane as qml from pennylane.templates import RandomLayers from pennylane.init import random_layers_uniform dev = qml.device('default.qubit', wires=3) @qml.qnode(dev) def circuit(weights): RandomLayers(weights=weights, wires=[0, 2]) return qml.expval(qml.PauliZ(0)) init_pars = random_layers_uniform(n_layers=3, n_wires=2) circuit(init_pars)
Templates that take more than one parameter array require several initialization functions:
from pennylane.templates import Interferometer from pennylane.init import (interferometer_theta_uniform, interferometer_phi_uniform, interferometer_varphi_normal) dev = qml.device('default.gaussian', wires=3) @qml.qnode(dev) def circuit(theta, phi, varphi): Interferometer(theta=theta, phi=phi, varphi=varphi, wires=[0, 2]) return qml.expval(qml.X(0)) init_theta = interferometer_theta_uniform(n_wires=2) init_phi = interferometer_phi_uniform(n_wires=2) init_varphi = interferometer_varphi_normal(n_wires=2) circuit(init_theta, init_phi, init_varphi)
For templates with multiple parameters, initializations that
return a list of all parameter arrays at once are provided, and can
be conveniently used in conjunction with the unpacking operator
from pennylane.templates import Interferometer from pennylane.init import interferometer_all dev = qml.device('default.gaussian', wires=3) @qml.qnode(dev) def circuit(*pars): Interferometer(*pars, wires=[0, 2]) return qml.expval(qml.X(0)) init_pars = interferometer_all(n_wires=2) circuit(*init_pars)
Initial parameters can be converted to Torch or TensorFlow tensors, which can be used in the respective interfaces.
import torch import tensorflow as tf from pennylane.init import strong_ent_layers_normal init_pars = strong_ent_layers_normal(n_layers=3, n_wires=2) init_torch = torch.tensor(init_pars) init_tf = tf.Variable(init_pars)
The initialization functions can be found in the
In addition, custom templates can be created; simply
decorate a Python function that applies quantum gates
@qml.template def bell_state_preparation(wires): qml.Hadamard(wires=wires) qml.CNOT(wires=wires)
This registers the template with PennyLane, making it compatible with
functions that act on templates, such as
dev = qml.device('default.qubit', wires=2) @qml.qnode(dev) def circuit(): qml.inv(bell_state_preparation(wires=[0, 1])) return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))