code: def vjp(tape, dy, gradient_fn, gradient_kwargs=None):
      r"""Generate the gradient tapes and processing function required to compute
      the vector-Jacobian products of a tape.
  
      Consider a function :math:`\mathbf{f}(\mathbf{x})`. The Jacobian is given by
  
      .. math::
  
          \mathbf{J}_{\mathbf{f}}(\mathbf{x}) = \begin{pmatrix}
              \frac{\partial f_1}{\partial x_1} &\cdots &\frac{\partial f_1}{\partial x_n}\\
              \vdots &\ddots &\vdots\\
              \frac{\partial f_m}{\partial x_1} &\cdots &\frac{\partial f_m}{\partial x_n}\\
          \end{pmatrix}.
  
      During backpropagation, the chain rule is applied. For example, consider the
      cost function :math:`h = y\circ f: \mathbb{R}^n \rightarrow \mathbb{R}`,
      where :math:`y: \mathbb{R}^m \rightarrow \mathbb{R}`.
      The gradient is:
  
      .. math::
  
          \nabla h(\mathbf{x}) = \frac{\partial y}{\partial \mathbf{f}} \frac{\partial \mathbf{f}}{\partial \mathbf{x}}
          = \frac{\partial y}{\partial \mathbf{f}} \mathbf{J}_{\mathbf{f}}(\mathbf{x}).
  
      Denote :math:`d\mathbf{y} = \frac{\partial y}{\partial \mathbf{f}}`; we can write this in the form
      of a matrix multiplication:
  
      .. math:: \left[\nabla h(\mathbf{x})\right]_{j} = \sum_{i=0}^m d\mathbf{y}_i ~ \mathbf{J}_{ij}.
  
      Thus, we can see that the gradient of the cost function is given by the so-called
      **vector-Jacobian product**; the product of the row-vector :math:`d\mathbf{y}`, representing
      the gradient of subsequent components of the cost function, and :math:`\mathbf{J}`,
      the Jacobian of the current node of interest.
  
      Args:
          tape (.QuantumTape): quantum tape to differentiate
          dy (tensor_like): Gradient-output vector. Must have shape
              matching the output shape of the corresponding tape.
          gradient_fn (callable): the gradient transform to use to differentiate
              the tape
          gradient_kwargs (dict): dictionary of keyword arguments to pass when
              determining the gradients of tapes
  
      Returns:
          tensor_like or None: Vector-Jacobian product. Returns None if the tape
          has no trainable parameters.
  
      **Example**
  
      Consider the following quantum tape with PyTorch parameters:
  
      .. code-block:: python
  
          import torch
  
          x = torch.tensor([[0.1, 0.2, 0.3],
                            [0.4, 0.5, 0.6]], requires_grad=True, dtype=torch.float64)
  
          ops = [
              qml.RX(x[0, 0], wires=0),
              qml.RY(x[0, 1], wires=1),
              qml.RZ(x[0, 2], wires=0),
              qml.CNOT(wires=[0, 1]),
              qml.RX(x[1, 0], wires=1),
              qml.RY(x[1, 1], wires=0),
              qml.RZ(x[1, 2], wires=1)
          ]
          measurements = [qml.expval(qml.PauliZ(0)), qml.probs(wires=1)]
          tape = qml.tape.QuantumTape(ops, measurements)
  
      We can use the ``vjp`` function to compute the vector-Jacobian product,
      given a gradient-output vector ``dy``:
  
      >>> dy = torch.tensor([1., 1., 1.], dtype=torch.float64)
      >>> vjp_tapes, fn = qml.gradients.vjp(tape, dy, qml.gradients.param_shift)
  
      Note that ``dy`` has shape ``(3,)``, matching the output dimension of the tape
      (1 expectation and 2 probability values).
  
      Executing the VJP tapes, and applying the processing function:
  
      >>> dev = qml.device("default.qubit", wires=2)
      >>> vjp = fn(qml.execute(vjp_tapes, dev, gradient_fn=qml.gradients.param_shift, interface="torch"))
      >>> vjp
      tensor([-1.1562e-01, -1.3862e-02, -9.0841e-03, -1.3878e-16, -4.8217e-01,
               2.1329e-17], dtype=torch.float64, grad_fn=<ViewBackward>)
  
      The output VJP is also differentiable with respect to the tape parameters:
  
      >>> cost = torch.sum(vjp)
      >>> cost.backward()
      >>> x.grad
      tensor([[-1.1025e+00, -2.0554e-01, -1.4917e-01],
              [-1.2490e-16, -9.1580e-01,  0.0000e+00]], dtype=torch.float64)
      """
      gradient_kwargs = gradient_kwargs or {}
      num_params = len(tape.trainable_params)
  
      if num_params == 0:
          # The tape has no trainable parameters; the VJP
          # is simply none.
          return [], lambda _, num=None: None
  
      try:
          if _all_close_to_zero(dy):
              # If the dy vector is zero, then the
              # corresponding element of the VJP will be zero,
              # and we can avoid a quantum computation.
  
              def func(_, num=None):  # pylint: disable=unused-argument
                  res = qml.math.convert_like(
                      np.zeros([num_params]), dy
                  )
                  multi = len(tape.measurements) > 1
                  if multi:
                      multi_dy = dy[0]
                      res = qml.math.convert_like(res, multi_dy)
                      return qml.math.cast_like(res, multi_dy)
                  return qml.math.cast_like(res, dy)
  
              return [], func
      except (AttributeError, TypeError, NotImplementedError):
          pass
  
      gradient_tapes, fn = gradient_fn(tape, **gradient_kwargs)
  
      def processing_fn(results, num=None):
          # postprocess results to compute the Jacobian
          jac = fn(results)
  
          multi = len(tape.measurements) > 1
          comp_vjp_fn = (
              compute_vjp_multi if multi else compute_vjp_single
          )
  
          if not tape.shots.has_partitioned_shots:
              return comp_vjp_fn(dy, jac, num=num)
  
          vjp_ = [
              comp_vjp_fn(dy_, jac_, num=num)
              for dy_, jac_ in zip(dy, jac)
          ]
          return qml.math.sum(qml.math.stack(vjp_), 0)
  
      return gradient_tapes, processing_fn
  
file_path: pennylane/pennylane/gradients/vjp.py
imports: import numpy
  import autograd
  import pennylane
label_desc: Use image node_id 5 for calling a global function with example usage: vjp(tape, dy, gradient_fn, gradient_kwargs) and returns: gradient_tapes,  processing_fn, list,  function, qml, list,  func, comp_vjp_fn, qml, qml