Skip to content

[BUG] Tree-traversal + lightning throws confusing errors (analytic mode) and results (finite shots) when it shouldn't #6539

@isaacdevlugt

Description

@isaacdevlugt

Expected behavior

I expect mcm_method="tree-traversal" + lightning.qubit to throw a meaningful error (not a supported feature at the moment) in analytic and finite shot modes.

Actual behavior

  • An unhelpful error message is raised in analytic mode
  • Results are returned in finite shots mode

Additional information

No response

Source code

import pennylane as qml

dev = qml.device("lightning.qubit", wires=1)

@qml.qnode(dev, mcm_method="tree-traversal")
def circuit(x):
    qml.RX(x, 0)

    m0 = qml.measure(0)
    qml.cond(m0 == 0, qml.H)(0)

    return qml.expval(qml.Y(0)) 

print(qml.draw(circuit)(1.23))
circuit(1.23, shots=10)
circuit(1.23)

Tracebacks

(array(1), array(0), array(1), array(1), array(1), array(0), array(0), array(0), array(0), array(0))

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[53], line 18
     15     return qml.expval(qml.Y(0)) 
     17 print(circuit(1.23, shots=10))
---> 18 print(circuit(1.23))

File ~/Documents/pennylane/pennylane/workflow/qnode.py:987, in QNode.__call__(self, *args, **kwargs)
    985 if qml.capture.enabled():
    986     return qml.capture.qnode_call(self, *args, **kwargs)
--> 987 return self._impl_call(*args, **kwargs)

File ~/Documents/pennylane/pennylane/workflow/qnode.py:977, in QNode._impl_call(self, *args, **kwargs)
    974     self._interface = interface
    976 try:
--> 977     res = self._execution_component(args, kwargs)
    978 finally:
    979     if old_interface == "auto":

File ~/Documents/pennylane/pennylane/workflow/qnode.py:935, in QNode._execution_component(self, args, kwargs)
    932 interface = None if self.interface == "numpy" else self.interface
    934 # pylint: disable=unexpected-keyword-arg
--> 935 res = qml.execute(
    936     (self._tape,),
    937     device=self.device,
    938     gradient_fn=gradient_fn,
    939     interface=interface,
    940     transform_program=full_transform_program,
    941     inner_transform=inner_transform_program,
    942     config=config,
    943     gradient_kwargs=gradient_kwargs,
    944     **execute_kwargs,
    945 )
    946 res = res[0]
    948 # convert result to the interface in case the qfunc has no parameters

File ~/Documents/pennylane/pennylane/workflow/execution.py:523, in execute(tapes, device, gradient_fn, interface, transform_program, inner_transform, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, device_vjp, mcm_config)
    521 # Exiting early if we do not need to deal with an interface boundary
    522 if no_interface_boundary_required:
--> 523     results = inner_execute(tapes)
    524     return post_processing(results)
    526 if config.use_device_jacobian_product and interface in jpc_interfaces:

File ~/Documents/pennylane/pennylane/workflow/execution.py:199, in _make_inner_execute.<locals>.inner_execute(tapes, **_)
    196 if cache is not None:
    197     transform_program.add_transform(_cache_transform, cache=cache)
--> 199 transformed_tapes, transform_post_processing = transform_program(tapes)
    201 if transformed_tapes:
    202     results = device.execute(transformed_tapes, execution_config=execution_config)

File ~/Documents/pennylane/pennylane/transforms/core/transform_program.py:515, in TransformProgram.__call__(self, tapes)
    513 if self._argnums is not None and self._argnums[i] is not None:
    514     tape.trainable_params = self._argnums[i][j]
--> 515 new_tapes, fn = transform(tape, *targs, **tkwargs)
    516 execution_tapes.extend(new_tapes)
    518 fns.append(fn)

File ~/Documents/pennylane/pennylane/devices/preprocess.py:400, in decompose(tape, stopping_condition, stopping_condition_shots, skip_initial_state_prep, decomposer, max_expansion, name, error)
    397     return (tape,), null_postprocessing
    398 try:
--> 400     new_ops = [
    401         final_op
    402         for op in tape.operations[len(prep_op) :]
    403         for final_op in _operator_decomposition_gen(
    404             op,
    405             stopping_condition,
    406             decomposer=decomposer,
    407             max_expansion=max_expansion,
    408             name=name,
    409             error=error,
    410         )
    411     ]
    412 except RecursionError as e:
    413     raise error(
    414         "Reached recursion limit trying to decompose operations. "
    415         "Operator decomposition may have entered an infinite loop."
    416     ) from e

File ~/Documents/pennylane/pennylane/devices/preprocess.py:400, in <listcomp>(.0)
    397     return (tape,), null_postprocessing
    398 try:
--> 400     new_ops = [
    401         final_op
    402         for op in tape.operations[len(prep_op) :]
    403         for final_op in _operator_decomposition_gen(
    404             op,
    405             stopping_condition,
    406             decomposer=decomposer,
    407             max_expansion=max_expansion,
    408             name=name,
    409             error=error,
    410         )
    411     ]
    412 except RecursionError as e:
    413     raise error(
    414         "Reached recursion limit trying to decompose operations. "
    415         "Operator decomposition may have entered an infinite loop."
    416     ) from e

File ~/Documents/pennylane/pennylane/devices/preprocess.py:64, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     62 else:
     63     try:
---> 64         decomp = decomposer(op)
     65         current_depth += 1
     66     except qml.operation.DecompositionUndefinedError as e:

File ~/Documents/pennylane/pennylane/devices/preprocess.py:386, in decompose.<locals>.decomposer(op)
    385 def decomposer(op):
--> 386     return op.decomposition()

AttributeError: 'MidMeasureMP' object has no attribute 'decomposition'

System information

Name: PennyLane
Version: 0.39.0
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: /Users/isaac/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, packaging, pennylane-lightning, requests, rustworkx, scipy, toml, typing-extensions
Required-by: PennyLane-Catalyst, PennyLane_Lightning

Platform info:           macOS-15.1-arm64-arm-64bit
Python version:          3.11.9
Numpy version:           1.26.4
Scipy version:           1.12.0
Installed devices:
- default.clifford (PennyLane-0.39.0)
- default.gaussian (PennyLane-0.39.0)
- default.mixed (PennyLane-0.39.0)
- default.qubit (PennyLane-0.39.0)
- default.qutrit (PennyLane-0.39.0)
- default.qutrit.mixed (PennyLane-0.39.0)
- default.tensor (PennyLane-0.39.0)
- null.qubit (PennyLane-0.39.0)
- reference.qubit (PennyLane-0.39.0)
- nvidia.custatevec (PennyLane-Catalyst-0.9.0)
- nvidia.cutensornet (PennyLane-Catalyst-0.9.0)
- oqc.cloud (PennyLane-Catalyst-0.9.0)
- softwareq.qpp (PennyLane-Catalyst-0.9.0)
- lightning.qubit (PennyLane_Lightning-0.39.0)

Existing GitHub issues

  • I have searched existing GitHub issues to make sure the issue does not already exist.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug 🐛Something isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions