qml.transforms¶
This subpackage contains PennyLane transforms and their building blocks.
Custom transforms¶
qml.transform
can be used to define custom transformations
that work with PennyLane QNodes; such transformations can map a circuit
to one or many new circuits alongside associated classical post-processing.
|
Generalizes a function that transforms tapes to work with additional circuit-like objects such as a |
Transforms library¶
A range of ready-to-use transforms are available in PennyLane.
Transforms for circuit compilation¶
A set of transforms to perform basic circuit compilation tasks.
|
Compile a circuit by applying a series of transforms to a quantum function. |
|
Quantum function transform to remove any operations that are applied next to their (self-)inverses or adjoint. |
|
Quantum transform to move commuting gates past control and target qubits of controlled operations. |
|
Quantum transform to combine rotation gates of the same type that act sequentially. |
|
Quantum function transform to fuse together groups of single-qubit operations into a general single-qubit unitary operation ( |
|
Quantum function transform to decomposes all instances of single-qubit and select instances of two-qubit |
Quantum function transform to combine amplitude embedding templates that act on different qubits. |
|
|
Quantum transform to remove Barrier gates. |
|
Quantum function transform to remove SWAP gates by running from right to left through the circuit changing the position of the qubits accordingly. |
|
Quantum function transform to optimize a circuit given a list of patterns (templates). |
|
Transpile a circuit according to a desired coupling map |
There are also utility functions and decompositions available that assist with both transforms, and decompositions within the larger PennyLane codebase.
|
Context manager for setting custom decompositions. |
|
Function that applies the pattern matching algorithm and returns the list of maximal matches. |
|
This transform converts a PennyLane quantum tape to a ZX-Graph in the PyZX framework. |
|
Converts a graph from PyZX to a PennyLane tape, if the graph is diagram-like. |
There are also utility functions that take a circuit and return a DAG.
|
Construct the pairwise-commutation DAG (directed acyclic graph) representation of a quantum circuit. |
|
Class to represent a quantum circuit as a directed acyclic graph (DAG). |
|
Class to store information about a quantum operation in a node of the commutation DAG. |
Transform for Clifford+T decomposition¶
This transform accepts quantum circuits and decomposes them to the Clifford+T basis.
|
Decomposes a circuit into the Clifford+T basis. |
Transforms for error mitigation¶
|
Mitigate an input circuit using zero-noise extrapolation. |
|
Differentiable circuit folding of the global unitary |
|
Extrapolator to \(f(0)\) for polynomial fit. |
|
Polynomial fit where the degree of the polynomial is fixed to being equal to the length of |
|
Extrapolate to the zero-noise limit using an exponential model (\(Ae^{Bx} + C\)). |
Other transforms¶
These transforms use the pennylane.transform()
function/decorator and can be used on
pennylane.tape.QuantumTape
, pennylane.QNode
. They fulfill multiple purposes like circuit
preprocessing, getting information from a circuit, and more.
|
Transform a QNode to support an initial batch dimension for operation parameters. |
|
Transform a circuit to support an initial batch dimension for gate inputs. |
|
Insert an operation into specified points in an input circuit. |
|
Insert operations according to a provided noise model. |
|
Quantum function transform that substitutes operations conditioned on measurement outcomes to controlled operations. |
|
Diagonalize a set of measurements into the standard basis. |
|
Splits a circuit into tapes measuring groups of commuting observables. |
|
Splits any expectation values of multi-term observables in a circuit into single term expectation values for devices that don’t natively support measuring expectation values of sums of observables. |
|
Expand a broadcasted tape into multiple tapes and a function that stacks and squeezes the results. |
|
Splits a tape measuring a Hamiltonian expectation into mutliple tapes of Pauli expectations, and provides a function to recombine the results. |
|
Splits a tape measuring a (fast-forwardable) Hamiltonian expectation into mutliple tapes of the Xi or sgn decomposition, and provides a function to recombine the results. |
|
Splits a quantum tape measuring a Sum expectation into multiple tapes of summand expectations, and provides a function to recombine the results. |
Transforms a circuit to one with purely numpy parameters. |
|
|
Applies the transform that performs a controlled version of the \(\mathcal{Q}\) unitary defined in this paper. |
|
Applies the transform quantum Monte Carlo estimation algorithm. |
Transforms that act only on QNodes¶
These transforms only accept QNodes, and return new transformed functions that compute the desired quantity.
|
Create a batched partial callable object from the QNode specified. |
|
Create a function that draws the given qnode or quantum function. |
|
Draw a qnode with matplotlib |
Decorators and utility functions¶
The following decorators and convenience functions are provided to help build custom QNode, quantum function, and tape transforms:
|
Returns a function that generates a qscript from a quantum function without any operation queuing taking place. |
|
Create a function for expanding a tape to a given depth, and with a specific stopping criterion. |
|
Creates a custom expansion function for a device that applies a set of specified custom decompositions. |
|
Expand out a tape so that it supports differentiation of requested operations. |
Expand out a tape so that it supports differentiation of requested operations with the Hadamard test gradient. |
|
|
Expand out a tape so that all its parametrized operations have a single parameter. |
|
Expand out a tape so that all its trainable operations have a single parameter. |
|
Expand out a tape so that all its parametrized operations have a unitary generator. |
Transforms developer functions¶
TransformContainer
, TransformDispatcher
, and TransformProgram
are
developer-facing objects that allow the
creation, dispatching, and composability of transforms. If you would like to make a custom transform, refer
instead to the documentation of qml.transform
.
This module contains the transform dispatcher and the transform container. |
|
This module contains the |
Transforming circuits¶
A quantum transform is a crucial concept in PennyLane, and refers to mapping a quantum circuit to one or more circuits, alongside a classical post-processing function. Once a transform is registered with PennyLane, the transformed circuits will be executed, and the classical post-processing function automatically applied to the outputs. This becomes particularly valuable when a transform generates multiple circuits, requiring a method to aggregate or reduce the results (e.g., applying the parameter-shift rule or computing the expectation value of a Hamiltonian term-by-term).
Note
For examples of built-in transforms that come with PennyLane, see the Compiling circuits documentation.
Creating your own transform¶
To streamline the creation of transforms and ensure their versatility across
various circuit abstractions in PennyLane, the
pennylane.transform()
is available.
This decorator registers transforms that accept a QuantumTape
as its primary input and returns a sequence of QuantumTape
and an associated processing function.
To illustrate the process of creating a quantum transform, let’s consider an example. Suppose we want
a transform that removes all RX
operations from a given circuit. In this case, we merely need to filter the
original QuantumTape
and return a new one without the filtered operations. As we don’t require a specific processing
function in this scenario, we include a function that simply returns the first and only result.
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.typing import PostprocessingFn
def remove_rx(tape: QuantumScript) -> tuple[QuantumScriptBatch, PostprocessingFn]:
operations = filter(lambda op: op.name != "RX", tape.operations)
new_tape = type(tape)(operations, tape.measurements, shots=tape.shots)
def null_postprocessing(results):
return results[0]
return [new_tape], null_postprocessing
To make your transform applicable to both QNode
and quantum functions, you can use the pennylane.transform()
decorator.
dispatched_transform = qml.transform(remove_rx)
For a more advanced example, let’s consider a transform that sums a circuit with its adjoint. We define the adjoint
of the tape operations, create a new tape with these new operations, and return both tapes.
The processing function then sums the results of the original and the adjoint tape.
In this example, we use qml.transform
in the form of a decorator in order to turn the custom
function into a quantum transform.
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.typing import PostprocessingFn
@qml.transform
def sum_circuit_and_adjoint(tape: QuantumScript) -> tuple[QuantumScriptBatch, PostprocessingFn]:
operations = [qml.adjoint(op) for op in tape.operation]
new_tape = type(tape)(operations, tape.measurements, shots=tape.shots)
def sum_postprocessing(results):
return qml.sum(results)
return [tape, new_tape], sum_postprocessing
Composability of transforms¶
Transforms are inherently composable on a QNode
, meaning that transforms with compatible post-processing
functions can be successively applied to QNodes. For example, this allows for the application of multiple compilation
passes on a QNode to maximize gate reduction before execution.
dev = qml.device("default.qubit", wires=1)
@qml.transforms.merge_rotations
@qml.transforms.cancel_inverses
@qml.qnode(device=dev)
def circuit(x, y):
qml.Hadamard(wires=0)
qml.Hadamard(wires=0)
qml.RX(x, wires=0)
qml.RY(y, wires=0)
qml.RZ(y, wires=0)
qml.RY(x, wires=0)
return qml.expval(qml.Z(0))
In this example, inverses are canceled, leading to the removal of two Hadamard gates. Subsequently, rotations are
merged into a single qml.Rot
gate. Consequently, two transforms are successfully applied to the circuit.
Passing arguments to transforms¶
We can decorate a QNode with @partial(transform_fn, **transform_kwargs)
to provide additional keyword arguments to a transform function.
In the following example, we pass the keyword argument grouping_strategy="wires"
to the split_non_commuting()
quantum transform,
which splits a circuit into tapes measuring groups of commuting observables.
from functools import partial
dev = qml.device("default.qubit", wires=2)
@partial(qml.transforms.split_non_commuting, grouping_strategy="wires")
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RZ(params[1], wires=1)
return [
qml.expval(qml.X(0)),
qml.expval(qml.Y(1)),
qml.expval(qml.Z(0) @ qml.Z(1)),
qml.expval(qml.X(0) @ qml.Z(1) + 0.5 * qml.Y(1) + qml.Z(0)),
]
Additional information¶
Explore practical examples of transforms focused on compiling circuits in the compiling circuits documentation. For gradient transforms, refer to the examples in the gradients documentation. Discover quantum information transformations in the quantum information documentation. Finally, for a comprehensive overview of transforms and core functionalities, consult the summary above.