# -*- coding:Utf-8 -*-
#CA2.py - Touzet - 2013-2018 - Carte auto-organisatrice pour la visualisation de données multidimensionnelles (>3) "pays"
# les data viennent de : http://www.heritage.org/
'''
CountryID;WEBNAME;Property Rights;Freedom from Corruption;Fiscal Freedom ;Gov't Spending;Business Freedom;Labor Freedom;Monetary Freedom;Trade Freedom;Investment Freedom ;Financial Freedom;Tariff Rate (%);Income Tax Rate (%);Corporate Tax Rate (%);Tax Burden % of GDP;Gov't Expenditure % of GDP ;Population (Millions);Unemployment (%);Inflation (%);Public Debt (% of GDP)
1.00;Afghanistan;-1.0;15.00;-1.0;83.20;59.70;75.80;69.50;-1.0;65.00;-1.0;-1.0;20.00;20.00;9.24;23.66;31.08;-1.0;11.25;12.10
2.00;Albania;30.00;31.00;92.60;75.10;81.00;49.00;78.40;79.80;65.00;70.00;5.10;10.00;10.00;23.30;28.80;3.22;13.50;3.43;58.92
3.00;Algeria;30.00;29.00;80.40;44.10;65.20;52.60;76.60;67.80;20.00;30.00;8.60;35.00;25.00;10.40;43.15;35.95;10.00;4.50;9.93
4.00;Angola;15.00;20.00;82.60;60.60;43.10;44.80;61.50;70.20;35.00;40.00;7.40;17.00;35.00;14.90;36.26;19.63;-1.0;13.50;30.90
...
'''
import sys,codecs,locale
from random import random

data_file="index2013_data-2.csv"
#data_file="index2018_data-2.csv"
Data=[] # les données de chaque pays
labelPays=[] # la liste des pays
nbPays=-1 #index des lignes du fichier data (la 1ere est un commentaire à éviter)
for line in codecs.open(data_file,'r','utf8').readlines() :
    if (nbPays>=0) : # permet de supprimer la première ligne (intitulés)
        word1 = line.rstrip('\r\n') # enleve retour chariot final
        Data.append([])
        word = word1.rsplit(';') # decoupe selon ';'
        for i in range (1,len(word)) :#on saute le numéro du pays (colonne 1)
            valeur = word[i]
            #print (valeur)
            if ((valeur[0]>='A') & (valeur[0]<='Z')) :
                labelPays.append(valeur)
            else :
                Data[nbPays].append(float (valeur))
    nbPays=nbPays+1

# les variables suivantes sont à fixer par l'utilisateur
ligne=10 # nombre de lignes de la carte (1 à ...)
col=40 # nombre de colonnes de la carte (1 à ...)
nbE=len(Data[0]) # nombre de dimensions de l'espace des entrées (2 ou 3)
nbN=ligne * col # nb de colonnes corticales de la carte

W=[]  # poids des neurones
Fq=[] # fréquence de chaque colonne
alpha=0.5 #alpha
beta=0.1 # beta
nbit = 100 # nb iterations apprentissage
F=[] #fréquence
debut = True # pour que cela commence au centre 

for a in range(nbE) :
    W.append([])
    for i in range(nbN): # initialisation aleatoire entre 45 et 55 des poids
        W[a].append(random()*10+45)
for k in range (nbN) :
    Fq.append(1.0) # initialisation des fréquences à 1
    
for i in range (nbit):
    if (i%10 == 0) : print ("itération ", i)
    for j in range(len(Data)) : 
        alpha1 = alpha - alpha * i / nbit + 0.1 # decroissance pas d apprentissage du gagnant
        beta1 = beta - beta * i / nbit + 0.05 # decroissance pas d apprentissage des voisins
        Ex = Data[j] # les données d'apprentissage 
        D=[] # distance des N
        for k in range (nbN):
            d=0
            for a in range (nbE) : 
                if (Ex[a] != -1.0) :           # -1.0 signifie que la données est "N/A", on ne tient 
                    d=d + abs(Ex[a] - W[a][k]) # donc pas compte de cette dimension dans le calcul de distance. 
            #D.append(d * Fq[k]) # chaque colonne gagne aussi souvent qu'une autre
            D.append(d) # ou alors chacun gagne à son tour (ça ne change pas grand chose au résultat final)
        
        mini=D[0]; index=0
        for k in range (nbN): #on cherche l'index du minimum (le gagnant)
            if (D[k]<mini): mini=D[k]; index=k
        if debut == True :# pour que cela démarre au centre de la carte
            index = col*(ligne/2.0)+col*0.5; debut = False 
        # modification des poids
        for k in range (nbN):     
            if (k==index):
                #print"a: le gagnant"
                Fq[k]=Fq[k] + 1.0 #la fq du gagnant augmente
                for a in range (nbE) : 
                    if (Ex[a] != -1.0) :  W[a][k] = W[a][k] + alpha1 * (Ex[a] - W[a][k])
            else :
                Fq[k]=Fq[k] - 1.0/(nbN-1) #la fq des autres diminue
            if(index%col!=0):
                if (k==index-1) :
                    #print "b: il a des voisin a gauche"
                    for a in range (nbE) : 
                        if (Ex[a] != -1.0) :  W[a][k] = W[a][k] + beta1 * (Ex[a] - W[a][k])
            if ((index+1)%col!=0):
                if (k==index+1) :
                    #print "c: il a des voisins a droite"
                    for a in range (nbE) : 
                        if (Ex[a] != -1.0) :  W[a][k] = W[a][k] + beta1 * (Ex[a] - W[a][k])
            if ((index+ligne)<nbN):
                if (k==index+ligne):
                    #print "d: voisins au dessus"
                    for a in range (nbE) : 
                        if (Ex[a] != -1.0) :  W[a][k] = W[a][k] + beta1 * (Ex[a] - W[a][k])
            if ((index-ligne)>=0):
                if (k==index-ligne):
                    #print "e: voisins au dessous"
                    for a in range (nbE) : 
                        if (Ex[a] != -1.0) :  W[a][k] = W[a][k] + beta1 * (Ex[a] - W[a][k])

# on a fini l'apprentissage : on refait une itération pour trouver quelle colonne corticale code quel pays.
Labels=[]
for k in range (nbN) :
    Labels.append('')
for j in range(len(Data)) : 
    Ex = Data[j]
    #on calcule la distance des neurons a l'entree
    D=[] # distance des N
    for k in range (nbN):
        d=0
        for a in range (nbE) : 
            if (Ex[a] != -1.0) :           # -1.0 signifie que la données est "N/A", on ne tient 
                d=d + abs(Ex[a] - W[a][k]) # donc pas compte de cette dimension dans le calcul de distance. 
        #D.append(d * Fq[k]) # chaque colonne gagne aussi souvent qu'une autre
        D.append(d) # ou alors chacun gagne à son tour (ça ne change pas grand chose au résultat final)
    
    mini=D[0]; index=0
    for k in range (nbN): #on cherche l'index du minimum (le gagnant)
        if (D[k]<mini): mini=D[k];index=k
    Labels[index]=labelPays[j]

maxi=0
name1 = "pays.txt"
fich=open(name1, 'w')
for k in range(len(labelPays)) : #longueur max des noms de pays
    if (len(labelPays[k]) > maxi) :
        maxi=len(labelPays[k])
for k in range(nbN) :       
    fich.write (Labels[k]),
    taille = int(len(Labels[k]))
    for j in range (taille, maxi+1) :
        fich.write (' '),
    if ((k+1)%ligne==0) :
        fich.write ("\n")
fich.close()




