Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,10 @@

<h3>Internal changes ⚙️</h3>

* The `autograph` keyword argument has been removed from the `QNode` constructor.
To enable autograph conversion, use the `qjit` decorator together with the `qml.capture.disable_autograph` context manager.
[(#8104)](https://github.com/PennyLaneAI/pennylane/pull/8104)

* Add ability to disable autograph conversion using the newly added `qml.capture.disable_autograph` decorator or context manager.
[(#8102)](https://github.com/PennyLaneAI/pennylane/pull/8102)

Expand Down
7 changes: 3 additions & 4 deletions pennylane/workflow/_capture_qnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,6 @@ def _extract_qfunc_jaxpr(qnode, abstracted_axes, *args, **kwargs):
"""Process the quantum function of a QNode to create a Jaxpr."""

qfunc = partial(qnode.func, **kwargs) if kwargs else qnode.func
# pylint: disable=protected-access
qfunc = qml.capture.run_autograph(qfunc) if qnode._autograph else qfunc
flat_fn = FlatFn(qfunc)

try:
Expand All @@ -472,8 +470,9 @@ def _extract_qfunc_jaxpr(qnode, abstracted_axes, *args, **kwargs):
) as exc:
raise CaptureError(
"Autograph must be used when Python control flow is dependent on a dynamic "
"variable (a function input). Please ensure that autograph=True or use native control "
"flow functions like for_loop, while_loop, etc."
"variable (a function input). Please ensure that autograph is being correctly enabled with "
"`qml.capture.run_autograph` or disabled with `qml.capture.disable_autograph` or consider using PennyLane native control "
"flow functions like `qml.for_loop`, `qml.while_loop`, or `qml.cond`."
) from exc

assert flat_fn.out_tree is not None, "out_tree should be set by call to flat_fn"
Expand Down
5 changes: 0 additions & 5 deletions pennylane/workflow/qnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,6 @@ class QNode:
on supported options for your chosen gradient transform.
static_argnums (int | Sequence[int]): *Only applicable when the experimental capture mode is enabled.*
An ``int`` or collection of ``int``\ s that specify which positional arguments to treat as static.
autograph (bool): *Only applicable when the experimental capture mode is enabled.* Whether to use AutoGraph to
convert Python control flow to native PennyLane control flow. For more information, refer to
:doc:`Autograph </development/autograph>`. Defaults to ``True``.
executor_backend (ExecBackends | str): The backend executor for concurrent function execution. This argument
allows for selective control of how to run data-parallel/task-based parallel functions via a defined execution
environment. All supported options can be queried using
Expand Down Expand Up @@ -533,7 +530,6 @@ def __init__(
mcm_method: Literal["deferred", "one-shot", "tree-traversal"] | None = None,
gradient_kwargs: dict | None = None,
static_argnums: int | Iterable[int] = (),
autograph: bool = True,
executor_backend: ExecBackends | str | None = None,
):
self._init_args = locals()
Expand Down Expand Up @@ -577,7 +573,6 @@ def __init__(
self._qfunc_uses_shots_arg = False

# input arguments
self._autograph = autograph
self.func = func
self.device = device
self._interface = get_canonical_interface_name(interface)
Expand Down
37 changes: 15 additions & 22 deletions tests/capture/autograph/test_autograph.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,12 @@ def test_transform_on_lambda(self):
assert new_fn(1.23) == 2.46
assert "inner_factory.<locals>.<lambda>" in str(new_fn)

@pytest.mark.parametrize("autograph", [True, False])
def test_transform_on_qnode(self, autograph):
def test_transform_on_qnode(self):
"""Test the transform method on a QNode updates the qnode.func"""
transformer = PennyLaneTransformer()
user_context = converter.ProgramContext(TOPLEVEL_OPTIONS)

@qml.qnode(qml.device("default.qubit", wires=3), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=3))
def circ(x):
qml.RX(x, 0)
return qml.expval(qml.Z(0))
Expand Down Expand Up @@ -245,11 +244,10 @@ def fn(x: int):
assert check_cache(fn)
assert check_cache(inner)

@pytest.mark.parametrize("autograph", [True, False])
def test_qnode(self, autograph):
def test_qnode(self):
"""Test autograph on a QNode."""

@qml.qnode(qml.device("default.qubit", wires=1), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=1))
def circ(x: float):
qml.RY(x, wires=0)
return qml.expval(qml.PauliZ(0))
Expand Down Expand Up @@ -302,23 +300,21 @@ def fn(x: float):
assert check_cache(inner1.func)
assert check_cache(inner2.func)

@pytest.mark.parametrize("autograph", [True, False])
def test_adjoint_op(self, autograph):
def test_adjoint_op(self):
"""Test that the adjoint of an operator successfully passes through autograph"""

@qml.qnode(qml.device("default.qubit", wires=2), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=2))
def circ():
qml.adjoint(qml.X(0))
return qml.expval(qml.Z(0))

plxpr = qml.capture.make_plxpr(circ, autograph=True)()
plxpr = qml.capture.make_plxpr(circ)()
assert jax.core.eval_jaxpr(plxpr.jaxpr, plxpr.consts)[0] == -1

@pytest.mark.parametrize("autograph", [True, False])
def test_ctrl_op(self, autograph):
def test_ctrl_op(self):
"""Test that controlled operators successfully pass through autograph"""

@qml.qnode(qml.device("default.qubit", wires=2), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=2))
def circ():
qml.X(1)
qml.ctrl(qml.X(0), 1)
Expand All @@ -327,14 +323,13 @@ def circ():
plxpr = qml.capture.make_plxpr(circ, autograph=True)()
assert jax.core.eval_jaxpr(plxpr.jaxpr, plxpr.consts)[0] == -1

@pytest.mark.parametrize("autograph", [True, False])
def test_adjoint_wrapper(self, autograph):
def test_adjoint_wrapper(self):
"""Test conversion is happening successfully on functions wrapped with 'adjoint'."""

def inner(x):
qml.RY(x, wires=0)

@qml.qnode(qml.device("default.qubit", wires=1), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=1))
def circ(x: float):
inner(x * 2)
qml.adjoint(inner)(x)
Expand All @@ -351,14 +346,13 @@ def circ(x: float):
@pytest.mark.xfail(
reason="ctrl_transform_prim not working with autograph. See sc-84934",
)
@pytest.mark.parametrize("autograph", [True, False])
def test_ctrl_wrapper(self, autograph):
def test_ctrl_wrapper(self):
"""Test conversion is happening successfully on functions wrapped with 'ctrl'."""

def inner(x):
qml.RY(x, wires=0)

@qml.qnode(qml.device("default.qubit", wires=2), autograph=autograph)
@qml.qnode(qml.device("default.qubit", wires=2))
def circ(x: float):
qml.PauliX(1)
qml.ctrl(inner, control=1)(x)
Expand Down Expand Up @@ -403,8 +397,7 @@ def fn(x: float):
assert check_cache(fn)
assert check_cache(inner)

@pytest.mark.parametrize("autograph", [True, False])
def test_tape_transform(self, autograph):
def test_tape_transform(self):
"""Test if tape transform is applied when autograph is on."""

dev = qml.device("default.qubit", wires=1)
Expand All @@ -414,7 +407,7 @@ def my_quantum_transform(tape):
raise NotImplementedError

@my_quantum_transform
@qml.qnode(dev, autograph=autograph)
@qml.qnode(dev)
def circuit(x):
qml.RY(x, wires=0)
qml.RX(x, wires=0)
Expand Down
Loading