class_docstr: An operation representing the Suzuki-Trotter product approximation for the complex matrix
  exponential of a given Hamiltonian.
  
  The Suzuki-Trotter product formula provides a method to approximate the matrix exponential of
  Hamiltonian expressed as a linear combination of terms which in general do not commute. Consider
  the Hamiltonian :math:`H = \Sigma^{N}_{j=0} O_{j}`, the product formula is constructed using
  symmetrized products of the terms in the Hamiltonian. The symmetrized products of order
  :math:`m \in [1, 2, 4, ..., 2k]` with :math:`k \in \mathbb{N}` are given by:
  
  .. math::
  
      \begin{align}
          S_{1}(t) &= \Pi_{j=0}^{N} \ e^{i t O_{j}} \\
          S_{2}(t) &= \Pi_{j=0}^{N} \ e^{i \frac{t}{2} O_{j}} \cdot \Pi_{j=N}^{0} \ e^{i \frac{t}{2} O_{j}} \\
          &\vdots \\
          S_{m}(t) &= S_{m-2}(p_{m}t)^{2} \cdot S_{m-2}((1-4p_{m})t) \cdot S_{m-2}(p_{m}t)^{2},
      \end{align}
  
  where the coefficient is :math:`p_{m} = 1 / (4 - \sqrt[m - 1]{4})`. The :math:`m`th order,
  :math:`n`-step Suzuki-Trotter approximation is then defined as:
  
  .. math:: e^{iHt} \approx \left [S_{m}(t / n)  \right ]^{n}.
  
  For more details see `J. Math. Phys. 32, 400 (1991) <https://pubs.aip.org/aip/jmp/article-abstract/32/2/400/229229>`_.
  
  Args:
      hamiltonian (Union[.Hamiltonian, .Sum]): The Hamiltonian written as a linear combination
          of operators with known matrix exponentials.
      time (float): The time of evolution, namely the parameter :math:`t` in :math:`e^{iHt}`
      n (int): An integer representing the number of Trotter steps to perform
      order (int): An integer (:math:`m`) representing the order of the approximation (must be 1 or even)
      check_hermitian (bool): A flag to enable the validation check to ensure this is a valid unitary operator
  
  Raises:
      TypeError: The ``hamiltonian`` is not of type :class:`~.Hamiltonian`, or :class:`~.Sum`.
      ValueError: The ``hamiltonian`` must have atleast two terms.
      ValueError: One or more of the terms in ``hamiltonian`` are not Hermitian.
      ValueError: The ``order`` is not one or a positive even integer.
  
  **Example**
  
  .. code-block:: python3
  
      coeffs = [0.25, 0.75]
      ops = [qml.PauliX(0), qml.PauliZ(0)]
      H = qml.dot(coeffs, ops)
  
      dev = qml.device("default.qubit", wires=2)
      @qml.qnode(dev)
      def my_circ():
          # Prepare some state
          qml.Hadamard(0)
  
          # Evolve according to H
          qml.TrotterProduct(H, time=2.4, order=2)
  
          # Measure some quantity
          return qml.state()
  
  >>> my_circ()
  array([-0.13259524+0.59790098j,  0.        +0.j        , -0.13259524-0.77932754j,  0.        +0.j        ])
  
  .. details::
      :title: Usage Details
  
      This operation is similar to the :class:`~.ApproxTimeEvolution`. One can recover the behaviour
      of :class:`~.ApproxTimeEvolution` by taking the adjoint:
  
      >>> qml.adjoint(qml.TrotterProduct(hamiltonian, time, order=1, n=n))
  
      We can also compute the gradient with respect to the coefficients of the Hamiltonian and the
      evolution time:
  
      .. code-block:: python3
  
          @qml.qnode(dev)
          def my_circ(c1, c2, time):
              # Prepare H:
              H = qml.dot([c1, c2], [qml.PauliX(0), qml.PauliZ(0)])
  
              # Prepare some state
              qml.Hadamard(0)
  
              # Evolve according to H
              qml.TrotterProduct(H, time, order=2)
  
              # Measure some quantity
              return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))
  
      >>> args = np.array([1.23, 4.5, 0.1])
      >>> qml.grad(my_circ)(*tuple(args))
      (tensor(0.00961064, requires_grad=True), tensor(-0.12338274, requires_grad=True), tensor(-5.43401259, requires_grad=True))
