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: Computes the sparse matrix representation of a Hamiltonian in the computational basis.
  
  Args:
      wire_order (Iterable): global wire order, must contain all wire labels from the operator's wires.
          If not provided, the default order of the wires (self.wires) of the Hamiltonian is used.
  
  Returns:
      csr_matrix: a sparse matrix in scipy Compressed Sparse Row (CSR) format with dimension
      :math:`(2^n, 2^n)`, where :math:`n` is the number of wires
  
  **Example:**
  
  >>> coeffs = [1, -0.45]
  >>> obs = [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliY(0) @ qml.PauliZ(1)]
  >>> H = qml.Hamiltonian(coeffs, obs)
  >>> H_sparse = H.sparse_matrix()
  >>> H_sparse
  <4x4 sparse matrix of type '<class 'numpy.complex128'>'
          with 8 stored elements in Compressed Sparse Row format>
  
  The resulting sparse matrix can be either used directly or transformed into a numpy array:
  
  >>> H_sparse.toarray()
  array([[ 1.+0.j  ,  0.+0.j  ,  0.+0.45j,  0.+0.j  ],
         [ 0.+0.j  , -1.+0.j  ,  0.+0.j  ,  0.-0.45j],
         [ 0.-0.45j,  0.+0.j  , -1.+0.j  ,  0.+0.j  ],
         [ 0.+0.j  ,  0.+0.45j,  0.+0.j  ,  1.+0.j  ]])
code: def sparse_matrix(self, wire_order=None):
      r"""Computes the sparse matrix representation of a Hamiltonian in the computational basis.
  
      Args:
          wire_order (Iterable): global wire order, must contain all wire labels from the operator's wires.
              If not provided, the default order of the wires (self.wires) of the Hamiltonian is used.
  
      Returns:
          csr_matrix: a sparse matrix in scipy Compressed Sparse Row (CSR) format with dimension
          :math:`(2^n, 2^n)`, where :math:`n` is the number of wires
  
      **Example:**
  
      >>> coeffs = [1, -0.45]
      >>> obs = [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliY(0) @ qml.PauliZ(1)]
      >>> H = qml.Hamiltonian(coeffs, obs)
      >>> H_sparse = H.sparse_matrix()
      >>> H_sparse
      <4x4 sparse matrix of type '<class 'numpy.complex128'>'
              with 8 stored elements in Compressed Sparse Row format>
  
      The resulting sparse matrix can be either used directly or transformed into a numpy array:
  
      >>> H_sparse.toarray()
      array([[ 1.+0.j  ,  0.+0.j  ,  0.+0.45j,  0.+0.j  ],
             [ 0.+0.j  , -1.+0.j  ,  0.+0.j  ,  0.-0.45j],
             [ 0.-0.45j,  0.+0.j  , -1.+0.j  ,  0.+0.j  ],
             [ 0.+0.j  ,  0.+0.45j,  0.+0.j  ,  1.+0.j  ]])
      """
      if wire_order is None:
          wires = self.wires
      else:
          wires = wire_order
      n = len(wires)
      matrix = scipy.sparse.csr_matrix(
          (2**n, 2**n), dtype="complex128"
      )
  
      coeffs = qml.math.toarray(self.data)
  
      temp_mats = []
      for coeff, op in zip(coeffs, self.ops):
          obs = []
          for o in qml.operation.Tensor(op).obs:
              if len(o.wires) > 1:
                  # todo: deal with operations created from multi-qubit operations such as Hermitian
                  raise ValueError(
                      f"Can only sparsify Hamiltonians whose constituent observables consist of "
                      f"(tensor products of) single-qubit operators; got {op}."
                  )
              obs.append(o.matrix())
  
          # Array to store the single-wire observables which will be Kronecker producted together
          mat = []
          # i_count tracks the number of consecutive single-wire identity matrices encountered
          # in order to avoid unnecessary Kronecker products, since I_n x I_m = I_{n+m}
          i_count = 0
          for wire_lab in wires:
              if wire_lab in op.wires:
                  if i_count > 0:
                      mat.append(
                          scipy.sparse.eye(2**i_count, format="coo")
                      )
                  i_count = 0
                  idx = op.wires.index(wire_lab)
                  # obs is an array storing the single-wire observables which
                  # make up the full Hamiltonian term
                  sp_obs = scipy.sparse.coo_matrix(obs[idx])
                  mat.append(sp_obs)
              else:
                  i_count += 1
  
          if i_count > 0:
              mat.append(scipy.sparse.eye(2**i_count, format="coo"))
  
          red_mat = (
              functools.reduce(
                  lambda i, j: scipy.sparse.kron(i, j, format="coo"),
                  mat,
              )
              * coeff
          )
  
          temp_mats.append(red_mat.tocsr())
          # Value of 100 arrived at empirically to balance time savings vs memory use. At this point
          # the `temp_mats` are summed into the final result and the temporary storage array is
          # cleared.
          if (len(temp_mats) % 100) == 0:
              matrix += sum(temp_mats)
              temp_mats = []
  
      matrix += sum(temp_mats)
      return matrix
  
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 14 for calling the Hamiltonian obj's underlying member method code with example usage: obj.sparse_matrix(wire_order) and returns: matrix