qml.transforms.insert¶
- insert(tape, op, op_args, position='all', before=False)[source]¶
Insert an operation into specified points in an input circuit.
Circuits passed through this transform will be updated to have the operation, specified by the
op
argument, added according to the positioning specified in theposition
argument. Only single qubit operations are permitted to be inserted.The type of
op
can be either a single operation or a quantum function acting on a single wire. A quantum function can be used to specify a sequence of operations acting on a single qubit (see the usage details for more information).- Parameters
tape (QNode or QuantumTape or Callable or pennylane.devices.Device) – the input circuit to be transformed.
op (callable or Type[Operation]) – the single-qubit operation, or sequence of operations acting on a single qubit, to be inserted into the circuit
op_args (tuple or float) – the arguments fed to the operation, either as a tuple or a single float
position (str or PennyLane operation or list of operations) – Specification of where to add the operation. Should be one of:
"all"
to add the operation after all gates (except state preparations);"start"
to add the operation to all wires at the start of the circuit (but after state preparations);"end"
to add the operation to all wires at the end of the circuit; list of operations to add the operation before or after depending onbefore
.before (bool) – Whether to add the operation before the given operation(s) in
position
. Default isFalse
and the operation is inserted after.
- Returns
The transformed circuit as described in
qml.transform
.- Return type
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function] or device (pennylane.devices.Device)
- Raises
ValueError – if a single operation acting on multiple wires is passed to
op
ValueError – if the requested
position
argument is not'start'
,'end'
or'all'
OR PennyLane Operation
Example:
The following QNode can be transformed to add noise to the circuit:
from functools import partial dev = qml.device("default.mixed", wires=2) @partial(qml.transforms.insert, op=qml.AmplitudeDamping, op_args=0.2, position="end") @qml.qnode(dev) def f(w, x, y, z): qml.RX(w, wires=0) qml.RY(x, wires=1) qml.CNOT(wires=[0, 1]) qml.RY(y, wires=0) qml.RX(z, wires=1) return qml.expval(qml.Z(0) @ qml.Z(1))
Executions of this circuit will differ from the noise-free value:
>>> f(0.9, 0.4, 0.5, 0.6) tensor(0.754847, requires_grad=True) >>> print(qml.draw(f)(0.9, 0.4, 0.5, 0.6)) 0: ──RX(0.90)─╭●──RY(0.50)──AmplitudeDamping(0.20)─┤ ╭<Z@Z> 1: ──RY(0.40)─╰X──RX(0.60)──AmplitudeDamping(0.20)─┤ ╰<Z@Z>
Usage Details
Specifying the operation as a quantum function:
Instead of specifying
op
as a singleOperation
, we can instead define a quantum function. For example:def op(x, y, wires): qml.RX(x, wires=wires) qml.PhaseShift(y, wires=wires)
This operation can be inserted into the following circuit:
dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) @partial(qml.transforms.insert, op=op, op_args=[0.2, 0.3], position="end") def f(w, x, y, z): qml.RX(w, wires=0) qml.RY(x, wires=1) qml.CNOT(wires=[0, 1]) qml.RY(y, wires=0) qml.RX(z, wires=1) return qml.expval(qml.Z(0) @ qml.Z(1))
To check this, let’s print out the circuit:
>>> print(qml.draw(f)(0.9, 0.4, 0.5, 0.6)) 0: ──RX(0.90)─╭●──RY(0.50)──RX(0.20)──Rϕ(0.30)─┤ ╭<Z@Z> 1: ──RY(0.40)─╰X──RX(0.60)──RX(0.20)──Rϕ(0.30)─┤ ╰<Z@Z>
Transforming tapes:
Consider the following tape:
ops = [ qml.RX(0.9, wires=0), qml.RY(0.4, wires=1), qml.CNOT((0,1)), qml.RY(0.5, wires=0), qml.RX(0.6, wires=1) ] measurements = [qml.expval(qml.Z(0) @ qml.Z(1))] tape = qml.tape.QuantumTape(ops, measurements)
We can add the
AmplitudeDamping
channel to the end of the circuit using:>>> from pennylane.transforms import insert >>> [noisy_tape], _ = insert(tape, qml.AmplitudeDamping, 0.05, position="end") >>> print(qml.drawer.tape_text(noisy_tape, decimals=2)) 0: ──RX(0.90)─╭●──RY(0.50)──AmplitudeDamping(0.05)─┤ ╭<Z@Z> 1: ──RY(0.40)─╰X──RX(0.60)──AmplitudeDamping(0.05)─┤ ╰<Z@Z>
Transforming devices:
Consider the following QNode:
dev = qml.device("default.mixed", wires=2) def f(w, x, y, z): qml.RX(w, wires=0) qml.RY(x, wires=1) qml.CNOT(wires=[0, 1]) qml.RY(y, wires=0) qml.RX(z, wires=1) return qml.expval(qml.Z(0) @ qml.Z(1)) qnode = qml.QNode(f, dev)
Execution of the circuit on
dev
will be noise-free:>>> qnode(0.9, 0.4, 0.5, 0.6) tensor(0.86243536, requires_grad=True)
However, noise can be easily added to the device:
>>> dev_noisy = qml.transforms.insert(dev, qml.AmplitudeDamping, 0.2) >>> qnode_noisy = qml.QNode(f, dev_noisy) >>> qnode_noisy(0.9, 0.4, 0.5, 0.6) tensor(0.72945434, requires_grad=True)