Gradient Descent of real scalar-output function

I want to calculate gradient descent with the following setup of quantum circuit.

 import pennylane as qml
 from pennylane import numpy as np

dev = qml.device('default.qubit', wires = ['wire1', 'wire2'], shots = 1000)

@qml.qnode(dev, interface='autograd')
def circuit(params):
    qml.RX(params[0], wires = 'wire1') # Rx is applied with the 1st parameter, on the first qubit
    qml.RY(params[1], wires = 'wire1') # Ry is applied with the 2nd parameter, on the first qubit
    qml.CNOT(wires = ['wire1', 'wire2']) # CNOT is applied on the first and second qubit
    #my_circuit(wires = (1,0))
    return qml.sample(qml.PauliZ('wire1')), qml.sample(qml.PauliZ('wire2'))

I then implement the gradient descent function,

dcircuit = qml.grad(circuit, argnum=0)
    print(dcircuit([0, 0]))

which return the following error

Grad only applies to real scalar-output functions. Try jacobian, elementwise_grad or holomorphic_grad.

After a few trials, I realise that I can run gradient descent only the result is measured in expval(), but not sample()

I don’t know why, I hope someone can explain it to me.

What if I want to use to check the number of shots from sample()

result = circuit(params)
result.shape

how can I correct the code?

Thank you!

Hey @alanspace,

You are correct, it is not possible to differentiate the return type qml.sample(), and you can instead differentiate qml.expval() or qml.probs().

I don’t think differentiating on the level of samples makes sense conceptually. When you sample from a qubit, you get a collection of zeros and ones. The zero/one sample itself does not contain information about the circuit and hence cannot be differentiated with respect to one of the circuit parameters. Instead, the probability of obtaining a zero or one is controlled by the circuit and we can differentiate that. Since expectation values are effectively an additional function on top of the sample probabilities, we can also differentiate them.

The default.qubit device operates in an analytic (i.e. “infinite”-shot) mode by default and expectation values and probabilities are evaluated exactly. Instead, if you switch to analytic=False, these quantities will be approximated from samples:

dev = qml.device('default.qubit', wires = ['wire1', 'wire2'], analytic=False, shots = 1000)

If you later on want to query the number of shots being used, you can do:

print(dev.shots)

Hope that helps!