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","{","}"]
code: def execute_and_compute_jacobian(self, tapes):
      if (
          tapes not in self._results_cache
          and tapes not in self._jacs_cache
      ):
          results, jacs = self._dev_execute_and_compute_derivatives(
              tapes
          )
          self._results_cache[tapes] = results
          self._jacs_cache[tapes] = jacs
          return results, jacs
  
      if tapes not in self._jacs_cache:
          # Here the jac was not cached but the results were. This can not happen because results are never
          # cached alone (note that in the else clause below computing only results, jac must already be present)
          raise NotImplementedError(
              "No path to cache results without caching jac. This branch should not occur."
          )
      if logger.isEnabledFor(logging.DEBUG):  # pragma: no cover
          logger.debug("%s : Retrieving jacobian from cache.", self)
      jacs = self._jacs_cache[tapes]
  
      if tapes in self._results_cache:
          if logger.isEnabledFor(logging.DEBUG):  # pragma: no cover
              logger.debug("%s : Retrieving results from cache.", self)
          results = self._results_cache[tapes]
      else:
          results = self._dev_execute(tapes)
          self._results_cache[tapes] = results
  
      return results, jacs
  
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 10 for calling the DeviceDerivatives obj's underlying member method code with example usage: obj.execute_and_compute_jacobian(tapes) and returns: results,  jacs, results,  jacs