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

Calls to qml.ctrl(qml.QubitUnitary)) produces two QubitUnitaries #1494

Open
erick-xanadu opened this issue Feb 4, 2025 · 0 comments
Open
Assignees
Labels
bug Something isn't working

Comments

@erick-xanadu
Copy link
Contributor

erick-xanadu commented Feb 4, 2025

Code:

import pennylane as qml

import catalyst

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

matrix = qml.matrix(qml.Hadamard(wires=[0]))

@catalyst.qjit(keep_intermediate=True)
@qml.qnode(dev)
def foo():
    catalyst.ctrl(qml.QubitUnitary(matrix, wires=[0]), control=[1])
    return catalyst.measure(0)

We produce the following MLIR, notice that we have the Hadamard, and two QubitUnitaries.

      %out_qubits = quantum.unitary(%2 : tensor<2x2xcomplex<f64>>) %1 : !quantum.bit
      // ... snip ...
      %out_qubits_7, %out_ctrl_qubits = quantum.unitary(%4 : tensor<2x2xcomplex<f64>>) %out_qubits ctrls(%3) ctrlvals(%extracted_6) : !quantum.bit ctrls !quantum.bit

possibly related to #1483 and PennyLaneAI/pennylane#6839 . When running a different commit of Catalyst with PennyLane==0.40 we only have one single qubit unitary. Regarding the Hadamard, it may be that we have never had support for qml.matrix(gate) inside the qjit context. Having a gate would ensure it is traced even if it is used only for obtaining a matrix.

@erick-xanadu erick-xanadu changed the title Code Gen Issue Calls to qml.ctrl(qml.QubitUnitary)) produces two QubitUnitaries Feb 4, 2025
@JerryChen97 JerryChen97 self-assigned this Feb 5, 2025
@JerryChen97 JerryChen97 added the bug Something isn't working label Feb 5, 2025
JerryChen97 added a commit to PennyLaneAI/pennylane that referenced this issue Feb 6, 2025
**Context:**
A recent deprecation #6840
deprecated the usage of `QubitUnitary` type input `base` for
instantiation of `ControlledQubitUnitary`.
However, a modification that was equivalent in PennyLane caused
unexpected behavior in Catalyst,
PennyLaneAI/catalyst#1494.
After investigation, it appears to be the issue with the private method
`_try_wrap_in_custom_ctrl_op` of `pennylane/ops/op_math/controlled.py`,
since it used to call the deprecated `init` to directly use base as
`QubitUnitary`, and to safely deprecate it we decided to locally replace
with equivalent `ControlledQubitUnitary(base=op.matrix(), ...)`, this
caused Catalyst to received double `QubitUnitary`.

It is also noteable that the call `ControlledQubitUnitary` should not
appear in this script, since logically all the classes living in
`controlled_ops` depend on `controlled.py`, which means that from the
very beginning the affected private method served as a tricky hack with
cyclic dependence.

Therefore, we would like to replace the `ControlledQubitUnitary` call
with a direct `ControlledOp`.

**Description of the Change:**
source files: as mentioned above.

tests: necessary improvements were made to correctly reflect the
assertion results.

**Benefits:**
 - Remove bugs
 - Less cyclic dependency

**Possible Drawbacks:**
- Probably there're more that depend on this method, which might be
affected by this fix

**Related GitHub Issues:**
PennyLaneAI/catalyst#1494

---------

Co-authored-by: Christina Lee <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants