class_docstr: Calculate jacobian products via a device provided jacobian.  This class relies on either ``qml.Device.gradients`` or
  ``qml.devices.Device.compute_derivatives``.
  
  Args:
  
      device (Union[pennylane.Device, pennylane.devices.Device]): the device for execution and derivatives.
          Must support first order gradients with the requested configuration.
      execution_config (pennylane.devices.ExecutionConfig): a datastructure containing the options needed to fully
         describe the execution. Only used with :class:`pennylane.devices.Device` from the new device interface.
      gradient_kwargs (dict): a dictionary of keyword arguments for the gradients. Only used with a :class:`~.pennylane.Device`
          from the old device interface.
  
  **Examples:**
  
  >>> device = qml.device('default.qubit')
  >>> config = qml.devices.ExecutionConfig(gradient_method="adjoint")
  >>> jpc = DeviceDerivatives(device, config, {})
  
  This same class can also be used with the old device interface.
  
  >>> device = qml.device('lightning.qubit', wires=5)
  >>> gradient_kwargs = {"method": "adjoint_jacobian"}
  >>> jpc_lightning = DeviceDerivatives(device, gradient_kwargs=gradient_kwargs)
  
  **Technical comments on caching and calculating the gradients on execution:**
  
  In order to store results and Jacobians for the backward pass during the forward pass,
  the ``_jacs_cache`` and ``_results_cache`` properties are ``LRUCache`` objects with a maximum size of 10.
  In the current execution pipeline, only one batch will be used per instance, but a size of 10 adds some extra
  flexibility for future uses.
  
  Note that batches of identically looking :class:`~.QuantumScript` s that are different instances will be cached separately.
  This is because the ``hash`` of  :class:`~.QuantumScript` is expensive, as it requires inspecting all its constituents,
  which is not worth the effort in this case.
  
  When a forward pass with :meth:`~.execute_and_cache_jacobian` is called, both the results and the jacobian for the object are stored.
  
  >>> tape = qml.tape.QuantumScript([qml.RX(1.0, wires=0)], [qml.expval(qml.PauliZ(0))])
  >>> batch = (tape, )
  >>> with device.tracker:
  ...     results = jpc.execute_and_cache_jacobian(batch )
  >>> results
  (0.5403023058681398,)
  >>> device.tracker.totals
  {'execute_and_derivative_batches': 1, 'executions': 1, 'derivatives': 1}
  >>> jpc._jacs_cache
  LRUCache({5660934048: (array(-0.84147098),)}, maxsize=10, currsize=1)
  
  Then when the vjp, jvp, or jacobian is requested, that cached value is used instead of requesting from
  the device again.
  
  >>> with device.tracker:
  ...     vjp = jpc.compute_vjp(batch , (0.5, ) )
  >>> vjp
  (array([-0.42073549]),)
  >>> device.tracker.totals
  {}
