qml.execute

execute(tapes, device, diff_method=None, interface=Interface.AUTO, *, grad_on_execution='best', cache='auto', cachesize=10000, max_diff=1, device_vjp=False, postselect_mode=None, mcm_method=None, gradient_kwargs=None, transform_program=None, executor_backend=None)[source]

A function for executing a batch of tapes on a device with compatibility for auto-differentiation.

Parameters:
  • tapes (Sequence[.QuantumTape]) – batch of tapes to execute

  • device (pennylane.devices.LegacyDevice) – Device to use to execute the batch of tapes. If the device does not provide a batch_execute method, by default the tapes will be executed in serial.

  • diff_method (Optional[str | TransformDispatcher]) – The gradient transform function to use for backward passes. If “device”, the device will be queried directly for the gradient (if supported).

  • interface (str, Interface) – The interface that will be used for classical auto-differentiation. This affects the types of parameters that can exist on the input tapes. Available options include autograd, torch, tf, jax, and auto.

  • transform_program (.TransformProgram) – A transform program to be applied to the initial tape.

  • grad_on_execution (bool, str) – Whether the gradients should be computed on the execution or not. It only applies if the device is queried for the gradient; gradient transform functions available in qml.gradients are only supported on the backward pass. The ‘best’ option chooses automatically between the two options and is default.

  • cache="auto" (str or bool or dict or Cache) – Whether to cache evalulations. "auto" indicates to cache only when max_diff > 1. This can result in a reduction in quantum evaluations during higher order gradient computations. If True, a cache with corresponding cachesize is created for each batch execution. If False, no caching is used. You may also pass your own cache to be used; this can be any object that implements the special methods __getitem__(), __setitem__(), and __delitem__(), such as a dictionary.

  • cachesize (int) – the size of the cache.

  • max_diff (int) – If diff_method is a gradient transform, this option specifies the maximum number of derivatives to support. Increasing this value allows for higher-order derivatives to be extracted, at the cost of additional (classical) computational overhead during the backward pass.

  • device_vjp=False (Optional[bool]) – whether or not to use the device-provided Jacobian product if it is available.

  • postselect_mode (Optional[str]) – Configuration for handling shots with mid-circuit measurement postselection. Use "hw-like" to discard invalid shots and "fill-shots" to keep the same number of shots. Default is None.

  • mcm_method (Optional[str]) – Strategy to use when executing circuits with mid-circuit measurements. "deferred" is ignored. If mid-circuit measurements are found in the circuit, the device will use "tree-traversal" if specified and the "one-shot" method otherwise. For usage details, please refer to the dynamic quantum circuits page.

  • gradient_kwargs (Optional[dict]) – dictionary of keyword arguments to pass when determining the gradients of tapes.

  • executor_backend (Optional[str | ExecBackends]) – concurrent task-based executor for function dispatch. If supported by a device, the configured executor provides an abstraction for task-based function execution, which can provide speed-ups for computationally demanding execution. Defaults to None.

Returns:

A nested list of tape results. Each element in the returned list corresponds in order to the provided tapes.

Return type:

list[tensor_like[float]]

Example

Consider the following cost function:

dev = qml.device("lightning.qubit", wires=2)

def cost_fn(params, x):
    ops1 = [qml.RX(params[0], wires=0), qml.RY(params[1], wires=0)]
    measurements1 = [qml.expval(qml.Z(0))]
    tape1 = qml.tape.QuantumTape(ops1, measurements1)

    ops2 = [
        qml.RX(params[2], wires=0),
        qml.RY(x[0], wires=1),
        qml.CNOT(wires=(0,1))
    ]
    measurements2 = [qml.probs(wires=0)]
    tape2 = qml.tape.QuantumTape(ops2, measurements2)

    tapes = [tape1, tape2]

    # execute both tapes in a batch on the given device
    res = qml.execute(tapes, dev, diff_method=qml.gradients.param_shift, max_diff=2)

    return res[0] + res[1][0] - res[1][1]

In this cost function, two independent quantum tapes are being constructed; one returning an expectation value, the other probabilities. We then batch execute the two tapes, and reduce the results to obtain a scalar.

Let’s execute this cost function while tracking the gradient:

>>> params = np.array([0.1, 0.2, 0.3], requires_grad=True)
>>> x = np.array([0.5], requires_grad=True)
>>> cost_fn(params, x)
1.93050682

Since the execute function is differentiable, we can also compute the gradient:

>>> qml.grad(cost_fn)(params, x)
(array([-0.0978434 , -0.19767681, -0.29552021]), array([5.37764278e-17]))

Finally, we can also compute any nth-order derivative. Let’s compute the Jacobian of the gradient (that is, the Hessian):

>>> x.requires_grad = False
>>> qml.jacobian(qml.grad(cost_fn))(params, x)
array([[-0.97517033,  0.01983384,  0.        ],
       [ 0.01983384, -0.97517033,  0.        ],
       [ 0.        ,  0.        , -0.95533649]])