Second order (and mixed) QNN Pennylane derivatives with shots are not working ( dfdxdp, dfdxdx, dfdxdop)
Describe the bug
Simulations with high order QNN Pennylane derivatives with shots (dfdxdp, dfdxdx, dfdxdop) give different results when comparing to qiskit_shots, qiskit_statevector and penylane_statevector (all giving the correct results).
To Reproduce
I calculated f, dfdx, dfdxdp, dfdxdx, for a simple qnn with ChebyshevRx encoding:
import numpy as np
from squlearn.observables import SummedPaulis
from squlearn.encoding_circuit import QiskitEncodingCircuit, ChebyshevRx
from squlearn.qnn.lowlevel_qnn import LowLevelQNN
from squlearn import Executor
num_qubits = 2
x_array = np.array([[0.75],
[0.1]])
circuit = ChebyshevRx(num_features=1, num_qubits=num_qubits, num_layers=1)
observable = SummedPaulis(num_qubits)
qnn_pennylane_shots = LowLevelQNN(circuit, observable, Executor("pennylane", shots=50000))
qnn_pennylane_statevector = LowLevelQNN(circuit, observable, Executor("pennylane"))
qnn_qiskit_shots = LowLevelQNN(circuit, observable, Executor("qiskit", shots=50000))
qnn_qiskit = LowLevelQNN(circuit, observable, Executor("qiskit"))
np.random.seed(1)
param = np.random.rand(qnn_pennylane_shots.num_parameters)
param_obs = np.random.rand(observable.num_parameters)
print("Pennylane statevector ")
print("f\n", qnn_pennylane_statevector.evaluate(x_array, param, param_obs, "f")["f"])
print("dfdx\n", qnn_pennylane_statevector.evaluate(x_array, param, param_obs, "dfdx")["dfdx"])
print("dfdpdx\n", qnn_pennylane_statevector.evaluate(x_array, param, param_obs, "dfdpdx")["dfdpdx"])
print("dfdxdx\n", qnn_pennylane_statevector.evaluate(x_array, param, param_obs, "dfdxdx")["dfdxdx"])
#print("dfdxdop\n", qnn_pennylane_statevector.evaluate(x_array, param, param_obs, "dfdopdx")["dfdopdx"])
print("-----------------")
print("Pennylane shots")
print("f \n", qnn_pennylane_shots.evaluate(x_array, param, param_obs, "f")["f"])
print("dfdx \n", qnn_pennylane_shots.evaluate(x_array, param, param_obs, "dfdx")["dfdx"])
print("dfdpdx \n", qnn_pennylane_shots.evaluate(x_array, param, param_obs, "dfdpdx")["dfdpdx"])
print("dfdxdx \n", qnn_pennylane_shots.evaluate(x_array, param, param_obs, "dfdxdx")["dfdxdx"])
#print("dfdxdop\n", qnn_pennylane_shots.evaluate(x_array, param, param_obs, "dfdopdx")["dfdopdx"])
print("-----------------")
print("qiskit")
print("f \n", qnn_qiskit.evaluate(x_array, param, param_obs, "f")["f"])
print("dfdx \n", qnn_qiskit.evaluate(x_array, param, param_obs, "dfdx")["dfdx"])
print("dfdpdx \n", qnn_qiskit.evaluate(x_array, param, param_obs, "dfdpdx")["dfdpdx"])
print("dfdxdx \n", qnn_qiskit.evaluate(x_array, param, param_obs, "dfdxdx")["dfdxdx"])
print("-----------------")
print("qiskit shots")
print("f \n", qnn_qiskit_shots.evaluate(x_array, param, param_obs, "f")["f"])
print("dfdx \n", qnn_qiskit_shots.evaluate(x_array, param, param_obs, "dfdx")["dfdx"])
print("dfdpdx \n", qnn_qiskit_shots.evaluate(x_array, param, param_obs, "dfdpdx")["dfdpdx"])
print("dfdxdx \n", qnn_qiskit_shots.evaluate(x_array, param, param_obs, "dfdxdx")["dfdxdx"])
Expected behavior
The output of dfdxdx, dfdxdp should give the same values as the other implementations (like for f and dfdx implementation below).
Pennylane statevector
f
[0.3558851 0.25388108]
dfdx
[[0.18300929]
[0.1394669 ]]
dfdpdx
[[[ 0.16170338]
[ 0.27386335]
[ 0.08768908]
[ 0.10615746]]
[[ 0.03015719]
[ 0.11875324]
[-0.03103286]
[-0.02106788]]]
dfdxdx
[[[0.14283571]]
[[0.04234631]]]
-----------------
Pennylane shots
f
[0.35595153 0.25376274]
dfdx
[[0.18361726]
[0.14007897]]
dfdpdx
[[[0.09823249]
[0.19851102]
[0. ]
[0. ]]
[[0.07489638]
[0.15020733]
[0. ]
[0. ]]]
dfdxdx
[[[0.31401326]]
[[0.0140488 ]]]
-----------------
qiskit
f
[0.3558851 0.25388108]
dfdx
[[0.18300929]
[0.1394669 ]]
dfdpdx
[[[ 0.16170338]
[ 0.27386335]
[ 0.08768908]
[ 0.10615746]]
[[ 0.03015719]
[ 0.11875324]
[-0.03103286]
[-0.02106788]]]
dfdxdx
[[[0.14283571]]
[[0.04234631]]]
-----------------
qiskit shots
f
[0.35561856 0.25455449]
dfdx
[[0.184588 ]
[0.13953619]]
dfdpdx
[[[ 0.16126975]
[ 0.27412348]
[ 0.087647 ]
[ 0.10636382]]
[[ 0.03027624]
[ 0.11678895]
[-0.03101101]
[-0.02085382]]]
dfdxdx
[[[0.14369644]]
[[0.04309145]]]
I am happy to help if you have some suggestion :)
Thank you very much!
Additional context
- I used squlearn: 0.7.4
Fix in PR #272
Higher-order derivatives like dxdx deppend on the PennyLane issue: https://github.com/PennyLaneAI/pennylane/issues/5824 There is nothing, we can do right now. :/