code: def _adjoint_jacobian_expansion(
      tapes: Sequence[QuantumTape],
      grad_on_execution: bool,
      interface: str,
      max_expansion: int,
  ):
      """Performs adjoint jacobian specific expansion.  Expands so that every
      trainable operation has a generator.
  
      TODO: Let the device specify any gradient-specific expansion logic.  This
      function will be removed once the device-support pipeline is improved.
      """
      if grad_on_execution and INTERFACE_MAP[interface] == "jax":
          # qml.math.is_trainable doesn't work with jax on the forward pass
          non_trainable = qml.operation.has_nopar
      else:
          non_trainable = ~qml.operation.is_trainable
  
      stop_at = ~qml.operation.is_measurement & (
          non_trainable
          | qml.operation.has_gen  # pylint: disable=unsupported-binary-operation
      )
      for i, tape in enumerate(tapes):
          if any(not stop_at(op) for op in tape.operations):
              tapes[i] = tape.expand(
                  stop_at=stop_at, depth=max_expansion
              )
  
      return tapes
  
file_path: pennylane/pennylane/workflow/execution.py
imports: import inspect
  import warnings
  from functools import wraps, partial
  from typing import Callable, Sequence, Optional, Union, Tuple
  import logging
  from cachetools import LRUCache, Cache
  import pennylane
  from pennylane.tape import QuantumTape
  from pennylane.typing import ResultBatch
  from .set_shots import set_shots
  from .jacobian_products import TransformJacobianProducts, DeviceDerivatives, DeviceJacobianProducts, LightningVJPs
label_desc: Use image node_id 1 for calling a global function with example usage: _adjoint_jacobian_expansion(tapes, grad_on_execution, interface, max_expansion) and returns: tapes