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] `Tensor` class allows non-hermitian observables to be passed into a measurement process! #2861

Open Jaybsoni opened 2 years ago

Jaybsoni commented 2 years ago

Expected behavior

We expect that when a non hermitian observable is passed into the measurement process, a reasonable error message is displayed which informs the user that they cannot perform such a measurement.

Actual behavior

>>> import pennylane as qml
>>> dev = qml.device("default.qubit", wires=[0,1]) 
>>> 
>>> @qml.qnode(dev)
... def my_circ(op):
...     qml.Hadamard(0)
...     qml.CNOT(wires=[0,1])
...     return qml.expval(op)
... 
>>> 
>>> op = qml.PauliX(0) @ qml.PauliZ(0)
>>> op
PauliX(wires=[0]) @ PauliZ(wires=[0])
>>> op.matrix()
array([[ 0, -1],
       [ 1,  0]])
>>> 
>>> my_circ(op)
tensor(0., requires_grad=True)
>>> 
>>> op.is_hermitian
True
>>> 
>>> qml.math.conjugate(op.matrix().T) == op.matrix()
array([[ True, False],
       [False,  True]])

Additional information

The Tensor class does not perform any validation to check if the tensor product of observables is in fact still hermitian. This causes issues when you compose hermitian observables which don't commute with each other. :tear

Source code

No response

Tracebacks

No response

System information

Name: PennyLane
Version: 0.25.0.dev0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: /Users/jay/Desktop/PL/pennylane
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, retworkx, scipy, semantic-version, toml
Required-by: amazon-braket-pennylane-plugin, PennyLane-Cirq, PennyLane-Forest, PennyLane-Lightning, PennyLane-Orquestra, PennyLane-Qchem, PennyLane-qiskit, PennyLane-qsharp

Platform info:           macOS-10.16-x86_64-i386-64bit
Python version:          3.9.7
Numpy version:           1.21.0
Scipy version:           1.7.1
Installed devices:
- default.gaussian (PennyLane-0.25.0.dev0)
- default.mixed (PennyLane-0.25.0.dev0)
- default.qubit (PennyLane-0.25.0.dev0)
- default.qubit.autograd (PennyLane-0.25.0.dev0)
- default.qubit.jax (PennyLane-0.25.0.dev0)
- default.qubit.tf (PennyLane-0.25.0.dev0)
- default.qubit.torch (PennyLane-0.25.0.dev0)
- lightning.qubit (PennyLane-Lightning-0.24.0)
- braket.aws.qubit (amazon-braket-pennylane-plugin-1.5.1)
- braket.local.qubit (amazon-braket-pennylane-plugin-1.5.1)
- forest.numpy_wavefunction (PennyLane-Forest-0.18.0.dev0)
- forest.qvm (PennyLane-Forest-0.18.0.dev0)
- forest.wavefunction (PennyLane-Forest-0.18.0.dev0)
- cirq.mixedsimulator (PennyLane-Cirq-0.18.0.dev0)
- cirq.pasqal (PennyLane-Cirq-0.18.0.dev0)
- cirq.qsim (PennyLane-Cirq-0.18.0.dev0)
- cirq.qsimh (PennyLane-Cirq-0.18.0.dev0)
- cirq.simulator (PennyLane-Cirq-0.18.0.dev0)
- microsoft.QuantumSimulator (PennyLane-qsharp-0.9.0.dev0)
- qiskit.aer (PennyLane-qiskit-0.19.0.dev0)
- qiskit.basicaer (PennyLane-qiskit-0.19.0.dev0)
- qiskit.ibmq (PennyLane-qiskit-0.19.0.dev0)
- orquestra.forest (PennyLane-Orquestra-0.16.0.dev0)
- orquestra.ibmq (PennyLane-Orquestra-0.16.0.dev0)
- orquestra.qiskit (PennyLane-Orquestra-0.16.0.dev0)
- orquestra.qulacs (PennyLane-Orquestra-0.16.0.dev0)

Existing GitHub issues

Jaybsoni commented 2 years ago

its unclear if we should add expensive checks for hermiticity or if there is something more clever we can do.

glassnotes commented 1 year ago

A collaborator just reported something similar to me. As a consequence, even the more broad qml.is_hermitian check fails in these cases, because it relies on the op.is_hermitian property.

>>> qml.matrix( qml.PauliZ(0) @ qml.PauliY(0) )
[[0.+0.j 0.-1.j]
 [0.-1.j 0.+0.j]] 
>>> qml.is_hermitian( qml.PauliZ(0) @ qml.PauliY(0) )
True

One solution is to update qml.is_hermitian to always check the matrix representation rather than op.is_hermitian but that is less efficient. Another option is to add a check on commutativity of two operators when constructing their product, in order to properly set the value of is_hermitian. This is pretty efficient when everything is a Pauli, but I think you'd have to resort to matrix representations if something is just a general qml.Hermitian.