class_docstr: Online clustering method for speaker diarization based on cosine similarity.
  
  Regular Clustering Attributes:
  
      max_num_speakers (int):
          The upper bound for the number of speakers in each session
      max_rp_threshold (float):
          Limits the range of parameter search.
          Clustering performance can vary depending on this range.
          Default is 0.15.
      enhanced_count_thres (int):
          For the short audio recordings, clustering algorithm cannot
          accumulate enough amount of speaker profile for each cluster.
          Thus, function `getEnhancedSpeakerCount` employs anchor embeddings
          (dummy representations) to mitigate the effect of cluster sparsity.
          enhanced_count_thres = 40 is recommended.
      sparse_search_volume (int):
          Number of p_values we search during NME analysis.
          Default is 30. The lower the value, the faster NME-analysis becomes.
          Lower than 20 might cause a poor parameter estimation.
      fixed_thres (float):
          A fixed threshold for finding p-closest neighbors in affinity matrix for clustering.
          If fixed_thres value is provided, NME-analysis process will be skipped.
          This value should be optimized on a development set to obtain a quality result.
          Default is None and performs NME-analysis to estimate the threshold.
      min_samples_for_nmesc (int):
          The minimum number of samples required for NME clustering. This avoids
          zero p_neighbour_lists. If the input has fewer segments than min_samples,
          it is directed to the enhanced speaker counting mode.
      sparse_search (bool):
          Toggle sparse search mode. If True, limit the size of p_value_list to sparse_search_volume.
      cuda (bool):
          Use cuda for Eigen decomposition if cuda=True.
  
  Additional Online Processing Attributes:
  
      history_buffer_size (int):
          - This is a buffer where diarization history is saved in the form of averaged speaker embedding vector.
          - The values in [50, 200] range is recommended while the system requires bigger buffer size for
            sessions with larger number of speakers.
      current_buffer_size (int):
          - This is a buffer which process the most recent speaker embedding vector inputs.
            current-buffer is first-in-first-out (FIFO) queue where the embeddings accepted earlier
            get to merged and saved to history buffer.
          - In general, [50, 200] range is recommended and the performance can be sensitive on this buffer size.
      min_spk_counting_buffer_size (int):
          Integer number for speaker counting buffer. Number of speakers are estimated through a small buffer
          and the number is obtained by taking majority vote.
      min_frame_per_spk (int):
          Below this number, the system considers the whole input segments as a single speaker.
      p_update_freq (int):
          Frequency (interval) of updating p_value for NMESC algorithm.
      p_value_skip_frame_thres (int):
          After `frame_index` passes this number, `p_value` estimation is skipped for inference speed
      p_value_queue_size (int):
          `p_value` buffer for major voting
      use_temporal_label_major_vote (bool):
          Boolean that determines whether to use temporal majorvoting for the final speaker labels
      temporal_label_major_vote_buffer_size (int):
          Buffer size for major-voting the
      num_spk_stat (list):
          List of number of speakers for major voting. Number of speakers are estimated through 
          majority voting of `self.num_spk_stat` list.
      p_value_hist (list):
          List of p_values for major voting.
          To save the computation time, p_value is estimated every `p_update_freq` frames and
          saved to `self.p_value_hist`.
  
  Attributes for counters and buffers in streaming system:
      
      is_online (bool):
          - If self.is_online is False:
              FIFO queue does not push out any speaker embedding vector
          - If self.is_online is True:
              FIFO queue starts push out speaker embedding vectors and saving them into
              history buffer.
      max_embed_count (int):
          The maximum number of segments the streaming system has ever seen.
          This value keeps increasing as the system processes more and more segments.
      memory_margin (int):
          The margin that is added to keep the segmentation data in the streaming system
      minimum_segments_per_buffer (int):
          Maximum number of embedding vectors kept in history buffer per speaker.
          Example:
              history_buffer_size (history_n) = 100
              max_num_speakers = 4
              minimum_segments_per_buffer = 25
      history_buffer_seg_end (int):
          Index that indicates the boundary between history embedding sets and current processing buffer
          when history embedding vectors and current input embedding vectors are concatenated into a
          single matrix.
  
  Attributes for history buffer:
  
      history_embedding_buffer_emb (Tensor)
          Tensor containing speaker embedding vectors for saving the history of the previous
          speaker profile in the given audio session
      history_embedding_buffer_label (Tensor)
          Speaker label (cluster label) for embedding vectors saved in the history buffer
      Y_fullhist (Tensor)
          Tensor containing the speaker label hypothesis from start to current frame
