class_docstr: Class for computation puncutation-related absolute amounts of operations and thier rates
  between reference and hypothesis strings:
      - Absolute amounts of correct predictions, deletions, insertions
      and substitutions for each given punctuation mark
      - Rates of correct predictions, deletions, insertions
      and substitutions for each given punctuation mark
      - Overall rates of correct predictions, deletions, insertions
      and substiturions between reference and hypothesis string
      - Punctuation Error Rate
  
  Args to init:
      punctuation_marks (list[str]) - list of punctuation marks for computing metrics
      punctuation_mask (str, by default "[PUNCT]") - mask token that will be applied to
      given punctuation marks while edit distance calculation 
  
  How to use:
      1. Create object of OccurancePunctuationErrorRate class.
         Example:
              punctuation_marks = [".", ",", "!", "?"]
              oper_obj = OccurancePunctuationErrorRate(punctuation_marks)
      
      2. To compute punctuation metrics, pass reference and hypothesis string to the "compute" method
      of created object.
          Example:
              reference_str = "Hi, dear! Nice to see you. What's"
              hypothesis_str = "Hi dear! Nice to see you! What's?"
              oper_obj.compute(reference_str, hypothesis_str)
  
  Output (listed in order of output):
      1. Dict of absolute operations amounts for each given punctuation mark:
          Example:
          {'.': {'Correct': 0, 'Deletions': 0, 'Insertions': 0, 'Substitutions': 1},
           ',': {'Correct': 0, 'Deletions': 1, 'Insertions': 0, 'Substitutions': 0},
           '!': {'Correct': 1, 'Deletions': 0, 'Insertions': 0, 'Substitutions': 0},
           '?': {'Correct': 0, 'Deletions': 0, 'Insertions': 1, 'Substitutions': 0}}
            
      2. Dict of substitutions absolute amounts between given punctuation marks:
          Example:
          {'.': {'.': 0, ',': 0, '!': 1, '?': 0},
           ',': {'.': 0, ',': 0, '!': 0, '?': 0},
           '!': {'.': 0, ',': 0, '!': 0, '?': 0},
           '?': {'.': 0, ',': 0, '!': 0, '?': 0}}
          
      3. namedtuple "PunctuationRates" of punctuation operation rates (in range from 0 to 1):
          3.1. correct_rate - overall correct rate 
              Example: correct_rate=0.25
          3.2. deletions_rate - overall deletions rate
              Example: deletions_rate=0.25
          3.3. insertions_rate - overall insertions rate
              Example: insertions_rate=0.25
          3.4. substitutions_rate - overall substitutions_rate
              Example: substitutions_rate=0.25
          3.5. punct_er - Punctuation Error Rate
              Example: punct_er=0.75
          3.6. operation_rates - dict of operations rates for each given punctuation mark
              Example: 
              operation_rates={
                  '.': {'Correct': 0.0, 'Deletions': 0.0, 'Insertions': 0.0, 'Substitutions': 1.0},
                  ',': {'Correct': 0.0, 'Deletions': 1.0, 'Insertions': 0.0, 'Substitutions': 0.0},
                  '!': {'Correct': 1.0, 'Deletions': 0.0, 'Insertions': 0.0, 'Substitutions': 0.0},
                  '?': {'Correct': 0.0, 'Deletions': 0.0, 'Insertions': 1.0, 'Substitutions': 0.0}
                  }
  
          3.7. substitution_rates - dict of substitution rates for each given punctuation mark
              Example:
              substitution_rates={
                  '.': {'.': 0.0, ',': 0.0, '!': 1.0, '?': 0.0},
                  ',': {'.': 0.0, ',': 0.0, '!': 0.0, '?': 0.0},
                  '!': {'.': 0.0, ',': 0.0, '!': 0.0, '?': 0.0},
                  '?': {'.': 0.0, ',': 0.0, '!': 0.0, '?': 0.0}
                  }
