qml.layer¶
- layer(template, depth, *args, **kwargs)[source]¶
Repeatedly applies a unitary a given number of times.
- Parameters
template (callable) – The sequence of quantum gates that is being repeated. This could be a single gate, a function of gates, or a “registered” PennyLane template.
depth (int) – The number of times the unitary is repeatedly applied.
*args – Dynamic parameters that are passed into the unitary each time it is repeated. Each dynamic argument must be a list of first dimension equal to
depth
. The \(j\)-th element of the list is the value of the argument the \(j\)-th time the unitary is applied.**kwargs – Static parameters that are passed into the unitary each time it is repeated.
See usage details for more information.
Usage Details
Layering Gates
The layering function can be used to repeatedly apply a function containing quantum operations, a template, or a quantum gate.
For example, we can define the following subroutine:
import pennylane as qml import numpy as np def subroutine(): qml.Hadamard(wires=[0]) qml.CNOT(wires=[0, 1]) qml.X(1)
and then pass it into the
qml.layer
function. In this instance, we repeatsubroutine
three times:dev = qml.device('default.qubit', wires=3) @qml.qnode(dev) def circuit(): qml.layer(subroutine, 3) return [qml.expval(qml.Z(0)), qml.expval(qml.Z(1))]
This creates the following circuit:
>>> print(qml.draw(circuit)()) 0: ──H─╭●──H─╭●──H─╭●────┤ <Z> 1: ────╰X──X─╰X──X─╰X──X─┤ <Z>
Static Arguments
Static arguments are arguments passed into
template
that don’t change with each repetition. Static parameters are always passed as keyword arguments intoqml.layer
. For example, consider the following subroutine:def subroutine(wires): qml.Hadamard(wires=wires[0]) qml.CNOT(wires=wires) qml.X(wires[1])
We wish to repeat this gate sequence three times on wires
1
and2
. Since the wires on which the subroutine acts don’t change with each repetition, thewires
parameter is passed as a keyword argument. Therefore, we define a circuit as:@qml.qnode(dev) def circuit(): qml.layer(subroutine, 3, wires=[1, 2]) return [qml.expval(qml.Z(1)), qml.expval(qml.Z(2))]
which yields the following circuit:
>>> print(qml.draw(circuit)()) 1: ──H─╭●──H─╭●──H─╭●────┤ <Z> 2: ────╰X──X─╰X──X─╰X──X─┤ <Z>
Dynamic Arguments
In addition to passing static arguments to
template
, we can also pass dynamic arguments. These are arguments that change with each repetition of the unitary. They are passed as non-keyword arguments toqml.layer
, aftertemplate
anddepth
. Each dynamic parameter must be a list of length equal todepth
. The \(j\)-th element of the list represents the value of the argument used for the \(j\)-th repetition.For example, let us define the following variational ansatz:
def ansatz(params): qml.RX(params[0], wires=[0]) qml.MultiRZ(params[1], wires=[0, 1]) qml.RY(params[2], wires=[1])
We wish to repeat this ansatz two times, with each layer having different
params
:@qml.qnode(dev) def circuit(params): qml.layer(ansatz, 2, params) return [qml.expval(qml.Z(0)), qml.expval(qml.Z(1))]
Since we only have one dynamic argument,
params
, we pass an array of first-dimension two, for the two layers of the repeated ansatz. We can also see that theparams
argument supplies three different parameters to three different gates. We therefore supply an array of size (2, 3) as an argument toqml.layer
:params = np.array([[0.5, 0.5, 0.5], [0.4, 0.4, 0.4]])
which yields the following circuit:
>>> print(qml.draw(circuit)(params)) 0: ──RX(0.50)─╭MultiRZ(0.50)──RX(0.40)─╭MultiRZ(0.40)───────────┤ <Z> 1: ───────────╰MultiRZ(0.50)──RY(0.50)─╰MultiRZ(0.40)──RY(0.40)─┤ <Z>
Passing Multiple Static and Dynamic Arguments
It is also possible to pass multiple static and dynamic arguments into the same unitary. Dynamic arguments must be ordered in
qml.layer
in the same order in which they are passed into thetemplate
.Consider the following ansatz:
def ansatz(param1, param2, wires, var): qml.RX(param1, wires=wires[0]) qml.MultiRZ(param2, wires=wires) if var: qml.Hadamard(wires=wires[1])
This circuit can be repeated as:
@qml.qnode(dev) def circuit(param1, param2): qml.layer(ansatz, 2, param1, param2, wires=[1, 2], var=True) return [qml.expval(qml.Z(1)), qml.expval(qml.Z(2))]
We can then run the circuit with a given set of parameters (note that the parameters are of size (2, 1), as the circuit is repeated twice, and for each repetition, both
param1
andparam2
are simply real numbers):param1 = np.array([0.1, 0.2]) param2 = np.array([0.3, 0.4])
This gives us the following circuit:
>>> print(qml.draw(circuit)(param1, param2)) 1: ──RX(0.10)─╭MultiRZ(0.30)──RX(0.20)─╭MultiRZ(0.40)────┤ <Z> 2: ───────────╰MultiRZ(0.30)──H────────╰MultiRZ(0.40)──H─┤ <Z>