class_docstr: A Solver class for the linear sum assignment (LSA) problem. 
  Designed for torch.jit.script compatibility in NeMo. 
      
  The LSA problem is also referred to as bipartite matching problem. An LSA problem is described 
  by a matrix `cost_mat`, where each cost_mat[i,j] is the cost of matching vertex i of the first partite 
  set (e.g. a "worker") and vertex j of the second set (e.g. a "job"). 
  
  Thus, the goal of LSA-solver is to find a complete assignment of column element to row element with 
  the minimal cost. Note that the solution may not be unique and there could be multiple solutions that 
  yield the same minimal cost.
  
  LSA problem solver is needed for the following tasks in NeMo: 
      - Permutation Invariant Loss (PIL) for diarization model training
      - Label permutation matching for online speaker diarzation 
      - Concatenated minimum-permutation Word Error Rate (cp-WER) calculation 
  
  This implementation is based on the LAP solver from scipy: 
      https://github.com/scipy/scipy/blob/v0.18.1/scipy/optimize/_hungarian.py
      The scipy implementation comes with the following license:
  
      Copyright (c) 2008 Brian M. Clapper <bmc@clapper.org>, Gael Varoquaux
      Author: Brian M. Clapper, Gael Varoquaux
      License: 3-clause BSD
  
  References
      1. http://csclab.murraystate.edu/bob.pilgrim/445/munkres.html
      2. https://en.wikipedia.org/wiki/Hungarian_algorithm
      3. https://github.com/scipy/scipy/blob/v0.18.1/scipy/optimize/_hungarian.py
  
  
  Attributes:
      cost_mat (Tensor): 2D matrix containing cost matrix. Number of columns must be larger than number of rows.
      row_uncovered (Tensor): 1D matrix containing boolean values indicating whether a row is covered.
      col_uncovered (Tensor): 1D matrix containing boolean values indicating whether a column is covered.
      zero_row (Tensor): 1D matrix containing the row index of the last zero found.
      zero_col (Tensor): 1D matrix containing the column index of the last zero found.
      path (Tensor): 2D matrix containing the path taken through the matrix.
      marked (Tensor): 2D matrix containing the marked zeros.
class_docstr_tok: ["A","Solver","class","for","the","linear","sum","assignment","(","LSA",")","problem",".","Designed","for","torch.jit.script","compatibility","in","NeMo",".","The","LSA","problem","is","also","referred","to","as","bipartite","matching","problem",".","An","LSA","problem","is","described","by","a","matrix","`","cost_mat","`",",","where","each","cost_mat","[","i",",","j","]","is","the","cost","of","matching","vertex","i","of","the","first","partite","set","(","e.g",".","a","``","worker","''",")","and","vertex","j","of","the","second","set","(","e.g",".","a","``","job","''",")",".","Thus",",","the","goal","of","LSA-solver","is","to","find","a","complete","assignment","of","column","element","to","row","element","with","the","minimal","cost",".","Note","that","the","solution","may","not","be","unique","and","there","could","be","multiple","solutions","that","yield","the","same","minimal","cost",".","LSA","problem","solver","is","needed","for","the","following","tasks","in","NeMo",":","-","Permutation","Invariant","Loss","(","PIL",")","for","diarization","model","training","-","Label","permutation","matching","for","online","speaker","diarzation","-","Concatenated","minimum-permutation","Word","Error","Rate","(","cp-WER",")","calculation","This","implementation","is","based","on","the","LAP","solver","from","scipy",":","https",":","\/\/github.com\/scipy\/scipy\/blob\/v0.18.1\/scipy\/optimize\/_hungarian.py","The","scipy","implementation","comes","with","the","following","license",":","Copyright","(","c",")","2008","Brian","M.","Clapper","<","bmc","@","clapper.org",">",",","Gael","Varoquaux","Author",":","Brian","M.","Clapper",",","Gael","Varoquaux","License",":","3-clause","BSD","References","1.","http",":","\/\/csclab.murraystate.edu\/bob.pilgrim\/445\/munkres.html","2.","https",":","\/\/en.wikipedia.org\/wiki\/Hungarian_algorithm","3.","https",":","\/\/github.com\/scipy\/scipy\/blob\/v0.18.1\/scipy\/optimize\/_hungarian.py","Attributes",":","cost_mat","(","Tensor",")",":","2D","matrix","containing","cost","matrix",".","Number","of","columns","must","be","larger","than","number","of","rows",".","row_uncovered","(","Tensor",")",":","1D","matrix","containing","boolean","values","indicating","whether","a","row","is","covered",".","col_uncovered","(","Tensor",")",":","1D","matrix","containing","boolean","values","indicating","whether","a","column","is","covered",".","zero_row","(","Tensor",")",":","1D","matrix","containing","the","row","index","of","the","last","zero","found",".","zero_col","(","Tensor",")",":","1D","matrix","containing","the","column","index","of","the","last","zero","found",".","path","(","Tensor",")",":","2D","matrix","containing","the","path","taken","through","the","matrix",".","marked","(","Tensor",")",":","2D","matrix","containing","the","marked","zeros","."]
docstr: Step 4
  
  Goal: Cover all columns containing a marked zero.
  
  Procedure:
  - Find a non-covered zero and put a prime mark on it. 
      - If there is no marked zero in the row containing this primed zero, Go to Step 5.
      - Otherwise, cover this row and uncover the column containing the marked zero. 
  - Continue in this manner until there are no uncovered zeros left. 
  - Save the smallest uncovered value.
  - Go to Step 6.
