pennylane
pennylane copied to clipboard
[BUG] Should the inverse of QubitStateVector be supported?
Expected behavior
Consider the following circuit:
import pennylane as qml
import numpy as np
dev = qml.device("default.qubit", wires=1)
# The state found by applying qml.RX(0.4, wires=0) to |0>:
state = np.array([0.98006658, -0.19866933j])
@qml.qnode(dev)
def f():
qml.QubitStateVector(state, wires=0)
return qml.expval(qml.PauliY(0))
f()
# tensor(-0.38941834, requires_grad=True)
Should we support qml.adjoint(qml.QubitStateVector)(state, wires=0)
or qml.QubitStateVector(state, wires=0).inv()
and what do we expect the output of the circuit to be? For me, I'd interpret |psi> = U|0>
and the inverse to be to apply U*
. The above would then be:
@qml.qnode(dev)
def f():
qml.adjoint(qml.QubitStateVector)(state, wires=0)
return qml.expval(qml.PauliY(0))
f()
# tensor(0.38941834, requires_grad=True)
However, maybe it's just better to raise an error if inverting a state preparation?
Actual behavior
An error is not raised when using qml.adjoint()
or .inv()
, but the results aren't what I'd expect.
For the adjoint
function:
@qml.qnode(dev)
def f():
qml.adjoint(qml.QubitStateVector)(state, wires=0)
return qml.expval(qml.PauliY(0))
f()
# tensor(-5.55111512e-17, requires_grad=True)
For the .inv()
method:
@qml.qnode(dev)
def f():
qml.QubitStateVector(state, wires=0).inv()
return qml.expval(qml.PauliY(0))
f()
# tensor(-0.38941834, requires_grad=True)
Additional information
No response
Source code
No response
Tracebacks
No response
System information
Dev PL
Existing GitHub issues
- [X] I have searched existing GitHub issues to make sure the issue does not already exist.
@trbromley I'm curious what happens here. My gut feeling is that since the adjoint of QubitStateVector
is not defined, this fallsback to the adjoint of the mottonen method, which should be equivalent to $U^\dagger|0\rangle$.
My gut feeling is that since the adjoint of QubitStateVector is not defined, this fallsback to the adjoint of the mottonen method, which should be equivalent to ...
That would be good! I don't think it's happening though, qml.adjoint
seems to result in the state preparation being ignored completely, whereas .inv()
seems to have no effect (i.e., just applies QubitStateVector
).
@trbromley Running on current master (this behaviour was updated last Friday), we get different behaviour for QubitStateVector
and Adjoint(QubitStateVector)
.
import pennylane as qml
import numpy as np
dev = qml.device("default.qubit", wires=1)
state = np.array([0.98006658, -0.19866933j])
@qml.qnode(dev)
def f():
qml.QubitStateVector(state, wires=0)
return qml.state()
@qml.qnode(dev)
def g():
qml.adjoint(qml.QubitStateVector)(state, wires=0)
return qml.state()
print(f())
print(g())
print(qml.draw(f, expansion_strategy="device")())
print(qml.draw(g, expansion_strategy="device")())
[ 0.98006658+0.j -0. -0.19866933j]
[ 0.69301172-0.69301172j -0.14048043+0.14048043j]
0: ──QubitStateVector(M0)─┤ State
0: ──RZ(1.57)──RY(-0.40)─┤ State
If we look at the expansion, we can see what happens:
>>> qml.QubitStateVector(state, wires=0).expand().expand().circuit
[RY(array(0.4), wires=[0]), RZ(array(-1.57079633), wires=[0])]
>>> qml.adjoint(qml.QubitStateVector(state, wires=0)).expand().expand(depth=2).circuit
[RZ(1.5707963267948966, wires=[0]), RY(-0.399999997583816, wires=[0])]
The adjoint of the QubitStateVector
applies the adjoint of the MottonenStatePrep
decomposition.
@trbromley just double-checking: can this issue be closed?