class_docstr_tok: ["Calculate","jacobian","products","via","a","device","provided","jacobian",".","This","class","relies","on","either","``","qml.Device.gradients","``","or","``","qml.devices.Device.compute_derivatives","``",".","Args",":","device","(","Union","[","pennylane.Device",",","pennylane.devices.Device","]",")",":","the","device","for","execution","and","derivatives",".","Must","support","first","order","gradients","with","the","requested","configuration",".","execution_config","(","pennylane.devices.ExecutionConfig",")",":","a","datastructure","containing","the","options","needed","to","fully","describe","the","execution",".","Only","used","with",":","class",":","`","pennylane.devices.Device","`","from","the","new","device","interface",".","gradient_kwargs","(","dict",")",":","a","dictionary","of","keyword","arguments","for","the","gradients",".","Only","used","with","a",":","class",":","`","~.pennylane.Device","`","from","the","old","device","interface",".","*","*","Examples",":","*","*",">",">",">","device","=","qml.device","(","'default.qubit","'",")",">",">",">","config","=","qml.devices.ExecutionConfig","(","gradient_method=","''","adjoint","''",")",">",">",">","jpc","=","DeviceDerivatives","(","device",",","config",",","{","}",")","This","same","class","can","also","be","used","with","the","old","device","interface",".",">",">",">","device","=","qml.device","(","'lightning.qubit","'",",","wires=5",")",">",">",">","gradient_kwargs","=","{","``","method","''",":","``","adjoint_jacobian","''","}",">",">",">","jpc_lightning","=","DeviceDerivatives","(","device",",","gradient_kwargs=gradient_kwargs",")","*","*","Technical","comments","on","caching","and","calculating","the","gradients","on","execution",":","*","*","In","order","to","store","results","and","Jacobians","for","the","backward","pass","during","the","forward","pass",",","the","``","_jacs_cache","``","and","``","_results_cache","``","properties","are","``","LRUCache","``","objects","with","a","maximum","size","of","10",".","In","the","current","execution","pipeline",",","only","one","batch","will","be","used","per","instance",",","but","a","size","of","10","adds","some","extra","flexibility","for","future","uses",".","Note","that","batches","of","identically","looking",":","class",":","`","~.QuantumScript","`","s","that","are","different","instances","will","be","cached","separately",".","This","is","because","the","``","hash","``","of",":","class",":","`","~.QuantumScript","`","is","expensive",",","as","it","requires","inspecting","all","its","constituents",",","which","is","not","worth","the","effort","in","this","case",".","When","a","forward","pass","with",":","meth",":","`","~.execute_and_cache_jacobian","`","is","called",",","both","the","results","and","the","jacobian","for","the","object","are","stored",".",">",">",">","tape","=","qml.tape.QuantumScript","(","[","qml.RX","(","1.0",",","wires=0",")","]",",","[","qml.expval","(","qml.PauliZ","(","0",")",")","]",")",">",">",">","batch","=","(","tape",",",")",">",">",">","with","device.tracker",":","...","results","=","jpc.execute_and_cache_jacobian","(","batch",")",">",">",">","results","(","0.5403023058681398",",",")",">",">",">","device.tracker.totals","{","'execute_and_derivative_batches","'",":","1",",","'executions","'",":","1",",","'derivatives","'",":","1","}",">",">",">","jpc._jacs_cache","LRUCache","(","{","5660934048",":","(","array","(","-0.84147098",")",",",")","}",",","maxsize=10",",","currsize=1",")","Then","when","the","vjp",",","jvp",",","or","jacobian","is","requested",",","that","cached","value","is","used","instead","of","requesting","from","the","device","again",".",">",">",">","with","device.tracker",":","...","vjp","=","jpc.compute_vjp","(","batch",",","(","0.5",",",")",")",">",">",">","vjp","(","array","(","[","-0.42073549","]",")",",",")",">",">",">","device.tracker.totals","{","}"]
docstr: Compute the vjp for a given batch of tapes.
  
  This method is used by autograd, torch, and tensorflow to compute VJPs.
  
  Args:
      tapes (tuple[`~.QuantumScript`]): the batch of tapes to take the derivatives of
      dy (tuple[tuple[TensorLike]]): the derivatives of the results of an execution.
          The ``i`` th entry (cotangent) corresponds to the ``i`` th tape, and the ``j`` th entry of the ``i`` th
          cotangent corresponds to the ``j`` th return value of the ``i`` th tape.
  
  Returns:
      TensorLike: the vector jacobian product.
  
  Side Effects:
      caches the newly computed jacobian if it wasn't already present in the cache.
  
  **Examples:**
  
  For an instance of :class:`~.DeviceDerivatives` ``jpc``, we have:
  
  >>> tape0 = qml.tape.QuantumScript([qml.RX(0.1, wires=0)], [qml.expval(qml.PauliZ(0))])
  >>> tape1 = qml.tape.QuantumScript([qml.RY(0.2, wires=0)], [qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(0))])
  >>> batch = (tape0, tape1)
  >>> dy0 = (0.5, )
  >>> dy1 = (2.0, 3.0)
  >>> dys = (dy0, dy1)
  >>> vjps = jpc.compute_vjp(batch, dys)
  >>> vjps
  (array([-0.04991671]), array([2.54286107]))
  >>> expected_vjp0 = 0.5 * -np.sin(0.1)
  >>> qml.math.allclose(vjps[0], expected_vjp0)
  True
  >>> expected_jvp1 = 2.0 * -np.sin(0.2) + 3.0 * np.cos(0.2)
  >>> qml.math.allclose(vjps[1], expected_vjp1)
  True
  
  While this method could support non-scalar parameters in theory, no implementation currently supports
  jacobians with non-scalar parameters.
