class_docstr: Translation model that keeps track of vacant positions in the target
  sentence to decide where to place translated words
  
  >>> bitext = []
  >>> bitext.append(AlignedSent(['klein', 'ist', 'das', 'haus'], ['the', 'house', 'is', 'small']))
  >>> bitext.append(AlignedSent(['das', 'haus', 'war', 'ja', 'groß'], ['the', 'house', 'was', 'big']))
  >>> bitext.append(AlignedSent(['das', 'buch', 'ist', 'ja', 'klein'], ['the', 'book', 'is', 'small']))
  >>> bitext.append(AlignedSent(['ein', 'haus', 'ist', 'klein'], ['a', 'house', 'is', 'small']))
  >>> bitext.append(AlignedSent(['das', 'haus'], ['the', 'house']))
  >>> bitext.append(AlignedSent(['das', 'buch'], ['the', 'book']))
  >>> bitext.append(AlignedSent(['ein', 'buch'], ['a', 'book']))
  >>> bitext.append(AlignedSent(['ich', 'fasse', 'das', 'buch', 'zusammen'], ['i', 'summarize', 'the', 'book']))
  >>> bitext.append(AlignedSent(['fasse', 'zusammen'], ['summarize']))
  >>> src_classes = {'the': 0, 'a': 0, 'small': 1, 'big': 1, 'house': 2, 'book': 2, 'is': 3, 'was': 3, 'i': 4, 'summarize': 5 }
  >>> trg_classes = {'das': 0, 'ein': 0, 'haus': 1, 'buch': 1, 'klein': 2, 'groß': 2, 'ist': 3, 'war': 3, 'ja': 4, 'ich': 5, 'fasse': 6, 'zusammen': 6 }
  
  >>> ibm5 = IBMModel5(bitext, 5, src_classes, trg_classes)
  
  >>> print(round(ibm5.head_vacancy_table[1][1][1], 3))
  1.0
  >>> print(round(ibm5.head_vacancy_table[2][1][1], 3))
  0.0
  >>> print(round(ibm5.non_head_vacancy_table[3][3][6], 3))
  1.0
  
  >>> print(round(ibm5.fertility_table[2]['summarize'], 3))
  1.0
  >>> print(round(ibm5.fertility_table[1]['book'], 3))
  1.0
  
  >>> print(round(ibm5.p1, 3))
  0.033
  
  >>> test_sentence = bitext[2]
  >>> test_sentence.words
  ['das', 'buch', 'ist', 'ja', 'klein']
  >>> test_sentence.mots
  ['the', 'book', 'is', 'small']
  >>> test_sentence.alignment
  Alignment([(0, 0), (1, 1), (2, 2), (3, None), (4, 3)])
docstr: Probability of target sentence and an alignment given the
  source sentence
docstr_tok: ["Probability","of","target","sentence","and","an","alignment","given","the","source","sentence"]
code: def prob_t_a_given_s(self, alignment_info):
      """
      Probability of target sentence and an alignment given the
      source sentence
      """
      probability = 1.0
      MIN_PROB = IBMModel.MIN_PROB
      slots = Slots(len(alignment_info.trg_sentence) - 1)
  
      def null_generation_term():
          # Binomial distribution: B(m - null_fertility, p1)
          value = 1.0
          p1 = self.p1
          p0 = 1 - p1
          null_fertility = alignment_info.fertility_of_i(0)
          m = len(alignment_info.trg_sentence) - 1
          value *= pow(p1, null_fertility) * pow(
              p0, m - 2 * null_fertility
          )
          if value < MIN_PROB:
              return MIN_PROB
  
          # Combination: (m - null_fertility) choose null_fertility
          for i in range(1, null_fertility + 1):
              value *= (m - null_fertility - i + 1) / i
          return value
  
      def fertility_term():
          value = 1.0
          src_sentence = alignment_info.src_sentence
          for i in range(1, len(src_sentence)):
              fertility = alignment_info.fertility_of_i(i)
              value *= (
                  factorial(fertility)
                  * self.fertility_table[fertility][src_sentence[i]]
              )
              if value < MIN_PROB:
                  return MIN_PROB
          return value
  
      def lexical_translation_term(j):
          t = alignment_info.trg_sentence[j]
          i = alignment_info.alignment[j]
          s = alignment_info.src_sentence[i]
          return self.translation_table[t][s]
  
      def vacancy_term(i):
          value = 1.0
          tablet = alignment_info.cepts[i]
          tablet_length = len(tablet)
          total_vacancies = slots.vacancies_at(len(slots))
  
          # case 1: NULL-aligned words
          if tablet_length == 0:
              return value
  
          # case 2: head word
          j = tablet[0]
          previous_cept = alignment_info.previous_cept(j)
          previous_center = alignment_info.center_of_cept(previous_cept)
          dv = slots.vacancies_at(j) - slots.vacancies_at(
              previous_center
          )
          max_v = total_vacancies - tablet_length + 1
          trg_class = self.trg_classes[alignment_info.trg_sentence[j]]
          value *= self.head_vacancy_table[dv][max_v][trg_class]
          slots.occupy(j)  # mark position as occupied
          total_vacancies -= 1
          if value < MIN_PROB:
              return MIN_PROB
  
          # case 3: non-head words
          for k in range(1, tablet_length):
              previous_position = tablet[k - 1]
              previous_vacancies = slots.vacancies_at(previous_position)
              j = tablet[k]
              dv = slots.vacancies_at(j) - previous_vacancies
              max_v = (
                  total_vacancies
                  - tablet_length
                  + k
                  + 1
                  - previous_vacancies
              )
              trg_class = self.trg_classes[
                  alignment_info.trg_sentence[j]
              ]
              value *= self.non_head_vacancy_table[dv][max_v][trg_class]
              slots.occupy(j)  # mark position as occupied
              total_vacancies -= 1
              if value < MIN_PROB:
                  return MIN_PROB
  
          return value
  
      # end nested functions
  
      # Abort computation whenever probability falls below MIN_PROB at
      # any point, since MIN_PROB can be considered as zero
      probability *= null_generation_term()
      if probability < MIN_PROB:
          return MIN_PROB
  
      probability *= fertility_term()
      if probability < MIN_PROB:
          return MIN_PROB
  
      for j in range(1, len(alignment_info.trg_sentence)):
          probability *= lexical_translation_term(j)
          if probability < MIN_PROB:
              return MIN_PROB
  
      for i in range(1, len(alignment_info.src_sentence)):
          probability *= vacancy_term(i)
          if probability < MIN_PROB:
              return MIN_PROB
  
      return probability
  
imports: import warnings
  from collections import defaultdict
  from math import factorial
  from nltk.translate import AlignedSent, Alignment, IBMModel, IBMModel4
  from nltk.translate.ibm_model import Counts, longest_target_sentence_length
label_desc: Use image node_id 8 for calling the IBMModel5 obj's underlying member method code with example usage: obj.prob_t_a_given_s(alignment_info) and returns: probability, value, value, self, value, MIN_PROB, MIN_PROB, MIN_PROB, value, MIN_PROB, MIN_PROB, MIN_PROB, MIN_PROB, MIN_PROB