def calculate_perplexity(models, coefs, data):
    '\n    Calculate perplexity with given model\n    :param models: language models\n    :param coefs: coefficients\n    :param data: test data\n    :return: perplexity\n    '
    pp = 0
    uniform_prob = []
    unigram_prob = []
    bigram_prob = []
    trigram_prob = []
    prob_table_unifrom = None
    prob_table_1gram = None
    prob_table_2gram = None
    prob_table_3gram = None
    min_freq = models[0].min_freq
    train_vocabulary = models[0].vocabulary
    (word_to_idx, idx_to_word) = (models[0].word_to_idx, models[0].idx_to_word)
    test_infrequent_words = find_infrequent_words(data, min_freq)
    replace_infrequent_words(data, test_infrequent_words)
    for i in range(len(data)):
        for j in range(len(data[i])):
            if (data[i][j] not in train_vocabulary):
                data[i][j] = 'UNK'
    (corpus_1gram, vocabulary, V, N) = get_vocabulary(data)
    corpus_2gram = [(corpus_1gram[i], corpus_1gram[(i + 1)]) for i in range((len(corpus_1gram) - 1))]
    corpus_3gram = [(corpus_1gram[i], corpus_1gram[(i + 1)], corpus_1gram[(i + 2)]) for i in range((len(corpus_1gram) - 2))]
    for i in range(len(models)):
        model = models[i]
        if model.uniform:
            prob_table_unifrom = model.uniform_table
            for word in corpus_1gram:
                uniform_prob.append((prob_table_unifrom[0][word_to_idx[word]] * coefs[0]))
        elif (model.ngram == 1):
            prob_table_1gram = model.unigram_table
            for word in corpus_1gram:
                unigram_prob.append((prob_table_1gram[0][word_to_idx[word]] * coefs[1]))
        elif (model.ngram == 2):
            prob_table_2gram = model.bigram_table
            bigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_2gram[0][0]]])
            for words in corpus_2gram:
                word1 = words[0]
                word2 = words[1]
                prob_1gram = prob_table_1gram[0][word_to_idx[word2]]
                prob_2gram = prob_table_2gram[word_to_idx[word1]][word_to_idx[word2]]
                if (prob_2gram != 0):
                    bigram_prob.append((prob_2gram * coefs[2]))
                else:
                    bigram_prob.append((prob_1gram * coefs[2]))
        elif (model.ngram == 3):
            prob_table_3gram = model.trigram_table
            train_corpus_3gram = set(model.corpus_3gram)
            trigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_3gram[0][0]]])
            trigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_3gram[0][1]]])
            for words in corpus_3gram:
                word1 = words[0]
                word2 = words[1]
                word3 = words[2]
                if (words in train_corpus_3gram):
                    prob_3gram = prob_table_3gram[(word1, word2, word3)]
                    trigram_prob.append((prob_3gram * coefs[3]))
                else:
                    prob_1gram = prob_table_1gram[0][word_to_idx[word3]]
                    prob_2gram = prob_table_2gram[word_to_idx[word2]][word_to_idx[word3]]
                    if (prob_2gram != 0):
                        trigram_prob.append((prob_2gram * coefs[3]))
                    else:
                        trigram_prob.append((prob_1gram * coefs[3]))
    prob = np.zeros((N,), dtype=np.float64)
    for i in range(len(prob)):
        prob[i] += uniform_prob[i]
        prob[i] += unigram_prob[i]
        prob[i] += bigram_prob[i]
        prob[i] += trigram_prob[i]
    for p in prob:
        pp += np.log2(p)
    pp /= (- N)
    pp = np.power(2, pp)
    return pp
Calculate perplexity with given model
:param models: language models
:param coefs: coefficients
:param data: test data
:return: perplexity
def calculate_perplexity(models, coefs, data):
    '\n    Calculate perplexity with given model\n    :param models: language models\n    :param coefs: coefficients\n    :param data: test data\n    :return: perplexity\n    '
    pp = 0
    uniform_prob = []
    unigram_prob = []
    bigram_prob = []
    trigram_prob = []
    prob_table_unifrom = None
    prob_table_1gram = None
    prob_table_2gram = None
    prob_table_3gram = None
    min_freq = models[0].min_freq
    train_vocabulary = models[0].vocabulary
    (word_to_idx, idx_to_word) = (models[0].word_to_idx, models[0].idx_to_word)
    test_infrequent_words = find_infrequent_words(data, min_freq)
    replace_infrequent_words(data, test_infrequent_words)
    for i in range(len(data)):
        for j in range(len(data[i])):
            if (data[i][j] not in train_vocabulary):
                data[i][j] = 'UNK'
    (corpus_1gram, vocabulary, V, N) = get_vocabulary(data)
    corpus_2gram = [(corpus_1gram[i], corpus_1gram[(i + 1)]) for i in range((len(corpus_1gram) - 1))]
    corpus_3gram = [(corpus_1gram[i], corpus_1gram[(i + 1)], corpus_1gram[(i + 2)]) for i in range((len(corpus_1gram) - 2))]
    for i in range(len(models)):
        model = models[i]
        if model.uniform:
            prob_table_unifrom = model.uniform_table
            for word in corpus_1gram:
                uniform_prob.append((prob_table_unifrom[0][word_to_idx[word]] * coefs[0]))
        elif (model.ngram == 1):
            prob_table_1gram = model.unigram_table
            for word in corpus_1gram:
                unigram_prob.append((prob_table_1gram[0][word_to_idx[word]] * coefs[1]))
        elif (model.ngram == 2):
            prob_table_2gram = model.bigram_table
            bigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_2gram[0][0]]])
            for words in corpus_2gram:
                word1 = words[0]
                word2 = words[1]
                prob_1gram = prob_table_1gram[0][word_to_idx[word2]]
                prob_2gram = prob_table_2gram[word_to_idx[word1]][word_to_idx[word2]]
                if (prob_2gram != 0):
                    bigram_prob.append((prob_2gram * coefs[2]))
                else:
                    bigram_prob.append((prob_1gram * coefs[2]))
        elif (model.ngram == 3):
            prob_table_3gram = model.trigram_table
            train_corpus_3gram = set(model.corpus_3gram)
            trigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_3gram[0][0]]])
            trigram_prob.append(prob_table_1gram[0][word_to_idx[corpus_3gram[0][1]]])
            for words in corpus_3gram:
                word1 = words[0]
                word2 = words[1]
                word3 = words[2]
                if (words in train_corpus_3gram):
                    prob_3gram = prob_table_3gram[(word1, word2, word3)]
                    trigram_prob.append((prob_3gram * coefs[3]))
                else:
                    prob_1gram = prob_table_1gram[0][word_to_idx[word3]]
                    prob_2gram = prob_table_2gram[word_to_idx[word2]][word_to_idx[word3]]
                    if (prob_2gram != 0):
                        trigram_prob.append((prob_2gram * coefs[3]))
                    else:
                        trigram_prob.append((prob_1gram * coefs[3]))
    prob = np.zeros((N,), dtype=np.float64)
    for i in range(len(prob)):
        prob[i] += uniform_prob[i]
        prob[i] += unigram_prob[i]
        prob[i] += bigram_prob[i]
        prob[i] += trigram_prob[i]
    for p in prob:
        pp += np.log2(p)
    pp /= (- N)
    pp = np.power(2, pp)
    return pp