class_docstr: Class for registering a tape transform that takes a tape, and outputs
  a batch of tapes to be independently executed on a quantum device.
  
  .. warning::
  
      Use of ``batch_transform`` to create a custom transform is deprecated. Instead
      switch to using the new :func:`transform` function. Follow the instructions
      `here <https://docs.pennylane.ai/en/stable/code/qml_transforms.html#custom-transforms>`_
      for further details
  
  Examples of such transforms include quantum gradient shift rules (such
  as finite-differences and the parameter-shift rule) and metrics such as
  the quantum Fisher information matrix.
  
  Args:
      transform_fn (function): The function to register as the batch tape transform.
          It can have an arbitrary number of arguments, but the first argument
          **must** be the input tape.
      expand_fn (function): An expansion function (if required) to be applied to the
          input tape before the transformation takes place.
          It **must** take the same input arguments as ``transform_fn``.
      differentiable (bool): Specifies whether the transform is differentiable or
          not. A transform may be non-differentiable for several reasons:
  
          - It does not use an autodiff framework for its tensor manipulations;
          - It returns a non-differentiable or non-numeric quantity, such as
            a boolean, string, or integer.
  
          In such a case, setting ``differentiable=False`` instructs the decorator
          to mark the output as 'constant', reducing potential overhead.
  
  **Example**
  
  A valid batch tape transform is a function that satisfies the following:
  
  - The first argument must be a tape.
  
  - Depending on the structure of this input tape, various quantum operations, functions,
    and templates may be called.
  
  - Any internal classical processing should use the ``qml.math`` module to ensure
    the transform is differentiable.
  
  - The transform should return a tuple containing:
  
    * Multiple transformed tapes to be executed on a device.
    * A classical processing function for post-processing the executed tape results.
      This processing function should have the signature ``f(list[tensor_like]) → Any``.
      If ``None``, no classical processing is applied to the results.
  
  For example:
  
  .. code-block:: python
  
      @qml.batch_transform
      def my_transform(tape, a, b):
          '''Generates two tapes, one with all RX replaced with RY,
          and the other with all RX replaced with RZ.'''
  
          ops1 = []
          ops2 = []
  
          # loop through all operations on the input tape
          for op in tape.operations:
              if op.name == "RX":
                  wires = op.wires
                  param = op.parameters[0]
  
                  ops1.append(qml.RY(a * qml.math.abs(param), wires=wires))
                  ops2.append(qml.RZ(b * qml.math.abs(param), wires=wires))
              else:
                  ops1.append(op)
                  ops2.append(op)
  
          tape1 = qml.tape.QuantumTape(ops1, tape.measurements)
          tape2 = qml.tape.QuantumTape(ops2, tape.measurements)
  
          def processing_fn(results):
              return qml.math.sum(qml.math.stack(results))
  
          return [tape1, tape2], processing_fn
  
  We can apply this transform to a quantum tape:
  
  >>> ops = [qml.Hadamard(wires=0), qml.RX(-0.5, wires=0)]
  >>> tape = qml.tape.QuantumTape(ops, [qml.expval(qml.PauliX(0))])
  >>> tapes, fn = my_transform(tape, 0.65, 2.5)
  >>> print(qml.drawer.tape_text(tapes[0], decimals=2))
  0: ──H──RY(0.33)─┤  <X>
  >>> print(qml.drawer.tape_text(tapes[1], decimals=2))
  0: ──H──RZ(1.25)─┤  <X>
  
  We can execute these tapes manually:
  
  >>> dev = qml.device("default.qubit", wires=1)
  >>> res = qml.execute(tapes, dev, interface="autograd", gradient_fn=qml.gradients.param_shift)
  >>> print(res)
  [0.9476507264148154, 0.31532236239526856]
  
  Applying the processing function, we retrieve the end result of the transform:
  
  >>> print(fn(res))
  1.2629730888100839
  
  Alternatively, we may also transform a QNode directly, using either
  decorator syntax:
  
  >>> @my_transform(0.65, 2.5)
  ... @qml.qnode(dev)
  ... def circuit(x):
  ...     qml.Hadamard(wires=0)
  ...     qml.RX(x, wires=0)
  ...     return qml.expval(qml.PauliX(0))
  >>> print(circuit(-0.5))
  1.2629730888100839
  
  or by transforming an existing QNode:
  
  >>> @qml.qnode(dev)
  ... def circuit(x):
  ...     qml.Hadamard(wires=0)
  ...     qml.RX(x, wires=0)
  ...     return qml.expval(qml.PauliX(0))
  >>> circuit = my_transform(circuit, 0.65, 2.5)
  >>> print(circuit(-0.5))
  1.2629730888100839
  
  Batch tape transforms are fully differentiable:
  
  >>> x = np.array(-0.5, requires_grad=True)
  >>> gradient = qml.grad(circuit)(x)
  >>> print(gradient)
  2.5800122591960153
  
  .. details::
      :title: Usage Details
  
      **Expansion functions**
  
      Tape expansion, decomposition, or manipulation may always be
      performed within the custom batch transform. However, by specifying
      a separate expansion function, PennyLane will be possible to access
      this separate expansion function where needed via
  
      >>> my_transform.expand_fn
  
      The provided ``expand_fn`` must have the same input arguments as
      ``transform_fn`` and return a ``tape``. Following the example above:
  
      .. code-block:: python
  
          def expand_fn(tape, a, b):
              stopping_crit = lambda obj: obj.name!="PhaseShift"
              return tape.expand(depth=10, stop_at=stopping_crit)
  
          my_transform = batch_transform(my_transform, expand_fn)
  
      Note that:
  
      - the transform arguments ``a`` and ``b`` must be passed to
        the expansion function, and
      - the expansion function must return a single tape.
