Skip to content

Graph decompose frontend#2568

Merged
kipawaa merged 23 commits intograph-decompose-passfrom
graph-decompose-frontend
Mar 16, 2026
Merged

Graph decompose frontend#2568
kipawaa merged 23 commits intograph-decompose-passfrom
graph-decompose-frontend

Conversation

@kipawaa
Copy link
Copy Markdown
Contributor

@kipawaa kipawaa commented Mar 10, 2026

Context:

Description of the Change:
Provides the interface for the graph-decompose pass.

Benefits:
graph decomposition occurs in C++ at runtime, using precompiled builtin rules and jit compiled user rules.

Possible Drawbacks:
N/A

Related GitHub Issues:

[sc-113641]
[sc-101036]

@kipawaa kipawaa changed the base branch from main to graph-decompose-pass March 10, 2026 20:51
Copy link
Copy Markdown
Member

@maliasadi maliasadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kipawaa!

from catalyst.compiler import _options_to_cli_flags, _quantum_opt
from catalyst.passes.pass_api import PassPipelineWrapper
from catalyst.utils.exceptions import CompileError
from catalyst.utils.precompile_decomposition_rules import BYTECODE_FILE_NAME, DEFAULT_RULE_DIR
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we create and import BYTECODE_FILE_PATH instead of BYTECODE_FILE_NAME, DEFAULT_RULE_DIR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more related to this PR, but I'll implement it there so that we can sync it up the branches. I think it makes sense to do this after merging this branch though, to reduce the amount of syncing required.

gate_set: Iterable,
fixed_decomps: dict | None = None,
alt_decomps: dict | None = None,
rule_path: Path = DEFAULT_RULE_DIR / BYTECODE_FILE_NAME,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably add builtin, standard or something else to the name of this optional kwarg to better convey the use case:

Suggested change
rule_path: Path = DEFAULT_RULE_DIR / BYTECODE_FILE_NAME,
builtin_rule_path: Path = DEFAULT_RULE_DIR / BYTECODE_FILE_NAME,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also a dev utility and it's not supposed to be used by users.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the name to _builtin_rule_path here - I think having this parameter around for a bit longer to allow different rule caches in development and testing might be useful, but I'm open to removing it if you think it should not be exposed at all.

Comment thread frontend/catalyst/passes/builtin_passes.py
Comment thread frontend/catalyst/passes/builtin_passes.py Outdated
)

if not isinstance(gate_set, dict):
gate_set = {op.__name__: 1.0 for op in gate_set}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update the logic to support string gates too. From PL, users can provide a mix of PL Op types and Op strings: https://github.com/PennyLaneAI/pennylane/blob/494cd943c4ce675f8c392a9b8fb98626d1b78c02/pennylane/decomposition/gate_set.py#L24

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to use the to_name utility from PL, so we should have near-identical support. I've also added some tests for this.

Comment thread frontend/catalyst/passes/builtin_passes.py
@github-actions
Copy link
Copy Markdown
Contributor

Hello. You may have forgotten to update the changelog!
Please edit doc/releases/changelog-dev.md on your branch with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

Comment thread frontend/test/lit/test_decomposition.py
def graph_decomposition(
qnode=None,
*,
gate_set: Iterable,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

@kipawaa kipawaa Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the types here, not sure about supporting Gateset at the moment but it looks as though adding a __dict__ method to gateset that we can use internally here would be quite reasonable.

@kipawaa kipawaa marked this pull request as ready for review March 16, 2026 19:19
Comment thread frontend/catalyst/passes/builtin_passes.py
Comment thread frontend/catalyst/passes/builtin_passes.py
@kipawaa
Copy link
Copy Markdown
Contributor Author

kipawaa commented Mar 16, 2026

Note that CI won't pass here since it's currently broken in mlirbc-decomp-rules, which is upstream of this branch.

Copy link
Copy Markdown
Member

@maliasadi maliasadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to approve! We can address the remaining updates in the pass PR.

@kipawaa kipawaa merged commit 4ad39c7 into graph-decompose-pass Mar 16, 2026
38 of 40 checks passed
@kipawaa kipawaa deleted the graph-decompose-frontend branch March 16, 2026 21:55
@maliasadi maliasadi added this to the delightning milestone Mar 17, 2026
with pytest.raises(check=ValueError, match="Requested specs levels 2, 3"):
qml.specs(no_passes, level=[2, 3])()

@pytest.mark.xfail(reason="pending on specs fix")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to provide a pr, issue, or ticket reference so that anyone can check later whether the referenced fix has been completed or not

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan is to check the file into the git tree now?

_builtin_rule_path: Path = DEFAULT_RULE_DIR / BYTECODE_FILE_NAME,
):
R"""
Specify that the ``-graph-decomposition`` MLIR compiler pass for applying optimal gate
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimality is a strong claim, imo we should be careful with such language. Maybe "optimal gate decompositions" could be interpreted in different ways, but I don't think our rules themselves are necessary optimal, the only thing we can guarantee is that we choose the optimal path from the given set of rules.

Comment on lines +1509 to +1511
To instead view the optimized circuit, the MLIR must be viewed
after the ``"QuantumCompilationStage"`` stage via the
:func:`~.get_compilation_stage` function.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have inspection tools now beyond just looking at the MLIR, including qml.specs and catalyst.draw_graph

maliasadi added a commit that referenced this pull request Apr 17, 2026
**Context:**
The objective is to develop a high-performance, hybrid decomposition
framework that further migrates the graph-decomposition logic from
Python to the native MLIR compiler. The new framework needs to adhere to
four pillars:

1. We will migrate the `GraphDecomposition` build and solver logic from
Python into C++ #2578. By
co-locating the solver with the decomposition-rule rewrite MLIR pass
into a `graph-decomposition` system at MLIR, we enable late-stage
circuit rewrites and multi-pass optimization cycles that were previously
inaccessible in the frontend-only framework.

2. To minimize runtime latency, PL’s standard and built-in decomposition
rules will be precompiled for release, and lazily re-compiled if
necessary on import #2531
#2539. By treating built-in
rules as static compiler assets rather than dynamic JIT targets, we try
to eliminate the redundant capture and compilation overhead typically
incurred during every workflow execution.

2. To maintain the flexibility of PL, the system will need to still
support JIT compilation of rules. While standard rules are handled by
the AOT backend, custom user-defined device rules will be resolved via a
JIT fallback mechanism
#2568. This is to ensure
that researcher-defined gatesets and rules remain fully supported
without requiring a full compiler re-build.

4. Short-term, a "PLxPR Guard" stage will handle edge cases before MLIR
lowering, acting as a fallback until the C++ system offers full support.
Compiler-incompatible operators and complex high-level templates (e.g.,
Subroutine/Template work) will continue to be handled/decomposed at the
PLxPR level; so that the backend receives a valid, lowerable MLIR
representation while deferring hardware-specific passes to MLIR/C++.
This step is temporary and will be revisited aligned with the updates in
the Operator class and the program capture mechanism for Symbolic Ops.

**Benefits:**
- Enable "late-stage" and iterative decomposition passes at MLIR with a
C++ decomposition graph
- Eliminate redundant compilation overhead of built-in decomposition
rules during JIT compilation of workflows
 
**Possible Drawbacks:**

**Related GitHub Issues:**
[sc-113535]
[sc-113537]
[sc-115445]

---------

Co-authored-by: River McCubbin <river.mccubbin@xanadu.ai>
Co-authored-by: Hong-Sheng Zheng <mathan0203@gmail.com>
Co-authored-by: David Ittah <dime10@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants