clear all;close all;clc;

% Skript pro uceni site 2-2-2 algorytmem zpetneho sireni chyby. 
% Struktura site je zobrazena na obrazku:
% 2 vstupy, 
% 2 neuronu (3 a 4 na obr.) ve skryte vrstve, 
% 2 neuronu (1 a 2 na obr.) ve vystupni vrstve :
%
%           x1--3--1--y1  
%             \/ \/
%             /\ /\
%           x2--4--2--y2
%
%_______________________________________________________________________
% 1. NASTAVENI INICIACNICH HODNOT PARAMETRU SITE:

% Prahove hodnoty pro kazdy neuron (daji se nastavit pomoci prikazu rand(1)):
teta1 =  0.01; 
teta2 = -0.05; 
teta3 =  0.04;
teta4 = -0.02; 

% Vektory vah pro kazdy neuron (daji se nastavit pomoci prikazu 2*rand(1,2)-1):
w1    =  2*[0.43; 0.51]-1;
w2    =  2*[0.05; 0.02]-1;
w3    =  2*[0.1;  0.02]-1;
w4    =  2*[0.3;  0.04]-1; 

% Ukladani iniciacnich hodnot vah a prahu do samostatnych vektoru (jenom pro nasledne porovnani):
w1_inic = w1; teta1_inic = teta1;
w2_inic = w2; teta2_inic = teta2;
w3_inic = w3; teta3_inic = teta3;
w4_inic = w4; teta4_inic = teta4;
%_______________________________________________________________________
% 2. VYTVORENI UCEBNI MNOZINY:

% Matice vstupnich vzoru:
x = [  0,  1,  0,  1;...
       0,  0,  1,  1    ];
        
% Matice pozadovanych vystupu (kazdy sloupec odpovida dvojice vystupu
% y1 a y2, viz obr.):        
d = [  0,  1,  1,  1;...
       0,  0,  0,  1    ];
        
% Pocet vstupnich/vystupnich vektoru (pocet iteraci v jedne epose):        
M = 4;

for ind=1:M
%     y(ind)=neuron_skok(x(:,ind),w,theta);
    y3=neuron_sigm(x(:,ind),w3,teta3,0.5); %
    y4=neuron_sigm(x(:,ind),w4,teta4,0.5); %
    y1(ind)=neuron_sigm([y3; y4],w1,teta1,0.5); %
    y2(ind)=neuron_sigm([y3; y4],w2,teta2,0.5); %
end
y1 % vystupy nenaucene site
y2
% Zobrazeni 3D (hranicni plocha misto hranicni privky):
[xs,ys]=meshgrid(0:0.02:1,0:0.02:1);
N = size(xs,1)*size(xs,2);
xx=[reshape(xs,1,N); reshape(ys,1,N)];
for ind=1:N
%     y(ind)=neuron_skok(x(:,ind),w,theta);
    y3=neuron_sigm(xx(:,ind),w3,teta3,0.5); %
    y4=neuron_sigm(xx(:,ind),w4,teta4,0.5); %
    y1(ind)=neuron_sigm([y3; y4],w1,teta1,0.5); %
    y2(ind)=neuron_sigm([y3; y4],w2,teta2,0.5); %
end
figure
subplot(1,2,1)
yv = reshape(y1,size(xs));
surf(xs,ys,yv); % zobrazeni (vektory x-ovych, y-ovych a z-ovych souradnic)
shading interp
colormap(jet);
xlabel('x_1');
ylabel('x_2');
zlabel('y')
subplot(1,2,2)
yv = reshape(y2,size(xs));
surf(xs,ys,yv); % zobrazeni (vektory x-ovych, y-ovych a z-ovych souradnic)
shading interp
colormap(jet);
xlabel('x_1');
ylabel('x_2');
zlabel('y')

title('Vystupy pred ucenim')
        

%______________________________________________________________________
% 3. NASTAVENI PARAMETRU UCENI SITE:
T        = 0.5;        % parametr sigmoidalni funkce, ovlivnuje strmost sigmoidy
mu       = 1;          % konstanta uceni
Ep       = 0.05;       % pripustna hodnota chyby
N_epocha = 50000;      % maximalni pocet iteraci (epoch uceni)
y34      = zeros(1,2); % inicializace vystupu ze skryte vrstvy
%_____________________________________________________________________
% 4. UCENI ZPETNYM SIRENIM CHYBY:

