class_docstr: Operator representing a Hamiltonian.
  
  The Hamiltonian is represented as a linear combination of other operators, e.g.,
  :math:`\sum_{k=0}^{N-1} c_k O_k`, where the :math:`c_k` are trainable parameters.
  
  Args:
      coeffs (tensor_like): coefficients of the Hamiltonian expression
      observables (Iterable[Observable]): observables in the Hamiltonian expression, of same length as coeffs
      simplify (bool): Specifies whether the Hamiltonian is simplified upon initialization
                       (like-terms are combined). The default value is `False`.
      grouping_type (str): If not None, compute and store information on how to group commuting
          observables upon initialization. This information may be accessed when QNodes containing this
          Hamiltonian are executed on devices. The string refers to the type of binary relation between Pauli words.
          Can be ``'qwc'`` (qubit-wise commuting), ``'commuting'``, or ``'anticommuting'``.
      method (str): The graph coloring heuristic to use in solving minimum clique cover for grouping, which
          can be ``'lf'`` (Largest First) or ``'rlf'`` (Recursive Largest First). Ignored if ``grouping_type=None``.
      id (str): name to be assigned to this Hamiltonian instance
  
  **Example:**
  
  A Hamiltonian can be created by simply passing the list of coefficients
  as well as the list of observables:
  
  >>> coeffs = [0.2, -0.543]
  >>> obs = [qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.Hadamard(2)]
  >>> H = qml.Hamiltonian(coeffs, obs)
  >>> print(H)
    (-0.543) [Z0 H2]
  + (0.2) [X0 Z1]
  
  The coefficients can be a trainable tensor, for example:
  
  >>> coeffs = tf.Variable([0.2, -0.543], dtype=tf.double)
  >>> obs = [qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.Hadamard(2)]
  >>> H = qml.Hamiltonian(coeffs, obs)
  >>> print(H)
    (-0.543) [Z0 H2]
  + (0.2) [X0 Z1]
  
  The user can also provide custom observables:
  
  >>> obs_matrix = np.array([[0.5, 1.0j, 0.0, -3j],
                             [-1.0j, -1.1, 0.0, -0.1],
                             [0.0, 0.0, -0.9, 12.0],
                             [3j, -0.1, 12.0, 0.0]])
  >>> obs = qml.Hermitian(obs_matrix, wires=[0, 1])
  >>> H = qml.Hamiltonian((0.8, ), (obs, ))
  >>> print(H)
  (0.8) [Hermitian0,1]
  
  Alternatively, the :func:`~.molecular_hamiltonian` function from the
  :doc:`/introduction/chemistry` module can be used to generate a molecular
  Hamiltonian.
  
  In many cases, Hamiltonians can be constructed using Pythonic arithmetic operations.
  For example:
  
  >>> qml.Hamiltonian([1.], [qml.PauliX(0)]) + 2 * qml.PauliZ(0) @ qml.PauliZ(1)
  
  is equivalent to the following Hamiltonian:
  
  >>> qml.Hamiltonian([1, 2], [qml.PauliX(0), qml.PauliZ(0) @ qml.PauliZ(1)])
  
  While scalar multiplication requires native python floats or integer types,
  addition, subtraction, and tensor multiplication of Hamiltonians with Hamiltonians or
  other observables is possible with tensor-valued coefficients, i.e.,
  
  >>> H1 = qml.Hamiltonian(torch.tensor([1.]), [qml.PauliX(0)])
  >>> H2 = qml.Hamiltonian(torch.tensor([2., 3.]), [qml.PauliY(0), qml.PauliX(1)])
  >>> obs3 = [qml.PauliX(0), qml.PauliY(0), qml.PauliX(1)]
  >>> H3 = qml.Hamiltonian(torch.tensor([1., 2., 3.]), obs3)
  >>> H3.compare(H1 + H2)
  True
  
  A Hamiltonian can store information on which commuting observables should be measured together in
  a circuit:
  
  >>> obs = [qml.PauliX(0), qml.PauliX(1), qml.PauliZ(0)]
  >>> coeffs = np.array([1., 2., 3.])
  >>> H = qml.Hamiltonian(coeffs, obs, grouping_type='qwc')
  >>> H.grouping_indices
  [[0, 1], [2]]
  
  This attribute can be used to compute groups of coefficients and observables:
  
  >>> grouped_coeffs = [coeffs[indices] for indices in H.grouping_indices]
  >>> grouped_obs = [[H.ops[i] for i in indices] for indices in H.grouping_indices]
  >>> grouped_coeffs
  [tensor([1., 2.], requires_grad=True), tensor([3.], requires_grad=True)]
  >>> grouped_obs
  [[qml.PauliX(0), qml.PauliX(1)], [qml.PauliZ(0)]]
  
  Devices that evaluate a Hamiltonian expectation by splitting it into its local observables can
  use this information to reduce the number of circuits evaluated.
  
  Note that one can compute the ``grouping_indices`` for an already initialized Hamiltonian by
  using the :func:`compute_grouping <pennylane.Hamiltonian.compute_grouping>` method.
