Skip to content
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
034e500
add translation and lowering of OperatorOp
albi3ro Jun 19, 2026
a9308fc
sonnet's AI recommendation to fix python bindings issue
albi3ro Jun 19, 2026
8599ec6
switch to StrAttr
albi3ro Jun 24, 2026
5c4504e
bump pl version
albi3ro Jun 24, 2026
b23289a
remove qref patch
albi3ro Jun 24, 2026
6d4de2b
formatting
albi3ro Jun 24, 2026
daca7ae
black
albi3ro Jun 24, 2026
05fa495
Merge branch 'main' into handle-operator2
albi3ro Jun 24, 2026
79e060e
starting to add some tests
albi3ro Jun 24, 2026
65af9f5
Merge branch 'handle-operator2' of github.com:PennyLaneAI/catalyst in…
albi3ro Jun 24, 2026
98c88c4
tests, changelog, formatting
albi3ro Jun 25, 2026
862375e
pylint
albi3ro Jun 25, 2026
6e4eaf7
why didn't black work
albi3ro Jun 25, 2026
5546ee7
Merge branch 'main' into handle-operator2
albi3ro Jun 25, 2026
78b4f9e
more pylint
albi3ro Jun 25, 2026
ffca762
Merge branch 'handle-operator2' of github.com:PennyLaneAI/catalyst in…
albi3ro Jun 25, 2026
54ba606
Merge branch 'main' into handle-operator2
albi3ro Jun 25, 2026
51639cd
add specialized lowerings
albi3ro Jun 26, 2026
6725b02
Merge branch 'main' into operator2-custom-op
albi3ro Jun 30, 2026
8513e91
Apply suggestions from code review
albi3ro Jun 30, 2026
ca108c8
styling
albi3ro Jun 30, 2026
65ec5fb
move things to their own file
albi3ro Jun 30, 2026
ab0c04d
more testing
albi3ro Jun 30, 2026
277c485
more tests
albi3ro Jun 30, 2026
a42a5c6
more testing, changelog, formatting
albi3ro Jul 2, 2026
bb0728a
codefactor
albi3ro Jul 2, 2026
862632d
Merge branch 'main' into operator2-custom-op
albi3ro Jul 2, 2026
6a40341
I HATE LITgit add *git add *git add *git add *git add *git add *git a…
albi3ro Jul 2, 2026
32c3a81
Apply suggestions from code review
albi3ro Jul 2, 2026
2903e03
add general validation that wires are actual wires in lowering
albi3ro Jul 2, 2026
7fb66dc
stupid mistake
albi3ro Jul 2, 2026
fdd290a
Apply suggestion from @albi3ro
albi3ro Jul 2, 2026
ab5484d
Add support for lowering adjoint and control with Operator2
mudit2812 Jun 26, 2026
95f62c3
Change adjoint from property to attribute
mudit2812 Jun 29, 2026
801caaa
Revert formatting
mudit2812 Jun 29, 2026
a561f53
Add lit tests
mudit2812 Jun 29, 2026
1ae3875
Update operator_p import path
mudit2812 Jun 29, 2026
0f8efa8
[skip ci] Skip CI
mudit2812 Jun 29, 2026
6a2b581
Transmit ctrl/adjoint information to spacial lowerings
mudit2812 Jun 30, 2026
360851e
[skip ci] Skip CI
mudit2812 Jun 30, 2026
e235a1f
LIT IS THE WORST THING EVER INVENTED
albi3ro Jul 2, 2026
1f2b72a
Merge branch 'operator2-custom-op' of github.com:PennyLaneAI/catalyst…
albi3ro Jul 2, 2026
01f2b23
Update dep-versions
mudit2812 Jul 2, 2026
f65c967
[skip ci] Skip CI
mudit2812 Jul 2, 2026
aaa491f
Merge branch 'main' into operator2-custom-op
albi3ro Jul 2, 2026
e6788d3
Update based on upstream changes
mudit2812 Jul 2, 2026
25005e2
Merge branch 'operator2-custom-op' into operator2-adj-ctrl
mudit2812 Jul 2, 2026
b49010b
Merge branch 'main' into operator2-adj-ctrl
mudit2812 Jul 2, 2026
c236102
Finish adding tests. Won't pass until PL-side fix is uploaded to Test…
mudit2812 Jul 3, 2026
3666553
Merge branch 'main' into operator2-adj-ctrl
mudit2812 Jul 3, 2026
e3b96bb
Fix merge conflict
mudit2812 Jul 3, 2026
20998c6
[skip ci] Skip CI
mudit2812 Jul 3, 2026
8b4f496
Merge branch 'main' into operator2-adj-ctrl
mudit2812 Jul 3, 2026
aab165a
[skip ci]
mudit2812 Jul 3, 2026
342f7d3
Merge branch 'operator2-adj-ctrl' of https://github.com/PennyLaneAI/c…
mudit2812 Jul 3, 2026
16f9aee
[skip ci]
mudit2812 Jul 3, 2026
e273e73
Remove wayward comment
mudit2812 Jul 3, 2026
429fda0
[skip ci] Skip CI
mudit2812 Jul 3, 2026
fd14cb9
Replace qp.ops.ControlledOp2 with qp.ctrl
mudit2812 Jul 3, 2026
6be5efb
[skip ci] Skip CI
mudit2812 Jul 3, 2026
5af372d
Merge branch 'main' into operator2-adj-ctrl
mudit2812 Jul 6, 2026
20a2867
Update PL dep
mudit2812 Jul 6, 2026
341f314
Merge branch 'operator2-adj-ctrl' of https://github.com/PennyLaneAI/c…
mudit2812 Jul 6, 2026
4b4d65f
Address code review
mudit2812 Jul 7, 2026
8bf1a52
Merge branch 'main' into operator2-adj-ctrl
mudit2812 Jul 7, 2026
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: 2 additions & 1 deletion doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
without non-lowerable arguments. `Operator2` classes are now lowered to specialized operations
where applicable, unlocking compilation and execution for these cases.
[(#2979)](https://github.com/PennyLaneAI/catalyst/pull/2979)
[(#2969)](https://github.com/PennyLaneAI/catalyst/pull/2969/)
[(#2969)](https://github.com/PennyLaneAI/catalyst/pull/2969)
[(#2980)](https://github.com/PennyLaneAI/catalyst/pull/2980)
[(#2990)](https://github.com/PennyLaneAI/catalyst/pull/2990)

* The `ResourceAnalysis` pass now reports each loop body and each subroutine as its own entry
Expand Down
17 changes: 15 additions & 2 deletions frontend/catalyst/from_plxpr/qfunc_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
from pennylane.capture.primitives import cond_prim as pl_cond_prim
from pennylane.capture.primitives import ctrl_transform_prim as plxpr_ctrl_transform_prim
from pennylane.capture.primitives import measure_prim as plxpr_measure_prim
from pennylane.capture.primitives import operator_p
from pennylane.capture.primitives import pauli_measure_prim as plxpr_pauli_measure_prim
from pennylane.capture.primitives import quantum_subroutine_prim, transform_prim
from pennylane.core.operator.operator2 import operator_p
from pennylane.ftqc.primitives import measure_in_basis_prim as plxpr_measure_in_basis_prim
from pennylane.measurements import CountsMP
from pennylane.wires import AbstractQubit, is_abstract_qubit
Expand Down Expand Up @@ -300,14 +300,27 @@ def _handle_operator(self, *args, op_cls, hybrid_lens, hybrid_trees, adjoint, n_
# only support compilable_argnames for the moment
raise NotImplementedError

wire_inputs = args[len(op_cls.dynamic_argnames) :]
if n_ctrls:
wire_inputs = args[len(op_cls.dynamic_argnames) : -2 * n_ctrls]
control_wire_inputs = args[-2 * n_ctrls : -n_ctrls]
control_values = args[-n_ctrls:]
Comment thread
paul0403 marked this conversation as resolved.
else:
wire_inputs = args[len(op_cls.dynamic_argnames) :]
control_wire_inputs = control_values = ()
Comment thread
mudit2812 marked this conversation as resolved.

new_wires = [
w if is_abstract_qubit(w) else qref_get_p.bind(self.init_qreg, w) for w in wire_inputs
]
new_control_wires = [
w if is_abstract_qubit(w) else qref_get_p.bind(self.init_qreg, w)
for w in control_wire_inputs
]

qref_operator_p.bind(
*args[: len(op_cls.dynamic_argnames)],
*new_wires,
*new_control_wires,
*control_values,
op_cls=op_cls,
hybrid_lens=hybrid_lens,
hybrid_trees=hybrid_trees,
Expand Down
127 changes: 54 additions & 73 deletions frontend/catalyst/from_plxpr/qref_operator2_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,40 @@ def _qref_operator_p_lowering(
op_cls,
**kwargs,
):
_general_validation(*args, op_cls=op_cls, **kwargs)
ctx = jax_ctx.module_context.context
ctx.allow_unregistered_dialects = True
if op_cls.__name__ in _SPECIAL_LOWERINGS:
return _SPECIAL_LOWERINGS[op_cls.__name__](jax_ctx, *args, op_cls=op_cls, **kwargs)
# will be used in future improvements
_general_validation(*args, op_cls=op_cls, **kwargs)

hybrid_lens = kwargs.pop("hybrid_lens") # pylint: disable=unused-variable
hybrid_trees = kwargs.pop("hybrid_trees") # pylint: disable=unused-variable
adjoint = kwargs.pop("adjoint") # pylint: disable=unused-variable
n_ctrls = kwargs.pop("n_ctrls") # pylint: disable=unused-variable
adjoint = kwargs.pop("adjoint")
n_ctrls = kwargs.pop("n_ctrls")
wire_lens = kwargs.pop("wire_lens")

if n_ctrls:
ctrl_qubits = args[-2 * n_ctrls : -n_ctrls]
ctrl_values = [
TensorExtractOp(ir.IntegerType.get_signless(1), val, []).result
for val in args[-n_ctrls:]
]
qubits_slice = slice(len(op_cls.dynamic_argnames), -2 * n_ctrls)
Comment thread
paul0403 marked this conversation as resolved.
else:
ctrl_qubits = ctrl_values = ()
qubits_slice = slice(len(op_cls.dynamic_argnames), None)

params = args[: len(op_cls.dynamic_argnames)]
qubits = args[len(op_cls.dynamic_argnames) :]
qubits = args[qubits_slice]

if op_cls.__name__ in _SPECIAL_LOWERINGS:
Comment thread
paul0403 marked this conversation as resolved.
return _SPECIAL_LOWERINGS[op_cls.__name__](
*params,
*qubits,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values,
adjoint=adjoint,
**kwargs,
)
# will be used in future improvements
Comment thread
mudit2812 marked this conversation as resolved.
Outdated

name_attr = get_mlir_attribute_from_pyval(op_cls.__name__)

Expand All @@ -136,10 +157,6 @@ def _qref_operator_p_lowering(

processed_qubit_map = get_mlir_attribute_from_pyval(qubit_map)

ctrl_qubits = []
ctrl_values = []
adjoint = False

if _is_custom_op(op_cls, jax_ctx.avals_in[: len(op_cls.dynamic_argnames)]):
params = [extract_scalar(safe_cast_to_f64(p, op_cls), op_cls) for p in params]
CustomOp(
Expand All @@ -157,9 +174,9 @@ def _qref_operator_p_lowering(
qubits=qubits,
qreg=None,
forward_args=[],
ctrl_qubits=[],
ctrl_values=[],
adjoint=False,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values,
adjoint=adjoint,
UID=None,
arr_qubit_indices=[],
param_map=processed_param_map,
Expand All @@ -170,58 +187,43 @@ def _qref_operator_p_lowering(


@_register_special_lowering("MultiRZ")
def _multirz_lowering(jax_ctx: mlir.LoweringRuleContext, *args, **_):
theta = extract_scalar(safe_cast_to_f64(args[0], "MultiRZ"), "MultiRZ")
qubits = args[1:]
def _multirz_lowering(theta, *qubits, ctrl_qubits, ctrl_values, adjoint):
MultiRZOp(
theta=theta,
theta=extract_scalar(safe_cast_to_f64(theta, "MultiRZ"), "MultiRZ"),
qubits=qubits,
ctrl_qubits=[],
ctrl_values=[],
adjoint=False,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values,
adjoint=adjoint,
)
return []


@_register_special_lowering("PCPhase")
def _pcphase_lowering(
jax_ctx: mlir.LoweringRuleContext,
*args,
**_,
):
qubits = args[2:]
def _pcphase_lowering(theta, dim, *qubits, ctrl_qubits, ctrl_values, adjoint):
PCPhaseOp(
theta=extract_scalar(safe_cast_to_f64(args[0], "PCPhase"), "PCPhase"),
dim=extract_scalar(safe_cast_to_f64(args[1], "PCPhase"), "PCPhase"),
theta=extract_scalar(safe_cast_to_f64(theta, "PCPhase"), "PCPhase"),
dim=extract_scalar(safe_cast_to_f64(dim, "PCPhase"), "PCPhase"),
qubits=qubits,
ctrl_qubits=[],
ctrl_values=[],
adjoint=False,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values,
adjoint=adjoint,
)
return ()


@_register_special_lowering("GlobalPhase")
def _special_gphase_lowering(
jax_ctx: mlir.LoweringRuleContext,
*args,
op_cls,
**_,
):
def _special_gphase_lowering(angle, *_, ctrl_qubits, ctrl_values, adjoint):
GlobalPhaseOp(
angle=extract_scalar(safe_cast_to_f64(args[0], "GlobalPhase"), "GlobalPhase"),
ctrl_qubits=[],
ctrl_values=[],
adjoint=False,
angle=extract_scalar(safe_cast_to_f64(angle, "GlobalPhase"), "GlobalPhase"),
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values,
adjoint=adjoint,
)
return ()


@_register_special_lowering("QubitUnitary")
def _special_unitary_lowering(jax_ctx: mlir.LoweringRuleContext, matrix, *qubits, **_):
ctrl_qubits = []
ctrl_values = []

def _special_unitary_lowering(matrix, *qubits, ctrl_qubits, ctrl_values, adjoint):
matrix_type = matrix.type
is_tensor = ir.RankedTensorType.isinstance(matrix_type)
shape = ir.RankedTensorType(matrix_type).shape if is_tensor else None
Expand All @@ -245,50 +247,29 @@ def _special_unitary_lowering(jax_ctx: mlir.LoweringRuleContext, matrix, *qubits
tensor_complex_f64_type = ir.RankedTensorType.get(shape, complex_f64_type)
matrix = StableHLOConvertOp(tensor_complex_f64_type, matrix).result

ctrl_values_i1 = [
TensorExtractOp(ir.IntegerType.get_signless(1), v, []).result for v in ctrl_values
]

QubitUnitaryOp(
matrix=matrix,
qubits=qubits,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values_i1,
adjoint=False,
ctrl_values=ctrl_values,
adjoint=adjoint,
)

return ()


@_register_special_lowering("PauliRot")
def _special_paulirot_lowering(
jax_ctx: mlir.LoweringRuleContext,
angle,
*qubits,
pauli_word,
**_,
):
def _special_paulirot_lowering(angle, *qubits, ctrl_qubits, ctrl_values, adjoint, pauli_word):
pauli_word = unflatten(*pauli_word)
ctrl_qubits = []
ctrl_values = []

angle = safe_cast_to_f64(angle, "PauliRot")
angle = extract_scalar(angle, "PauliRot")
assert ir.F64Type.isinstance(angle.type)

pauli_word = ir.ArrayAttr.get([ir.StringAttr.get(p) for p in pauli_word])

ctrl_values_i1 = [
TensorExtractOp(ir.IntegerType.get_signless(1), v, []).result for v in ctrl_values
]

PauliRotOp(
angle=angle,
angle=extract_scalar(safe_cast_to_f64(angle, "PauliRot"), "PauliRot"),
pauli_product=pauli_word,
qubits=qubits,
ctrl_qubits=ctrl_qubits,
ctrl_values=ctrl_values_i1,
adjoint=False,
ctrl_values=ctrl_values,
adjoint=adjoint,
)

return ()
Loading
Loading