Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 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
b8137f2
[PROTOTYPE] Add prototype implementation of PLModulePass
mudit2812 Nov 19, 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
cb7dcf5
Merge branch 'migrate-unified-compiler' into xdsl-module-pass-prototype
mudit2812 Nov 26, 2025
4cbe02a
Remove reference to 'remove-chained-self-inverses'
mudit2812 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
3395581
Merge branch 'main' into migrate-unified-compiler
mudit2812 Dec 1, 2025
a69c9ba
Remove more references to python_compiler
mudit2812 Dec 1, 2025
9d208f9
Address more code review comments
mudit2812 Dec 1, 2025
f20b29e
Merge branch 'migrate-unified-compiler' into xdsl-module-pass-prototype
mudit2812 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
08f891d
Update how greedy and recursive are defined
mudit2812 Dec 2, 2025
58e391b
Merge branch 'migrate-unified-compiler' into xdsl-module-pass-prototype
mudit2812 Dec 2, 2025
9e1d164
Allow using unions of ops to match
mudit2812 Dec 2, 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
3 changes: 3 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ coverage:
status:
project: false
patch: true

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
70 changes: 70 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,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)

* A new ``"changed"`` option has been added to the ``keep_intermediate`` parameter of
:func:`~.qjit`. This option saves intermediate IR files after each pass,
but only when the IR is actually modified by the pass.
Expand Down Expand Up @@ -187,6 +229,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)

* Fixes an issue where a heap-to-stack allocation conversion pass was causing SIGSEGV issues
during program execution at runtime.
[(#2172)](https://github.com/PennyLaneAI/catalyst/pull/2172)
Expand Down Expand Up @@ -246,6 +302,15 @@

<h3>Internal changes ⚙️</h3>

* 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 @@ -316,6 +381,11 @@

<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 @@ -376,9 +376,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(_pass.name):
uses_xdsl_passes = True
Expand Down
26 changes: 26 additions & 0 deletions frontend/catalyst/python_interface/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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
from .parser import QuantumParser
from .pass_api import compiler_transform

__all__ = [
"Compiler",
"compiler_transform",
"QuantumParser",
"QMLCollector",
]
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