class_docstr_tok: ["Operator","representing","a","Hamiltonian",".","The","Hamiltonian","is","represented","as","a","linear","combination","of","other","operators",",","e.g.",",",":","math",":","`","\\sum_","{","k=0","}","^","{","N-1","}","c_k","O_k","`",",","where","the",":","math",":","`","c_k","`","are","trainable","parameters",".","Args",":","coeffs","(","tensor_like",")",":","coefficients","of","the","Hamiltonian","expression","observables","(","Iterable","[","Observable","]",")",":","observables","in","the","Hamiltonian","expression",",","of","same","length","as","coeffs","simplify","(","bool",")",":","Specifies","whether","the","Hamiltonian","is","simplified","upon","initialization","(","like-terms","are","combined",")",".","The","default","value","is","`","False","`",".","grouping_type","(","str",")",":","If","not","None",",","compute","and","store","information","on","how","to","group","commuting","observables","upon","initialization",".","This","information","may","be","accessed","when","QNodes","containing","this","Hamiltonian","are","executed","on","devices",".","The","string","refers","to","the","type","of","binary","relation","between","Pauli","words",".","Can","be","``","'qwc","'","``","(","qubit-wise","commuting",")",",","``","'commuting","'","``",",","or","``","'anticommuting","'","``",".","method","(","str",")",":","The","graph","coloring","heuristic","to","use","in","solving","minimum","clique","cover","for","grouping",",","which","can","be","``","'lf","'","``","(","Largest","First",")","or","``","'rlf","'","``","(","Recursive","Largest","First",")",".","Ignored","if","``","grouping_type=None","``",".","id","(","str",")",":","name","to","be","assigned","to","this","Hamiltonian","instance","*","*","Example",":","*","*","A","Hamiltonian","can","be","created","by","simply","passing","the","list","of","coefficients","as","well","as","the","list","of","observables",":",">",">",">","coeffs","=","[","0.2",",","-0.543","]",">",">",">","obs","=","[","qml.PauliX","(","0",")","@","qml.PauliZ","(","1",")",",","qml.PauliZ","(","0",")","@","qml.Hadamard","(","2",")","]",">",">",">","H","=","qml.Hamiltonian","(","coeffs",",","obs",")",">",">",">","print","(","H",")","(","-0.543",")","[","Z0","H2","]","+","(","0.2",")","[","X0","Z1","]","The","coefficients","can","be","a","trainable","tensor",",","for","example",":",">",">",">","coeffs","=","tf.Variable","(","[","0.2",",","-0.543","]",",","dtype=tf.double",")",">",">",">","obs","=","[","qml.PauliX","(","0",")","@","qml.PauliZ","(","1",")",",","qml.PauliZ","(","0",")","@","qml.Hadamard","(","2",")","]",">",">",">","H","=","qml.Hamiltonian","(","coeffs",",","obs",")",">",">",">","print","(","H",")","(","-0.543",")","[","Z0","H2","]","+","(","0.2",")","[","X0","Z1","]","The","user","can","also","provide","custom","observables",":",">",">",">","obs_matrix","=","np.array","(","[","[","0.5",",","1.0j",",","0.0",",","-3j","]",",","[","-1.0j",",","-1.1",",","0.0",",","-0.1","]",",","[","0.0",",","0.0",",","-0.9",",","12.0","]",",","[","3j",",","-0.1",",","12.0",",","0.0","]","]",")",">",">",">","obs","=","qml.Hermitian","(","obs_matrix",",","wires=","[","0",",","1","]",")",">",">",">","H","=","qml.Hamiltonian","(","(","0.8",",",")",",","(","obs",",",")",")",">",">",">","print","(","H",")","(","0.8",")","[","Hermitian0,1","]","Alternatively",",","the",":","func",":","`","~.molecular_hamiltonian","`","function","from","the",":","doc",":","`","\/introduction\/chemistry","`","module","can","be","used","to","generate","a","molecular","Hamiltonian",".","In","many","cases",",","Hamiltonians","can","be","constructed","using","Pythonic","arithmetic","operations",".","For","example",":",">",">",">","qml.Hamiltonian","(","[","1",".","]",",","[","qml.PauliX","(","0",")","]",")","+","2","*","qml.PauliZ","(","0",")","@","qml.PauliZ","(","1",")","is","equivalent","to","the","following","Hamiltonian",":",">",">",">","qml.Hamiltonian","(","[","1",",","2","]",",","[","qml.PauliX","(","0",")",",","qml.PauliZ","(","0",")","@","qml.PauliZ","(","1",")","]",")","While","scalar","multiplication","requires","native","python","floats","or","integer","types",",","addition",",","subtraction",",","and","tensor","multiplication","of","Hamiltonians","with","Hamiltonians","or","other","observables","is","possible","with","tensor-valued","coefficients",",","i.e.",",",">",">",">","H1","=","qml.Hamiltonian","(","torch.tensor","(","[","1",".","]",")",",","[","qml.PauliX","(","0",")","]",")",">",">",">","H2","=","qml.Hamiltonian","(","torch.tensor","(","[","2.",",","3",".","]",")",",","[","qml.PauliY","(","0",")",",","qml.PauliX","(","1",")","]",")",">",">",">","obs3","=","[","qml.PauliX","(","0",")",",","qml.PauliY","(","0",")",",","qml.PauliX","(","1",")","]",">",">",">","H3","=","qml.Hamiltonian","(","torch.tensor","(","[","1.",",","2.",",","3",".","]",")",",","obs3",")",">",">",">","H3.compare","(","H1","+","H2",")","True","A","Hamiltonian","can","store","information","on","which","commuting","observables","should","be","measured","together","in","a","circuit",":",">",">",">","obs","=","[","qml.PauliX","(","0",")",",","qml.PauliX","(","1",")",",","qml.PauliZ","(","0",")","]",">",">",">","coeffs","=","np.array","(","[","1.",",","2.",",","3",".","]",")",">",">",">","H","=","qml.Hamiltonian","(","coeffs",",","obs",",","grouping_type='qwc","'",")",">",">",">","H.grouping_indices","[","[","0",",","1","]",",","[","2","]","]","This","attribute","can","be","used","to","compute","groups","of","coefficients","and","observables",":",">",">",">","grouped_coeffs","=","[","coeffs","[","indices","]","for","indices","in","H.grouping_indices","]",">",">",">","grouped_obs","=","[","[","H.ops","[","i","]","for","i","in","indices","]","for","indices","in","H.grouping_indices","]",">",">",">","grouped_coeffs","[","tensor","(","[","1.",",","2",".","]",",","requires_grad=True",")",",","tensor","(","[","3",".","]",",","requires_grad=True",")","]",">",">",">","grouped_obs","[","[","qml.PauliX","(","0",")",",","qml.PauliX","(","1",")","]",",","[","qml.PauliZ","(","0",")","]","]","Devices","that","evaluate","a","Hamiltonian","expectation","by","splitting","it","into","its","local","observables","can","use","this","information","to","reduce","the","number","of","circuits","evaluated",".","Note","that","one","can","compute","the","``","grouping_indices","``","for","an","already","initialized","Hamiltonian","by","using","the",":","func",":","`","compute_grouping","<","pennylane.Hamiltonian.compute_grouping",">","`","method","."]
docstr: Set the grouping indices, if known without explicit computation, or if
  computation was done externally. The groups are not verified.
  
  **Example**
  
  Examples of valid groupings for the Hamiltonian
  
  >>> H = qml.Hamiltonian([qml.PauliX('a'), qml.PauliX('b'), qml.PauliY('b')])
  
  are
  
  >>> H.grouping_indices = [[0, 1], [2]]
  
  or
  
  >>> H.grouping_indices = [[0, 2], [1]]
  
  since both ``qml.PauliX('a'), qml.PauliX('b')`` and ``qml.PauliX('a'), qml.PauliY('b')`` commute.
  
  
  Args:
      value (list[list[int]]): List of lists of indexes of the observables in ``self.ops``. Each sublist
          represents a group of commuting observables.