class_docstr_tok: ["Class","for","registering","a","tape","transform","that","takes","a","tape",",","and","outputs","a","batch","of","tapes","to","be","independently","executed","on","a","quantum","device",".","..","warning",":",":","Use","of","``","batch_transform","``","to","create","a","custom","transform","is","deprecated",".","Instead","switch","to","using","the","new",":","func",":","`","transform","`","function",".","Follow","the","instructions","`","here","<","https",":","\/\/docs.pennylane.ai\/en\/stable\/code\/qml_transforms.html","#","custom-transforms",">","`","_","for","further","details","Examples","of","such","transforms","include","quantum","gradient","shift","rules","(","such","as","finite-differences","and","the","parameter-shift","rule",")","and","metrics","such","as","the","quantum","Fisher","information","matrix",".","Args",":","transform_fn","(","function",")",":","The","function","to","register","as","the","batch","tape","transform",".","It","can","have","an","arbitrary","number","of","arguments",",","but","the","first","argument","*","*","must","*","*","be","the","input","tape",".","expand_fn","(","function",")",":","An","expansion","function","(","if","required",")","to","be","applied","to","the","input","tape","before","the","transformation","takes","place",".","It","*","*","must","*","*","take","the","same","input","arguments","as","``","transform_fn","``",".","differentiable","(","bool",")",":","Specifies","whether","the","transform","is","differentiable","or","not",".","A","transform","may","be","non-differentiable","for","several","reasons",":","-","It","does","not","use","an","autodiff","framework","for","its","tensor","manipulations",";","-","It","returns","a","non-differentiable","or","non-numeric","quantity",",","such","as","a","boolean",",","string",",","or","integer",".","In","such","a","case",",","setting","``","differentiable=False","``","instructs","the","decorator","to","mark","the","output","as","'constant","'",",","reducing","potential","overhead",".","*","*","Example","*","*","A","valid","batch","tape","transform","is","a","function","that","satisfies","the","following",":","-","The","first","argument","must","be","a","tape",".","-","Depending","on","the","structure","of","this","input","tape",",","various","quantum","operations",",","functions",",","and","templates","may","be","called",".","-","Any","internal","classical","processing","should","use","the","``","qml.math","``","module","to","ensure","the","transform","is","differentiable",".","-","The","transform","should","return","a","tuple","containing",":","*","Multiple","transformed","tapes","to","be","executed","on","a","device",".","*","A","classical","processing","function","for","post-processing","the","executed","tape","results",".","This","processing","function","should","have","the","signature","``","f","(","list","[","tensor_like","]",")","\u2192","Any","``",".","If","``","None","``",",","no","classical","processing","is","applied","to","the","results",".","For","example",":","..","code-block",":",":","python","@","qml.batch_transform","def","my_transform","(","tape",",","a",",","b",")",":","``","'Generates","two","tapes",",","one","with","all","RX","replaced","with","RY",",","and","the","other","with","all","RX","replaced","with","RZ",".","''","'","ops1","=","[","]","ops2","=","[","]","#","loop","through","all","operations","on","the","input","tape","for","op","in","tape.operations",":","if","op.name","==","``","RX","''",":","wires","=","op.wires","param","=","op.parameters","[","0","]","ops1.append","(","qml.RY","(","a","*","qml.math.abs","(","param",")",",","wires=wires",")",")","ops2.append","(","qml.RZ","(","b","*","qml.math.abs","(","param",")",",","wires=wires",")",")","else",":","ops1.append","(","op",")","ops2.append","(","op",")","tape1","=","qml.tape.QuantumTape","(","ops1",",","tape.measurements",")","tape2","=","qml.tape.QuantumTape","(","ops2",",","tape.measurements",")","def","processing_fn","(","results",")",":","return","qml.math.sum","(","qml.math.stack","(","results",")",")","return","[","tape1",",","tape2","]",",","processing_fn","We","can","apply","this","transform","to","a","quantum","tape",":",">",">",">","ops","=","[","qml.Hadamard","(","wires=0",")",",","qml.RX","(","-0.5",",","wires=0",")","]",">",">",">","tape","=","qml.tape.QuantumTape","(","ops",",","[","qml.expval","(","qml.PauliX","(","0",")",")","]",")",">",">",">","tapes",",","fn","=","my_transform","(","tape",",","0.65",",","2.5",")",">",">",">","print","(","qml.drawer.tape_text","(","tapes","[","0","]",",","decimals=2",")",")","0",":","\u2500\u2500H\u2500\u2500RY","(","0.33",")","\u2500\u2524","<","X",">",">",">",">","print","(","qml.drawer.tape_text","(","tapes","[","1","]",",","decimals=2",")",")","0",":","\u2500\u2500H\u2500\u2500RZ","(","1.25",")","\u2500\u2524","<","X",">","We","can","execute","these","tapes","manually",":",">",">",">","dev","=","qml.device","(","``","default.qubit","''",",","wires=1",")",">",">",">","res","=","qml.execute","(","tapes",",","dev",",","interface=","''","autograd","''",",","gradient_fn=qml.gradients.param_shift",")",">",">",">","print","(","res",")","[","0.9476507264148154",",","0.31532236239526856","]","Applying","the","processing","function",",","we","retrieve","the","end","result","of","the","transform",":",">",">",">","print","(","fn","(","res",")",")","1.2629730888100839","Alternatively",",","we","may","also","transform","a","QNode","directly",",","using","either","decorator","syntax",":",">",">",">","@","my_transform","(","0.65",",","2.5",")","...","@","qml.qnode","(","dev",")","...","def","circuit","(","x",")",":","...","qml.Hadamard","(","wires=0",")","...","qml.RX","(","x",",","wires=0",")","...","return","qml.expval","(","qml.PauliX","(","0",")",")",">",">",">","print","(","circuit","(","-0.5",")",")","1.2629730888100839","or","by","transforming","an","existing","QNode",":",">",">",">","@","qml.qnode","(","dev",")","...","def","circuit","(","x",")",":","...","qml.Hadamard","(","wires=0",")","...","qml.RX","(","x",",","wires=0",")","...","return","qml.expval","(","qml.PauliX","(","0",")",")",">",">",">","circuit","=","my_transform","(","circuit",",","0.65",",","2.5",")",">",">",">","print","(","circuit","(","-0.5",")",")","1.2629730888100839","Batch","tape","transforms","are","fully","differentiable",":",">",">",">","x","=","np.array","(","-0.5",",","requires_grad=True",")",">",">",">","gradient","=","qml.grad","(","circuit",")","(","x",")",">",">",">","print","(","gradient",")","2.5800122591960153","..","details",":",":",":","title",":","Usage","Details","*","*","Expansion","functions","*","*","Tape","expansion",",","decomposition",",","or","manipulation","may","always","be","performed","within","the","custom","batch","transform",".","However",",","by","specifying","a","separate","expansion","function",",","PennyLane","will","be","possible","to","access","this","separate","expansion","function","where","needed","via",">",">",">","my_transform.expand_fn","The","provided","``","expand_fn","``","must","have","the","same","input","arguments","as","``","transform_fn","``","and","return","a","``","tape","``",".","Following","the","example","above",":","..","code-block",":",":","python","def","expand_fn","(","tape",",","a",",","b",")",":","stopping_crit","=","lambda","obj",":","obj.name","!","=","''","PhaseShift","''","return","tape.expand","(","depth=10",",","stop_at=stopping_crit",")","my_transform","=","batch_transform","(","my_transform",",","expand_fn",")","Note","that",":","-","the","transform","arguments","``","a","``","and","``","b","``","must","be","passed","to","the","expansion","function",",","and","-","the","expansion","function","must","return","a","single","tape","."]
docstr: A wrapper method that takes a QNode and transform arguments,
  and returns a function that 'wraps' the QNode execution.
  
  The returned function should accept the same keyword arguments as
  the QNode, and return the output of applying the tape transform
  to the QNode's constructed tape.
