class_docstr: Normalized Maximum Eigengap based Spectral Clustering (NME-SC)
  uses Eigengap analysis to get an estimated p-value for
  affinity binarization and an estimated number of speakers.
  
  p_value (also referred to as p_neighbors) is for taking
  top p number of affinity values and convert those to 1 while
  convert the rest of values to 0.
  
  p_value can be also tuned on a development set without performing
  NME-analysis. Fixing p_value brings about significantly faster clustering
  speed, but the performance is limited to the development set.
  
  References:
      Tae Jin Park et al., Auto-Tuning Spectral Clustering for Speaker Diarization
      Using Normalized Maximum Eigengap, IEEE Signal Processing Letters 27 (2019),
      https://arxiv.org/abs/2003.02405
  
  Args:
      Please refer to def __init__().
  
  Methods:
      NMEanalysis():
          Performs NME-analysis to estimate p_value and the number of speakers
      subsampleAffinityMat(nme_mat_size):
          Subsamples the number of speakers to reduce the computational load
      getPvalueList():
          Generates a list containing p-values that need to be examined.
      getEigRatio(p_neighbors):
          Calculates g_p, which is a ratio between p_neighbors and the maximum eigengap
      getLamdaGaplist(lambdas):
          Calculates lambda gap values from an array contains lambda values
      estimateNumofSpeakers(affinity_mat):
          Estimates the number of speakers using lambda gap list
class_docstr_tok: ["Normalized","Maximum","Eigengap","based","Spectral","Clustering","(","NME-SC",")","uses","Eigengap","analysis","to","get","an","estimated","p-value","for","affinity","binarization","and","an","estimated","number","of","speakers",".","p_value","(","also","referred","to","as","p_neighbors",")","is","for","taking","top","p","number","of","affinity","values","and","convert","those","to","1","while","convert","the","rest","of","values","to","0.","p_value","can","be","also","tuned","on","a","development","set","without","performing","NME-analysis",".","Fixing","p_value","brings","about","significantly","faster","clustering","speed",",","but","the","performance","is","limited","to","the","development","set",".","References",":","Tae","Jin","Park","et","al.",",","Auto-Tuning","Spectral","Clustering","for","Speaker","Diarization","Using","Normalized","Maximum","Eigengap",",","IEEE","Signal","Processing","Letters","27","(","2019",")",",","https",":","\/\/arxiv.org\/abs\/2003.02405","Args",":","Please","refer","to","def","__init__","(",")",".","Methods",":","NMEanalysis","(",")",":","Performs","NME-analysis","to","estimate","p_value","and","the","number","of","speakers","subsampleAffinityMat","(","nme_mat_size",")",":","Subsamples","the","number","of","speakers","to","reduce","the","computational","load","getPvalueList","(",")",":","Generates","a","list","containing","p-values","that","need","to","be","examined",".","getEigRatio","(","p_neighbors",")",":","Calculates","g_p",",","which","is","a","ratio","between","p_neighbors","and","the","maximum","eigengap","getLamdaGaplist","(","lambdas",")",":","Calculates","lambda","gap","values","from","an","array","contains","lambda","values","estimateNumofSpeakers","(","affinity_mat",")",":","Estimates","the","number","of","speakers","using","lambda","gap","list"]
docstr: Subsample the input matrix to reduce the computational load.
  
  Returns:
      est_num_of_spk (Tensor):
          Estimated number of speakers from NMESC approach
      p_hat_value (Tensor):
          Estimated p-value (determines how many neighboring values to be selected)
code: def forward(self) -> Tuple[torch.Tensor, torch.Tensor]:
      """
      Subsample the input matrix to reduce the computational load.
  
      Returns:
          est_num_of_spk (Tensor):
              Estimated number of speakers from NMESC approach
          p_hat_value (Tensor):
              Estimated p-value (determines how many neighboring values to be selected)
      """
      if self.use_subsampling_for_nme:
          subsample_ratio = self.subsampleAffinityMat(self.nme_mat_size)
      else:
          subsample_ratio = torch.tensor(1)
  
      # Scans p_values and find a p_value that generates the smallest g_p value.
      results: List[torch.Tensor] = []
      est_spk_n_dict: Dict[int, torch.Tensor] = {}
      self.p_value_list = self.getPvalueList()
      p_volume = self.p_value_list.shape[0]
      eig_ratio_list = torch.zeros(
          p_volume,
      )
      est_num_of_spk_list = torch.zeros(
          p_volume,
      )
  
      if self.parallelism:
          futures: List[torch.jit.Future[torch.Tensor]] = []
          for p_idx, p_value in enumerate(self.p_value_list):
              futures.append(torch.jit.fork(self.getEigRatio, p_value))
          for future in futures:
              results.append(torch.jit.wait(future))
  
      else:
          for p_idx, p_value in enumerate(self.p_value_list):
              results.append(self.getEigRatio(p_value))
  
      # Retrieve the eigen analysis results
      for p_idx, p_value in enumerate(self.p_value_list):
          output = results[p_idx]
          g_p, est_num_of_spk = output[0], output[1].int()
          eig_ratio_list[p_idx] = g_p
          est_spk_n_dict[p_value.item()] = est_num_of_spk
          est_num_of_spk_list[p_idx] = est_num_of_spk
  
      index_nn = torch.argmin(eig_ratio_list)
      rp_p_value = self.p_value_list[index_nn]
      affinity_mat = getAffinityGraphMat(self.mat, rp_p_value)
  
      # Checks whether the affinity graph is fully connected.
      # If not, it adds a minimum number of connections to make it fully connected.
      if not isGraphFullyConnected(affinity_mat, device=self.device):
          affinity_mat, rp_p_value = getMinimumConnection(
              self.mat,
              self.max_N,
              self.p_value_list,
              device=self.device,
          )
  
      p_hat_value = (subsample_ratio * rp_p_value).type(torch.int)
      if self.maj_vote_spk_count:
          est_num_of_spk = torch.mode(
              torch.tensor(est_num_of_spk_list)
          )[0]
      else:
          est_num_of_spk = est_spk_n_dict[rp_p_value.item()]
      return est_num_of_spk, p_hat_value
  
imports: from typing import Dict, List, Tuple
  import torch
  from torch.linalg import eigh, eigvalsh
label_desc: Use image node_id 2 for calling the NMESC obj's underlying member method code with example usage: obj.forward() and returns: est_num_of_spk,  p_hat_value