diff --git a/.dep-versions b/.dep-versions index 6a8b1153af..dc5d78feeb 100644 --- a/.dep-versions +++ b/.dep-versions @@ -8,7 +8,7 @@ enzyme=v0.0.238 # For a custom PL version, update the package version here and at # 'doc/requirements.txt' -pennylane=0.46.0-dev130 +pennylane=0.46.0-dev131 # For a custom LQ/LK version, update the package version here and at # 'doc/requirements.txt' diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index c74cf5a7a4..c19c26fa34 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -811,6 +811,9 @@

Bug fixes 🐛

+* Controlled quantum regions now keeps track of the `work_wire_type` passed from `qp.ctrl`. + [(#3366)](https://github.com/PennyLaneAI/catalyst/pull/3366) + * MLIR passes that recreate `scf.for`, `scf.while`, `scf.if`, and `scf.index_switch` ops (`ctrl-lowering`, `adjoint-lowering`, `--convert-to-value-semantics`) now preserve discardable attributes such as `catalyst.estimated_iterations`, `catalyst.estimated_probability`, and diff --git a/doc/requirements.txt b/doc/requirements.txt index fb37ce2ec0..38fa1ce790 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -34,4 +34,4 @@ lxml_html_clean --extra-index-url https://test.pypi.org/simple/ pennylane-lightning-kokkos==0.46.0-dev27 pennylane-lightning==0.46.0-dev27 -pennylane==0.46.0-dev130 +pennylane==0.46.0-dev131 diff --git a/frontend/catalyst/from_plxpr/qfunc_interpreter.py b/frontend/catalyst/from_plxpr/qfunc_interpreter.py index fb20641dcc..0bc529ec11 100644 --- a/frontend/catalyst/from_plxpr/qfunc_interpreter.py +++ b/frontend/catalyst/from_plxpr/qfunc_interpreter.py @@ -888,9 +888,18 @@ def handle_adjoint_transform(self, *invals, jaxpr, lazy, n_consts): ) -# pylint: disable=unused-argument +# pylint: disable=unused-argument,too-many-arguments @PLxPRToQuantumJaxprInterpreter.register_primitive(plxpr_ctrl_transform_prim) -def handle_ctrl_transform(self, *invals, jaxpr, n_control, control_values, work_wires, n_consts): +def handle_ctrl_transform( + self, + *invals, + jaxpr, + n_control, + control_values, + work_wires, + n_consts, + work_wire_type="borrowed", +): """Interpret a control transform, then re-bind it for lowering to a `qref.ctrl` region op.""" consts = invals[:n_consts] args = invals[n_consts:-n_control] @@ -912,6 +921,7 @@ def handle_ctrl_transform(self, *invals, jaxpr, n_control, control_values, work_ jaxpr=body.jaxpr, control_values=control_values, work_wires=work_wires, + work_wire_type=work_wire_type, n_consts=len(body.consts), ) diff --git a/frontend/catalyst/from_plxpr/qref_jax_primitives.py b/frontend/catalyst/from_plxpr/qref_jax_primitives.py index a78ff8a595..03dd9c8276 100644 --- a/frontend/catalyst/from_plxpr/qref_jax_primitives.py +++ b/frontend/catalyst/from_plxpr/qref_jax_primitives.py @@ -745,6 +745,7 @@ def _pl_ctrl_lowering( control_values, work_wires, n_consts, + work_wire_type="borrowed", ): """Lower a `qp.ctrl` transform to a `qref.ctrl` region op.""" body_invals = plxpr_invals[: len(plxpr_invals) - n_control] diff --git a/frontend/test/pytest/from_plxpr/test_from_plxpr.py b/frontend/test/pytest/from_plxpr/test_from_plxpr.py index 79eee21ed1..059b053fdf 100644 --- a/frontend/test/pytest/from_plxpr/test_from_plxpr.py +++ b/frontend/test/pytest/from_plxpr/test_from_plxpr.py @@ -520,6 +520,24 @@ def circuit(): assert s_eqn.primitive == qref_operator_p assert s_eqn.params["n_ctrls"] == 0 + @pytest.mark.usefixtures("use_capture") + @pytest.mark.parametrize("work_wire_type", ("zeroed", "borrowed")) + def test_qfunc_ctrl_work_wire_type(self, work_wire_type): + """Test that a qfunc control with a work wire type is converted and keeps the type.""" + + @qp.qnode(qp.device("lightning.qubit", wires=3)) + def circuit(): + qp.ctrl(qp.S, control=1, work_wires=[2], work_wire_type=work_wire_type)(0) + return qp.state() + + plxpr = jax.make_jaxpr(circuit)() + catalyst_xpr = from_plxpr(plxpr)() + qfunc_xpr = catalyst_xpr.eqns[0].params["call_jaxpr"] + + eqn = next(e for e in qfunc_xpr.eqns if e.primitive == ctrl_transform_prim) + assert eqn.params["work_wires"] == qp.wires.Wires([2]) + assert eqn.params["work_wire_type"] == work_wire_type + @pytest.mark.parametrize("as_qfunc", (True, False)) def test_doubly_ctrl(self, as_qfunc): """Test doubly controlled op.""" diff --git a/frontend/test/pytest/python_interface/transforms/quantum/test_xdsl_diagonalize_measurements.py b/frontend/test/pytest/python_interface/transforms/quantum/test_xdsl_diagonalize_measurements.py index 70a76db9b9..2f01b37da2 100644 --- a/frontend/test/pytest/python_interface/transforms/quantum/test_xdsl_diagonalize_measurements.py +++ b/frontend/test/pytest/python_interface/transforms/quantum/test_xdsl_diagonalize_measurements.py @@ -538,9 +538,6 @@ def test_with_composite_observables(self, capture_mode): """Test the transform works for an observable built using operator arithmetic (sprod, prod, sum)""" - if capture_mode: - pytest.xfail("Requires fixes from PennyLane #10156") - dev = qp.device("lightning.qubit", wires=3) @qp.qnode(dev) @@ -683,9 +680,6 @@ def test_with_composite_observables(self, capture_mode): """Test the transform works for an observable built using operator arithmetic (sprod, prod, sum)""" - if capture_mode: - pytest.xfail("Requires fixes from PennyLane #10156") - dev = qp.device("lightning.qubit", wires=3) @qp.qnode(dev)