class_docstr: Convert a function that applies to operators into a functional transform.
  
  This allows the operator function to be used across PennyLane
  on both instantiated operators as well as quantum functions.
  
  By default, this decorator creates functional transforms that
  accept a single operator. However, you can also register how the
  transform acts on multiple operators. Once this is defined,
  the transform can be used anywhere in PennyLane --- at the operator
  level for operator arithmetic, or at the qfunc/QNode level.
  
  .. warning::
  
      Use of ``op_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
  
  Args:
      fn (function): The function to register as the operator transform.
          It can have an arbitrary number of arguments, but the first argument
          **must** be the input operator.
  
  **Example**
  
  Consider an operator function that computes the trace of an operator:
  
  .. code-block:: python
  
      @qml.op_transform
      def trace(op):
          try:
              return qml.math.real(qml.math.sum(op.eigvals()))
          except qml.operation.EigvalsUndefinedError:
              return qml.math.real(qml.math.trace(op.matrix()))
  
  We can use this function as written:
  
  >>> op = qml.RX(0.5, wires=0)
  >>> trace(op)
  1.9378248434212895
  
  By using the ``op_transform`` decorator, we also enable it to be used
  as a functional transform:
  
  >>> trace(qml.RX)(0.5, wires=0)
  1.9378248434212895
  
  Note that if we apply our function to an operation that does not define its
  matrix or eigenvalues representation, we get an error:
  
  >>> weights = np.array([[[0.7, 0.6, 0.5], [0.1, 0.2, 0.3]]])
  >>> trace(qml.StronglyEntanglingLayers(weights, wires=[0, 1]))
  pennylane.operation.EigvalsUndefinedError
  During handling of the above exception, another exception occurred:
  pennylane.operation.MatrixUndefinedError
  
  The most powerful reason for using ``op_transform`` is the ability to define
  how the transform behaves if applied to a datastructure that supports multiple
  operations, such as a qfunc, tape, or QNode.
  
  We do this by defining a tape transform:
  
  .. code-block:: python
  
      @trace.tape_transform
      def trace(tape):
          tr = qml.math.trace(qml.matrix(tape))
          return qml.math.real(tr)
  
  We can now apply this transform directly to a qfunc:
  
  >>> def circuit(x, y):
  ...     qml.RX(x, wires=0)
  ...     qml.Hadamard(wires=1)
  ...     qml.CNOT(wires=[0, 1])
  ...     qml.CRY(y, wires=[1, 0])
  >>> trace(circuit)(0.1, 0.8)
  1.4124461636742214
  
  Our example above, applying our function to an operation that does not
  define the matrix or eigenvalues, will now work, since PennyLane will
  decompose the operation automatically into multiple operations:
  
  >>> trace(qml.StronglyEntanglingLayers)(weights, wires=[0, 1])
  0.4253851061350833
  
  .. note::
  
      If the operator transform takes additional (optional) transform parameters,
      then the registered tape transform should take the same transform parameters.
  
      E.g., consider a transform that takes the transform parameter ``lower``:
  
      .. code-block:: python
  
          @qml.op_transform
          def name(op, lower=True):
              return op.name().lower() if lower else op.name()
  
          @name.tape_transform
          def name(tape, lower=True):
              return [name(op, lower=lower) for op in tape.operations]
  
  If the transformation has purely quantum output, we can register the tape transformation
  as a qfunc transformation in addition:
  
  .. code-block:: python
  
      @qml.op_transform
      def simplify_rotation(op):
          if op.name == "Rot":
              params = op.parameters
              wires = op.wires
  
              if qml.math.allclose(params, 0):
                  return
  
              if qml.math.allclose(params[1:2], 0):
                  return qml.RZ(params[0], wires)
  
          return op
  
      @simplify_rotation.tape_transform
      @qml.qfunc_transform
      def simplify_rotation(tape):
          for op in tape:
              if op.name == "Rot":
                  simplify_rotation(op)
              else:
                  qml.apply(op)
  
  We can now use this combined operator and quantum function transform in compilation pipelines:
  
  .. code-block:: python
  
      @qml.qnode(dev)
      @qml.compile(pipeline=[simplify_rotation])
      def circuit(weights):
          ansatz(weights)
          qml.CNOT(wires=[0, 1])
          qml.Rot(0.0, 0.0, 0.0, wires=0)
          return qml.expval(qml.PauliX(1))
