class_docstr: Abstract base class for PennyLane qubit devices.
  
  The following abstract method **must** be defined:
  
  * :meth:`~.apply`: append circuit operations, compile the circuit (if applicable),
    and perform the quantum computation.
  
  Devices that generate their own samples (such as hardware) may optionally
  overwrite :meth:`~.probability`. This method otherwise automatically
  computes the probabilities from the generated samples, and **must**
  overwrite the following method:
  
  * :meth:`~.generate_samples`: Generate samples from the device from the
    exact or approximate probability distribution.
  
  Analytic devices **must** overwrite the following method:
  
  * :meth:`~.analytic_probability`: returns the probability or marginal probability from the
    device after circuit execution. :meth:`~.marginal_prob` may be used here.
  
  This device contains common utility methods for qubit-based devices. These
  do not need to be overwritten. Utility methods include:
  
  * :meth:`~.expval`, :meth:`~.var`, :meth:`~.sample`: return expectation values,
    variances, and samples of observables after the circuit has been rotated
    into the observable eigenbasis.
  
  Args:
      wires (int, Iterable[Number, str]]): Number of subsystems represented by the device,
          or iterable that contains unique labels for the subsystems as numbers (i.e., ``[-1, 0, 2]``)
          or strings (``['ancilla', 'q1', 'q2']``). Default 1 if not specified.
      shots (None, int, list[int]): Number of circuit evaluations/random samples used to estimate
          expectation values of observables. If ``None``, the device calculates probability, expectation values,
          and variances analytically. If an integer, it specifies the number of samples to estimate these quantities.
          If a list of integers is passed, the circuit evaluations are batched over the list of shots.
      r_dtype: Real floating point precision type.
      c_dtype: Complex floating point precision type.
docstr: Implements the adjoint method outlined in
  `Jones and Gacon <https://arxiv.org/abs/2009.02823>`__ to differentiate an input tape.
  
  After a forward pass, the circuit is reversed by iteratively applying adjoint
  gates to scan backwards through the circuit.
  
  .. note::
      The adjoint differentiation method has the following restrictions:
  
      * As it requires knowledge of the statevector, only statevector simulator devices can be
        used.
  
      * Only expectation values are supported as measurements.
  
      * Cannot differentiate with respect to state-prep operations.
  
      * Does not work for parametrized observables like
        :class:`~.Hamiltonian` or :class:`~.Hermitian`.
  
  Args:
      tape (.QuantumTape): circuit that the function takes the gradient of
  
  Keyword Args:
      starting_state (tensor_like): post-forward pass state to start execution with. It should be
          complex-valued. Takes precedence over ``use_device_state``.
      use_device_state (bool): use current device state to initialize. A forward pass of the same
          circuit should be the last thing the device has executed. If a ``starting_state`` is
          provided, that takes precedence.
  
  Returns:
      array or tuple[array]: the derivative of the tape with respect to trainable parameters.
      Dimensions are ``(len(observables), len(trainable_params))``.
  
  Raises:
      QuantumFunctionError: if the input tape has measurements that are not expectation values
          or contains a multi-parameter operation aside from :class:`~.Rot`
