Source code for pennylane.workflow.marker
# Copyright 2026 Xanadu Quantum Technologies Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Contains the 'marker' utility for marking PennyLane objects."""
from collections.abc import Callable
from .qnode import QNode
[docs]
def marker(obj: QNode | None = None, label: str | None = None) -> QNode | Callable:
"""Mark a location in a compilation pipeline for easy access with inspectability.
Args:
obj (QNode | None): The ``QNode`` containing the compilation pipeline to be marked.
If ``None``, this function acts as a decorator for a ``QNode``.
label (str | None): A descriptive label for this specific stage in the compilation process.
Check :func:`~.workflow.get_transform_program` for more information on the allowed values and usage details of this argument.
Returns:
QNode | Callable: The marked ``QNode`` or a decorator function if ``obj`` is not provided.
Raises:
ValueError: If the 'label' argument is not provided.
.. seealso::
Markers can also be manually added to pipelines with :meth:`~.CompilePipeline.add_marker`.
**Example:**
Consider the following circuit where several stages have been marked within the transforms applied:
.. code-block:: python
@qml.marker("after-merge-rotations")
@qml.transforms.merge_rotations
@qml.marker("after-cancel-inverses")
@qml.transforms.cancel_inverses
@qml.marker("nothing-applied")
@qml.qnode(qml.device("null.qubit"))
def c():
qml.RX(0.5, 0)
qml.H(0)
qml.H(0)
qml.RX(0.5, 0)
return qml.probs()
We can identify where each marker sits relative to the applied transforms by printing the pipeline,
>>> print(c.compile_pipeline)
CompilePipeline(
├─▶ nothing-applied
[1] cancel_inverses(),
├─▶ after-cancel-inverses
[2] merge_rotations()
└─▶ after-merge-rotations
)
>>> print(c.compile_pipeline.markers)
['nothing-applied', 'after-cancel-inverses', 'after-merge-rotations']
These markers are then recognized by a few of our inspectability features.
For example, we can verify the circuit resources after the ``Hadamard`` gates have been cancelled by using ``level="after-cancel-inverses"`` with :func:`~.specs`:
>>> print(qml.specs(c, level="after-cancel-inverses")()) # or level=1
Device: null.qubit
Device wires: None
Shots: Shots(total=None)
Level: after-cancel-inverses
<BLANKLINE>
Resource specifications:
Total wire allocations: 1
Total gates: 2
Circuit depth: 2
<BLANKLINE>
Gate types:
RX: 2
<BLANKLINE>
Measurements:
probs(all wires): 1
Similarly, we can print the circuit after the ``merge_rotations`` transform has been applied by passing ``level="after-merge-rotations"`` to :func:`~.draw`:
>>> print(qml.draw(c, level="after-merge-rotations")()) # or level=2
0: ──RX(1.00)─┤ Probs
or even display our circuit before any transformations,
>>> print(qml.draw(c, level="nothing-applied")()) # or level=0
0: ──RX(0.50)──H──H──RX(0.50)─┤ Probs
"""
if isinstance(obj, QNode) and label is not None:
obj.compile_pipeline.add_marker(label)
return obj
# NOTE: In order to use as decorator: @qml.marker(label="blah")
if isinstance(obj, str):
label = obj
obj = None
if obj is None and label is not None:
def decorator(qnode: QNode) -> QNode:
qnode.compile_pipeline.add_marker(label)
return qnode
return decorator
if obj is not None and not isinstance(obj, QNode):
raise ValueError("Object to mark must be a QNode.")
raise ValueError("marker requires a 'label' argument.")
_modules/pennylane/workflow/marker
Download Python script
Download Notebook
View on GitHub