code: def HEM(W, levels, rid=None):
      """
      Coarsen a graph multiple times using the Heavy Edge Matching (HEM).
      Input
      W: symmetric sparse weight (adjacency) matrix
      levels: the number of coarsened graphs
      Output
      graph[0]: original graph of size N_1
      graph[2]: coarser graph of size N_2 < N_1
      graph[levels]: coarsest graph of Size N_levels < ... < N_2 < N_1
      parents[i] is a vector of size N_i with entries ranging from 1 to N_{i+1}
          which indicate the parents in the coarser graph[i+1]
      nd_sz{i} is a vector of size N_i that contains the size of the supernode in the graph{i}
      Note
      if "graph" is a list of length k, then "parents" will be a list of length k-1
      """
  
      N, N = W.shape
  
      if rid is None:
          rid = np.random.permutation(range(N))
  
      ss = np.array(W.sum(axis=0)).squeeze()
      rid = np.argsort(ss)
  
      parents = []
      degree = W.sum(axis=0) - W.diagonal()
      graphs = []
      graphs.append(W)
  
      print("Heavy Edge Matching coarsening with Xavier version")
  
      for _ in range(levels):
          # CHOOSE THE WEIGHTS FOR THE PAIRING
          # weights = ones(N,1)       # metis weights
          weights = degree  # graclus weights
          # weights = supernode_size  # other possibility
          weights = np.array(weights).squeeze()
  
          # PAIR THE VERTICES AND CONSTRUCT THE ROOT VECTOR
          idx_row, idx_col, val = scipy.sparse.find(W)
          cc = idx_row
          rr = idx_col
          vv = val
  
          # TO BE SPEEDUP
          if not (list(cc) == list(np.sort(cc))):
              tmp = cc
              cc = rr
              rr = tmp
  
          cluster_id = HEM_one_level(
              cc, rr, vv, rid, weights
          )  # cc is ordered
          parents.append(cluster_id)
  
          # COMPUTE THE EDGES WEIGHTS FOR THE NEW GRAPH
          nrr = cluster_id[rr]
          ncc = cluster_id[cc]
          nvv = vv
          Nnew = cluster_id.max() + 1
          # CSR is more appropriate: row,val pairs appear multiple times
          W = scipy.sparse.csr_matrix(
              (nvv, (nrr, ncc)), shape=(Nnew, Nnew)
          )
          W.eliminate_zeros()
  
          # Add new graph to the list of all coarsened graphs
          graphs.append(W)
          N, N = W.shape
  
          # COMPUTE THE DEGREE (OMIT OR NOT SELF LOOPS)
          degree = W.sum(axis=0)
          # degree = W.sum(axis=0) - W.diagonal()
  
          # CHOOSE THE ORDER IN WHICH VERTICES WILL BE VISTED AT THE NEXT PASS
          # [~, rid]=sort(ss);     # arthur strategy
          # [~, rid]=sort(supernode_size);    #  thomas strategy
          # rid=randperm(N);                  #  metis/graclus strategy
          ss = np.array(W.sum(axis=0)).squeeze()
          rid = np.argsort(ss)
  
      return graphs, parents
  
file_path: dgl/examples/pytorch/model_zoo/geometric/coarsening.py
imports: import numpy
  import scipy.sparse
  import sklearn.metrics
label_desc: Use image node_id 5 for calling a global function with example usage: HEM(W, levels, rid) and returns: graphs,  parents