class_docstr_tok: ["Convert","a","function","that","applies","to","operators","into","a","functional","transform",".","This","allows","the","operator","function","to","be","used","across","PennyLane","on","both","instantiated","operators","as","well","as","quantum","functions",".","By","default",",","this","decorator","creates","functional","transforms","that","accept","a","single","operator",".","However",",","you","can","also","register","how","the","transform","acts","on","multiple","operators",".","Once","this","is","defined",",","the","transform","can","be","used","anywhere","in","PennyLane","--","-","at","the","operator","level","for","operator","arithmetic",",","or","at","the","qfunc\/QNode","level",".","..","warning",":",":","Use","of","``","op_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","Args",":","fn","(","function",")",":","The","function","to","register","as","the","operator","transform",".","It","can","have","an","arbitrary","number","of","arguments",",","but","the","first","argument","*","*","must","*","*","be","the","input","operator",".","*","*","Example","*","*","Consider","an","operator","function","that","computes","the","trace","of","an","operator",":","..","code-block",":",":","python","@","qml.op_transform","def","trace","(","op",")",":","try",":","return","qml.math.real","(","qml.math.sum","(","op.eigvals","(",")",")",")","except","qml.operation.EigvalsUndefinedError",":","return","qml.math.real","(","qml.math.trace","(","op.matrix","(",")",")",")","We","can","use","this","function","as","written",":",">",">",">","op","=","qml.RX","(","0.5",",","wires=0",")",">",">",">","trace","(","op",")","1.9378248434212895","By","using","the","``","op_transform","``","decorator",",","we","also","enable","it","to","be","used","as","a","functional","transform",":",">",">",">","trace","(","qml.RX",")","(","0.5",",","wires=0",")","1.9378248434212895","Note","that","if","we","apply","our","function","to","an","operation","that","does","not","define","its","matrix","or","eigenvalues","representation",",","we","get","an","error",":",">",">",">","weights","=","np.array","(","[","[","[","0.7",",","0.6",",","0.5","]",",","[","0.1",",","0.2",",","0.3","]","]","]",")",">",">",">","trace","(","qml.StronglyEntanglingLayers","(","weights",",","wires=","[","0",",","1","]",")",")","pennylane.operation.EigvalsUndefinedError","During","handling","of","the","above","exception",",","another","exception","occurred",":","pennylane.operation.MatrixUndefinedError","The","most","powerful","reason","for","using","``","op_transform","``","is","the","ability","to","define","how","the","transform","behaves","if","applied","to","a","datastructure","that","supports","multiple","operations",",","such","as","a","qfunc",",","tape",",","or","QNode",".","We","do","this","by","defining","a","tape","transform",":","..","code-block",":",":","python","@","trace.tape_transform","def","trace","(","tape",")",":","tr","=","qml.math.trace","(","qml.matrix","(","tape",")",")","return","qml.math.real","(","tr",")","We","can","now","apply","this","transform","directly","to","a","qfunc",":",">",">",">","def","circuit","(","x",",","y",")",":","...","qml.RX","(","x",",","wires=0",")","...","qml.Hadamard","(","wires=1",")","...","qml.CNOT","(","wires=","[","0",",","1","]",")","...","qml.CRY","(","y",",","wires=","[","1",",","0","]",")",">",">",">","trace","(","circuit",")","(","0.1",",","0.8",")","1.4124461636742214","Our","example","above",",","applying","our","function","to","an","operation","that","does","not","define","the","matrix","or","eigenvalues",",","will","now","work",",","since","PennyLane","will","decompose","the","operation","automatically","into","multiple","operations",":",">",">",">","trace","(","qml.StronglyEntanglingLayers",")","(","weights",",","wires=","[","0",",","1","]",")","0.4253851061350833","..","note",":",":","If","the","operator","transform","takes","additional","(","optional",")","transform","parameters",",","then","the","registered","tape","transform","should","take","the","same","transform","parameters",".","E.g.",",","consider","a","transform","that","takes","the","transform","parameter","``","lower","``",":","..","code-block",":",":","python","@","qml.op_transform","def","name","(","op",",","lower=True",")",":","return","op.name","(",")",".lower","(",")","if","lower","else","op.name","(",")","@","name.tape_transform","def","name","(","tape",",","lower=True",")",":","return","[","name","(","op",",","lower=lower",")","for","op","in","tape.operations","]","If","the","transformation","has","purely","quantum","output",",","we","can","register","the","tape","transformation","as","a","qfunc","transformation","in","addition",":","..","code-block",":",":","python","@","qml.op_transform","def","simplify_rotation","(","op",")",":","if","op.name","==","``","Rot","''",":","params","=","op.parameters","wires","=","op.wires","if","qml.math.allclose","(","params",",","0",")",":","return","if","qml.math.allclose","(","params","[","1:2","]",",","0",")",":","return","qml.RZ","(","params","[","0","]",",","wires",")","return","op","@","simplify_rotation.tape_transform","@","qml.qfunc_transform","def","simplify_rotation","(","tape",")",":","for","op","in","tape",":","if","op.name","==","``","Rot","''",":","simplify_rotation","(","op",")","else",":","qml.apply","(","op",")","We","can","now","use","this","combined","operator","and","quantum","function","transform","in","compilation","pipelines",":","..","code-block",":",":","python","@","qml.qnode","(","dev",")","@","qml.compile","(","pipeline=","[","simplify_rotation","]",")","def","circuit","(","weights",")",":","ansatz","(","weights",")","qml.CNOT","(","wires=","[","0",",","1","]",")","qml.Rot","(","0.0",",","0.0",",","0.0",",","wires=0",")","return","qml.expval","(","qml.PauliX","(","1",")",")"]
docstr: Register a tape transformation to enable the operator transform
  to apply to datastructures containing multiple operations, such as QNodes, qfuncs,
  and tapes.
  
  .. note::
  
      The registered tape transform should have the same parameters as the
      original operation transform function.
  
  .. note::
  
      If the transformation maps a tape to a tape (or equivalently, a qfunc to a qfunc)
      then the transformation is simultaneously a :func:`~.qfunc_transform`, and
      can be declared as such. This enables additional functionality, for example
      the ability to use the transform in a compilation pipeline.
  
  Args:
      fn (callable): The function to register as the tape transform. This function
          should accept a :class:`~.QuantumTape` as the first argument.
  
  **Example**
  
  .. code-block:: python
  
      @qml.op_transform
      def name(op, lower=False):
          if lower:
              return op.name.lower()
          return op.name
  
      @name.tape_transform
      def name(tape, lower=True):
          return [name(op, lower=lower) for op in tape.operations]
  
  We can now use this function on a qfunc, tape, or QNode:
  
  >>> def circuit(x, y):
  ...     qml.RX(x, wires=0)
  ...     qml.Hadamard(wires=1)
  ...     qml.CNOT(wires=[0, 1])
  ...     qml.CRY(y, wires=[1, 0])
  >>> name(circuit, lower=True)(0.1, 0.8)
  ['rx', 'hadamard', 'cnot', 'cry']
  
  If the transformation has purely quantum output, we can register the tape transformation
  as a qfunc transformation in addition:
  
  .. code-block:: python
  
      @qml.op_transform
      def simplify_rotation(op):
          if op.name == "Rot":
              params = op.parameters
              wires = op.wires
  
              if qml.math.allclose(params, 0):
                  return
  
              if qml.math.allclose(params[1:2], 0):
                  return qml.RZ(params[0], wires)
  
          return op
  
      @simplify_rotation.tape_transform
      @qml.qfunc_transform
      def simplify_rotation(tape):
          for op in tape:
              if op.name == "Rot":
                  simplify_rotation(op)
              else:
                  qml.apply(op)
  
  We can now use this combined operator and quantum function transform in compilation pipelines:
  
  .. code-block:: python
  
      @qml.qnode(dev)
      @qml.compile(pipeline=[simplify_rotation])
      def circuit(weights):
          ansatz(weights)
          qml.CNOT(wires=[0, 1])
          qml.Rot(0.0, 0.0, 0.0, wires=0)
          return qml.expval(qml.PauliX(1))
