'''
Computing the misclassification error distance between to 2 k-means clustering
according to Marina Meila, "The Uniqueness of a Good Optimum for K-Means", ICML 2006
Author : Diviyan Kalainathan
Date : 20/06/2016

'''

import csv,numpy,itertools
from sklearn import metrics

def Clustering_performance_evaluation(mode, folder_name, run1, run2, num_clusters, num_init):
    """
    :param mode: selects which metric is to be used
    :param folder_name: Folder of the runs (String)
    :param run1: Number of the run 1 (int)
    :param run2: Number of the run 2 (int)
    :param num_clusters:
    :param num_init:
    :return:  distance value (float?)

    """
    numpy.set_printoptions(threshold='nan')
    print('-'+str(num_clusters)+'---performance evaluation between runs : ' + str(run1) + ' ,' + str(run2))
    valid_data= True
    #Checking if the data is valid by loading & testing the shape of it
    try:
        data_1=numpy.loadtxt('output/'+folder_name+'/cluster_predictions_c'+ str(num_clusters)
                      + '_n'+ str(num_init) +'_r'+ str(run1)+'.csv',delimiter=';')
        data_2=numpy.loadtxt('output/'+folder_name+'/cluster_predictions_c'+ str(num_clusters)
                      + '_n'+ str(num_init) +'_r'+ str(run2)+'.csv',delimiter=';')

        if data_1.shape != data_2.shape:
            valid_data=False

    except IOError as e:
        print "I/O error({0}): {1}".format(e.errno, e.strerror)
        valid_data=False


    if valid_data:
        n_samples=data_1.shape[0]
        data_1 = numpy.asarray(sorted(data_1, key=lambda x: x[1]))
        data_2 = numpy.asarray(sorted(data_2, key=lambda x: x[1]))
        if mode==1:
            #Distance defined by Marina Meila : k! complexity
            clustering_1=numpy.zeros((n_samples,num_clusters))
            clustering_2=numpy.zeros((n_samples,num_clusters))

            for x in range(0,n_samples):
                clustering_1[x,data_1[x,0]]+=1
                clustering_2[x,data_2[x,0]]+=1

            '''for y in range(0,num_clusters):
                try:
                    clustering_1[:,y]*=1/numpy.sqrt(numpy.sum(clustering_1[:,y]))
                except ZeroDivisionError:
                    clustering_1[:,y]=0
                try:
                    clustering_2[:,y]*=1/numpy.sqrt(numpy.sum(clustering_2[:,y]))
                except ZeroDivisionError:
                    clustering_2[:,y]=0
            ''' # No normalisation needed


            confusion_matrix=numpy.dot(numpy.transpose(clustering_1),clustering_2)
            max_confusion=0
            result = []

            for perm in itertools.permutations(range(num_clusters)):
                confusion=0
                for i in range(0, num_clusters):
                    confusion += confusion_matrix[i, perm[i]]

                if max_confusion<confusion:
                    max_confusion=confusion


            distance=(max_confusion/n_samples)
            return distance


        elif mode==2:
            #Ajusted rand index
            distance=metrics.adjusted_rand_score(data_1[:,0],data_2[:,0])

            return distance

        elif mode==3:
            #V-mesure
            distance=metrics.v_measure_score(data_1[:,0],data_2[:,0])

            return distance

    return 0