% weight_vector = perceptron(InputSamples,TrainingRate)
% the perceptron training algorithm pg 47 Elements of ANN
% Given Input, a set of training input vectors of the form 
%   [X0,X1,...Xn-1,Class] 
% where X0 is a constant 1 and Class is -1 for Class0 or +1 for Class1
% and a TrainingRate = (0,1]
% returns weight a vector of the form 
%   [W0,W1,...Wm] : m = n-1
% such that the weight vector dichotomizes Input. If the training samples 
% are not linearly seperable it does not terminate. In other words 
% determines (approximates) a weight vector such that 
%  W0 + W1*X1 + ,..., + Wm*Xn-1 = 0
function w = perceptron(Input,n)
    Ip = Input(:,1:end-1); % Ip: the sample x's
    c  = Input(:,end);     % c: vector of corresponding classes
    [r,cols] = size(Ip);   % cols: number of columns in Ip
    w{1} = rand(1,cols)';  % create random weight vector of size cols
    k = 2;                 % using 1-based indexing set k to 2
    
    % while there exist input vectors in Ip that are missclassified
    % by w{k-1} pick a missclassifed Ij in Ip and adjust w{k-1} by delta w
    % to get w{k}
    i = misclassified(Ip,w{k-1},c,r);
    while i 
        xk = c(i)*Ip(i,:); 
        w{k} = w{k-1} + n*xk'; 
        k = k + 1;
        i = misclassified(Ip,w{k-1},c,r);
    end
    w = w{k-1}'; % return the column vector
    
    % result = misclassified(I,w,c,n)
    % returns the index of the first misclassified input vector 
    % in I if no input vectors in I are misclassifed returns 0
    function result = misclassified(I,w,c,n)
        result = 0;
        ij = I * w;

        for i = 1:n
            if (ij(i) <= 0 && c(i) ~= -1) || (ij(i) > 0 && c(i) ~= 1) 
                result = i;
                return;
            end
        end
        