docstr_tok: ["Register","a","tape","transformation","to","enable","the","operator","transform","to","apply","to","datastructures","containing","multiple","operations",",","such","as","QNodes",",","qfuncs",",","and","tapes",".","..","note",":",":","The","registered","tape","transform","should","have","the","same","parameters","as","the","original","operation","transform","function",".","..","note",":",":","If","the","transformation","maps","a","tape","to","a","tape","(","or","equivalently",",","a","qfunc","to","a","qfunc",")","then","the","transformation","is","simultaneously","a",":","func",":","`","~.qfunc_transform","`",",","and","can","be","declared","as","such",".","This","enables","additional","functionality",",","for","example","the","ability","to","use","the","transform","in","a","compilation","pipeline",".","Args",":","fn","(","callable",")",":","The","function","to","register","as","the","tape","transform",".","This","function","should","accept","a",":","class",":","`","~.QuantumTape","`","as","the","first","argument",".","*","*","Example","*","*","..","code-block",":",":","python","@","qml.op_transform","def","name","(","op",",","lower=False",")",":","if","lower",":","return","op.name.lower","(",")","return","op.name","@","name.tape_transform","def","name","(","tape",",","lower=True",")",":","return","[","name","(","op",",","lower=lower",")","for","op","in","tape.operations","]","We","can","now","use","this","function","on","a","qfunc",",","tape",",","or","QNode",":",">",">",">","def","circuit","(","x",",","y",")",":","...","qml.RX","(","x",",","wires=0",")","...","qml.Hadamard","(","wires=1",")","...","qml.CNOT","(","wires=","[","0",",","1","]",")","...","qml.CRY","(","y",",","wires=","[","1",",","0","]",")",">",">",">","name","(","circuit",",","lower=True",")","(","0.1",",","0.8",")","[","'rx","'",",","'hadamard","'",",","'cnot","'",",","'cry","'","]","If","the","transformation","has","purely","quantum","output",",","we","can","register","the","tape","transformation","as","a","qfunc","transformation","in","addition",":","..","code-block",":",":","python","@","qml.op_transform","def","simplify_rotation","(","op",")",":","if","op.name","==","``","Rot","''",":","params","=","op.parameters","wires","=","op.wires","if","qml.math.allclose","(","params",",","0",")",":","return","if","qml.math.allclose","(","params","[","1:2","]",",","0",")",":","return","qml.RZ","(","params","[","0","]",",","wires",")","return","op","@","simplify_rotation.tape_transform","@","qml.qfunc_transform","def","simplify_rotation","(","tape",")",":","for","op","in","tape",":","if","op.name","==","``","Rot","''",":","simplify_rotation","(","op",")","else",":","qml.apply","(","op",")","We","can","now","use","this","combined","operator","and","quantum","function","transform","in","compilation","pipelines",":","..","code-block",":",":","python","@","qml.qnode","(","dev",")","@","qml.compile","(","pipeline=","[","simplify_rotation","]",")","def","circuit","(","weights",")",":","ansatz","(","weights",")","qml.CNOT","(","wires=","[","0",",","1","]",")","qml.Rot","(","0.0",",","0.0",",","0.0",",","wires=0",")","return","qml.expval","(","qml.PauliX","(","1",")",")"]
code: def tape_transform(self, fn):
      """Register a tape transformation to enable the operator transform
      to apply to datastructures containing multiple operations, such as QNodes, qfuncs,
      and tapes.
  
      .. note::
  
          The registered tape transform should have the same parameters as the
          original operation transform function.
  
      .. note::
  
          If the transformation maps a tape to a tape (or equivalently, a qfunc to a qfunc)
          then the transformation is simultaneously a :func:`~.qfunc_transform`, and
          can be declared as such. This enables additional functionality, for example
          the ability to use the transform in a compilation pipeline.
  
      Args:
          fn (callable): The function to register as the tape transform. This function
              should accept a :class:`~.QuantumTape` as the first argument.
  
      **Example**
  
      .. code-block:: python
  
          @qml.op_transform
          def name(op, lower=False):
              if lower:
                  return op.name.lower()
              return op.name
  
          @name.tape_transform
          def name(tape, lower=True):
              return [name(op, lower=lower) for op in tape.operations]
  
      We can now use this function on a qfunc, tape, or QNode:
  
      >>> def circuit(x, y):
      ...     qml.RX(x, wires=0)
      ...     qml.Hadamard(wires=1)
      ...     qml.CNOT(wires=[0, 1])
      ...     qml.CRY(y, wires=[1, 0])
      >>> name(circuit, lower=True)(0.1, 0.8)
      ['rx', 'hadamard', 'cnot', 'cry']
  
      If the transformation has purely quantum output, we can register the tape transformation
      as a qfunc transformation in addition:
  
      .. code-block:: python
  
          @qml.op_transform
          def simplify_rotation(op):
              if op.name == "Rot":
                  params = op.parameters
                  wires = op.wires
  
                  if qml.math.allclose(params, 0):
                      return
  
                  if qml.math.allclose(params[1:2], 0):
                      return qml.RZ(params[0], wires)
  
              return op
  
          @simplify_rotation.tape_transform
          @qml.qfunc_transform
          def simplify_rotation(tape):
              for op in tape:
                  if op.name == "Rot":
                      simplify_rotation(op)
                  else:
                      qml.apply(op)
  
      We can now use this combined operator and quantum function transform in compilation pipelines:
  
      .. code-block:: python
  
          @qml.qnode(dev)
          @qml.compile(pipeline=[simplify_rotation])
          def circuit(weights):
              ansatz(weights)
              qml.CNOT(wires=[0, 1])
              qml.Rot(0.0, 0.0, 0.0, wires=0)
              return qml.expval(qml.PauliX(1))
      """
      self._tape_fn = fn
      return self
  
file_path: pennylane/pennylane/transforms/op_transforms.py
imports: import functools
  import inspect
  import os
  import warnings
  import pennylane
label_desc: Use image node_id 7 for calling the op_transform obj's underlying member method code with example usage: obj.tape_transform(fn) and returns: self