for i_epocha = 1:N_epocha
    e = 0;
    for i_vzor = 1:M
    
    % 1. Vypocet vystupu site doprednim sirenim
        
        % Vypocet vystupu neuronu skryte vrstvy:
        % Neuron 3
        y3 = neuron_sigm(x(:,i_vzor),w3,teta3,T);
        % Neuron 4
        y4 = neuron_sigm(x(:,i_vzor),w4,teta4,T);
        % Vystup skryte vrstvy: 
        y34 = [y3; y4];
        
        % Vypocet vystupu neuronu vystupni vrstvy:
        % Neuron 1
        y1 = neuron_sigm(y34,w1,teta1,T);
        % Neuron 2
        y2 = neuron_sigm(y34,w2,teta2,T);
        
    % 2. Vypocet chyby zpetnym sirenim
    
        % Vypocet chyby vystupnich neuronu na predlozeny vzor:
        % Neuron 1
        delta1 = d(1,i_vzor)-y1;
        % Neuron 2
        delta2 = d(2,i_vzor)-y2;
        
        % Prenos chyby na skrytou vrstvu: 
        % Neuron 3
        delta3 = delta1*w1(1)+delta2*w2(1);
        % Neuron 4
        delta4 = delta1*w1(2)+delta2*w2(2);
     
    % 3. Uprava vah vsech neuronu (krome vstupnich):
        % -----------------------------------------------------------------
        % Poznamka:
        % w(t)=w(t-1)+ mu*grad(w), kde grad(w)=dE/dw je parcialni derivace
        % chyby E podle vahy w.
        %
        % Parcialni derevaci si vypocteme podle vztahu:
        % dE/dw=(dE/dy)*(dy/da)*(da/dw), kde a je aktivita neuronu.
        %
        % Dale: dE/dy=delta; dy/da=df(a)/da (fa-aktivacni funkce => pro 
        % sigmoidalni funkci plati: dy/da=y(1-y));
        % da/dw=y (tj. vystup predchozi vrstvy, ktery je vstupem pro 
        % danou aktualni vrstvu);
        %------------------------------------------------------------------
        
        % Uprava vah pro skrytou vrstvu:
        % Neuron 3
        teta3 = teta3-mu*delta3*1/T*(y3*(1-y3));
        w3(1) = w3(1)+mu*delta3*1/T*(y3*(1-y3))*x(1,i_vzor); 
        w3(2) = w3(2)+mu*delta3*1/T*(y3*(1-y3))*x(2,i_vzor);
        % Neuron 4
        teta4 = teta4-mu*delta4*1/T*(y4*(1-y4));
        w4(1) = w4(1)+mu*delta4*1/T*(y4*(1-y4))*x(1,i_vzor);
        w4(2) = w4(2)+mu*delta4*1/T*(y4*(1-y4))*x(2,i_vzor);
        
        % Uprava vah pro vystupni vrstvu:
        % Neuron 1
        teta1 = teta1-mu*delta1*1/T*(y1*(1-y1));
        w1(1) = w1(1)+mu*delta1*1/T*(y1*(1-y1))*y34(1);
        w1(2) = w1(2)+mu*delta1*1/T*(y1*(1-y1))*y34(2);
        % Neuron 2 
        teta2 = teta2-mu*delta2*1/T*(y2*(1-y2));
        w2(1) = w2(1)+mu*delta2*1/T*(y2*(1-y2))*y34(1);
        w2(2) = w2(2)+mu*delta2*1/T*(y2*(1-y2))*y34(2);
            
    % 4. Vypocet kvadraticke chyby site (vystupni chyba):        
        delta12 = [delta1 delta2];
        e       = e+delta12*delta12'; % e=e+delta12^2;
    end
    % Stredni kvadraticka chyba za epochu:
    E(i_epocha) = e/M;
    
    % Podminka zastaveni procesu uceni:
    if E(i_epocha) <= Ep
        break
    end
end
%__________________________________________________________________________
% 5. VYKRESLENI PRUBEHU STREDNI KVADRATICKE CHYBY
        figure;
        plot(E);
        title('Prubeh stredni kvadraticke chyby')
        xlabel('Pocet epoch')
        ylabel('Stredni kvadraticka chyba')
        disp(['Pocet provedenych epoch: ', num2str(i_epocha)])
        disp(['Prahova hodnota 1. neuronu:', num2str(teta1)])
        disp(['Vahove hodnoty 1. neuronu: ', num2str(w1')])
        disp(['Prahova hodnota 2. neuronu:', num2str(teta2)])
        disp(['Vahove hodnoty 2. neuronu: ', num2str(w2')])
        disp(['Prahova hodnota 3. neuronu:', num2str(teta3)])
        disp(['Vahove hodnoty 3. neuronu: ', num2str(w3')])
        disp(['Prahova hodnota 4. neuronu:', num2str(teta4)])
        disp(['Vahove hodnoty 4. neuronu: ', num2str(w4')])

        
       
for ind=1:M
%     y(ind)=neuron_skok(x(:,ind),w,theta);
    y3=neuron_sigm(x(:,ind),w3,teta3,0.5); %
    y4=neuron_sigm(x(:,ind),w4,teta4,0.5); %
    y1(ind)=neuron_sigm([y3; y4],w1,teta1,0.5); %
    y2(ind)=neuron_sigm([y3; y4],w2,teta2,0.5); %
end
y1 % vystup naucene site
y2
% Zobrazeni 3D (plocha misto primky):
for ind=1:N
%     y(ind)=neuron_skok(x(:,ind),w,theta);
    y3=neuron_sigm(xx(:,ind),w3,teta3,0.5); %
    y4=neuron_sigm(xx(:,ind),w4,teta4,0.5); %
    y1(ind)=neuron_sigm([y3; y4],w1,teta1,0.5); %
    y2(ind)=neuron_sigm([y3; y4],w2,teta2,0.5); %
end
figure
subplot(1,2,1)
yv = reshape(y1,size(xs));
surf(xs,ys,yv); % zobrazeni (vektory x-ovych, y-ovych a z-ovych souradnic)
shading interp
colormap(jet);
xlabel('x_1');
ylabel('x_2');
zlabel('y')
subplot(1,2,2)
yv = reshape(y2,size(xs));
surf(xs,ys,yv); % zobrazeni (vektory x-ovych, y-ovych a z-ovych souradnic)
shading interp
colormap(jet);
xlabel('x_1');
ylabel('x_2');
zlabel('y')
title('Vystupy po uceni')
        