class_docstr_tok: ["Class","for","computation","puncutation-related","absolute","amounts","of","operations","and","thier","rates","between","reference","and","hypothesis","strings",":","-","Absolute","amounts","of","correct","predictions",",","deletions",",","insertions","and","substitutions","for","each","given","punctuation","mark","-","Rates","of","correct","predictions",",","deletions",",","insertions","and","substitutions","for","each","given","punctuation","mark","-","Overall","rates","of","correct","predictions",",","deletions",",","insertions","and","substiturions","between","reference","and","hypothesis","string","-","Punctuation","Error","Rate","Args","to","init",":","punctuation_marks","(","list","[","str","]",")","-","list","of","punctuation","marks","for","computing","metrics","punctuation_mask","(","str",",","by","default","``","[","PUNCT","]","''",")","-","mask","token","that","will","be","applied","to","given","punctuation","marks","while","edit","distance","calculation","How","to","use",":","1",".","Create","object","of","OccurancePunctuationErrorRate","class",".","Example",":","punctuation_marks","=","[","``",".","``",",","``",",","''",",","``","!","``",",","``","?","''","]","oper_obj","=","OccurancePunctuationErrorRate","(","punctuation_marks",")","2",".","To","compute","punctuation","metrics",",","pass","reference","and","hypothesis","string","to","the","``","compute","''","method","of","created","object",".","Example",":","reference_str","=","``","Hi",",","dear","!","Nice","to","see","you",".","What","'s","''","hypothesis_str","=","``","Hi","dear","!","Nice","to","see","you","!","What","'s","?","''","oper_obj.compute","(","reference_str",",","hypothesis_str",")","Output","(","listed","in","order","of","output",")",":","1",".","Dict","of","absolute","operations","amounts","for","each","given","punctuation","mark",":","Example",":","{","'",".","'",":","{","'Correct","'",":","0",",","'Deletions","'",":","0",",","'Insertions","'",":","0",",","'Substitutions","'",":","1","}",",","'",",","'",":","{","'Correct","'",":","0",",","'Deletions","'",":","1",",","'Insertions","'",":","0",",","'Substitutions","'",":","0","}",",","'","!","'",":","{","'Correct","'",":","1",",","'Deletions","'",":","0",",","'Insertions","'",":","0",",","'Substitutions","'",":","0","}",",","'","?","'",":","{","'Correct","'",":","0",",","'Deletions","'",":","0",",","'Insertions","'",":","1",",","'Substitutions","'",":","0","}","}","2",".","Dict","of","substitutions","absolute","amounts","between","given","punctuation","marks",":","Example",":","{","'",".","'",":","{","'",".","'",":","0",",","'",",","'",":","0",",","'","!","'",":","1",",","'","?","'",":","0","}",",","'",",","'",":","{","'",".","'",":","0",",","'",",","'",":","0",",","'","!","'",":","0",",","'","?","'",":","0","}",",","'","!","'",":","{","'",".","'",":","0",",","'",",","'",":","0",",","'","!","'",":","0",",","'","?","'",":","0","}",",","'","?","'",":","{","'",".","'",":","0",",","'",",","'",":","0",",","'","!","'",":","0",",","'","?","'",":","0","}","}","3.","namedtuple","``","PunctuationRates","''","of","punctuation","operation","rates","(","in","range","from","0","to","1",")",":","3.1.","correct_rate","-","overall","correct","rate","Example",":","correct_rate=0.25","3.2.","deletions_rate","-","overall","deletions","rate","Example",":","deletions_rate=0.25","3.3.","insertions_rate","-","overall","insertions","rate","Example",":","insertions_rate=0.25","3.4.","substitutions_rate","-","overall","substitutions_rate","Example",":","substitutions_rate=0.25","3.5.","punct_er","-","Punctuation","Error","Rate","Example",":","punct_er=0.75","3.6.","operation_rates","-","dict","of","operations","rates","for","each","given","punctuation","mark","Example",":","operation_rates=","{","'",".","'",":","{","'Correct","'",":","0.0",",","'Deletions","'",":","0.0",",","'Insertions","'",":","0.0",",","'Substitutions","'",":","1.0","}",",","'",",","'",":","{","'Correct","'",":","0.0",",","'Deletions","'",":","1.0",",","'Insertions","'",":","0.0",",","'Substitutions","'",":","0.0","}",",","'","!","'",":","{","'Correct","'",":","1.0",",","'Deletions","'",":","0.0",",","'Insertions","'",":","0.0",",","'Substitutions","'",":","0.0","}",",","'","?","'",":","{","'Correct","'",":","0.0",",","'Deletions","'",":","0.0",",","'Insertions","'",":","1.0",",","'Substitutions","'",":","0.0","}","}","3.7.","substitution_rates","-","dict","of","substitution","rates","for","each","given","punctuation","mark","Example",":","substitution_rates=","{","'",".","'",":","{","'",".","'",":","0.0",",","'",",","'",":","0.0",",","'","!","'",":","1.0",",","'","?","'",":","0.0","}",",","'",",","'",":","{","'",".","'",":","0.0",",","'",",","'",":","0.0",",","'","!","'",":","0.0",",","'","?","'",":","0.0","}",",","'","!","'",":","{","'",".","'",":","0.0",",","'",",","'",":","0.0",",","'","!","'",":","0.0",",","'","?","'",":","0.0","}",",","'","?","'",":","{","'",".","'",":","0.0",",","'",",","'",":","0.0",",","'","!","'",":","0.0",",","'","?","'",":","0.0","}","}"]
code: def compute_operation_amounts(self, reference: str, hypothesis: str):
      operation_amounts = {
          pm: {operation: 0 for operation in self.operations}
          for pm in self.punctuation_marks
      }
      substitution_amounts = {
          pm: {pm: 0 for pm in self.punctuation_marks}
          for pm in self.punctuation_marks
      }
  
      def tokenize(text: str, punctuation_marks: list[str]):
          punctuation_marks = "\\" + "\\".join(self.punctuation_marks)
          tokens = re.findall(rf"[\w']+|[{punctuation_marks}]", text)
          return tokens
  
      def mask_punct_tokens(
          tokens: list[str],
          punctuation_marks: list[str],
          punctuation_mask: str,
      ):
          masked = [
              punctuation_mask if token in punctuation_marks else token
              for token in tokens
          ]
          return masked
  
      r_tokens = tokenize(reference, self.punctuation_marks)
      h_tokens = tokenize(hypothesis, self.punctuation_marks)
  
      r_masked = mask_punct_tokens(
          r_tokens, self.punctuation_marks, self.punctuation_mask
      )
      h_masked = mask_punct_tokens(
          h_tokens, self.punctuation_marks, self.punctuation_mask
      )
  
      r_punct_amount = r_masked.count(self.punctuation_mask)
      h_punct_amount = h_masked.count(self.punctuation_mask)
  
      if r_punct_amount + h_punct_amount == 0:
          return operation_amounts, substitution_amounts
  
      r_len = len(r_masked)
      h_len = len(h_masked)
  
      costs = [
          [0 for inner in range(h_len + 1)]
          for outer in range(r_len + 1)
      ]
      backtrace = [
          [0 for inner in range(h_len + 1)]
          for outer in range(r_len + 1)
      ]
  
      COR = "C"
      DEL, DEL_PENALTY = "D", 1
      INS, INS_PENALTY = "I", 1
      SUB, SUB_PENALTY = "S", 1
  
      for i in range(1, r_len + 1):
          costs[i][0] = DEL_PENALTY * i
          backtrace[i][0] = DEL
  
      for j in range(1, h_len + 1):
          costs[0][j] = INS_PENALTY * j
          backtrace[0][j] = INS
  
      for j in range(1, h_len + 1):
          costs[0][j] = INS_PENALTY * j
          backtrace[0][j] = INS
  
      for i in range(1, r_len + 1):
          for j in range(1, h_len + 1):
              if r_masked[i - 1] == h_masked[j - 1]:
                  costs[i][j] = costs[i - 1][j - 1]
                  backtrace[i][j] = COR
              else:
                  substitution_cost = costs[i - 1][j - 1] + SUB_PENALTY
                  insertion_cost = costs[i][j - 1] + INS_PENALTY
                  deletion_cost = costs[i - 1][j] + DEL_PENALTY
  
                  costs[i][j] = min(
                      substitution_cost, insertion_cost, deletion_cost
                  )
                  if costs[i][j] == substitution_cost:
                      backtrace[i][j] = SUB
                  elif costs[i][j] == insertion_cost:
                      backtrace[i][j] = INS
                  else:
                      backtrace[i][j] = DEL
  
      i = r_len
      j = h_len
  
      while i > 0 or j > 0:
          if backtrace[i][j] == COR:
              if (
                  r_masked[i - 1] == self.punctuation_mask
                  or h_masked[j - 1] == self.punctuation_mask
              ):
                  r_token = r_tokens[i - 1]
                  h_token = h_tokens[j - 1]
  
                  if r_token == h_token:
                      operation_amounts[r_token]["Correct"] += 1
                  else:
                      operation_amounts[r_token]["Substitutions"] += 1
                      substitution_amounts[r_token][h_token] += 1
              i -= 1
              j -= 1
  
          elif backtrace[i][j] == SUB:
              i -= 1
              j -= 1
  
          elif backtrace[i][j] == INS:
              j -= 1
  
          elif backtrace[i][j] == DEL:
              i -= 1
  
      for pm in self.punctuation_marks:
          num_of_correct = operation_amounts[pm]["Correct"]
  
          num_substitutions_of_pm = operation_amounts[pm][
              "Substitutions"
          ]
          num_substitutions_to_pm = sum(
              [
                  substitution_amounts[_pm][pm]
                  for _pm in self.punctuation_marks
              ]
          )
  
          num_of_deletions = r_tokens.count(pm) - (
              num_of_correct + num_substitutions_of_pm
          )
          operation_amounts[pm]["Deletions"] = num_of_deletions
  
          num_of_insertions = h_tokens.count(pm) - (
              num_of_correct + num_substitutions_to_pm
          )
          operation_amounts[pm]["Insertions"] = num_of_insertions
  
      return operation_amounts, substitution_amounts
  
file_path: NeMo/nemo/collections/common/metrics/punct_er.py
imports: import re
  from collections import namedtuple
  from tqdm import tqdm
  from nemo.utils import logging
label_desc: Use image node_id 3 for calling the OccurancePunctuationErrorRate obj's underlying member method code with example usage: obj.compute_operation_amounts(reference, hypothesis) and returns: operation_amounts,  substitution_amounts, tokens, masked, operation_amounts,  substitution_amounts