# -*- coding: utf-8 -*-
"""
Created on Mon Mar 13 21:34:47 2023

@author: dconduche
"""

from donnees_app_TP1 import *


def d_carre(x, y):
    assert len(x) == len(y)
    s = 0
    for i in range(len(x)):
        s += (x[i] - y[i])**2
    return s


def liste_dc(x, Ly):
    L = []
    for y in Ly:
        L.append(d_carre(x, y))
    return L


Lx, labels = obtenir_disque()
affiche_donnees_disque(Lx, labels)

x = [0,.5]
Ldist = liste_dc(x, Lx)


def imin(L):
    n = len(L)
    i_mini = 0
    mini = L[i_mini][1]
    for i in range(n):
        if L[i][1] < mini:
            i_mini = i
            mini = L[i_mini][1]
    return i_mini


def tri_partiel(M, k):
    for j in range(k):
        indice = imin(M[j:]) + j
        M[j], M[indice] = M[indice], M[j]


def indice_voisins(x, Ly, k):
    L = liste_dc(x, Ly)
    M = [(i, L[i]) for i in range(len(L))]
    tri_partiel(M, k)
    Lvoisins = [m[0] for m in M[:k]]
    return Lvoisins

k = 5
#print(indice_voisins(x, Lx, k))


def label(Lindices, labels):
    dico = {}
    for i in Lindices:
        lab = labels[i]
        if lab in dico:
            dico[lab] += 1
        else:
            dico[lab] = 1
    maxi = 0  # c'est la fonction max sur un dictionnaire,
    for k in dico.keys():  # On cherche la clef
        if dico[k] > maxi:
            maxi = dico[k]
            lab_max = k
    return lab_max


def kNN(x, Lx, labels, k):
    Lindices_voisins = indice_voisins(x, Lx, k)
    return label(Lindices_voisins, labels)


#print(kNN(x, Lx, labels, k))

k = 1
N = 30
xtest = np.linspace(-1, 1, N)
ytest = np.linspace(-1, 1, N)
Lx_test = []
labels_test = []

for i in range(N):
    for j in range(N):
        x = np.array([xtest[i], ytest[j]])
        Lx_test.append(x)
        labels_test.append(kNN(x, Lx, labels, k))
Lx_test = np.array(Lx_test)
labels_test = np.array(labels_test)

affiche_donnees_disque(Lx_test, labels_test)


def partage_donnees(Lx, labels, ratio):
    N = len(Lx)
    Lindices = list(range(N))
    np.random.shuffle(Lindices)
    n = int(ratio * N)
    Lx_test = [Lx[i] for i in Lindices[:n]]
    labels_test = [labels[i] for i in Lindices[:n]]
    Lx_app = [Lx[i] for i in Lindices[n:]]
    labels_app = [labels[i] for i in Lindices[n:]]
    return (Lx_test, labels_test, Lx_app, labels_app)

ratio = 0.2
Lx_test, labels_test, Lx_app, labels_app = partage_donnees(Lx, labels, ratio)


def prediction(Lx_app, labels_app, Lx_test, k):
    labels_kNN = [kNN(x, Lx_app, labels_app, k) for x in Lx_test]
    return np.array(labels_kNN)

lab_kNN = prediction(Lx_app, labels_app, Lx_test, k)


def pourcentage_reussite(labels_test, labels_kNN):
    n = len(labels_kNN)
    echecs = 0
    for i in range(n):
        if not labels_kNN[i] == labels_test[i]:
            echecs += 1
    return 1 - echecs/n


#print(pourcentage_reussite(labels_test, lab_kNN))

nb_test = 30  # Pour tester plusieurs séparation E_A/E_T
ratio = 0.2
Lk = list(range(1, 50, 4))
Lp = []
for k in Lk:
    p = 0
    for i in range(nb_test):
        L = partage_donnees(Lx, labels, ratio)
        Lx_test, labels_test, Lx_app, labels_app = L
        lab_kNN = prediction(Lx_app, labels_app, Lx_test, k)
        p += pourcentage_reussite(labels_test, lab_kNN)
    Lp.append(p/nb_test)
plt.plot(Lk, Lp)
plt.show()

