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] `qml.matrix` for a `qml.Hamiltonian` produces a NumPy array for non-NumPy coefficients #2970

Open eddddddy opened 2 years ago

eddddddy commented 2 years ago

Expected behavior

qml.matrix should respect the framework-specific tensors used to construct the qml.Hamiltonian, and return the matrix representation of that Hamiltonian in the same framework. For example, executing the following code should yield a TensorFlow tensor:

>>> h = qml.Hamiltonian([tf.Variable(0.3)], [qml.PauliX(0)])
>>> qml.matrix(h)

Actual behavior

The code above instead produces a NumPy array:

>>> h = qml.Hamiltonian([tf.Variable(0.3)], [qml.PauliX(0)])
>>> qml.matrix(h)
array([[0.        +0.j, 0.30000001+0.j],
       [0.30000001+0.j, 0.        +0.j]])

Additional information

The matrix representation of the Hamiltonian is computed in qml.utils.sparse_hamiltonian, which uses a SciPy sparse matrix data structure and thus converts the framework-specific tensors into NumPy arrays.

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: None
Author-email: None
License: Apache License 2.0
Location: c:\users\edward.jiang\documents\pennylane
Requires: numpy, scipy, networkx, retworkx, autograd, toml, appdirs, semantic-version, autoray, cachetools, pennylane
-lightning
Required-by: PennyLane-qiskit, PennyLane-Lightning

Platform info:           Windows-10-10.0.19042-SP0
Python version:          3.8.10
Numpy version:           1.20.3
Scipy version:           1.7.3
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)
- qiskit.aer (PennyLane-qiskit-0.24.0)
- qiskit.basicaer (PennyLane-qiskit-0.24.0)
- qiskit.ibmq (PennyLane-qiskit-0.24.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.24.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.24.0)
- lightning.qubit (PennyLane-Lightning-0.25.0)

Existing GitHub issues

AlbertMitjans commented 2 years ago

I believe this will be fixed with the new operator arithmetic:

>>> s_prod = qml.s_prod(tf.Variable(0.3), qml.PauliX(0))
>>> qml.matrix(s_prod)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[0. , 0.3],
       [0.3, 0. ]], dtype=float32)>

However I just realised that we still need to support the dunder methods for all interfaces.

eddddddy commented 2 years ago

That's great! Is the above code also differentiable in the expected way? If so, then it's definitely something I can replace in my code to get the behaviour I want.

AlbertMitjans commented 2 years ago

That's great! Is the above code also differentiable in the expected way? If so, then it's definitely something I can replace in my code to get the behaviour I want.

@albi3ro or @Jaybsoni might know better.

albi3ro commented 2 years ago
import tensorflow as tf

dev = qml.device("default.qubit", wires=5)

@qml.qnode(dev, interface="tensorflow", diff_method='backprop')
def circuit(s):
    return qml.expval(qml.s_prod(s, qml.PauliZ(0)))

x = tf.Variable(2.0)
with tf.GradientTape() as tape:
    res = circuit(x)

tape.gradient(res, [x])

Works absolutely fine.

Jaybsoni commented 2 years ago

Yes I think this is another issue with Hamiltonian, it uses this sparse representation by default. This is a problem because the I don't think the logic is compatible with any other interface other then scipy sparse arrays!