docstr: Serialize the operation into trainable and non-trainable components.
  
  Returns:
      data, metadata: The trainable and non-trainable components.
  
  See ``Operator._unflatten``.
  
  The data component can be recursive and include other operations. For example, the trainable component of ``Adjoint(RX(1, wires=0))``
  will be the operator ``RX(1, wires=0)``.
  
  The metadata **must** be hashable.  If the hyperparameters contain a non-hashable component, then this
  method and ``Operator._unflatten`` should be overridden to provide a hashable version of the hyperparameters.
  
  **Example:**
  
  >>> op = qml.Rot(1.2, 2.3, 3.4, wires=0)
  >>> qml.Rot._unflatten(*op._flatten())
  Rot(1.2, 2.3, 3.4, wires=[0])
  >>> op = qml.PauliRot(1.2, "XY", wires=(0,1))
  >>> qml.PauliRot._unflatten(*op._flatten())
  PauliRot(1.2, XY, wires=[0, 1])
  
  Operators that have trainable components that differ from their ``Operator.data`` must implement their own
  ``_flatten`` methods.
  
  >>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
  >>> op._flatten()
  ((U2(3.4, 4.5, wires=['a']),),
  (<Wires = ['b', 'c']>, (True, True), <Wires = []>))
docstr_tok: ["Serialize","the","operation","into","trainable","and","non-trainable","components",".","Returns",":","data",",","metadata",":","The","trainable","and","non-trainable","components",".","See","``","Operator._unflatten","``",".","The","data","component","can","be","recursive","and","include","other","operations",".","For","example",",","the","trainable","component","of","``","Adjoint","(","RX","(","1",",","wires=0",")",")","``","will","be","the","operator","``","RX","(","1",",","wires=0",")","``",".","The","metadata","*","*","must","*","*","be","hashable",".","If","the","hyperparameters","contain","a","non-hashable","component",",","then","this","method","and","``","Operator._unflatten","``","should","be","overridden","to","provide","a","hashable","version","of","the","hyperparameters",".","*","*","Example",":","*","*",">",">",">","op","=","qml.Rot","(","1.2",",","2.3",",","3.4",",","wires=0",")",">",">",">","qml.Rot._unflatten","(","*","op._flatten","(",")",")","Rot","(","1.2",",","2.3",",","3.4",",","wires=","[","0","]",")",">",">",">","op","=","qml.PauliRot","(","1.2",",","``","XY","''",",","wires=","(","0,1",")",")",">",">",">","qml.PauliRot._unflatten","(","*","op._flatten","(",")",")","PauliRot","(","1.2",",","XY",",","wires=","[","0",",","1","]",")","Operators","that","have","trainable","components","that","differ","from","their","``","Operator.data","``","must","implement","their","own","``","_flatten","``","methods",".",">",">",">","op","=","qml.ctrl","(","qml.U2","(","3.4",",","4.5",",","wires=","''","a","''",")",",","(","``","b","''",",","``","c","''",")",")",">",">",">","op._flatten","(",")","(","(","U2","(","3.4",",","4.5",",","wires=","[","'","a","'","]",")",",",")",",","(","<","Wires","=","[","'","b","'",",","'","c","'","]",">",",","(","True",",","True",")",",","<","Wires","=","[","]",">",")",")"]
code: def _flatten(self):
      """Serialize the operation into trainable and non-trainable components.
  
      Returns:
          data, metadata: The trainable and non-trainable components.
  
      See ``Operator._unflatten``.
  
      The data component can be recursive and include other operations. For example, the trainable component of ``Adjoint(RX(1, wires=0))``
      will be the operator ``RX(1, wires=0)``.
  
      The metadata **must** be hashable.  If the hyperparameters contain a non-hashable component, then this
      method and ``Operator._unflatten`` should be overridden to provide a hashable version of the hyperparameters.
  
      **Example:**
  
      >>> op = qml.Rot(1.2, 2.3, 3.4, wires=0)
      >>> qml.Rot._unflatten(*op._flatten())
      Rot(1.2, 2.3, 3.4, wires=[0])
      >>> op = qml.PauliRot(1.2, "XY", wires=(0,1))
      >>> qml.PauliRot._unflatten(*op._flatten())
      PauliRot(1.2, XY, wires=[0, 1])
  
      Operators that have trainable components that differ from their ``Operator.data`` must implement their own
      ``_flatten`` methods.
  
      >>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
      >>> op._flatten()
      ((U2(3.4, 4.5, wires=['a']),),
      (<Wires = ['b', 'c']>, (True, True), <Wires = []>))
      """
      hamiltonian = self.hyperparameters["base"]
      time = self.parameters[0]
  
      hashable_hyperparameters = tuple(
          (key, value)
          for key, value in self.hyperparameters.items()
          if key != "base"
      )
      return (hamiltonian, time), hashable_hyperparameters
  
file_path: pennylane/pennylane/templates/subroutines/trotter.py
imports: import pennylane
  from pennylane.operation import Operation
  from pennylane.ops import Sum
label_desc: Use image node_id 2 for calling the TrotterProduct obj's underlying member method code with example usage: obj._flatten() and returns: hamiltonian,  time,  hashable_hyperparameters