Open cvjjm opened 1 month ago
While trying to debug the problem that made me notice the behavior above, I also noticed the following unexpected behavior: Some of the asserts in the following code do not work as I/one would expect:
hermitian_obs = qml.PauliZ(0)
assert hermitian_obs.is_hermitian
assert qml.adjoint(hermitian_obs) == hermitian_obs # fails
assert hermitian_obs.adjoint() == hermitian_obs
hermitian_obs2 = 0.2 * qml.PauliZ(0)
assert hermitian_obs2.is_hermitian
assert qml.adjoint(hermitian_obs2) == hermitian_obs2 # fails
assert hermitian_obs2.adjoint() == hermitian_obs2 # fails
non_hermitian_obs = 0.2j * qml.PauliZ(0)
assert qml.adjoint(non_hermitian_obs) != non_hermitian_obs
assert non_hermitian_obs.adjoint() != non_hermitian_obs
assert not non_hermitian_obs.is_hermitian
The qml.adjoint
function is lazy by default, simply wrapping the target in an Adjoint
class for later handling. You can either specify lazy=False
when constructing the adjoint, or simplify the operators before comparison:
assert qml.adjoint(hermitian_obs, lazy=False) == hermitian_obs
assert qml.simplify(qml.adjoint(hermitian_obs)) == hermitian_obs
As for the error from:
>>> op = 0.2 * qml.PauliZ(0)
>>> qml.equal(qml.adjoint(op, lazy=False), op)
AttributeError: 'PauliZ' object has no attribute 'base'
That does seem to indeed be a bug.
Handling non-hermitian observables has been an ongoing debate. We used to raise a warning when constructing measurments from non-hermitian observables, but found that introduced a substantial performance penalty for a more obscure edge case. The challenge is finding a middle ground between returning always real results for hermitian observables, but also sometimes permitting non-hermitian obs.
Thanks @cvjjm for reporting this. So far we've not focused too much on taking expectation values of non-Hermitian operators, so it doesn't surprise me too much that we are casting the result to a real value. However, it would be nice to have some limited support for non-Hermitian operators, or to at least not preclude it by casting to reals if otherwise the result would be correct.
We can definitely look into this, how blocking is it for you?
Not high priority. We can work around it. It was just unexpected behavior that cause a hard to debug problem and I though I could save other peoples time by reporting...
Thanks for reporting this @cvjjm ! It can surely help others in the future.
Expected behavior
The PL operator arithmetic allows for operators with imaginary/complex coefficients. If such expectation values of such operators are measured I expect to either get a imaginary/complex value (the real expectation value of the Hermitian operator times the complex coefficient) or an exception that only Hermitian observables can be measured.
Actual behavior
Instead PennyLane silently discards the imaginary part, as the attached example code shows.
Additional information
No response
Source code
Tracebacks
No response
System information
Existing GitHub issues