% Questa funzione esegue un training ogni volta che sia necessario, cioè
% ogni qualvolta ci sia il rischio di avere delle misclassification.
% Si è deciso di effettuare un nuovo training quando la distanza tra i due
% gruppi di punti da analizzare scende sotto una soglia definita, perchè è
% in queste occasioni che si rischia di eseguire classificazioni errate se
% ci si affida all'iperpiano costruito al passo precedente.

function [beta_tot dist_min] = fun_trainclassify(P,P_r,P_b,y_label)

global N t n_f x pp
addpath('libsvm-mat-3.0-1');

%% SVM TRAIN
% si richiama il metodo svmtrain:
% INPUT = etichette iniziali, posizioni iniziali
% OUTPUT = modello --> SV, stato iniziale, iperpiano iniziale
beta_tot = [];
dist_min = [];
model = svmtrain(y_label,P(:,1:2,1),'-t 0');

% calcolo stato iniziale per trovare iperpiano iniziale
beta_0_iniz = -model.rho;
beta_iniz = zeros(n_f,1);
N_sv = model.totalSV;
sv_tmp = zeros(N_sv,n_f);

for s = 1:N_sv
    for q = 1:n_f
        sv_tmp(s,q) = model.SVs(s,q);
    end
        beta_iniz = beta_iniz + model.sv_coef(s)*sv_tmp(s,:)';
end

% calcolo iperpiano ottimo
beta = beta_iniz;
beta_0 = beta_0_iniz;
b = [beta; beta_0];
retta = -(beta(1)/beta(2)*x + beta_0/beta(2));
    
% memorizzazione degli stati ottenuti
b_ott = b;
beta_tot = [beta_tot b_ott];


% Plot iniziale
% plot punti in esame (rossi e blu)
figure(3)
plot(P_r(:,1,1),P_r(:,2,1),'o','MarkerEdgeColor','r','MarkerFaceColor','r');
hold on
title('Algoritmo Train-Classify','fontsize',12)
plot(P_b(:,1,1),P_b(:,2,1),'o','MarkerEdgeColor','b','MarkerFaceColor','b');
axis([-100 200 -100 200])
grid on
pause(0.2)
hold on

% plot SV + iperpiano ottimo
plot(sv_tmp(:,1),sv_tmp(:,2),'o','MarkerEdgeColor','g','MarkerFaceColor','g');
plot(x,retta,'k');
pause(pp)
hold off


%% SVM CLASSIFY
% Si classificano i nuovi punti prendendo di riferimento l'iperpiano
% ottenuto dal training. Viene eseguito un nuovo training solo quando
% serve.

for t = 2:N
    
    % plot dell'iperpiano ottimo calcolato dall'ultimo Training
    figure(3)
    plot(x,retta,'k');
    axis([-100 200 -100 200])
    title('Algoritmo Train-Classify','fontsize',12)
    grid on
    pause(pp);
    hold on
    
    
    % SVM classify - in base all'ultimo iperpiano ottenuto si esegue la
    % classificazione dei nuovi punti
    % INPUT --> etichette correnti, posizioni correnti, modello uscente dal
    % Training
    % OUTPUT --> nuove etichette dei punti ottenute dalla classificazione
    [predicted_label] = svmpredict(y_label, P(:,:,t), model);
    
    
    % plot dei nuovi punti
    plot(P_r(:,1,t),P_r(:,2,t),'o','MarkerEdgeColor','r','MarkerFaceColor','r');
    plot(P_b(:,1,t),P_b(:,2,t),'o','MarkerEdgeColor','b','MarkerFaceColor','b');
    pause(pp)
    
    
    % Calcolo della distanza punto/retta (iperpiano ottimo) di ogni punto e
    % memorizzazione di quella minima
    % distanza punto/retta --> |ax + by + c|/sqrt(a^2 + b^2)
    % dove (x,y) sono le coordinate del punto considerato
    % e a,b,c sono i coefficienti della retta in esame    
    d_r = zeros(length(P_r(:,:,t)),1);
    d_b = zeros(length(P_b(:,:,t)),1);
        
    % minimo dei ROSSI
    for i = 1:length(d_r)
        d_r(i) = abs(b(1)*P_r(i,1,t) + b(2)*P_r(i,2,t) + b(3))/sqrt(b(1)^2 + b(2)^2);
        % al primo passo prendo come dist. minima quella corrente per poi
        % confrontarla con le successive
        if i == 1
            d_min_1 = d_r(i);
            x_min_1 = P_r(i,:,t);
        else
            % se la nuova distanza calcolata è minore di quella salvata
            % viene aggiornato d_min e vengono salvate le coordinate del
            % punto corrispondente
            if d_r(i) < d_min_1
                x_min_1 = P_r(i,:,t);
                d_min_1 = d_r(i);
            end
        end
    end
        
    % minimo dei BLU (stesso procedimento usato sopra)
    for i = 1:length(d_b)
        d_b(i) = abs(b(1)*P_b(i,1,t) + b(2)*P_b(i,2,t) + b(3))/sqrt(b(1)^2 + b(2)^2);
        if i == 1
            d_min_2 = d_b(i);
            x_min_2 = P_b(i,:,t);
        else
            if d_b(i) < d_min_2
                x_min_2 = P_b(i,:,t);
                d_min_2 = d_b(i);
            end
        end
    end
    
    % memorizzazione delle distanze minime relative ad ogni passo
    dist_min = [dist_min; d_min_1 d_min_2];
    
    % memorizzazione delle coordinate dei punti più vicini all'iperpiano
    x_min = [x_min_1;x_min_2];

    
    % Se la distanza calcolata è minore della soglia fissata (10) viene 
    % eseguito un training aggiuntivo
    if d_min_1 < 10 || d_min_2 < 10
        
        % predicted_label = etichette assegnate ai punti dalla
        % classificazione eseguita con il comando svmclassify
        model = svmtrain(predicted_label,P(:,:,t),'-t 0');
        
        % Vengono rieseguite le operazioni effettuate al primo passo dopo 
        % il Training
        beta_0_iniz = -model.rho;
        beta_iniz = zeros(n_f,1);
        N_sv = model.totalSV;
        sv_tmp = zeros(N_sv,n_f);

        for s = 1:N_sv
            for q = 1:n_f
                sv_tmp(s,q) = model.SVs(s,q);
            end
            beta_iniz = beta_iniz + model.sv_coef(s)*sv_tmp(s,:)';
        end

        beta = beta_iniz;
        beta_0 = beta_0_iniz;
        b = [beta; beta_0];
        
        % nuovo iperpiano ottimo
        retta = -(b(1)/b(2)*x + b(3)/b(2));

        % Memorizzazione del nuovo stato calcolato
        beta_tot = [beta_tot b];
    
        % plot SV + iperpiano ottimo nuovo (verde)
        plot(sv_tmp(:,1),sv_tmp(:,2),'o','MarkerEdgeColor','g','MarkerFaceColor','g');
        plot(x,retta,'g');
        pause(pp)
    end
    
    hold off
end
