EKNN <- function(trainX, trainLabel, K, para_gamma, para_alpha, test_method, testX) {
    
#   EKNN classifier by Denoeux. 
#   The case of BeliefKNN function for Dempster rule 

#   For this function, it is the same as the matlab knndsval function by Denoeux.
#    we only change the names of variables to be easy understood

#  	The decision rule corresponds together to the minimum of the
# 	upper, lower and pignistic risks in the case of {0,1} costs:
# 	the chosen class is the one for which the value 
# 	of the Basic Probability Assignment is maximum.
# 
#  	Inputs:
# 
# 	K : number of neighbours
#  	trainX : matrix (napp,d) of the training set 
#  	trainLabel : vector (napp,1) of corresponding labels
# 	para_gamma : vector (M,1) of parameters of the BPA
# 	para_alpha: parameter of the BPA
#    test_method: 0 = validation set; 1 = leave-one-out
#  	testX : matrix (N,d) of the test set (relevant only when test_method=0)
#          If test_method=1, testX is set automatically to trainX
# 
#  	Outputs:
# 		
#  	predictMass: matrix (N,M+1) of final Basic Probability Assignment 
# 	(M is the total number of classes, and N is the number of test 
#    examples). The first M columns contain the masses given to the 
#    singletons; the last column contains m(Omega))
#   predictLabel: vector (N,1) of predicted labels
# 
#  	
# 	The method can be divided in 2 steps:
# 
# 	* for every x of the evaluation set, computing the K-nearest 
# 	neighbours among the training set vectors.
# 	* computing the BPA of the evaluation vectors
# 
# 
    
    nTrain = nrow(trainX)
    nd = ncol(trainX)
    M = max(trainLabel)
    
    if (test_method == 1) {
        testX = trainX
    }
    
    nTest = nrow(testX)
    
    # ---- Computation of the K-nearest neighbours in the training set----################
    
    dst = c()
    ist = c()
    for (i in 1:nTest) {
        # dist = t(colSums(t((matrix(1, nTrain, 1) %*% testX[i,]) - trainX)^2));
        dist = rowSums((matrix(1, nTrain, 1) %*% testX[i, ] - trainX)^2)
        # [dss,iss]=sort(dist);
        dss = sort(dist)
        iss = order(dist)
        dst = cbind(dst, dss[(1 + test_method):(K + test_method)])
        ist = cbind(ist, iss[(1 + test_method):(K + test_method)])
    }
    
    
    ########################################### Computation of the BPA
    
    m = classeknn(para_alpha, para_gamma, testX, dst, ist, trainLabel, K)
    # [temp, L] = max(t(m(:,1:M)));
    L = apply(m[, 1:M], 1, which.max)
    # L = t(L);
    re = list(predictMass = m, predictLabel = L)
    return(re)
}



############ dependent programs#############################

classeknn <- function(para_alpha, para_gamma, testX, ds, is, trainLabel, K) {
    
# classeknn:  m = classeknn(para_alpha,para_gamma,ds,is,trainLabel,K)
#
#	This program provides the BPA, the labels and the
#	error rate  in a K-nearest neighbour rule based on 
#	Dempster-Shafer theory.  
# 		
# 	para_alpha (1,1), para_gamma (M,1): parameters of the BPA
#	(M is the number of classes)
# 	ds, is : matrices (K,N) containing respectively 
#	distances and indices of the K - nearest neighbours 
#	of N vectors belonging to the test set. 
#	trainLabel: vector (napp,1) of labels of the training set.
#	K: number of neighbours
#
# 	m: matrix (N, M + 1) of the final BPA. Each row is a bba of data i in the test data set 
    
    N = nrow(testX)
    M = max(trainLabel)
    # m = [zeros(M,N);ones(1,N)];
    m = matrix(0, M + 1, N)
    m[M + 1, ] = 1
    
    for (i in 1:N) for (j in 1:K) {
        m1 = matrix(0, M + 1, 1)
        m1[trainLabel[is[j, i]]] = para_alpha * exp(-para_gamma[trainLabel[is[j, i]]]^2 * ds[j, i])
        m1[M + 1] = 1 - m1[trainLabel[is[j, i]]]
        ## the conjunctive rule for two bbas
        m[1:M, i] = m1[1:M] * m[1:M, i] + m1[1:M] * m[M + 1, i] + m[1:M, i] * m1[M + 1]
        m[M + 1, i] = m1[M + 1] * m[M + 1, i]
    }
    ## normalized by column, each column is a bba
    m = m/(matrix(1, M + 1, 1) %*% colSums(m))
    m = t(m)
    return(m)
}
 
