Rajkumar Arun, V. Suresh, C. E. Veni Madhavan, and M. N. Narasimha Murthy. 2010. On finding the natural number of
    topics with latent dirichlet allocation: Some observations. In Advances in knowledge discovery and data mining,
    Mohammed J. Zaki, Jeffrey Xu Yu, Balaraman Ravindran and Vikram Pudi (eds.). Springer Berlin Heidelberg, 391–402.
    http://doi.org/10.1007/978-3-642-13657-3_43

def metric_arun_2010(topic_word_distrib, doc_topic_distrib, doc_lengths):
    """
    Rajkumar Arun, V. Suresh, C. E. Veni Madhavan, and M. N. Narasimha Murthy. 2010. On finding the natural number of
    topics with latent dirichlet allocation: Some observations. In Advances in knowledge discovery and data mining,
    Mohammed J. Zaki, Jeffrey Xu Yu, Balaraman Ravindran and Vikram Pudi (eds.). Springer Berlin Heidelberg, 391–402.
    http://doi.org/10.1007/978-3-642-13657-3_43
    """
    # Note: It will fail when num. of words in the vocabulary is less then the num. of topics (which is very unusual).

    # CM1 = SVD(M1)
    cm1 = np.linalg.svd(topic_word_distrib, compute_uv=False)
    #cm1 /= np.sum(cm1)  # normalize by L1 norm # the paper says nothing about normalizing so let's leave it as it is...

    # CM2 = L*M2 / norm2(L)
    if doc_lengths.shape[0] != 1:
        doc_lengths = doc_lengths.T
    cm2 = np.array(doc_lengths * np.matrix(doc_topic_distrib))[0]
    cm2 /= np.linalg.norm(doc_lengths, 2)
    # wrong:
    #cm2 /= np.linalg.norm(cm2, 2)  # normalize by L2 norm
    # also wrong:
    #cm2 /= np.sum(cm2)          # normalize by L1 norm

    # symmetric Kullback-Leibler divergence KL(cm1||cm2) + KL(cm2||cm1)
    # KL is called entropy in scipy
    # we can't use this because entropy() will normalize the vectors so that they sum up to 1 but this should not
    # be done according to the paper
    #return entropy(cm1, cm2) + entropy(cm2, cm1)

    # use it as in the paper (note: cm1 and cm2 are not prob. distributions that sum up to 1)
    return np.sum(cm1*np.log(cm1/cm2)) + np.sum(cm2*np.log(cm2/cm1))