sQUlearn / squlearn

scikit-learn interface for quantum algorithms
https://squlearn.github.io
Apache License 2.0
53 stars 18 forks source link

Pennylane backend QNN derivatives with complex observable coefficients are not working #254

Closed rupof closed 2 months ago

rupof commented 2 months ago

Hi! I came around two bugs in the QNN pennylane executor implementation.

Describe the bug

  1. Pennylane QNN derivatives (dfdx, dfdxdx, dfdop ) with complex observable coefficients (params_obs) return an error, whereas: Qiskit QNNs do not and Pennylane QNNs derivatives with real observables also work fine.
  2. When using real observables the output from Pennylane QNNs dfdop is different than Qiskit QNNs dfdop, at least in the example below.

To Reproduce

num_qubits = 1
x_array = np.array([[0.75], 
                    [0.1]])
circuit = LayeredEncodingCircuit(num_qubits, 1, "x")
circuit.Rx("x") 

param_obs = [(1 + 0j) for i in range(observable.num_parameters)] # complex coefficients
qnn_pennylane = LowLevelQNN(circuit, observable, Executor("pennylane"))

print("params_obs", param_obs)

print("Pennylane with complex coefficients for the observable") 
print(qnn_pennylane.evaluate(x_array, [], param_obs, "f")["f"])
print(qnn_pennylane.evaluate(x_array, [], param_obs, "dfdx")["dfdx"])

The above code returns a ValueError when evaluating dfdx and dfdop (the last two lines).

Expected behavior

We should obtain the same results as the QNNs using qiskit, or the QNNs using pennylane with real coefficients:

print("Qiskit with real coefficients for the observable")
param_obs = [(1) for i in range(observable.num_parameters)] # real coefficients
print("f ", qnn_qiskit.evaluate(x_array, [], param_obs, "f")["f"])
print("dfdx", qnn_qiskit.evaluate(x_array, [], param_obs, "dfdx")["dfdx"])
print("dfdop", qnn_qiskit.evaluate(x_array, [], param_obs, "dfdop")["dfdop"])

print("Pennylane with real coefficients for the observable") 
param_obs = [(1) for i in range(observable.num_parameters)] # real coefficients
print("f", qnn_pennylane.evaluate(x_array, [], param_obs, "f")["f"])
print("dfdx", qnn_pennylane.evaluate(x_array, [], param_obs, "dfdx")["dfdx"])
print("dfdop", qnn_pennylane.evaluate(x_array, [], param_obs, "dfdop")["dfdop"])

Returns

Qiskit with real coefficients for the observable
f  [0.73168887 0.99500417]
dfdx [[-0.68163876]
 [-0.09983342]]
dfdop [[0.73168887]
 [0.99500417]]
Pennylane with real coefficients for the observable
f [0.73168887 0.99500417]
dfdx [[-0.68163876]
 [-0.09983342]]
dfdop [[0] #Regarding point 2: This is not the same as Qiskits dfdop
 [0]]

I ran this code using 0.7.1

Thank you very much! Hopefully it is a quick fix. If there is anything I can do, I am happy to help :)

David-Kreplin commented 2 months ago

Thanks for the report! Complex numbers are not supported in both, the PennyLane and the Qiskit implementation. I wouldn't trust the numbers of the Qiskit Implementation. I will add some checks to raise errors for complex numbers.

I will also take care about the dfop issue.

David-Kreplin commented 2 months ago

The second issue is due to integer values, if converted to floating point values, it works. PR #255 resolves both errors.