docstr_tok: ["Step","4","Goal",":","Cover","all","columns","containing","a","marked","zero",".","Procedure",":","-","Find","a","non-covered","zero","and","put","a","prime","mark","on","it",".","-","If","there","is","no","marked","zero","in","the","row","containing","this","primed","zero",",","Go","to","Step","5",".","-","Otherwise",",","cover","this","row","and","uncover","the","column","containing","the","marked","zero",".","-","Continue","in","this","manner","until","there","are","no","uncovered","zeros","left",".","-","Save","the","smallest","uncovered","value",".","-","Go","to","Step","6","."]
code: def _step4(self, bypass: bool = False) -> int:
      """
      Step 4
  
      Goal: Cover all columns containing a marked zero.
  
      Procedure:
      - Find a non-covered zero and put a prime mark on it.
          - If there is no marked zero in the row containing this primed zero, Go to Step 5.
          - Otherwise, cover this row and uncover the column containing the marked zero.
      - Continue in this manner until there are no uncovered zeros left.
      - Save the smallest uncovered value.
      - Go to Step 6.
      """
      # We convert to int as numpy operations are faster on int
      cost_mat = (self.cost_mat == 0).int()
      covered_cost_mat = cost_mat * self.row_uncovered.unsqueeze(1)
      covered_cost_mat *= self.col_uncovered.long()
      row_len, col_len = self.cost_mat.shape
      if not bypass:
          while True:
              urv = unravel_index(
                  torch.argmax(covered_cost_mat).item(),
                  torch.tensor([col_len, row_len]),
              )
              row, col = int(urv[0].item()), int(urv[1].item())
              if covered_cost_mat[row, col] == 0:
                  return 6
              else:
                  self.marked[
                      row, col
                  ] = 2  # Find the first marked element in the row
                  mark_col = torch.argmax((self.marked[row] == 1).int())
                  if (
                      self.marked[row, mark_col] != 1
                  ):  # No marked element in the row
                      self.zero_row = torch.tensor(row)
                      self.zero_col = torch.tensor(col)
                      return 5
                  else:
                      col = mark_col
                      self.row_uncovered[row] = False
                      self.col_uncovered[col] = True
                      covered_cost_mat[:, col] = (
                          cost_mat[:, col] * self.row_uncovered
                      )
                      covered_cost_mat[row] = 0
      return 0
  
file_path: NeMo/nemo/collections/asr/parts/utils/optimization_utils.py
imports: import torch
label_desc: Use image node_id 6 for calling the LinearSumAssignmentSolver obj's underlying member method code with example usage: obj._step4(bypass) and returns: int, int, int