% Two classes classification
% train a neural classifier
% evaluate the obtained results in a graphical mode
% evaluate the obtained error



clear variables
close all

% number of samples of each class
N = 200;
% define 2 clusters of input data
q = .6; % offset of classes
A = [rand(1,N/2)-q; rand(1,N/2)+q];
B = [rand(1,N/2)+q; rand(1,N/2)+q];
A = [A, [rand(1,N/2)+q; rand(1,N/2)-q]];
B = [B, [rand(1,N/2)-q; rand(1,N/2)-q]];

%Number of classes in the classification problem
numClasses=2;

% plot
figure
h1=plot(A(1,:),A(2,:),'xr');
hold on
h2=plot(B(1,:),B(2,:),'o');
grid on


% draw reference lines
xlim([-1 2]);
hline=refline(0,0.5);
hline.Color='black';
vline=line([0.5 0.5], [-1 2]);
vline.Color='black';

legend([h1 h2],{'A','B'})
xlabel('x')
ylabel('y')
title('Input data')


% INPUT vector
P = [A, B];
% TARGET vector
tA = zeros(1, size(A,2));
tB = ones(1, size(A,2));
T = [tA, tB];

% Divide into training and test DB

[trainInd,valInd,testInd] = dividerand(size(P,2),0.7,0,0.3);

P_train=P(:,trainInd);
T_train=T(:,trainInd);
P_test=P(:,testInd);
T_test=T(:,testInd);


% create a neural network
neuronsXLayer = 10; % number of neurons per layer
neuronTransferFunction{1} = 'tansig';


net = feedforwardnet(neuronsXLayer);

% training and testing data
net.divideParam.trainRatio = 1; 
net.divideParam.testRatio  = 0; 
net.divideParam.valRatio   = 0;

net.trainParam.epochs = 100;
net.trainParam.goal = 0.01;
for iL = 1: size(neuronsXLayer,2)
	net.layers{iL}.transferFcn = neuronTransferFunction{iL}; 
end


% train a neural network
[net,tr,Y,E] = train(net,P_train,T_train);


trainResult = net(P_train);
trainResult = round(trainResult);
trainResult(trainResult<0)=0;
trainResult(trainResult>numClasses-1)=numClasses-1;

testResult = net(P_test);
testResult = round(testResult);
testResult(testResult<0)=0;
testResult(testResult>numClasses-1)=numClasses-1;

%plot
figure,
plot(T_train)
hold on
plot(trainResult, '--r')
title('training results')

figure,
plot(T_test)
hold on
plot(testResult, '--r')
title('testing results')


trainErr = T_train ~= trainResult;
testErr = T_test ~= testResult;

figure,
plot(trainErr)
title('training error')

figure,
plot(testErr)
title('testing error')


% grid
coord = -1 : 0.01 : 2;
[Px,Py] = meshgrid(coord,coord);
pGrid = [Px(:) Py(:)]';

% simulate neural network on a grid
risGrid = net(pGrid);
F = scatteredInterpolant(Px(:), Py(:), risGrid');
risGridFull = F(Px, Py);


% plot classification regions
figure
imshow(risGridFull,[]);
axis normal
colormap(gca,jet);
hold on
plot((A(1,:)+1)*100,(A(2,:)+1)*100,'xr')
plot((B(1,:)+1)*100,(B(2,:)+1)*100,'o')
% draw reference lines
hline=refline(0,(0.5+1)*100);
hline.Color='black';
vline=line([(0.5+1)*100 (0.5+1)*100], [(-1+1)*100 (2+1)*100]);
vline.Color='black';

legend('A=0','B=1')
xlabel('x')
ylabel('y')
title('Output space')
colorbar

%Results
numTrainErr = size(find(trainErr > 0),2);
percTrainErr = (numTrainErr/size(T_train,2))*100;
meanTrainErr = mean(trainErr);
stdTrainErr = std(trainErr);



numTestErr = size(find(testErr > 0),2);
percTestErr = (numTestErr/size(T_test,2))*100;
meanTestErr = mean(testErr);
stdTestErr = std(testErr);


totalErr = [trainErr, testErr];
numTotalErr = size(find(totalErr > 0),2);
percTotalErr = (numTotalErr/size(T,2))*100;
meanTotalErr = mean(totalErr);
stdTotalErr = std(totalErr);


fprintf('\nRESULTS \n')
fprintf('TRAINING\n')
fprintf('n. of el. = %i \n', size(trainErr,2))
fprintf('n. of errors = %i \n', numTrainErr)
fprintf('Percentage of errors = %6.2f %%\n', percTrainErr)
fprintf('mean error = %6.2f \n', meanTrainErr)
fprintf('std error = %6.2f \n\n', stdTrainErr)
fprintf('TESTING\n')
fprintf('n. of el. = %i \n', size(testErr,2))
fprintf('n. of errors = %i \n', numTestErr)
fprintf('Percentage of errors = %6.2f %%\n', percTestErr)
fprintf('mean error = %6.2f \n', meanTestErr)
fprintf('std error = %6.2f \n\n', stdTestErr)
fprintf('TOTAL\n')
fprintf('n. of el. = %i \n', size(totalErr,2))
fprintf('n. of errors = %i \n', numTotalErr)
fprintf('Percentage of errors = %6.2f %%\n', percTotalErr)
fprintf('mean error = %6.2f \n', meanTotalErr)
fprintf('std error = %6.2f \n\n', stdTotalErr)