class_docstr_tok: ["Online","clustering","method","for","speaker","diarization","based","on","cosine","similarity",".","Regular","Clustering","Attributes",":","max_num_speakers","(","int",")",":","The","upper","bound","for","the","number","of","speakers","in","each","session","max_rp_threshold","(","float",")",":","Limits","the","range","of","parameter","search",".","Clustering","performance","can","vary","depending","on","this","range",".","Default","is","0.15.","enhanced_count_thres","(","int",")",":","For","the","short","audio","recordings",",","clustering","algorithm","can","not","accumulate","enough","amount","of","speaker","profile","for","each","cluster",".","Thus",",","function","`","getEnhancedSpeakerCount","`","employs","anchor","embeddings","(","dummy","representations",")","to","mitigate","the","effect","of","cluster","sparsity",".","enhanced_count_thres","=","40","is","recommended",".","sparse_search_volume","(","int",")",":","Number","of","p_values","we","search","during","NME","analysis",".","Default","is","30",".","The","lower","the","value",",","the","faster","NME-analysis","becomes",".","Lower","than","20","might","cause","a","poor","parameter","estimation",".","fixed_thres","(","float",")",":","A","fixed","threshold","for","finding","p-closest","neighbors","in","affinity","matrix","for","clustering",".","If","fixed_thres","value","is","provided",",","NME-analysis","process","will","be","skipped",".","This","value","should","be","optimized","on","a","development","set","to","obtain","a","quality","result",".","Default","is","None","and","performs","NME-analysis","to","estimate","the","threshold",".","min_samples_for_nmesc","(","int",")",":","The","minimum","number","of","samples","required","for","NME","clustering",".","This","avoids","zero","p_neighbour_lists",".","If","the","input","has","fewer","segments","than","min_samples",",","it","is","directed","to","the","enhanced","speaker","counting","mode",".","sparse_search","(","bool",")",":","Toggle","sparse","search","mode",".","If","True",",","limit","the","size","of","p_value_list","to","sparse_search_volume",".","cuda","(","bool",")",":","Use","cuda","for","Eigen","decomposition","if","cuda=True",".","Additional","Online","Processing","Attributes",":","history_buffer_size","(","int",")",":","-","This","is","a","buffer","where","diarization","history","is","saved","in","the","form","of","averaged","speaker","embedding","vector",".","-","The","values","in","[","50",",","200","]","range","is","recommended","while","the","system","requires","bigger","buffer","size","for","sessions","with","larger","number","of","speakers",".","current_buffer_size","(","int",")",":","-","This","is","a","buffer","which","process","the","most","recent","speaker","embedding","vector","inputs",".","current-buffer","is","first-in-first-out","(","FIFO",")","queue","where","the","embeddings","accepted","earlier","get","to","merged","and","saved","to","history","buffer",".","-","In","general",",","[","50",",","200","]","range","is","recommended","and","the","performance","can","be","sensitive","on","this","buffer","size",".","min_spk_counting_buffer_size","(","int",")",":","Integer","number","for","speaker","counting","buffer",".","Number","of","speakers","are","estimated","through","a","small","buffer","and","the","number","is","obtained","by","taking","majority","vote",".","min_frame_per_spk","(","int",")",":","Below","this","number",",","the","system","considers","the","whole","input","segments","as","a","single","speaker",".","p_update_freq","(","int",")",":","Frequency","(","interval",")","of","updating","p_value","for","NMESC","algorithm",".","p_value_skip_frame_thres","(","int",")",":","After","`","frame_index","`","passes","this","number",",","`","p_value","`","estimation","is","skipped","for","inference","speed","p_value_queue_size","(","int",")",":","`","p_value","`","buffer","for","major","voting","use_temporal_label_major_vote","(","bool",")",":","Boolean","that","determines","whether","to","use","temporal","majorvoting","for","the","final","speaker","labels","temporal_label_major_vote_buffer_size","(","int",")",":","Buffer","size","for","major-voting","the","num_spk_stat","(","list",")",":","List","of","number","of","speakers","for","major","voting",".","Number","of","speakers","are","estimated","through","majority","voting","of","`","self.num_spk_stat","`","list",".","p_value_hist","(","list",")",":","List","of","p_values","for","major","voting",".","To","save","the","computation","time",",","p_value","is","estimated","every","`","p_update_freq","`","frames","and","saved","to","`","self.p_value_hist","`",".","Attributes","for","counters","and","buffers","in","streaming","system",":","is_online","(","bool",")",":","-","If","self.is_online","is","False",":","FIFO","queue","does","not","push","out","any","speaker","embedding","vector","-","If","self.is_online","is","True",":","FIFO","queue","starts","push","out","speaker","embedding","vectors","and","saving","them","into","history","buffer",".","max_embed_count","(","int",")",":","The","maximum","number","of","segments","the","streaming","system","has","ever","seen",".","This","value","keeps","increasing","as","the","system","processes","more","and","more","segments",".","memory_margin","(","int",")",":","The","margin","that","is","added","to","keep","the","segmentation","data","in","the","streaming","system","minimum_segments_per_buffer","(","int",")",":","Maximum","number","of","embedding","vectors","kept","in","history","buffer","per","speaker",".","Example",":","history_buffer_size","(","history_n",")","=","100","max_num_speakers","=","4","minimum_segments_per_buffer","=","25","history_buffer_seg_end","(","int",")",":","Index","that","indicates","the","boundary","between","history","embedding","sets","and","current","processing","buffer","when","history","embedding","vectors","and","current","input","embedding","vectors","are","concatenated","into","a","single","matrix",".","Attributes","for","history","buffer",":","history_embedding_buffer_emb","(","Tensor",")","Tensor","containing","speaker","embedding","vectors","for","saving","the","history","of","the","previous","speaker","profile","in","the","given","audio","session","history_embedding_buffer_label","(","Tensor",")","Speaker","label","(","cluster","label",")","for","embedding","vectors","saved","in","the","history","buffer","Y_fullhist","(","Tensor",")","Tensor","containing","the","speaker","label","hypothesis","from","start","to","current","frame"]
docstr: This function performs the following tasks:
      1. Decide whether to extract more embeddings or not (by setting `is_update`)
  (Only if we need update):
      2. Calculate how many embeddings should be updated (set `new_emb_n` variable)
      3. Update history embedding vectors and save it to `pre_embs`.
  
  We only save the index and clustering label of each embedding.
  
  - Case-1: The very first step
      This else statement is for the very first diarization loop.
      This is the very first reduction frame.
  
  - Case-2: Number of embedding vectors is increased, therefore we need to update.
      Since there are new embeddings, we push the same amount (new_emb_n)
      of old embeddings to the history buffer.
      We should also update self.history_buffer_seg_end which is a pointer.
          update to history emb: emb_in[emb_idx_stt:emb_idx_end]
          update to history label: self.Y_fullhist[label_stt:_end]
  
  - Case-3: Number of embedding vectors is decreased
      If the number of embeddings is decreased compared to the last trial,
      then skip embedding merging.
  
  Variables:
      hist_curr_boundary (int):
          The current boundary of between history buffer and current buffer.
          This is the new history-current buffer boundary while self.history_buffer_seg_end is the old one.
          Thus, the new set of embedding vectors are collected from 
          `label_stt=self.hist_buffer_seg_end` to `label_end=hist_curr_boundary`.
      total_segments_processed_count (int):
          The number of segments that are processed so far in integer format.
  
  Args:
      emb_in (Tensor):
          Tensor containing embedding vectors
          Dimensions: (number of embedding vectors) x (embedding dimension)
      segment_indexes_matrix (Tensor):
          Tensor containing unique segment (embedding vector) index
  
  Returns:
      is_update (bool):
          Boolean indicates whether to update speaker embedding vectors.
      new_emb_n (int):
          The amount of embedding vectors that are exceeding FIFO queue size.
          new_emb_n is also an amount of embedding vectors that needs to be merged in history buffer.
      pre_embs (Tensor):
          Embedding vector matrix before merging.
          The subset of `pre_embs` embedding vectors will be merged.
          Dimensions: (number of embedding vectors) x (embedding dimension)
      pre_clus_labels (Tensor):
          A set of clustering labels for each embedding vector in `pre_embs`.
