Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lightning.qubit is not decomposing a controlled operator with a global phase #900

Open
isaacdevlugt opened this issue Sep 9, 2024 · 2 comments

Comments

@isaacdevlugt
Copy link
Contributor

isaacdevlugt commented Sep 9, 2024

Issue description

The following code does not work (NB: the -1 factor in ops).

ops = [-1 * qml.Z(0) @ qml.Z(1)]
coeffs = [1.]

reg = qml.registers({"physical": 2, "prep": 1})
all_qubits = reg["physical"] + reg["prep"]

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

@qml.qnode(dev)
def prep_circuit():
    qml.PrepSelPrep(qml.Hamiltonian(coeffs, ops), control=reg["prep"])
    return qml.expval(qml.Z(0))

prep_circuit()
DeviceError: Operator Controlled(-1 * Z(0), control_wires=[2]) not supported with lightning.qubit and does not provide a decomposition.
  • Expected behavior: lightning.qubit should decompose the given controlled operator into that + GlobalPhase

  • Actual behavior: It does not.

  • Reproduces how often: 100%

  • System information:

Name: PennyLane
Version: 0.38.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](https://file+.vscode-resource.vscode-cdn.net/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-14.6.1-arm64-arm-64bit
Python version:          3.11.9
Numpy version:           1.26.4
Scipy version:           1.12.0
Installed devices:
- nvidia.custatevec (PennyLane-Catalyst-0.8.0)
- nvidia.cutensornet (PennyLane-Catalyst-0.8.0)
- oqc.cloud (PennyLane-Catalyst-0.8.0)
- softwareq.qpp (PennyLane-Catalyst-0.8.0)
- lightning.qubit (PennyLane_Lightning-0.38.0)
- default.clifford (PennyLane-0.38.0)
- default.gaussian (PennyLane-0.38.0)
- default.mixed (PennyLane-0.38.0)
- default.qubit (PennyLane-0.38.0)
- default.qubit.autograd (PennyLane-0.38.0)
- default.qubit.jax (PennyLane-0.38.0)
- default.qubit.legacy (PennyLane-0.38.0)
- default.qubit.tf (PennyLane-0.38.0)
- default.qubit.torch (PennyLane-0.38.0)
- default.qutrit (PennyLane-0.38.0)
- default.qutrit.mixed (PennyLane-0.38.0)
- default.tensor (PennyLane-0.38.0)
- null.qubit (PennyLane-0.38.0)

Source code and tracebacks

---------------------------------------------------------------------------
DecompositionUndefinedError               Traceback (most recent call last)
File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:64, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     63 try:
---> 64     decomp = decomposer(op)
     65     current_depth += 1

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:355, in decompose.<locals>.decomposer(op)
    354 def decomposer(op):
--> 355     return op.decomposition()

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/ops/op_math/controlled.py:725, in Controlled.decomposition(self)
    724 if decomp is None:
--> 725     raise qml.operation.DecompositionUndefinedError
    726 return decomp

DecompositionUndefinedError: 

The above exception was the direct cause of the following exception:

DeviceError                               Traceback (most recent call last)
Cell In[6], line 14
     11     qml.PrepSelPrep(qml.Hamiltonian(coeffs, ops), control=reg["prep"])
     12     return qml.expval(qml.Z(0))
---> 14 prep_circuit()

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/workflow/qnode.py:1020, in QNode.__call__(self, *args, **kwargs)
   1018 if qml.capture.enabled():
   1019     return qml.capture.qnode_call(self, *args, **kwargs)
-> 1020 return self._impl_call(*args, **kwargs)

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/workflow/qnode.py:1008, in QNode._impl_call(self, *args, **kwargs)
   1005 self._update_gradient_fn(shots=override_shots, tape=self._tape)
   1007 try:
-> 1008     res = self._execution_component(args, kwargs, override_shots=override_shots)
   1009 finally:
   1010     if old_interface == "auto":

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/workflow/qnode.py:957, in QNode._execution_component(self, args, kwargs, override_shots)
    951     warnings.filterwarnings(
    952         action="ignore",
    953         message=r".*argument is deprecated and will be removed in version 0.39.*",
    954         category=qml.PennyLaneDeprecationWarning,
    955     )
    956     # pylint: disable=unexpected-keyword-arg
--> 957     res = qml.execute(
    958         (self._tape,),
    959         device=self.device,
    960         gradient_fn=self.gradient_fn,
    961         interface=self.interface,
    962         transform_program=full_transform_program,
    963         inner_transform=inner_transform_program,
    964         config=config,
    965         gradient_kwargs=self.gradient_kwargs,
    966         override_shots=override_shots,
    967         **execute_kwargs,
    968     )
    969 res = res[0]
    971 # convert result to the interface in case the qfunc has no parameters

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/workflow/execution.py:653, in execute(tapes, device, gradient_fn, interface, transform_program, inner_transform, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform, device_vjp, mcm_config)
    647 if not device_batch_transform:
    648     warnings.warn(
    649         "Device batch transforms cannot be turned off with the new device interface.",
    650         UserWarning,
    651     )
--> 653 tapes, post_processing = transform_program(tapes)
    655 if transform_program.is_informative:
    656     return post_processing(tapes)

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/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 ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:369, in decompose(tape, stopping_condition, stopping_condition_shots, skip_initial_state_prep, decomposer, max_expansion, name, error)
    366     return (tape,), null_postprocessing
    367 try:
--> 369     new_ops = [
    370         final_op
    371         for op in tape.operations[len(prep_op) :]
    372         for final_op in _operator_decomposition_gen(
    373             op,
    374             stopping_condition,
    375             decomposer=decomposer,
    376             max_expansion=max_expansion,
    377             name=name,
    378             error=error,
    379         )
    380     ]
    381 except RecursionError as e:
    382     raise error(
    383         "Reached recursion limit trying to decompose operations. "
    384         "Operator decomposition may have entered an infinite loop."
    385     ) from e

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:369, in <listcomp>(.0)
    366     return (tape,), null_postprocessing
    367 try:
--> 369     new_ops = [
    370         final_op
    371         for op in tape.operations[len(prep_op) :]
    372         for final_op in _operator_decomposition_gen(
    373             op,
    374             stopping_condition,
    375             decomposer=decomposer,
    376             max_expansion=max_expansion,
    377             name=name,
    378             error=error,
    379         )
    380     ]
    381 except RecursionError as e:
    382     raise error(
    383         "Reached recursion limit trying to decompose operations. "
    384         "Operator decomposition may have entered an infinite loop."
    385     ) from e

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:72, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     67     raise error(
     68         f"Operator {op} not supported with {name} and does not provide a decomposition."
     69     ) from e
     71 for sub_op in decomp:
---> 72     yield from _operator_decomposition_gen(
     73         sub_op,
     74         acceptance_function,
     75         decomposer=decomposer,
     76         max_expansion=max_expansion,
     77         current_depth=current_depth,
     78         name=name,
     79         error=error,
     80     )

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:72, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     67     raise error(
     68         f"Operator {op} not supported with {name} and does not provide a decomposition."
     69     ) from e
     71 for sub_op in decomp:
---> 72     yield from _operator_decomposition_gen(
     73         sub_op,
     74         acceptance_function,
     75         decomposer=decomposer,
     76         max_expansion=max_expansion,
     77         current_depth=current_depth,
     78         name=name,
     79         error=error,
     80     )

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:72, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     67     raise error(
     68         f"Operator {op} not supported with {name} and does not provide a decomposition."
     69     ) from e
     71 for sub_op in decomp:
---> 72     yield from _operator_decomposition_gen(
     73         sub_op,
     74         acceptance_function,
     75         decomposer=decomposer,
     76         max_expansion=max_expansion,
     77         current_depth=current_depth,
     78         name=name,
     79         error=error,
     80     )

File ~/.virtualenvs/pennylane-catalyst/lib/python3.11/site-packages/pennylane/devices/preprocess.py:67, in _operator_decomposition_gen(op, acceptance_function, decomposer, max_expansion, current_depth, name, error)
     65     current_depth += 1
     66 except qml.operation.DecompositionUndefinedError as e:
---> 67     raise error(
     68         f"Operator {op} not supported with {name} and does not provide a decomposition."
     69     ) from e
     71 for sub_op in decomp:
     72     yield from _operator_decomposition_gen(
     73         sub_op,
     74         acceptance_function,
   (...)
     79         error=error,
     80     )

DeviceError: Operator Controlled(-1 * Z(0), control_wires=[2]) not supported with lightning.qubit and does not provide a decomposition.

Additional information

--

@maliasadi
Copy link
Member

Hey @isaacdevlugt, Controlled(-1 * Z(0) @ Z(1)) and any other C(SProd) are supported in Lightning by calling the PL decomposition methods of the unsupported ops. You ran into this issue as there is not any generic 'decomposition' method for C(SProd) in PL.

In Lightning, however, we can support this either by gate diagonalization OR decomposition of C(SProd) to a QubitUnitary op as alternatives. I could run your example with the latter. Here's the branch if you want to try it out.

@isaacdevlugt
Copy link
Contributor Author

Thanks @maliasadi! I think the QubitUnitary option suffices for now 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants