Repository: PennyLaneAI/pennylane
Pull request #7066: Update Compiling Circuits page to include new decompositions system
Author: login: isaacdevlugt
Created: 2025-03-10T18:15:35Z | Merged: 2025-04-04T20:06:28Z

**Context:** Updates the [Compiling circuits page](https://docs.pennylane.ai/en/stable/introduction/compiling_circuits.html#custom-operator-decomposition) to include verbiage on the new decompositions system. ([sc-86152](https://app.shortcut.com/xanaduai/story/86152/new-decompositions-behaviour-is-documented-in-compiling-circuits))

**Description of the Change:** ^

**Benefits:** Documents the new behaviour

**Possible Drawbacks:** Hopefully none!

**Related GitHub Issues:**
[sc-85637]


Diff:
diff --git a/doc/introduction/compiling_circuits.rst b/doc/introduction/compiling_circuits.rst
index 5177903e683..cdcc25d87b1 100644
--- a/doc/introduction/compiling_circuits.rst
+++ b/doc/introduction/compiling_circuits.rst
@@ -211,71 +211,26 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
-
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
+Gate decompositions
+-------------------
 
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
 
-Circuit Decomposition
----------------------
-
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    **experimental** decomposition algorithm (by default, this new system is *not* 
+    enabled). This new system uses a graph-based approach, which provides better 
+    overall versatility and resource efficiency.
 
 Using a gate set
 ****************
 
-The example below demonstrates how a three-wire circuit can be decomposed using a pre-defined set of gates: 
+The example below demonstrates how a three-wire circuit can be decomposed using 
+a pre-defined set of gates: 
 
 .. code-block:: python
     
@@ -292,7 +247,8 @@ The example below demonstrates how a three-wire circuit can be decomposed using
         qml.Toffoli(wires=[0,1,2])
         return qml.expval(qml.Z(0))
     
-With the Hadamard gate not in our gate set, it will be decomposed into the respective rotation gate operators.
+With the Hadamard gate not in our gate set, it will be decomposed into allowed rotation 
+gate operators.
 
 >>> print(qml.draw(circuit)())
 0: ──RZ(1.57)──RX(1.57)──RZ(1.57)─╭●─┤  <Z>
@@ -302,13 +258,16 @@ With the Hadamard gate not in our gate set, it will be decomposed into the respe
 Using a gate rule
 *****************
 
-The example below demonstrates how a three-wire circuit can be decomposed into single or two-qubit gates using a rule:
+The example below demonstrates how a three-wire circuit can be decomposed into single 
+or two-qubit gates using a rule:
 
 .. code-block:: python
 
-    @partial(decompose, gate_set=lambda op: len(op.wires)<=2) 
-    @qml.qnode(dev)
+    # functions in gate_set can only be used with graph decomposition system disabled
+    qml.decompositions.disable_graph()
 
+    @partial(decompose, gate_set=lambda op: len(op.wires) <= 2) 
+    @qml.qnode(dev)
     def circuit():
         qml.Toffoli(wires=[0,1,2])
         return qml.expval(qml.Z(0)) 
@@ -321,11 +280,12 @@ The example below demonstrates how a three-wire circuit can be decomposed into s
 Decomposition in stages
 ***********************
 
-You can use the ``max_expansion`` argument to control the number of decomposition stages applied to
-the circuit. By default, the function will decompose the circuit until the desired gate set is reached.
+You can use the ``max_expansion`` argument to control the number of decomposition 
+stages applied to the circuit. By default, the function will decompose the circuit 
+until the desired gate set is reached.
 
-The example below shows how the user can visualize the decomposition. 
-We begin with creating a :class:`~.pennylane.QuantumPhaseEstimation` circuit: 
+The example below shows how the user can visualize the decomposition. We begin 
+with creating a :class:`~.pennylane.QuantumPhaseEstimation` circuit: 
 
 .. code-block:: python
 
@@ -373,6 +333,197 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose gates 
+that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide *new* decomposition rules to be used, but the behaviour
+and user-interface is different depending on if the graph decompositions system is
+enabled.
+
+Default behaviour with custom decompositions
+********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the graph 
+    decompositions system functionality outlined in the next section.
+
+Custom decompositions with qml.decomposition.enable_graph
+*********************************************************
+
+With the graph decompositions system enabled, custom decompositions for operators 
+in PennyLane can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any decomposition for an operator type here will automatically 
+  be chosen by the new algorithm, regardless of how resource efficient it may or 
+  may not be.
+* ``alt_decomps``: any decompositions for an operator type list here are added as 
+  a *possible* decomposition rules the algorithm can choose based on its resource 
+  efficiency.
+
+Both keyword arguments above require a dictionary mapping PennyLane operator types to 
+custom decompositions. Creating custom decompositions that the graph-based system 
+can use involves a PennyLane quantum function that represents the decomposition, 
+and a declaration of its resource requirements (gate counts) via :func:`~.pennylane.register_resources`.
+
+Consider this example where we add a fixed decomposition to ``CNOT`` gates:
+
+.. code-block:: python
+
+    @qml.register_resources({qml.H: 2, qml.CZ: 1})
+    def my_cnot(wires, **__):
+        qml.H(wires=wires[1])
+        qml.CZ(wires=wires)
+        qml.H(wires=wires[1])
+
+The :func:`~.pennylane.register_resources` accepts a dictionary mapping operator 
+types within the custom decomposition to the number oftimes they occur in the decomposition. 
+With the resources registered, this can be used with ``fixed_decomps`` or ``alt_decomps``:
+
+.. code-block:: python
+
+    @partial(qml.transforms.decompose, fixed_decomps={qml.CNOT: my_cnot})
+    @qml.qnode(qml.device("default.qubit"))
+    def circuit():
+        qml.CNOT(wires=[0, 1])
+        return qml.state()
+
+>>> print(qml.draw(circuit, level="device")())
+0: ────╭●────┤  State
+1: ──H─╰Z──H─┤  State
+
+Note that the ``alt_decomps`` argument can handle multiple alternatives per operator
+type:
+
+.. code-block:: python
+
+    @qml.register_resources({qml.H: 2, qml.CZ: 1})
+    def my_cnot1(wires, **__):
+        qml.H(wires=wires[1])
+        qml.CZ(wires=wires)
+        qml.H(wires=wires[1])
+
+    @qml.register_resources({qml.RY: 2, qml.CZ: 1, qml.Z: 2})
+    def my_cnot2(wires, **__):
+        qml.RY(np.pi/2, wires[1])
+        qml.Z(wires[1])
+        qml.CZ(wires=wires)
+        qml.RY(np.pi/2, wires[1])
+        qml.Z(wires[1])
+
+    @partial(
+        qml.transforms.decompose,
+        alt_decomps={qml.CNOT: [my_cnot1, my_cnot2]}
+    )
+    @qml.qnode(qml.device("default.qubit"))
+    def circuit():
+        qml.CNOT(wires=[0, 1])
+        return qml.state()
+
+The decomposition that the algorithm chooses internally will be the most resource-efficient.
+More details on creating complex decomposition rules that may depend on runtime 
+parameters can be found in the usage details for :func:`~.pennylane.register_resources`.
+
+Alternatively, new decomposition rules can be added to operators *globally* with 
+the :func:`~.pennylane.add_decomps` function. This negates having to specify ``alt_decomps``
+in every instance of the ``decompose`` transform. The following example globally 
+adds the ``my_cnot1`` and ``my_cnot2`` decomposition rules to the ``qml.CNOT`` gate:
+
+>>> qml.add_decomps(qml.CNOT, my_cnot1, my_cnot2)
+
+The newly added rules for the ``qml.CNOT`` operator can be verified or inspected 
+with the :func:`~.pennylane.list_decomps` function:
+
+>>> my_new_rules = qml.list_decomps(qml.CNOT)[-2:]
+>>> print(qml.draw(my_new_rules[1])(wires=[0, 1]))
+0: ──────────────╭●──────────────┤  
+1: ──RY(1.57)──Z─╰Z──RY(1.57)──Z─┤ 
+
 Circuit cutting
 ---------------
 
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index ff64b9c3413..c32f4eac579 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -972,6 +972,14 @@ With `qml.decompositions.enable_graph()`, the following new features are availab
 
 <h3>Documentation 📝</h3>
 
+* The :doc:`Compiling Circuits page <../introduction/compiling_circuits>` has been updated to include information
+  on using the new experimental decompositions system.
+  [(#7066)](https://github.com/PennyLaneAI/pennylane/pull/7066)
+
+* The docstring for `qml.transforms.decompose` now recommends the `qml.clifford_t_decomposition` 
+  transform when decomposing to the Clifford + T gate set.
+  [(#7177)](https://github.com/PennyLaneAI/pennylane/pull/7177)
+
 * Typos were fixed in the docstring for `qml.QubitUnitary`.
   [(#7187)](https://github.com/PennyLaneAI/pennylane/pull/7187)
 
diff --git a/pennylane/transforms/decompose.py b/pennylane/transforms/decompose.py
index 0a497c54a8c..35583ae9acc 100644
--- a/pennylane/transforms/decompose.py
+++ b/pennylane/transforms/decompose.py
@@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the
+        :doc:`Compiling Circuits page </introduction/compiling_circuits>`.
+
     Args:
         tape (QuantumScript or QNode or Callable): a quantum circuit.
         gate_set (Iterable[str or type] or Callable, optional): The target gate set specified as
@@ -428,7 +433,9 @@ def decompose(
 
     .. seealso::
 
-        :func:`qml.devices.preprocess.decompose <.pennylane.devices.preprocess.decompose>` for a
+        For decomposing into Clifford + T, check out :func:`~.pennylane.clifford_t_decomposition`.
+
+        :func:`qml.devices.preprocess.decompose <.pennylane.devices.preprocess.decompose>` is a
         transform that is intended for device developers. This function will decompose a quantum
         circuit into a set of basis gates available on a specific device architecture.
 


Reviews:
user: login: josh146
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T02:08:09Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:20:27Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:20:38Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:21:38Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:22:38Z
user: login: josh146
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T20:46:32Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:51:34Z
user: login: astralcai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T14:47:54Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T17:55:32Z
user: login: astralcai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T19:54:04Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T21:14:19Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T21:19:44Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T21:21:25Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T21:43:52Z
user: login: josh146
body: 😎 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-04T01:48:59Z
user: login: astralcai
body: Just a minor comment left.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T13:21:32Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T14:48:53Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T14:49:10Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T17:21:58Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T17:22:21Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T17:43:06Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T17:43:19Z
user: login: isaacdevlugt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T17:43:46Z
user: login: astralcai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T18:25:35Z
user: login: astralcai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T18:26:24Z
user: login: maliasadi
body: Thanks @isaacdevlugt! :star_struck: 

Could you also fix the following typos/issues across the decomposition doc pages before merging the PR? :slightly_smiling_face: 

- Replace `enabled_garph` --> `enabled_graph` [here](https://docs.pennylane.ai/en/latest/code/qml_decomposition.html)
- Replace `guarentee` --> `guarantee` [here](https://docs.pennylane.ai/en/latest/code/qml_decomposition.html)
- Replace `wheras` --> whereas` [here](https://docs.pennylane.ai/en/latest/code/qml_decomposition.html)
- Fix the missing reference to the 'Quantum Functions as Decomposition Rules' section [here](https://docs.pennylane.ai/en/latest/code/api/pennylane.register_resources.html).
- Remove the duplicated `resource_keys = set()` attribute [here](https://github.com/PennyLaneAI/pennylane/blob/85f6ff7f65629f850e086d6a5189464cf04845b8/pennylane/ops/qubit/non_parametric_ops.py#L281)
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T19:50:06Z

Review comments:
diff_hunk: @@ -3,8 +3,8 @@
 
 .. _intro_ref_compile_circuits:
 
-Compiling circuits
-==================
+Quantum compilation
+===================
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: @isaacdevlugt the naming of this page as 'Compiling circuits' was deliberate, as we realized that 'quantum compilation' was too vague (does it mean catalyst, etc.) :)
created_at: 2025-03-21T00:58:40Z
author_association: MEMBER
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: ```suggestion
    experimental decomposition algorithm. This 
```
created_at: 2025-03-21T00:59:17Z
author_association: MEMBER
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
+    new system uses a graph-based approach, which provides better overall performance 
+    and versatility. By default, this new system is *not* enabled globally. 
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: > By default, this new system is *not* enabled globally.

I think this is implied already by the first sentence, no 😅 
created_at: 2025-03-21T01:00:03Z
author_association: MEMBER
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
+    new system uses a graph-based approach, which provides better overall performance 
+    and versatility. By default, this new system is *not* enabled globally. 
+    
+    Unless otherwise indicated, features outlined below work with the current, default 
+    system or when the new decomposition system is enabled globally with :func:`~.pennylane.decompositions.enable_graph`.
+    The new decompositions system can be disabled with :func:`~.pennylane.decompositions.disable_graph`.
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: Since reference docs are consulted, I would be explicit in the code examples instead
created_at: 2025-03-21T01:00:31Z
author_association: MEMBER
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: note: the table will look better if you use 

```rest
.. rst-class:: docstable

    +------+------+
    | col1 | col2 |
```
created_at: 2025-03-21T01:04:39Z
author_association: MEMBER
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: ```suggestion
When executing QNodes on a device, PennyLane will automatically decompose
gates that are unsupported by the device using built-in decomposition rules.

In addition, you can provide custom decomposition rules to be used.

The default behaviour in PennyLane
```
created_at: 2025-03-21T01:10:10Z
author_association: MEMBER
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: Rephrased to be a bit more explicit on what this feature is
created_at: 2025-03-21T01:10:20Z
author_association: MEMBER
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: I must admit I do not understand this table at all. It might be better to showcase this feature first, and come back to this table as an explanation after?
created_at: 2025-03-21T01:10:50Z
author_association: MEMBER
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: this section is great!
created_at: 2025-03-21T02:08:03Z
author_association: MEMBER
diff_hunk: @@ -3,8 +3,8 @@
 
 .. _intro_ref_compile_circuits:
 
-Compiling circuits
-==================
+Quantum compilation
+===================
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: Oh, to me "compiling circuits" was closer to catalyst 😅. I'll stick with the original name (if it ain't broke don't fix it)
created_at: 2025-03-21T13:20:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3,8 +3,8 @@
 
 .. _intro_ref_compile_circuits:
 
-Compiling circuits
-==================
+Quantum compilation
+===================
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: ```suggestion
Compiling circuits
==================
```
created_at: 2025-03-21T13:20:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: I couldn't find anything to properly insert a table in rst lol. Thank you for this!
created_at: 2025-03-21T13:21:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: Yeah this was just an experiment. Wanted to see how it would render in the docs and get a better overall picture of it in context. I just couldn't figure out how to create a table lol
created_at: 2025-03-21T13:22:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,188 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+PennyLane decomposes gates unknown to the device into other, "lower-level" gates. 
+As a user, you may want to fine-tune this mechanism. The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: RST also has list tables, which are more convenient https://sublime-and-sphinx-guide.readthedocs.io/en/latest/tables.html

created_at: 2025-03-21T20:46:32Z
author_association: MEMBER
diff_hunk: @@ -429,9 +429,12 @@ def decompose(
 
     .. seealso::
 
-        :func:`qml.devices.preprocess.decompose <.pennylane.devices.preprocess.decompose>` for a
+        For decomposing into Clifford + T, check out :func:`~.pennylane.clifford_t_decomposition`.
path: pennylane/transforms/decompose.py
user: login: isaacdevlugt
body: TODO add a link in the decompose docstring to the compiling circuits page
created_at: 2025-04-01T15:51:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
-
-    custom_decomps = {qml.CNOT: custom_cnot}
+Gate decompositions
+-------------------
 
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm. This 
+    new system uses a graph-based approach, which provides better overall performance 
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: ```suggestion
    new system uses a graph-based approach, which provides better overall resource efficiency 
```
created_at: 2025-04-02T14:07:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
+    new system uses a graph-based approach, which provides better overall performance 
+    and versatility. By default, this new system is *not* enabled globally. 
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: Should we also include a warning here that this system is still experimental?
created_at: 2025-04-02T14:07:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -318,11 +279,23 @@ The example below demonstrates how a three-wire circuit can be decomposed into s
 1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤     
 2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤ 
 
+.. note::
+
+    Using gate rules with :func:`~.pennylane.decompositions.enable_graph` present 
+    is not currently supported. 
+
 Decomposition in stages
 ***********************
 
-You can use the ``max_expansion`` argument to control the number of decomposition stages applied to
-the circuit. By default, the function will decompose the circuit until the desired gate set is reached.
+You can use the ``max_expansion`` argument to control the number of decomposition 
+stages applied to the circuit. By default, the function will decompose the circuit 
+until the desired gate set is reached.
+
+.. note::
+
+    Using the ``max_expansion`` argument with :func:`~.pennylane.decompositions.enable_graph`
+    does not do anything, as the new decompositions algorithm is not iterative in 
+    the same way.
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: I don't think so? ``max_expansion`` should always work.
```python
from functools import partial
import pennylane as qml

qml.decomposition.enable_graph()

@partial(qml.transforms.decompose, gate_set={"RZ", "RX", "CNOT", "GlobalPhase"}, max_expansion=1)
@qml.qnode(qml.device("default.qubit", wires=3))
def f():
    qml.QFT(wires=[0, 1, 2])
```
```pycon
>>> print(qml.draw(f)())
0: ──H─╭Rϕ(1.57)─╭Rϕ(0.79)─────────────────╭SWAP─┤  
1: ────╰●────────│──────────H─╭Rϕ(1.57)────│─────┤  
2: ──────────────╰●───────────╰●─────────H─╰SWAP─┤
```
created_at: 2025-04-02T14:14:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -318,11 +279,23 @@ The example below demonstrates how a three-wire circuit can be decomposed into s
 1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤     
 2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤ 
 
+.. note::
+
+    Using gate rules with :func:`~.pennylane.decompositions.enable_graph` present 
+    is not currently supported. 
+
 Decomposition in stages
 ***********************
 
-You can use the ``max_expansion`` argument to control the number of decomposition stages applied to
-the circuit. By default, the function will decompose the circuit until the desired gate set is reached.
+You can use the ``max_expansion`` argument to control the number of decomposition 
+stages applied to the circuit. By default, the function will decompose the circuit 
+until the desired gate set is reached.
+
+.. note::
+
+    Using the ``max_expansion`` argument with :func:`~.pennylane.decompositions.enable_graph`
+    does not do anything, as the new decompositions algorithm is not iterative in 
+    the same way.
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: I'm sorry if I misled you when you asked me about this. What I meant at the time was that it didn't make sense to use `max_expansion` on the decomposition graph, but you can still control the depth of recursion in the `decompose` transform.
created_at: 2025-04-02T14:16:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: What do you mean by QNode-level and Device-level exactly?
created_at: 2025-04-02T14:18:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: Since the new system is disabled by default, this is just the default behaviour. Maybe instead of phrasing it like enable_graph vs. disable_graph, phrase it like current behaviour / experimental behaviour with graph enabled?
created_at: 2025-04-02T14:20:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: ```suggestion
* ``fixed_decomps``: specify a single decomposition rule to use for each operator here, in place of any existing decomposition rules defined for these operators.
* ``alt_decomps``: specify a list of alternative decomposition rules for each operator here, and one of them may be chosen if they lead to a more resource-efficient decomposition.
```
created_at: 2025-04-02T14:44:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
+
+Both keyword arguments above require a dictionary mapping PennyLane operators to 
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: ```suggestion
Both keyword arguments above require a dictionary mapping PennyLane operator types to 
```
created_at: 2025-04-02T14:44:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
+
+Both keyword arguments above require a dictionary mapping PennyLane operators to 
+custom decompositions. Creating custom decompositions that the system can use involves 
+a PennyLane quantum function that represents the decomposition and a registering 
+resource data to it that tracks gate counts in the custom decomposition via :func:`~.pennylane.register_resources`.
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: ```suggestion
a PennyLane quantum function that represents the decomposition and a declaration of how much resource it requires in terms of gate counts, via :func:`~.pennylane.register_resources`.
```
created_at: 2025-04-02T14:46:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
+
+Both keyword arguments above require a dictionary mapping PennyLane operators to 
+custom decompositions. Creating custom decompositions that the system can use involves 
+a PennyLane quantum function that represents the decomposition and a registering 
+resource data to it that tracks gate counts in the custom decomposition via :func:`~.pennylane.register_resources`.
+
+Consider this example where we add a fixed decomposition to ``CNOT`` gates:
+
+.. code-block:: python
+
+    @qml.register_resources({qml.H: 2, qml.CZ: 1})
+    def my_cnot(wires, **__):
+        qml.H(wires=wires[1])
+        qml.CZ(wires=wires)
+        qml.H(wires=wires[1])
+
+The :func:`~.pennylane.register_resources` accepts a dictionary mapping operators 
+within the custom decomposition to the number of times they occur in the decomposition. 
+With the resources registered, this can be used with ``fixed_decomps`` or ``alt_decomps``:
+
+.. code-block:: python
+
+    @partial(qml.transforms.decompose, fixed_decomps={qml.CNOT: my_cnot})
+    @qml.qnode(qml.device("default.qubit"))
+    def circuit():
+        qml.CNOT(wires=[0, 1])
+        return qml.state()
+
+>>> print(qml.draw(circuit, level="device")())
+0: ────╭●────┤  State
+1: ──H─╰Z──H─┤  State
+
+Note that the ``alt_decomps`` argument can handle multiple options per operator:
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: ```suggestion
Note that the ``alt_decomps`` argument can handle multiple alternatives per operator:
```
created_at: 2025-04-02T14:47:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
+    new system uses a graph-based approach, which provides better overall performance 
+    and versatility. By default, this new system is *not* enabled globally. 
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: In the .. note:: directive above I have 

>Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new experimental decomposition algorithm.

But I'm happy to be more explicit about the experimental nature of this feature!
created_at: 2025-04-02T17:55:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -211,71 +211,30 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of basis gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    experimental decomposition algorithm is enabled (introduced in v0.41). This 
+    new system uses a graph-based approach, which provides better overall performance 
+    and versatility. By default, this new system is *not* enabled globally. 
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: Oh ooops guess I missed it.
created_at: 2025-04-02T19:54:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -318,11 +279,23 @@ The example below demonstrates how a three-wire circuit can be decomposed into s
 1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤     
 2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤ 
 
+.. note::
+
+    Using gate rules with :func:`~.pennylane.decompositions.enable_graph` present 
+    is not currently supported. 
+
 Decomposition in stages
 ***********************
 
-You can use the ``max_expansion`` argument to control the number of decomposition stages applied to
-the circuit. By default, the function will decompose the circuit until the desired gate set is reached.
+You can use the ``max_expansion`` argument to control the number of decomposition 
+stages applied to the circuit. By default, the function will decompose the circuit 
+until the desired gate set is reached.
+
+.. note::
+
+    Using the ``max_expansion`` argument with :func:`~.pennylane.decompositions.enable_graph`
+    does not do anything, as the new decompositions algorithm is not iterative in 
+    the same way.
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: @astralcai no worries! :) I'll msg you offline about this 👀 
created_at: 2025-04-03T21:14:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: ```suggestion
* ``fixed_decomps``: any decomposition for an operator type here will automatically 
  be chosen by the new algorithm, regardless of how resource efficient it may or 
  may not be.
* ``alt_decomps``: any decompositions for an operator type list here are added as 
  a *possible* decomposition rules the algorithm can choose based on its resource 
  efficiency.
```
created_at: 2025-04-03T21:19:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,6 +346,192 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose
+gates that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide custom decomposition rules to be used.
+
+The default behaviour in PennyLane
+versus that of the new decompositions system (enabled with ``qml.decomposition.enable_graph``)
+differ in the following ways when it comes to injecting custom decompositions for
+operators:
+
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+|                   | QNode-level decomposition    | Device-level decomposition  | Multiple decompositions per operator |
++===================+==============================+=============================+======================================+
+| ``disable_graph`` | No                           | Yes                         | No                                   |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+| ``enable_graph``  | Yes                          | Yes                         | Yes                                  |
++-------------------+------------------------------+-----------------------------+--------------------------------------+
+
+Behaviour with qml.decomposition.disable_graph
+**********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
+
+Behaviour with qml.decomposition.enable_graph
+*********************************************
+
+With the new graph-based system enabled, custom decompositions for operators in PennyLane
+can be added in a few ways depending on the application. 
+
+The :func:`~.pennylane.transforms.decompose` transform offers the ability to inject
+custom decompositions via two keyword arguments:
+
+* ``fixed_decomps``: any operator with a decomposition listed here will automatically 
+  be chosen by the new algorithm, regardless of how efficient it may or may not 
+  be.
+* ``alt_decomps``: any operator with a decomposition list here is added as a possible 
+  decomposition the algorithm can choose based on its resources.
+
+Both keyword arguments above require a dictionary mapping PennyLane operators to 
+custom decompositions. Creating custom decompositions that the system can use involves 
+a PennyLane quantum function that represents the decomposition and a registering 
+resource data to it that tracks gate counts in the custom decomposition via :func:`~.pennylane.register_resources`.
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: Nice! Slight amendment based on your suggestion

```suggestion
a PennyLane quantum function that represents the decomposition, and a declaration of its resource requirements (gate counts) via :func:`~.pennylane.register_resources`.
```
created_at: 2025-04-03T21:21:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -318,11 +279,23 @@ The example below demonstrates how a three-wire circuit can be decomposed into s
 1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤     
 2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤ 
 
+.. note::
+
+    Using gate rules with :func:`~.pennylane.decompositions.enable_graph` present 
+    is not currently supported. 
+
 Decomposition in stages
 ***********************
 
-You can use the ``max_expansion`` argument to control the number of decomposition stages applied to
-the circuit. By default, the function will decompose the circuit until the desired gate set is reached.
+You can use the ``max_expansion`` argument to control the number of decomposition 
+stages applied to the circuit. By default, the function will decompose the circuit 
+until the desired gate set is reached.
+
+.. note::
+
+    Using the ``max_expansion`` argument with :func:`~.pennylane.decompositions.enable_graph`
+    does not do anything, as the new decompositions algorithm is not iterative in 
+    the same way.
path: doc/introduction/compiling_circuits.rst
user: login: isaacdevlugt
body: Resolved offline :) 
created_at: 2025-04-03T21:43:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -211,77 +211,35 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
 `the compilation documentation
 <../code/qml_transforms.html#transforms-for-circuit-compilation>`_.
 
-Custom Operator Decomposition
------------------------------
-
-PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.
-
-For example, suppose we would like to implement the following QNode:
-
-.. code-block:: python
-
-    def circuit(weights):
-        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
-        return qml.expval(qml.Z(0))
-
-    original_dev = qml.device("default.qubit", wires=3)
-    original_qnode = qml.QNode(circuit, original_dev)
-
->>> weights = np.array([[0.4, 0.5, 0.6]])
->>> print(qml.draw(original_qnode, level="device")(weights))
-0: ──RX(0.40)─╭●────╭X─┤  <Z>
-1: ──RX(0.50)─╰X─╭●─│──┤     
-2: ──RX(0.60)────╰X─╰●─┤     
-
-Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into ``CZ``
-and ``Hadamard``.
-We define the custom decompositions like so, and pass them to a device:
-
-.. code-block:: python
-
-    def custom_cnot(wires, **_):
-        return [
-            qml.Hadamard(wires=wires[1]),
-            qml.CZ(wires=[wires[0], wires[1]]),
-            qml.Hadamard(wires=wires[1])
-        ]
+Gate decompositions
+-------------------
 
-    custom_decomps = {qml.CNOT: custom_cnot}
-
-    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
-    decomp_qnode = qml.QNode(circuit, decomp_dev)
-
-Note that custom decomposition functions should accept keyword arguments even when it is not used.
-
-Now when we draw or run a QNode on this device, the gates will be expanded
-according to our specifications:
-
->>> print(qml.draw(decomp_qnode, level="device")(weights))
-0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
-1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
-2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+When compiling a circuit, it is often beneficial to decompose the circuit into a 
+set of gates. To do this, we can use the :func:`~.pennylane.transforms.decompose` 
+function, which enables decomposition of circuits into a set of gates defined either 
+by their name, type, or by a set of rules they must follow.
 
 .. note::
-    If the custom decomposition is only supposed to be used in a specific code context,
-    a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.
-
-Circuit Decomposition
----------------------
 
-When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.  
-To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which enables decomposition of
-circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.
+    Using :func:`~.pennylane.decompositions.enable_graph` enables PennyLane's new 
+    **experimental** decomposition algorithm (by default, this new system is *not* 
+    enabled). This new system uses a graph-based approach, which provides better 
+    overall versatility and resource efficiency.
 
 Using a gate set
 ****************
 
-The example below demonstrates how a three-wire circuit can be decomposed using a pre-defined set of gates: 
+The example below demonstrates how a three-wire circuit can be decomposed using 
+a pre-defined set of gates: 
 
 .. code-block:: python
     
     from pennylane.transforms import decompose
     from functools import partial
 
+    # Works with the new decomposition system, as well.
+    # qml.decompositions.enable_graph()
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: @isaacdevlugt this might be superfluous -- e.g., if this works with graph enabled or disabled, I wouldn't even worry about mentioning this here as it can be confusing!
created_at: 2025-04-04T01:46:37Z
author_association: MEMBER
diff_hunk: @@ -373,6 +340,197 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose gates 
+that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide *new* decomposition rules to be used, but the behaviour
+and user-interface is different depending on if the new decompositions system is
+enabled.
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: ```suggestion
and user-interface is different depending on if the graph decompositions system is
enabled.
```

I would err towards not calling it 'new decomposition' system as it relies on readers knowing the temporal order of our systems. Rather, better to refer to it based on its feature/algorithm ('graph decompositions'). This also matches the function for turning it on :)
created_at: 2025-04-04T01:48:13Z
author_association: MEMBER
diff_hunk: @@ -373,6 +340,197 @@ From here, we can iterate through the stages of decomposition:
 ───H†─│────────────╰●───────────────┤  
 ──────╰●────────────────────────────┤  
 
+Custom Operator Decomposition
+-----------------------------
+
+When executing QNodes on a device, PennyLane will automatically decompose gates 
+that are unsupported by the device using built-in decomposition rules.
+
+In addition, you can provide *new* decomposition rules to be used, but the behaviour
+and user-interface is different depending on if the new decompositions system is
+enabled.
+
+Default behaviour with custom decompositions
+********************************************
+
+For example, suppose we would like to implement the following QNode:
+
+.. code-block:: python
+
+    def circuit(weights):
+        qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])
+        return qml.expval(qml.Z(0))
+
+    original_dev = qml.device("default.qubit", wires=3)
+    original_qnode = qml.QNode(circuit, original_dev)
+
+>>> weights = np.array([[0.4, 0.5, 0.6]])
+>>> print(qml.draw(original_qnode, level="device")(weights))
+0: ──RX(0.40)─╭●────╭X─┤  <Z>
+1: ──RX(0.50)─╰X─╭●─│──┤     
+2: ──RX(0.60)────╰X─╰●─┤     
+
+Now, let's swap out PennyLane's default decomposition of the ``CNOT`` gate into 
+``CZ`` and ``Hadamard``. We define the custom decompositions like so, and pass them 
+to a device:
+
+.. code-block:: python
+
+    def custom_cnot(wires, **_):
+        return [
+            qml.Hadamard(wires=wires[1]),
+            qml.CZ(wires=[wires[0], wires[1]]),
+            qml.Hadamard(wires=wires[1])
+        ]
+
+    custom_decomps = {qml.CNOT: custom_cnot}
+
+    decomp_dev = qml.device("default.qubit", wires=3, custom_decomps=custom_decomps)
+    decomp_qnode = qml.QNode(circuit, decomp_dev)
+
+Note that custom decomposition functions should accept keyword arguments even when 
+it is not used.
+
+Now when we draw or run a QNode on this device, the gates will be expanded according 
+to our specifications:
+
+>>> print(qml.draw(decomp_qnode, level="device")(weights))
+0: ──RX(0.40)────╭●──H───────╭Z──H─┤  <Z>
+1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤     
+2: ──RX(0.60)──H───────╰Z──H─╰●────┤     
+
+If the custom decomposition is only supposed to be used in a specific code context,
+a separate context manager :func:`~.pennylane.transforms.set_decomposition` can 
+be used.
+
+.. note::
+
+    Device-level custom decompositions **are not applied before other compilation 
+    passes (decorators on QNodes)**. For example, the following circuit has ``cancel_inverses`` 
+    applied to it, and the device was provided a decomposition for ``qml.CNOT``. 
+    The Hadamard gates applied around the ``qml.CNOT`` gate do not get cancelled 
+    with those introduced by the custom decomposition.
+
+    .. code-block:: python
+
+        def custom_cnot(wires, **_):
+            return [
+                qml.H(wires=wires[1]),
+                qml.CZ(wires=[wires[0], wires[1]]),
+                qml.H(wires=wires[1])
+            ]
+
+        dev = qml.device("default.qubit", custom_decomps={qml.CNOT: custom_cnot})
+
+        @qml.transforms.cancel_inverses
+        @qml.qnode(dev)
+        def circuit():
+            qml.H(1)
+            qml.CNOT([0, 1])
+            qml.H(1)
+            return qml.state()
+
+    >>> print(qml.draw(circuit, level="device")())
+    0: ───────╭●───────┤  State
+    1: ──H──H─╰Z──H──H─┤  State
+
+    To have better control over custom decompositions, consider using the new decompositions
+    system functionality outlined in the next section.
path: doc/introduction/compiling_circuits.rst
user: login: josh146
body: same comment here
created_at: 2025-04-04T01:48:31Z
author_association: MEMBER
diff_hunk: @@ -288,17 +288,13 @@ You can use the ``max_expansion`` argument to control the number of decompositio
 stages applied to the circuit. By default, the function will decompose the circuit 
 until the desired gate set is reached.
 
-.. note::
-
-    Using the ``max_expansion`` argument with :func:`~.pennylane.decompositions.enable_graph`
-    does not do anything.
-
 The example below shows how the user can visualize the decomposition. We begin 
 with creating a :class:`~.pennylane.QuantumPhaseEstimation` circuit: 
 
 .. code-block:: python
 
-    qml.decompositions.disable_graph()
+    # Works with the new decomposition system, as well.
+    # qml.decompositions.enable_graph()
path: doc/introduction/compiling_circuits.rst
user: login: astralcai
body: I think the reader can safely assume that everything in this doc works with the graph decomposition enabled or disabled, unless stated otherwise. There is no need to explicitly say that it works in both systems.
created_at: 2025-04-04T13:20:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -966,6 +966,14 @@ With `qml.decompositions.enable_graph()`, the following new features are availab
 
 <h3>Documentation 📝</h3>
 
+* The :doc:`Compiling Circuits page <introduction/compiling_circuits>` has been updated to include information
path: doc/releases/changelog-dev.md
user: login: isaacdevlugt
body: ```suggestion
* The :doc:`Compiling Circuits page <~/doc/introduction/compiling_circuits>` has been updated to include information
```
created_at: 2025-04-04T14:48:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the 
+        :doc:`Compiling Circuits page <introduction/compiling_circuits>`__.
path: pennylane/transforms/decompose.py
user: login: isaacdevlugt
body: ```suggestion
        :doc:`Compiling Circuits page <~/doc/introduction/compiling_circuits>`__.
```
created_at: 2025-04-04T14:49:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -966,6 +966,14 @@ With `qml.decompositions.enable_graph()`, the following new features are availab
 
 <h3>Documentation 📝</h3>
 
+* The :doc:`Compiling Circuits page <~/doc/introduction/compiling_circuits>` has been updated to include information
path: doc/releases/changelog-dev.md
user: login: isaacdevlugt
body: ```suggestion
* The :doc:`Compiling Circuits page <../doc/introduction/compiling_circuits>` has been updated to include information
```
created_at: 2025-04-04T17:21:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the 
+        :doc:`Compiling Circuits page <~/doc/introduction/compiling_circuits>`__.
path: pennylane/transforms/decompose.py
user: login: isaacdevlugt
body: ```suggestion
        :doc:`Compiling Circuits page <../../doc/introduction/compiling_circuits>`__.
```
created_at: 2025-04-04T17:22:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the 
path: pennylane/transforms/decompose.py
user: login: isaacdevlugt
body: ```suggestion
        For more information on PennyLane's decomposition tools and features, check out the
```
created_at: 2025-04-04T17:43:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -428,9 +433,12 @@ def decompose(
 
     .. seealso::
 
-        :func:`qml.devices.preprocess.decompose <.pennylane.devices.preprocess.decompose>` for a
+        For decomposing into Clifford + T, check out :func:`~.pennylane.clifford_t_decomposition`.
+
+        :func:`qml.devices.preprocess.decompose <.pennylane.devices.preprocess.decompose>` is a
         transform that is intended for device developers. This function will decompose a quantum
         circuit into a set of basis gates available on a specific device architecture.
+        
path: pennylane/transforms/decompose.py
user: login: isaacdevlugt
body: ```suggestion
```
created_at: 2025-04-04T17:43:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -969,6 +969,14 @@ With `qml.decompositions.enable_graph()`, the following new features are availab
 
 <h3>Documentation 📝</h3>
 
+* The :doc:`Compiling Circuits page <../doc/introduction/compiling_circuits>` has been updated to include information
path: doc/releases/changelog-dev.md
user: login: isaacdevlugt
body: ```suggestion
* The :doc:`Compiling Circuits page <../introduction/compiling_circuits>` has been updated to include information
```
created_at: 2025-04-04T17:43:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the
+        :doc:`Compiling Circuits page <../../doc/introduction/compiling_circuits>`__.
path: pennylane/transforms/decompose.py
user: login: astralcai
body: I think the issue is with this line here.
created_at: 2025-04-04T18:25:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,6 +393,11 @@ def decompose(
         decompositions towards any target gate set. The keyword arguments ``fixed_decomps`` and
         ``alt_decomps`` are only functional with this toggle present.
 
+    .. seealso::
+
+        For more information on PennyLane's decomposition tools and features, check out the
+        :doc:`Compiling Circuits page <../../doc/introduction/compiling_circuits>`__.
path: pennylane/transforms/decompose.py
user: login: astralcai
body: ```suggestion
        :doc:`Compiling Circuits page </introduction/compiling_circuits>`.
```
created_at: 2025-04-04T18:26:24Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-04-03T22:45:14Z
body: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/7066?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.64%. Comparing base [(`85f6ff7`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/85f6ff7f65629f850e086d6a5189464cf04845b8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`f886f53`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/f886f5369fad77a9b95b593e936067287a7d7dcc?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).
> Report is 341 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #7066   +/-   ##
=======================================
  Coverage   99.64%   99.64%           
=======================================
  Files         511      511           
  Lines       49885    49885           
=======================================
  Hits        49709    49709           
  Misses        176      176           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/7066?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: maliasadi
created_at: 2025-04-04T20:09:40Z
body: Ahh.. I had to remove it from the merge queue :smile: nwm -- we can address those suggestions as a follow-up 
author_association: MEMBER