qml.gradients.finite_diff

finite_diff(tape, argnum=None, h=1e-07, approx_order=1, n=1, strategy='forward', f0=None, validate_params=True, shots=None)[source]

Transform a QNode to compute the finite-difference gradient of all gate parameters with respect to its inputs.

Parameters
  • qnode (pennylane.QNode or QuantumTape) – quantum tape or QNode to differentiate

  • argnum (int or list[int] or None) – Trainable parameter indices to differentiate with respect to. If not provided, the derivatives with respect to all trainable parameters are returned.

  • h (float) – finite difference method step size

  • approx_order (int) – The approximation order of the finite-difference method to use.

  • n (int) – compute the \(n\)-th derivative

  • strategy (str) – The strategy of the finite difference method. Must be one of "forward", "center", or "backward". For the "forward" strategy, the finite-difference shifts occur at the points \(x_0, x_0+h, x_0+2h,\dots\), where \(h\) is some small stepsize. The "backwards" strategy is similar, but in reverse: \(x_0, x_0-h, x_0-2h, \dots\). Finally, the "center" strategy results in shifts symmetric around the unshifted point: \(\dots, x_0-2h, x_0-h, x_0, x_0+h, x_0+2h,\dots\).

  • f0 (tensor_like[float] or None) – Output of the evaluated input tape. If provided, and the gradient recipe contains an unshifted term, this value is used, saving a quantum evaluation.

  • validate_params (bool) – Whether to validate the tape parameters or not. If True, the Operation.grad_method attribute and the circuit structure will be analyzed to determine if the trainable parameters support the finite-difference method. If False, the finite-difference method will be applied to all parameters.

  • shots (None, int, list[int]) – The device shots that will be used to execute the tapes outputted by this transform. Note that this argument doesn’t influence the shots used for tape execution, but provides information to the transform about the device shots and helps in determining if a shot sequence was used to define the device shots for the new return types output system.

Returns

  • If the input is a QNode, an object representing the Jacobian (function) of the QNode that can be executed to obtain the Jacobian matrix. The returned matrix is a tensor of size (number_outputs, number_gate_parameters)

  • If the input is a tape, a tuple containing a list of generated tapes, together with a post-processing function to be applied to the results of the evaluated tapes in order to obtain the Jacobian matrix.

Return type

function or tuple[list[QuantumTape], function]

Example

This transform can be registered directly as the quantum gradient transform to use during autodifferentiation:

>>> dev = qml.device("default.qubit", wires=2)
>>> @qml.qnode(dev, diff_method=qml.gradients.finite_diff)
... def circuit(params):
...     qml.RX(params[0], wires=0)
...     qml.RY(params[1], wires=0)
...     qml.RX(params[2], wires=0)
...     return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))
>>> params = np.array([0.1, 0.2, 0.3], requires_grad=True)
>>> qml.jacobian(circuit)(params)
tensor([[-0.38751725, -0.18884792, -0.38355708],
        [ 0.69916868,  0.34072432,  0.69202365]], requires_grad=True)

This gradient transform can also be applied directly to QNode objects:

>>> @qml.qnode(dev)
... def circuit(params):
...     qml.RX(params[0], wires=0)
...     qml.RY(params[1], wires=0)
...     qml.RX(params[2], wires=0)
...     return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))
>>> qml.gradients.finite_diff(circuit)(params)
tensor([[-0.38751725, -0.18884792, -0.38355708],
        [ 0.69916868,  0.34072432,  0.69202365]], requires_grad=True)

This quantum gradient transform can also be applied to low-level QuantumTape objects. This will result in no implicit quantum device evaluation. Instead, the processed tapes, and post-processing function, which together define the gradient are directly returned:

>>> with qml.tape.QuantumTape() as tape:
...     qml.RX(params[0], wires=0)
...     qml.RY(params[1], wires=0)
...     qml.RX(params[2], wires=0)
...     qml.expval(qml.PauliZ(0))
...     qml.var(qml.PauliZ(0))
>>> gradient_tapes, fn = qml.gradients.finite_diff(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=3>,
 <QuantumTape: wires=[0], params=3>,
 <QuantumTape: wires=[0], params=3>,
 <QuantumTape: wires=[0], params=3>]

This can be useful if the underlying circuits representing the gradient computation need to be analyzed.

The output tapes can then be evaluated and post-processed to retrieve the gradient:

>>> dev = qml.device("default.qubit", wires=2)
>>> fn(qml.execute(gradient_tapes, dev, None))
[[-0.38751721 -0.18884787 -0.38355704]
 [ 0.69916862  0.34072424  0.69202359]]