docstr_tok: ["A","wrapper","method","that","takes","a","QNode","and","transform","arguments",",","and","returns","a","function","that","'wraps","'","the","QNode","execution",".","The","returned","function","should","accept","the","same","keyword","arguments","as","the","QNode",",","and","return","the","output","of","applying","the","tape","transform","to","the","QNode","'s","constructed","tape","."]
code: def default_qnode_wrapper(self, qnode, targs, tkwargs):
      """A wrapper method that takes a QNode and transform arguments,
      and returns a function that 'wraps' the QNode execution.
  
      The returned function should accept the same keyword arguments as
      the QNode, and return the output of applying the tape transform
      to the QNode's constructed tape.
      """
      transform_max_diff = tkwargs.pop("max_diff", None)
  
      if "shots" in inspect.signature(qnode.func).parameters:
          raise ValueError(
              "Detected 'shots' as an argument of the quantum function to transform. "
              "The 'shots' argument name is reserved for overriding the number of shots "
              "taken by the device."
          )
  
      def _wrapper(*args, **kwargs):
          shots = kwargs.pop("shots", False)
  
          argnums = kwargs.pop("argnums", None)
  
          if argnums:
              tkwargs["argnums"] = argnums  # pragma: no cover
  
          old_interface = qnode.interface
  
          if old_interface == "auto":
              qnode.interface = qml.math.get_interface(
                  *args, *list(kwargs.values())
              )
  
          qnode.construct(args, kwargs)
          tapes, processing_fn = self.construct(
              qnode.qtape, *targs, **tkwargs
          )
  
          interface = qnode.interface
          execute_kwargs = getattr(qnode, "execute_kwargs", {}).copy()
          max_diff = execute_kwargs.pop("max_diff", 2)
          max_diff = transform_max_diff or max_diff
  
          gradient_fn = getattr(qnode, "gradient_fn", qnode.diff_method)
          gradient_kwargs = getattr(qnode, "gradient_kwargs", {})
  
          if interface is None or not self.differentiable:
              gradient_fn = None
  
          if old_interface == "auto":
              qnode.interface = "auto"
  
          res = qml.execute(
              tapes,
              device=qnode.device,
              gradient_fn=gradient_fn,
              interface=interface,
              max_diff=max_diff,
              override_shots=shots,
              gradient_kwargs=gradient_kwargs,
              **execute_kwargs,
          )
  
          return processing_fn(res)
  
      return _wrapper
  
file_path: pennylane/pennylane/transforms/batch_transform.py
imports: import copy
  import functools
  import inspect
  import os
  import types
  import warnings
  from typing import Callable, Tuple
  import pennylane
  from pennylane.typing import ResultBatch
label_desc: Use image node_id 4 for calling the batch_transform obj's underlying member method code with example usage: obj.default_qnode_wrapper(qnode, targs, tkwargs) and returns: _wrapper, processing_fn