docstr_tok: ["This","function","performs","the","following","tasks",":","1",".","Decide","whether","to","extract","more","embeddings","or","not","(","by","setting","`","is_update","`",")","(","Only","if","we","need","update",")",":","2",".","Calculate","how","many","embeddings","should","be","updated","(","set","`","new_emb_n","`","variable",")","3",".","Update","history","embedding","vectors","and","save","it","to","`","pre_embs","`",".","We","only","save","the","index","and","clustering","label","of","each","embedding",".","-","Case-1",":","The","very","first","step","This","else","statement","is","for","the","very","first","diarization","loop",".","This","is","the","very","first","reduction","frame",".","-","Case-2",":","Number","of","embedding","vectors","is","increased",",","therefore","we","need","to","update",".","Since","there","are","new","embeddings",",","we","push","the","same","amount","(","new_emb_n",")","of","old","embeddings","to","the","history","buffer",".","We","should","also","update","self.history_buffer_seg_end","which","is","a","pointer",".","update","to","history","emb",":","emb_in","[","emb_idx_stt",":","emb_idx_end","]","update","to","history","label",":","self.Y_fullhist","[","label_stt",":","_end","]","-","Case-3",":","Number","of","embedding","vectors","is","decreased","If","the","number","of","embeddings","is","decreased","compared","to","the","last","trial",",","then","skip","embedding","merging",".","Variables",":","hist_curr_boundary","(","int",")",":","The","current","boundary","of","between","history","buffer","and","current","buffer",".","This","is","the","new","history-current","buffer","boundary","while","self.history_buffer_seg_end","is","the","old","one",".","Thus",",","the","new","set","of","embedding","vectors","are","collected","from","`","label_stt=self.hist_buffer_seg_end","`","to","`","label_end=hist_curr_boundary","`",".","total_segments_processed_count","(","int",")",":","The","number","of","segments","that","are","processed","so","far","in","integer","format",".","Args",":","emb_in","(","Tensor",")",":","Tensor","containing","embedding","vectors","Dimensions",":","(","number","of","embedding","vectors",")","x","(","embedding","dimension",")","segment_indexes_matrix","(","Tensor",")",":","Tensor","containing","unique","segment","(","embedding","vector",")","index","Returns",":","is_update","(","bool",")",":","Boolean","indicates","whether","to","update","speaker","embedding","vectors",".","new_emb_n","(","int",")",":","The","amount","of","embedding","vectors","that","are","exceeding","FIFO","queue","size",".","new_emb_n","is","also","an","amount","of","embedding","vectors","that","needs","to","be","merged","in","history","buffer",".","pre_embs","(","Tensor",")",":","Embedding","vector","matrix","before","merging",".","The","subset","of","`","pre_embs","`","embedding","vectors","will","be","merged",".","Dimensions",":","(","number","of","embedding","vectors",")","x","(","embedding","dimension",")","pre_clus_labels","(","Tensor",")",":","A","set","of","clustering","labels","for","each","embedding","vector","in","`","pre_embs","`","."]
code: def prepare_embedding_update(
      self, emb_in: torch.Tensor, segment_indexes_matrix: torch.Tensor
  ) -> Tuple[bool, int, torch.Tensor, torch.Tensor]:
      """
      This function performs the following tasks:
          1. Decide whether to extract more embeddings or not (by setting `is_update`)
      (Only if we need update):
          2. Calculate how many embeddings should be updated (set `new_emb_n` variable)
          3. Update history embedding vectors and save it to `pre_embs`.
  
      We only save the index and clustering label of each embedding.
  
      - Case-1: The very first step
          This else statement is for the very first diarization loop.
          This is the very first reduction frame.
  
      - Case-2: Number of embedding vectors is increased, therefore we need to update.
          Since there are new embeddings, we push the same amount (new_emb_n)
          of old embeddings to the history buffer.
          We should also update self.history_buffer_seg_end which is a pointer.
              update to history emb: emb_in[emb_idx_stt:emb_idx_end]
              update to history label: self.Y_fullhist[label_stt:_end]
  
      - Case-3: Number of embedding vectors is decreased
          If the number of embeddings is decreased compared to the last trial,
          then skip embedding merging.
  
      Variables:
          hist_curr_boundary (int):
              The current boundary of between history buffer and current buffer.
              This is the new history-current buffer boundary while self.history_buffer_seg_end is the old one.
              Thus, the new set of embedding vectors are collected from
              `label_stt=self.hist_buffer_seg_end` to `label_end=hist_curr_boundary`.
          total_segments_processed_count (int):
              The number of segments that are processed so far in integer format.
  
      Args:
          emb_in (Tensor):
              Tensor containing embedding vectors
              Dimensions: (number of embedding vectors) x (embedding dimension)
          segment_indexes_matrix (Tensor):
              Tensor containing unique segment (embedding vector) index
  
      Returns:
          is_update (bool):
              Boolean indicates whether to update speaker embedding vectors.
          new_emb_n (int):
              The amount of embedding vectors that are exceeding FIFO queue size.
              new_emb_n is also an amount of embedding vectors that needs to be merged in history buffer.
          pre_embs (Tensor):
              Embedding vector matrix before merging.
              The subset of `pre_embs` embedding vectors will be merged.
              Dimensions: (number of embedding vectors) x (embedding dimension)
          pre_clus_labels (Tensor):
              A set of clustering labels for each embedding vector in `pre_embs`.
      """
      total_segments_processed_count = int(
          segment_indexes_matrix[-1] + 1
      )
      hist_curr_boundary = int(
          total_segments_processed_count - self.current_n
      )
      new_emb_n: int = 0
      pre_embs: torch.Tensor = torch.empty(0)
      pre_clus_labels: torch.Tensor = torch.empty(0)
      is_update = True
  
      if total_segments_processed_count > self.max_embed_count:
          # Case-1: The very first step
          if len(self.history_embedding_buffer_emb) == 0:
              new_emb_n = total_segments_processed_count - (
                  self.current_n + self.history_n
              )
              hist_curr_boundary_emb_idx = get_first_arg_index(
                  segment_indexes_matrix, hist_curr_boundary
              )
              pre_embs = emb_in[:hist_curr_boundary_emb_idx]
              pre_clus_labels = self.Y_fullhist[:hist_curr_boundary]
  
          # Case-2: Number of embedding vectors is increased, need to update history and its label
          else:
              # Calculate the number of new embedding vectors: `new_emb_n`
              label_stt, label_end = (
                  self.history_buffer_seg_end,
                  hist_curr_boundary,
              )
              new_emb_n = label_end - label_stt
              # Add embedding vectors to `pre_embs` so that we can merge it with reducer function.
              emb_idx_stt = int(
                  get_first_arg_index(segment_indexes_matrix, label_stt)
              )
              emb_idx_end = int(
                  get_first_arg_index(segment_indexes_matrix, label_end)
              )
              pre_embs = torch.vstack(
                  (
                      self.history_embedding_buffer_emb,
                      emb_in[emb_idx_stt:emb_idx_end],
                  )
              )
              # Update labels for `pre_embs`
              pre_clus_labels = torch.hstack(
                  (
                      self.history_embedding_buffer_label,
                      self.Y_fullhist[label_stt:label_end],
                  )
              )
  
          if new_emb_n > self.current_n:
              raise ValueError(
                  "new_emb_n should be less than or equal to current buffer size (self.current_n)."
                  f" Getting too many segments: {new_emb_n} for the given current buffer size {self.current_n}."
                  " Please either (1) increase buffer size or (2) use longer segment lengths to get less number of segments."
              )
          elif new_emb_n <= 0:
              raise ValueError(
                  "Segment counting error. `new_emb_n` should be a positve integer number."
              )
          if pre_embs.shape[0] != pre_clus_labels.shape[0]:
              raise ValueError(
                  "`pre_embs` and `pre_clus_labels` should have the same length, "
                  f"but got {pre_embs.shape[0]} and {pre_clus_labels.shape[0]} respectively."
              )
  
      # Case-3: Number of embedding vectors is not increased.
      else:
          # There will be no embedding update, so new_emb_n is 0, pre_embs and pre_clus_labels are empty.
          is_update = False
  
      # Update the history buffer index for the next step
      self.history_buffer_seg_end = hist_curr_boundary
      self.max_embed_count = max(
          total_segments_processed_count, self.max_embed_count
      )
      return is_update, new_emb_n, pre_embs, pre_clus_labels
  
imports: from typing import List, Tuple
  import torch
  from nemo.collections.asr.parts.utils.offline_clustering import NMESC, SpeakerClustering, SpectralClustering, get_scale_interpolated_embs, getAffinityGraphMat, getCosAffinityMatrix, split_input_data
  from nemo.collections.asr.parts.utils.optimization_utils import linear_sum_assignment
label_desc: Use image node_id 6 for calling the OnlineSpeakerClustering obj's underlying member method code with example usage: obj.prepare_embedding_update(emb_in, segment_indexes_matrix) and returns: is_update,  new_emb_n,  pre_embs,  pre_clus_labels