docstr_tok: ["Compute","the","vjp","for","a","given","batch","of","tapes",".","This","method","is","used","by","autograd",",","torch",",","and","tensorflow","to","compute","VJPs",".","Args",":","tapes","(","tuple","[","`","~.QuantumScript","`","]",")",":","the","batch","of","tapes","to","take","the","derivatives","of","dy","(","tuple","[","tuple","[","TensorLike","]","]",")",":","the","derivatives","of","the","results","of","an","execution",".","The","``","i","``","th","entry","(","cotangent",")","corresponds","to","the","``","i","``","th","tape",",","and","the","``","j","``","th","entry","of","the","``","i","``","th","cotangent","corresponds","to","the","``","j","``","th","return","value","of","the","``","i","``","th","tape",".","Returns",":","TensorLike",":","the","vector","jacobian","product",".","Side","Effects",":","caches","the","newly","computed","jacobian","if","it","was","n't","already","present","in","the","cache",".","*","*","Examples",":","*","*","For","an","instance","of",":","class",":","`","~.DeviceDerivatives","`","``","jpc","``",",","we","have",":",">",">",">","tape0","=","qml.tape.QuantumScript","(","[","qml.RX","(","0.1",",","wires=0",")","]",",","[","qml.expval","(","qml.PauliZ","(","0",")",")","]",")",">",">",">","tape1","=","qml.tape.QuantumScript","(","[","qml.RY","(","0.2",",","wires=0",")","]",",","[","qml.expval","(","qml.PauliZ","(","0",")",")",",","qml.expval","(","qml.PauliX","(","0",")",")","]",")",">",">",">","batch","=","(","tape0",",","tape1",")",">",">",">","dy0","=","(","0.5",",",")",">",">",">","dy1","=","(","2.0",",","3.0",")",">",">",">","dys","=","(","dy0",",","dy1",")",">",">",">","vjps","=","jpc.compute_vjp","(","batch",",","dys",")",">",">",">","vjps","(","array","(","[","-0.04991671","]",")",",","array","(","[","2.54286107","]",")",")",">",">",">","expected_vjp0","=","0.5","*","-np.sin","(","0.1",")",">",">",">","qml.math.allclose","(","vjps","[","0","]",",","expected_vjp0",")","True",">",">",">","expected_jvp1","=","2.0","*","-np.sin","(","0.2",")","+","3.0","*","np.cos","(","0.2",")",">",">",">","qml.math.allclose","(","vjps","[","1","]",",","expected_vjp1",")","True","While","this","method","could","support","non-scalar","parameters","in","theory",",","no","implementation","currently","supports","jacobians","with","non-scalar","parameters","."]
code: def compute_vjp(self, tapes, dy):
      """Compute the vjp for a given batch of tapes.
  
      This method is used by autograd, torch, and tensorflow to compute VJPs.
  
      Args:
          tapes (tuple[`~.QuantumScript`]): the batch of tapes to take the derivatives of
          dy (tuple[tuple[TensorLike]]): the derivatives of the results of an execution.
              The ``i`` th entry (cotangent) corresponds to the ``i`` th tape, and the ``j`` th entry of the ``i`` th
              cotangent corresponds to the ``j`` th return value of the ``i`` th tape.
  
      Returns:
          TensorLike: the vector jacobian product.
  
      Side Effects:
          caches the newly computed jacobian if it wasn't already present in the cache.
  
      **Examples:**
  
      For an instance of :class:`~.DeviceDerivatives` ``jpc``, we have:
  
      >>> tape0 = qml.tape.QuantumScript([qml.RX(0.1, wires=0)], [qml.expval(qml.PauliZ(0))])
      >>> tape1 = qml.tape.QuantumScript([qml.RY(0.2, wires=0)], [qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(0))])
      >>> batch = (tape0, tape1)
      >>> dy0 = (0.5, )
      >>> dy1 = (2.0, 3.0)
      >>> dys = (dy0, dy1)
      >>> vjps = jpc.compute_vjp(batch, dys)
      >>> vjps
      (array([-0.04991671]), array([2.54286107]))
      >>> expected_vjp0 = 0.5 * -np.sin(0.1)
      >>> qml.math.allclose(vjps[0], expected_vjp0)
      True
      >>> expected_jvp1 = 2.0 * -np.sin(0.2) + 3.0 * np.cos(0.2)
      >>> qml.math.allclose(vjps[1], expected_vjp1)
      True
  
      While this method could support non-scalar parameters in theory, no implementation currently supports
      jacobians with non-scalar parameters.
  
      """
      if tapes in self._jacs_cache:
          if logger.isEnabledFor(logging.DEBUG):  # pragma: no cover
              logger.debug(
                  " %s : Retrieving jacobian from cache.", self
              )
          jacs = self._jacs_cache[tapes]
      else:
          jacs = self._dev_compute_derivatives(tapes)
          self._jacs_cache[tapes] = jacs
  
      return _compute_vjps(jacs, dy, tapes)
  
imports: import abc
  from functools import partial
  import inspect
  import logging
  from typing import Tuple, Callable, Optional, Union
  from cachetools import LRUCache
  import numpy
  import pennylane
  from pennylane.tape import QuantumScript
  from pennylane.typing import ResultBatch, TensorLike
label_desc: Use image node_id 8 for calling the DeviceDerivatives obj's underlying member method code with example usage: obj.compute_vjp(tapes, dy) and returns: _compute_vjps