Skip to content
Open
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
df8b97b
Migrate unified compiler to Catalyst
mudit2812 Nov 17, 2025
9536707
Fixing migration artifacts; linting
mudit2812 Nov 17, 2025
1453aae
Fix CI errors; Ignore unified compiler in coverage reports
mudit2812 Nov 17, 2025
efc0f88
Test out how graphviz is installed
mudit2812 Nov 17, 2025
10cd749
Lint some more
mudit2812 Nov 17, 2025
27de22d
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 17, 2025
f7aa2b6
[skip ci] Skip CI
mudit2812 Nov 17, 2025
012f58b
[skip ci] Skip CI
mudit2812 Nov 17, 2025
f0a0c90
Merge branch 'migrate-unified-compiler' of https://github.com/PennyLa…
mudit2812 Nov 17, 2025
c98755e
Try installing graphviz with apt
mudit2812 Nov 17, 2025
bb5bd00
Fix codefactor complaints
mudit2812 Nov 17, 2025
1448472
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 17, 2025
5e745f5
Try appeasing codefactor again
mudit2812 Nov 17, 2025
0409933
Try appeasing codefactor once again
mudit2812 Nov 17, 2025
e786a12
Pylint suppression
mudit2812 Nov 17, 2025
4ae10ff
Reduce complexity of stablehlo.reduce and stablehlo.dynamic_broadcast…
mudit2812 Nov 17, 2025
dc41a7b
Fix some failures
mudit2812 Nov 18, 2025
58b13e4
Try change to graphviz installation
mudit2812 Nov 18, 2025
4e5f904
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 18, 2025
637d2cf
Try installing graphviz with pip
mudit2812 Nov 18, 2025
091c5e1
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 18, 2025
64e0fd4
Try installing graphviz with both apt and pip
mudit2812 Nov 18, 2025
dc15d3a
Add utils file to remove conftest imports
mudit2812 Nov 18, 2025
e7e33d6
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 18, 2025
f919e8d
Remove unused imports
mudit2812 Nov 18, 2025
005ba9f
Add graphviz dependencies to lightning.kokkos testing workflow
mudit2812 Nov 18, 2025
6117189
Update cookbook
mudit2812 Nov 18, 2025
6961324
Migrate all changelog entries from PennyLane
mudit2812 Nov 18, 2025
0fdbb46
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 18, 2025
a868bc3
Add EOF new line to .codecov.yml
mudit2812 Nov 18, 2025
8f00b2f
change changelog entry slightly
mudit2812 Nov 18, 2025
22a6e6e
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 20, 2025
b4a321d
Merge branch 'main' into migrate-unified-compiler
mudit2812 Nov 26, 2025
e3ef736
Copy over xdsl_conversion changes
jzaia18 Nov 26, 2025
b7995ff
Rename visualization -> inspection
jzaia18 Nov 26, 2025
67705a9
finalize migration of branch
jzaia18 Nov 26, 2025
e735ca2
Update CHANGELOG
jzaia18 Nov 26, 2025
a979216
Copy over changes from PennyLane
jzaia18 Nov 26, 2025
4cbe02a
Remove reference to 'remove-chained-self-inverses'
mudit2812 Nov 26, 2025
e8e84e6
Woops, forgot to add the main files
jzaia18 Nov 26, 2025
c5f08c3
Remove leftover references to pennylane.compiler.python_compiler
mudit2812 Nov 27, 2025
fe76357
Streamline circuit inspection utilities (#2237)
jzaia18 Dec 1, 2025
be3ff3a
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 1, 2025
3395581
Merge branch 'main' into migrate-unified-compiler
mudit2812 Dec 1, 2025
c21850f
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 1, 2025
ad7c306
Better display for 'all' in compbasis
jzaia18 Dec 1, 2025
a69c9ba
Remove more references to python_compiler
mudit2812 Dec 1, 2025
9d208f9
Address more code review comments
mudit2812 Dec 1, 2025
7946287
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 1, 2025
e223b3f
Undo accidental change
jzaia18 Dec 1, 2025
8ce6f96
Fix jit
mudit2812 Dec 1, 2025
664d24a
Fix jit again
mudit2812 Dec 1, 2025
e07a332
Merge branch 'main' into migrate-unified-compiler
mudit2812 Dec 1, 2025
f9035c0
Fix line-too-long
mudit2812 Dec 1, 2025
ca1aa3a
Merge branch 'migrate-unified-compiler' of https://github.com/PennyLa…
mudit2812 Dec 1, 2025
d146453
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 2, 2025
87be66c
Update specs unit tests
jzaia18 Dec 2, 2025
f43cb3d
Remove vestigial workaround
jzaia18 Dec 2, 2025
0e4cd8d
Apply suggestions from code review
jzaia18 Dec 2, 2025
ef7c6c9
Update frontend/test/pytest/python_interface/inspection/test_mlir_spe…
jzaia18 Dec 2, 2025
eb11eb0
Update function names and docs
jzaia18 Dec 2, 2025
869dcc0
Merge branch 'feature/xdsl-specs' of github.com:PennyLaneAI/catalyst …
jzaia18 Dec 2, 2025
611a0ea
Oops
jzaia18 Dec 2, 2025
6711a0f
Minor tweaks to simplify
jzaia18 Dec 2, 2025
0288e6c
Update unit tests
jzaia18 Dec 2, 2025
02bbdfc
Simplify unit tests
jzaia18 Dec 2, 2025
28ab6e6
Separate out collect_region into 2 functions, 1 for regions and 1 for…
jzaia18 Dec 2, 2025
32261bf
Update changelog
jzaia18 Dec 3, 2025
7f4eb06
Remove the local transform dialect (#2261)
mehrdad2m Dec 3, 2025
3947e05
Remove unneeded XDSL plugin load
jzaia18 Dec 3, 2025
a4e86cd
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 3, 2025
24eb758
Merge branch 'main' into migrate-unified-compiler
dime10 Dec 3, 2025
2413520
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 4, 2025
5bf82d8
Apply PR review comments
jzaia18 Dec 4, 2025
b6fb585
[skip ci] add importorskip for graphviz to mlir_graph tests
mudit2812 Dec 5, 2025
0b1f237
Merge branch 'migrate-unified-compiler' of https://github.com/PennyLa…
mudit2812 Dec 5, 2025
8ef2b58
Merge branch 'main' into migrate-unified-compiler
mudit2812 Dec 5, 2025
848795d
[skip ci] Skip CI
mudit2812 Dec 5, 2025
58e06f0
Merge branch 'migrate-unified-compiler' of https://github.com/PennyLa…
mudit2812 Dec 5, 2025
14eb727
Update .codecov.yml
mudit2812 Dec 5, 2025
7477272
Add better testing for Hamiltonians
jzaia18 Dec 5, 2025
dce6a8d
Merge branch 'migrate-unified-compiler' into feature/xdsl-specs
jzaia18 Dec 5, 2025
14b8380
Small formatting fix
jzaia18 Dec 5, 2025
8980de6
Merge branch 'feature/xdsl-specs' of github.com:PennyLaneAI/catalyst …
jzaia18 Dec 5, 2025
4badc05
Add graph decomp test
jzaia18 Dec 5, 2025
d9647ca
Merge branch 'main' into feature/xdsl-specs
jzaia18 Dec 5, 2025
b5802db
Fix botched merge
jzaia18 Dec 5, 2025
187d283
Fix changelog
jzaia18 Dec 5, 2025
0a4eba3
Placate codefactor
jzaia18 Dec 5, 2025
792e807
More codefactor nitpicks
jzaia18 Dec 5, 2025
2e96f6d
YET MORE NITPICKS!
jzaia18 Dec 5, 2025
cf4b2ca
Change for xdsl is imported
jzaia18 Dec 5, 2025
b26c967
Reorder imports
jzaia18 Dec 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ coverage:
status:
project: false
patch: true

# TODO: add coverage for the python compiler interface
ignore:
- "frontend/catalyst/python_interface"
6 changes: 6 additions & 0 deletions .github/workflows/check-catalyst.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@ jobs:
# macOS requirements.txt
python3 -m pip install cuda-quantum==0.6.0
python3 -m pip install oqc-qcaas-client
# Install graphviz for testing the mlir-op-graph integration
sudo apt-get install -y graphviz
python3 -m pip install graphviz
make frontend

- name: Get Cached LLVM Build
Expand Down Expand Up @@ -556,6 +559,9 @@ jobs:
sudo apt-get install -y libasan6 make
python3 --version | grep ${{ needs.constants.outputs.primary_python_version }}
python3 -m pip install -r requirements.txt
# Install graphviz for testing the mlir-op-graph integration
sudo apt-get install -y graphviz
python3 -m pip install graphviz
make frontend

- name: Get Cached LLVM Build
Expand Down
79 changes: 78 additions & 1 deletion doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,48 @@

<h3>Improvements 🛠</h3>

* Add an experimental `outline_state_evolution_pass` xDSL pass to `catalyst.python_interface.transforms`,
which moves all quantum gate operations to a private callable.
[(#8367)](https://github.com/PennyLaneAI/pennylane/pull/8367)

* A new experimental `split_non_commuting_pass` compiler pass has been added to
`catalyst.python_interface.transforms`. This pass splits quantum functions that
measure observables on the same wires into multiple function executions, where
each execution measures observables on different wires (using the "wires" grouping
strategy). The original function is replaced with calls to these generated functions,
and the results are combined appropriately.
[(#8531)](https://github.com/PennyLaneAI/pennylane/pull/8531)

* Add the `PCPhaseOp` operation to the xDSL Quantum dialect.
[(#8621)](https://github.com/PennyLaneAI/pennylane/pull/8621)

* Users can now apply xDSL passes without the need to pass the `pass_plugins` argument to
the `qjit` decorator.
[(#8572)](https://github.com/PennyLaneAI/pennylane/pull/8572)
[(#8573)](https://github.com/PennyLaneAI/pennylane/pull/8573)
[(#2169)](https://github.com/PennyLaneAI/catalyst/pull/2169)
[(#2183)](https://github.com/PennyLaneAI/catalyst/pull/2183)

* The :meth:`catalyst.python_interface.transforms.convert_to_mbqc_formalism_pass` now
supports :class:`~xdsl.dialects.scf.IndexSwitchOp` in IR and ignores regions that have no body.
[(#8632)](https://github.com/PennyLaneAI/pennylane/pull/8632)

* The `convert_to_mbqc_formalism` compilation pass now outlines the operations to represent a gate
in the MBQC formalism into subroutines in order to reduce the IR size for large programs.
[(#8619)](https://github.com/PennyLaneAI/pennylane/pull/8619)

* The :meth:`catalyst.python_interface.Compiler.run` method now accepts a string as input,
which is parsed and transformed with xDSL.
[(#8587)](https://github.com/PennyLaneAI/pennylane/pull/8587)

* An `is_xdsl_pass` function has been added to the `catalyst.python_interface.pass_api` module.
This function checks if a pass name corresponds to an xDSL implemented pass.
[(#8572)](https://github.com/PennyLaneAI/pennylane/pull/8572)

* A new `catalyst.python_interface.utils` submodule has been added, containing general-purpose utilities for
working with xDSL. This includes a function that extracts the concrete value of scalar, constant SSA values.
[(#8514)](https://github.com/PennyLaneAI/pennylane/pull/8514)

* Catalyst can now use the new `pass_name` property of pennylane transform objects. Passes can now
be created using `qml.transform(pass_name=pass_name)` instead of `PassPipelineWrapper`.
[(#2149](https://github.com/PennyLaneAI/catalyst/pull/2149)
Expand Down Expand Up @@ -197,6 +239,20 @@

<h3>Bug fixes 🐛</h3>

* The experimental xDSL :func:`~catalyst.python_interface.transforms.measurements_from_samples_pass`
pass has been updated to support `shots` defined by an `arith.constant` operation.
[(#8460)](https://github.com/PennyLaneAI/pennylane/pull/8460)

* The experimental xDSL :func:`~catalyst.python_interface.transforms.diagonalize_measurements`
pass has been updated to fix a bug that included the wrong SSA value for final qubit insertion
and deallocation at the end of the circuit. A clear error is now also raised when there are
observables with overlapping wires.
[(#8383)](https://github.com/PennyLaneAI/pennylane/pull/8383)

* Fixes a bug in the constructor of the xDSL Quantum dialect's `QubitUnitaryOp` that
prevented an instance from being constructed.
[(#8456)](https://github.com/PennyLaneAI/pennylane/pull/8456)

* Added missing `detensorize-function-boundary` and `symbol-dce` passes to `Pipelines.cpp`.
[(#2266)](https://github.com/PennyLaneAI/catalyst/pull/2266)

Expand Down Expand Up @@ -272,6 +328,20 @@

<h3>Internal changes ⚙️</h3>

* A new `catalyst.python_interface.inspection.mlir_specs` method has been added to facilitate
PennyLane's new pass-by-pass specs feature. This function returns information gathered by parsing
the xDSL generated by a given QJIT object, such as gate counts, measurements, or qubit allocations.
[(#2238)](https://github.com/PennyLaneAI/catalyst/pull/2238)

* The `catalyst.python_interface.visualization` module has been renamed to
`catalyst.python_interface.inspection`, and various utility functions within this module
have been streamlined.
[(#2237)](https://github.com/PennyLaneAI/catalyst/pull/2237)

* Migrated the `pennylane.compiler.python_compiler` submodule from PennyLane to Catalyst.
It is now accessible as `catalyst.python_interface`.
[(#2199)](https://github.com/PennyLaneAI/catalyst/pull/2199)

* Resource tracking now writes out at device destruction time instead of qubit deallocation
time. The written resources will be the total amount of resources collected throughout the
lifetime of the execution. For executions that split work between multiple functions,
Expand Down Expand Up @@ -340,17 +410,24 @@
[(#2245)](https://github.com/PennyLaneAI/catalyst/pull/2245)
[(#2254)](https://github.com/PennyLaneAI/catalyst/pull/2254)

* Removed the `catalyst.python_interface.dialects.transform` module in favor of
using the `xdsl.dialects.transform` module directly.
[(#2261)](https://github.com/PennyLaneAI/catalyst/pull/2261)

* Refactor QEC tablegen files to separate QEC operations into a new `QECOp.td` file
[(#2253](https://github.com/PennyLaneAI/catalyst/pull/2253)


* Removed the `getRotationKind` and `setRotationKind` methods from
the QEC interface `QECOpInterface` to simplify the interface.
[(#2250)](https://github.com/PennyLaneAI/catalyst/pull/2250)

<h3>Documentation 📝</h3>

* Added a "Unified Compiler Cookbook" RST file, along with tutorials, to `catalyst.python_interface.doc`,
which provides a quickstart guide for getting started with xDSL and its integration with PennyLane and
Catalyst.
[(#8571)](https://github.com/PennyLaneAI/pennylane/pull/8571)

* A typo in the code example for :func:`~.passes.ppr_to_ppm` has been corrected.
[(#2136)](https://github.com/PennyLaneAI/catalyst/pull/2136)

Expand Down
19 changes: 10 additions & 9 deletions frontend/catalyst/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,13 @@ def to_mlir_opt(
*args, stdin=None, options: Optional[CompileOptions] = None, using_python_compiler=False
):
"""echo ${input} | catalyst --tool=opt *args *opts -"""
# Check if we need to use Python compiler for xDSL passes
# Check if we need to use the Python interface for xDSL passes
if using_python_compiler:
# Use Python compiler path for xDSL passes
# Use the Python interface path for xDSL passes
# pylint: disable-next=import-outside-toplevel
from pennylane.compiler.python_compiler import Compiler as PythonCompiler
from catalyst.python_interface import Compiler as UnifiedCompiler

compiler = PythonCompiler()
compiler = UnifiedCompiler()
stdin = compiler.run(stdin, callback=None)

# These are the options that may affect compilation
Expand Down Expand Up @@ -548,7 +548,7 @@ def check_nested_operations(op):

@debug_logger
def is_using_python_compiler(self, mlir_module=None):
"""Returns true if we need the Python compiler path.
"""Returns true if we need the Python interface path.

This happens when:
1. xDSL plugin is explicitly loaded (legacy), OR
Expand Down Expand Up @@ -594,7 +594,8 @@ def _create_xdsl_pass_save_callback(self, workspace):
workspace: The workspace directory path

Returns:
Callable or None: The callback function if intermediate saving is enabled, None otherwise
Callable or None: The callback function if intermediate saving is enabled, None
otherwise
"""
if not (workspace and self.options.keep_intermediate >= KeepIntermediateLevel.CHANGED):
return None
Expand All @@ -606,7 +607,7 @@ def _create_xdsl_pass_save_callback(self, workspace):
os.makedirs(user_transform_dir, exist_ok=True)

class SavePassIRCallback:
"""Callback to save IR after each pass in python_compiler."""
"""Callback to save IR after each pass in python_interface."""

def __init__(self, transform_dir):
self.transform_dir = transform_dir
Expand Down Expand Up @@ -666,10 +667,10 @@ def run(self, mlir_module, *args, **kwargs):
# We keep this module here to keep xDSL requirement optional
# Only move this is it has been decided that xDSL is no longer optional.
# pylint: disable-next=import-outside-toplevel
from pennylane.compiler.python_compiler import Compiler as PythonCompiler
from catalyst.python_interface import Compiler as UnifiedCompiler

callback = self._create_xdsl_pass_save_callback(workspace)
compiler = PythonCompiler()
compiler = UnifiedCompiler()
ir = compiler.run(ir, callback=callback)

return self.run_from_ir(
Expand Down
4 changes: 1 addition & 3 deletions frontend/catalyst/jax_primitives_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,7 @@ def transform_named_sequence_lowering(jax_ctx: mlir.LoweringRuleContext, pipelin

try:
# pylint: disable=import-outside-toplevel
from pennylane.compiler.python_compiler.pass_api import (
is_xdsl_pass,
)
from catalyst.python_interface.pass_api import is_xdsl_pass

if is_xdsl_pass(name):
uses_xdsl_passes = True
Expand Down
27 changes: 27 additions & 0 deletions frontend/catalyst/python_interface/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2025 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unified Compiler API for integration of Catalyst with xDSL."""

from .compiler import Compiler
from .inspection import QMLCollector, mlir_specs
from .parser import QuantumParser
from .pass_api import compiler_transform

__all__ = [
"Compiler",
"compiler_transform",
"QuantumParser",
"QMLCollector",
"mlir_specs",
]
83 changes: 83 additions & 0 deletions frontend/catalyst/python_interface/compiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright 2025 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This file contains the implementation of the PennyLane-xDSL integration API."""


import io

from jax._src.interpreters import mlir
from jaxlib.mlir.dialects import stablehlo
from jaxlib.mlir.ir import Context as jaxContext
from jaxlib.mlir.ir import Module as jaxModule
from pennylane.typing import Callable
from xdsl.context import Context as xContext
from xdsl.dialects.builtin import ModuleOp
from xdsl.passes import ModulePass, PassPipeline
from xdsl.printer import Printer

from catalyst.python_interface.parser import QuantumParser
from catalyst.python_interface.pass_api import ApplyTransformSequence


# pylint: disable=too-few-public-methods
class Compiler:
"""Compiler namespace"""

@staticmethod
def run(
module: jaxModule | str,
callback: Callable[[ModulePass, ModuleOp, ModulePass], None] | None = None,
) -> jaxModule | str:
"""Runs the apply-transform-sequence pass.

The apply-transform-sequence pass is a "meta-pass". In other words,
it is a pass that runs other passes.

Args:
module: Either a Jax MLIR module or MLIR IR as a string
callback: Optional callback function called between passes

Returns:
jaxModule | str: jaxModule if the input was a jaxModule, else a string.
"""
# Convert to generic text format
is_jax_module = isinstance(module, jaxModule)
if is_jax_module:
gentxtmod = module.operation.get_asm(
binary=False, print_generic_op_form=True, assume_verified=True
)
else:
gentxtmod = module

# Parse and transform with xDSL
ctx = xContext(allow_unregistered=True)
parser = QuantumParser(ctx, gentxtmod)
# xmod is modified in place
xmod = parser.parse_module()
pipeline = PassPipeline((ApplyTransformSequence(callback=callback),))
pipeline.apply(ctx, xmod)

# Convert back to string
buffer = io.StringIO()
Printer(stream=buffer, print_generic_format=True).print_op(xmod)

# Convert back to jaxModule if input was jaxModule
if is_jax_module:
with jaxContext() as jctx:
jctx.allow_unregistered_dialects = True
jctx.append_dialect_registry(mlir.upstream_dialects)
stablehlo.register_dialect(jctx) # pylint: disable=no-member
newmod: jaxModule = jaxModule.parse(buffer.getvalue())
return newmod
return buffer.getvalue()
Loading