'Probability of target sentence and an alignment given the
source sentence'

def prob_t_a_given_s(self, alignment_info):

    probability = 1.0
    MIN_PROB = IBMModel.MIN_PROB
    slots = Slots((len(alignment_info.trg_sentence) - 1))
    def null_generation_term():
        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
        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))
        if (tablet_length == 0):
            return value
        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)
        total_vacancies -= 1
        if (value < MIN_PROB):
            return MIN_PROB
        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)
            total_vacancies -= 1
            if (value < MIN_PROB):
                return MIN_PROB
        return value
    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
