code: def ctcBeamSearch(
      mat, classes, ignore_idx, lm, beamWidth=25, dict_list=[]
  ):
      blankIdx = 0
      maxT, maxC = mat.shape
  
      # initialise beam state
      last = BeamState()
      labeling = ()
      last.entries[labeling] = BeamEntry()
      last.entries[labeling].prBlank = 1
      last.entries[labeling].prTotal = 1
  
      # go over all time-steps
      for t in range(maxT):
          curr = BeamState()
          # get beam-labelings of best beams
          bestLabelings = last.sort()[0:beamWidth]
          # go over best beams
          for labeling in bestLabelings:
              # probability of paths ending with a non-blank
              prNonBlank = 0
              # in case of non-empty beam
              if labeling:
                  # probability of paths with repeated last char at the end
                  prNonBlank = (
                      last.entries[labeling].prNonBlank
                      * mat[t, labeling[-1]]
                  )
  
              # probability of paths ending with a blank
              prBlank = (last.entries[labeling].prTotal) * mat[
                  t, blankIdx
              ]
  
              # add beam at current time-step if needed
              prev_labeling = labeling
              if not last.entries[labeling].simplified:
                  labeling = simplify_label(labeling, blankIdx)
  
              # labeling = simplify_label(labeling, blankIdx)
              addBeam(curr, labeling)
  
              # fill in data
              curr.entries[labeling].labeling = labeling
              curr.entries[labeling].prNonBlank += prNonBlank
              curr.entries[labeling].prBlank += prBlank
              curr.entries[labeling].prTotal += prBlank + prNonBlank
              curr.entries[labeling].prText = last.entries[
                  prev_labeling
              ].prText
              # beam-labeling not changed, therefore also LM score unchanged from
  
              # curr.entries[labeling].lmApplied = True # LM already applied at previous time-step for this beam-labeling
  
              # extend current beam-labeling
              # char_highscore = np.argpartition(mat[t, :], -5)[-5:] # run through 5 highest probability
              char_highscore = np.where(mat[t, :] >= 0.5 / maxC)[
                  0
              ]  # run through all probable characters
              for c in char_highscore:
                  # for c in range(maxC - 1):
                  # add new char to current beam-labeling
                  # newLabeling = labeling + (c,)
                  # newLabeling = simplify_label(newLabeling, blankIdx)
                  newLabeling = fast_simplify_label(
                      labeling, c, blankIdx
                  )
  
                  # if new labeling contains duplicate char at the end, only consider paths ending with a blank
                  if labeling and labeling[-1] == c:
                      prNonBlank = (
                          mat[t, c]
                          * last.entries[prev_labeling].prBlank
                      )
                  else:
                      prNonBlank = (
                          mat[t, c]
                          * last.entries[prev_labeling].prTotal
                      )
  
                  # add beam at current time-step if needed
                  addBeam(curr, newLabeling)
  
                  # fill in data
                  curr.entries[newLabeling].labeling = newLabeling
                  curr.entries[newLabeling].prNonBlank += prNonBlank
                  curr.entries[newLabeling].prTotal += prNonBlank
  
                  # apply LM
                  # applyLM(curr.entries[labeling], curr.entries[newLabeling], classes, lm)
  
          # set new beam state
  
          last = curr
  
      # normalise LM scores according to beam-labeling-length
      last.norm()
  
      if dict_list == []:
          bestLabeling = last.sort()[0]  # get most probable labeling
          res = ""
          for i, l in enumerate(bestLabeling):
              # removing repeated characters and blank.
              if l not in ignore_idx and (
                  not (i > 0 and bestLabeling[i - 1] == bestLabeling[i])
              ):
                  res += classes[l]
      else:
          res = last.wordsearch(classes, ignore_idx, 20, dict_list)
      return res
  
imports: from __future__ import print_function
  import torch
  import pickle
  import numpy
  import math
  import cv2
  from PIL import Image, JpegImagePlugin
  from scipy import ndimage
  import hashlib
  import sys, os
  from zipfile import ZipFile
  from .imgproc import loadImage
label_desc: Use image node_id 7 for calling a global function with example usage: ctcBeamSearch(mat, classes, ignore_idx, lm, beamWidth, dict_list) and returns: res