docs: def normalized_hypergraph_cut(H, threshold=0):
      """Executes the min-cut algorithm described in the paper:
      Zhou, Dengyong, Jiayuan Huang, and Bernhard Scholkopf.
      "Learning with hypergraphs: Clustering, classification, and embedding."
      Advances in neural information processing systems. 2006.
      (http://machinelearning.wustl.edu/mlpapers/paper_files/NIPS2006_630.pdf)
  
      This algorithm uses the normalized Laplacian to partition the hypergraph
      into two disjoint components.
  
      :param H: the hypergraph to perform the hypergraph-cut algorithm on.
      :param threshold: The threshold value for the partitioning algorithm.
                      Typically, the value zero is selected for this purpose.
      :returns: set -- the S set of nodes in the S-T partition
                set -- the T set of nodes in the S-T partition
      :raises: TypeError -- Algorithm only applicable to undirected hypergraphs
  
      """
      if not isinstance(H, UndirectedHypergraph):
          raise TypeError("Algorithm only applicable to undirected hypergraphs")
  
      # TODO: make sure that the hypergraph is connected
  
      # Get index<->node mappings and index<->hyperedge_id mappings for matrices
      indices_to_nodes, nodes_to_indices = \
          umat.get_node_mapping(H)
      indices_to_hyperedge_ids, hyperedge_ids_to_indices = \
          umat.get_hyperedge_id_mapping(H)
  
      delta = _compute_normalized_laplacian(H,
                                            nodes_to_indices,
                                            hyperedge_ids_to_indices)
  
      # Since the eigs method in sparse.linalg library doesn't find
      # all the eigenvalues and eigenvectors, it doesn't give us an
      # exact and correct solution. Therefore, we should use the
      # numpy library which works on dense graphs. This might be
      # problematic for large graphs.
      # New note: I think we only need the 2 smallest eigenvalues, which
      # can be found with the sparse solver. Look into this if run-time
      # becomes an issue.
  
      # eigenvalues,eigenvectors = linalg.eigs(delta,k=numberOfEigenValues)
      eigenvalues, eigenvectors = np.linalg.eig(delta.todense())
  
      second_min_index = np.argsort(eigenvalues)[1]
      second_eigenvector = eigenvectors[:, second_min_index]
      partition_index = [i for i in range(len(second_eigenvector))
                         if second_eigenvector[i] >= threshold]
  
      S, T = set(), set()
      for key, value in nodes_to_indices.items():
          if value in partition_index:
              S.add(key)
          else:
              T.add(key)
  
      return S, T