PennyLaneAI / pennylane

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.
https://pennylane.ai
Apache License 2.0
2.27k stars 585 forks source link

[BUG] `ControlledQubitUnitary` behaves differently in `0.25` and `0.26` #3118

Closed isaacdevlugt closed 1 year ago

isaacdevlugt commented 1 year ago

Expected behavior

Here is a minimal example with v0.26:

U = qml.PauliX.compute_matrix() * (1.0j)

def subcircuit():
    qml.ControlledQubitUnitary(U @ U, control_wires=1, wires=2, control_values='0')

dev = qml.device("default.qubit", wires=3)
@qml.qnode(dev)
def circuit():
    qml.ctrl(subcircuit, control = 0, control_values=(0))()
    return qml.state()
>>> circuit()
[-1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]

Actual behavior

Differing outputs with 0.25 and 0.26 and not sure why 🤔

>>> circuit()
# v25: [1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]

# v26: [-1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]

Additional information

No response

Source code

U = qml.PauliX.compute_matrix() * (1.0j)

def subcircuit():
    qml.ControlledQubitUnitary(U @ U, control_wires=1, wires=2, control_values='0')

dev = qml.device("default.qubit", wires=3)
@qml.qnode(dev)
def circuit():
    qml.ctrl(subcircuit, control = 0, control_values=(0))()
    return qml.state()

Tracebacks

No response

System information

Depends on PennyLane version

Existing GitHub issues

albi3ro commented 1 year ago

Long story short, v0.26 is correct. Even though we are now getting the right answer, the bug still existed and would have shown up in decompositions and other devices.

Basically, the method _controlled returns a controlled version of the operator. That method did not consider control values.

You can easily see this by changing the control_values of the ControlledQubitUnitary:

U = qml.PauliX.compute_matrix() * (1.0j)

def subcircuit():
    qml.ControlledQubitUnitary(U @ U, control_wires=1, wires=2, control_values='1')

dev = qml.device("default.qubit", wires=3)
@qml.qnode(dev)
def circuit():
    qml.ctrl(subcircuit, control = 0, control_values=0)()
    return qml.state()

In v0.25, you would get the same value independent of control value.

isaacdevlugt commented 1 year ago

Thanks @albi3ro! 🚀