docstr_tok: ["Implements","the","adjoint","method","outlined","in","`","Jones","and","Gacon","<","https",":","\/\/arxiv.org\/abs\/2009.02823",">","`","__","to","differentiate","an","input","tape",".","After","a","forward","pass",",","the","circuit","is","reversed","by","iteratively","applying","adjoint","gates","to","scan","backwards","through","the","circuit",".","..","note",":",":","The","adjoint","differentiation","method","has","the","following","restrictions",":","*","As","it","requires","knowledge","of","the","statevector",",","only","statevector","simulator","devices","can","be","used",".","*","Only","expectation","values","are","supported","as","measurements",".","*","Can","not","differentiate","with","respect","to","state-prep","operations",".","*","Does","not","work","for","parametrized","observables","like",":","class",":","`","~.Hamiltonian","`","or",":","class",":","`","~.Hermitian","`",".","Args",":","tape","(",".QuantumTape",")",":","circuit","that","the","function","takes","the","gradient","of","Keyword","Args",":","starting_state","(","tensor_like",")",":","post-forward","pass","state","to","start","execution","with",".","It","should","be","complex-valued",".","Takes","precedence","over","``","use_device_state","``",".","use_device_state","(","bool",")",":","use","current","device","state","to","initialize",".","A","forward","pass","of","the","same","circuit","should","be","the","last","thing","the","device","has","executed",".","If","a","``","starting_state","``","is","provided",",","that","takes","precedence",".","Returns",":","array","or","tuple","[","array","]",":","the","derivative","of","the","tape","with","respect","to","trainable","parameters",".","Dimensions","are","``","(","len","(","observables",")",",","len","(","trainable_params",")",")","``",".","Raises",":","QuantumFunctionError",":","if","the","input","tape","has","measurements","that","are","not","expectation","values","or","contains","a","multi-parameter","operation","aside","from",":","class",":","`","~.Rot","`"]
code: def adjoint_jacobian(
      self,
      tape: QuantumTape,
      starting_state=None,
      use_device_state=False,
  ):  # pylint: disable=too-many-statements
      """Implements the adjoint method outlined in
      `Jones and Gacon <https://arxiv.org/abs/2009.02823>`__ to differentiate an input tape.
  
      After a forward pass, the circuit is reversed by iteratively applying adjoint
      gates to scan backwards through the circuit.
  
      .. note::
          The adjoint differentiation method has the following restrictions:
  
          * As it requires knowledge of the statevector, only statevector simulator devices can be
            used.
  
          * Only expectation values are supported as measurements.
  
          * Cannot differentiate with respect to state-prep operations.
  
          * Does not work for parametrized observables like
            :class:`~.Hamiltonian` or :class:`~.Hermitian`.
  
      Args:
          tape (.QuantumTape): circuit that the function takes the gradient of
  
      Keyword Args:
          starting_state (tensor_like): post-forward pass state to start execution with. It should be
              complex-valued. Takes precedence over ``use_device_state``.
          use_device_state (bool): use current device state to initialize. A forward pass of the same
              circuit should be the last thing the device has executed. If a ``starting_state`` is
              provided, that takes precedence.
  
      Returns:
          array or tuple[array]: the derivative of the tape with respect to trainable parameters.
          Dimensions are ``(len(observables), len(trainable_params))``.
  
      Raises:
          QuantumFunctionError: if the input tape has measurements that are not expectation values
              or contains a multi-parameter operation aside from :class:`~.Rot`
      """
      if tape.batch_size is not None:
          raise qml.QuantumFunctionError(
              "Parameter broadcasting is not supported with adjoint differentiation"
          )
  
      # broadcasted inner product not summing over first dimension of b
      sum_axes = tuple(range(1, self.num_wires + 1))
      # pylint: disable=unnecessary-lambda-assignment
      dot_product_real = lambda b, k: self._real(
          qmlsum(self._conj(b) * k, axis=sum_axes)
      )
  
      for m in tape.measurements:
          if not isinstance(m, ExpectationMP):
              raise qml.QuantumFunctionError(
                  "Adjoint differentiation method does not support"
                  f" measurement {m.__class__.__name__}"
              )
  
          if m.obs.name == "Hamiltonian":
              raise qml.QuantumFunctionError(
                  "Adjoint differentiation method does not support Hamiltonian observables."
              )
  
      if self.shot_vector is not None:
          raise qml.QuantumFunctionError(
              "Adjoint does not support shot vectors."
          )
  
      if self.shots is not None:
          warnings.warn(
              "Requested adjoint differentiation to be computed with finite shots. "
              "The derivative is always exact when using the adjoint differentiation method.",
              UserWarning,
          )
  
      # Initialization of state
      if starting_state is not None:
          ket = self._reshape(starting_state, [2] * self.num_wires)
      else:
          if not use_device_state:
              self.reset()
              self.execute(tape)
          ket = self._pre_rotated_state
  
      n_obs = len(tape.observables)
      bras = np.empty(
          [n_obs] + [2] * self.num_wires, dtype=np.complex128
      )
      for kk in range(n_obs):
          bras[kk, ...] = self._apply_operation(
              ket, tape.observables[kk]
          )
  
      expanded_ops = []
      for op in reversed(tape.operations):
          if op.num_params > 1:
              if not isinstance(op, qml.Rot):
                  raise qml.QuantumFunctionError(
                      f"The {op.name} operation is not supported using "
                      'the "adjoint" differentiation method'
                  )
              ops = op.decomposition()
              expanded_ops.extend(reversed(ops))
          elif op.name not in (
              "StatePrep",
              "QubitStateVector",
              "BasisState",
              "Snapshot",
          ):
              expanded_ops.append(op)
  
      trainable_params = []
      for k in tape.trainable_params:
          # pylint: disable=protected-access
          mp_or_op = tape[tape._par_info[k]["op_idx"]]
          if isinstance(mp_or_op, MeasurementProcess):
              warnings.warn(
                  "Differentiating with respect to the input parameters of "
                  f"{mp_or_op.obs.name} is not supported with the "
                  "adjoint differentiation method. Gradients are computed "
                  "only with regards to the trainable parameters of the circuit.\n\n Mark "
                  "the parameters of the measured observables as non-trainable "
                  "to silence this warning.",
                  UserWarning,
              )
          else:
              trainable_params.append(k)
  
      jac = np.zeros((len(tape.observables), len(trainable_params)))
  
      param_number = (
          len(
              tape.get_parameters(
                  trainable_only=False, operations_only=True
              )
          )
          - 1
      )
      trainable_param_number = len(trainable_params) - 1
      for op in expanded_ops:
          adj_op = qml.adjoint(op)
          ket = self._apply_operation(ket, adj_op)
  
          if op.num_params == 1:
              if param_number in trainable_params:
                  d_op_matrix = operation_derivative(op)
                  ket_temp = self._apply_unitary(
                      ket, d_op_matrix, op.wires
                  )
  
                  jac[:, trainable_param_number] = 2 * dot_product_real(
                      bras, ket_temp
                  )
  
                  trainable_param_number -= 1
              param_number -= 1
  
          for kk in range(n_obs):
              bras[kk, ...] = self._apply_operation(
                  bras[kk, ...], adj_op
              )
  
      return self._adjoint_jacobian_processing(jac)
  
imports: import abc
  import itertools
  import warnings
  from collections import defaultdict
  from typing import Union, List
  import inspect
  import logging
  import numpy
  import pennylane
  from pennylane import Device, DeviceError
  from pennylane.workflow import set_shots
  from pennylane.math import multiply
  from pennylane.math import sum
  from pennylane.measurements import ClassicalShadowMP, CountsMP, ExpectationMP, MeasurementProcess, MeasurementTransform, MeasurementValue, MutualInfoMP, ProbabilityMP, SampleMeasurement, SampleMP, ShadowExpvalMP, StateMeasurement, StateMP, VarianceMP, VnEntropyMP, Shots
  from pennylane.resource import Resources
  from pennylane.operation import operation_derivative, Operation
  from pennylane.tape import QuantumTape
  from pennylane.wires import Wires
label_desc: Use image node_id 37 for calling the QubitDevice obj's underlying member method code with example usage: obj.adjoint_jacobian(tape, starting_state, use_device_state) and returns: self