code: def grouping_indices(self, value):
      """Set the grouping indices, if known without explicit computation, or if
      computation was done externally. The groups are not verified.
  
      **Example**
  
      Examples of valid groupings for the Hamiltonian
  
      >>> H = qml.Hamiltonian([qml.PauliX('a'), qml.PauliX('b'), qml.PauliY('b')])
  
      are
  
      >>> H.grouping_indices = [[0, 1], [2]]
  
      or
  
      >>> H.grouping_indices = [[0, 2], [1]]
  
      since both ``qml.PauliX('a'), qml.PauliX('b')`` and ``qml.PauliX('a'), qml.PauliY('b')`` commute.
  
  
      Args:
          value (list[list[int]]): List of lists of indexes of the observables in ``self.ops``. Each sublist
              represents a group of commuting observables.
      """
  
      if (
          not isinstance(value, Iterable)
          or any(not isinstance(sublist, Iterable) for sublist in value)
          or any(
              i not in range(len(self.ops))
              for i in [i for sl in value for i in sl]
          )
      ):
          raise ValueError(
              f"The grouped index value needs to be a tuple of tuples of integers between 0 and the "
              f"number of observables in the Hamiltonian; got {value}"
          )
      # make sure all tuples so can be hashable
      self._grouping_indices = tuple(
          tuple(sublist) for sublist in value
      )
  
imports: import itertools
  import numbers
  from collections.abc import Iterable
  from copy import copy
  import functools
  from typing import List
  import numpy
  import scipy
  import pennylane
  from pennylane.operation import Observable, Tensor
  from pennylane.wires import Wires
label_desc: Use image node_id 12 for calling the Hamiltonian obj's underlying member method code with example usage: obj.grouping_indices(value) without return types