% iterations = plot_perceptron(Input,TrainingRate,Pause)
% shows the process of perceptron on 2-d data where Input is a set of input 
% vectors of the form 
%  [X0 X1 X2 Class] 
% such that X0 is a constant 1, X1 and X2 are the data and Class is either
% -1 for Class 0 or 1 for Class 1 and given TrainingRate (0-1]
function k = plot_perceptron(I,n,p)
    if nargin == 2 
        p = 0.3;
    end
        
    % seperate the two classes c0 and c1 by Class
    % then get X1 and X2 for both
    c0 = I(find(I(:,end) == -1),2:3);
    c1 = I(find(I(:,end) == 1),2:3);
    c0x1 = c0(:,1);
    c0x2 = c0(:,2);
    c1x1 = c1(:,1);
    c1x2 = c1(:,2);
    
    % plot the sample points, let class 0 be a green '+' and 
    % class1 a blue '*'
    plot(c0x1,c0x2,'g+',c1x1,c1x2,'b*');
    
    % scale the x and y axis - add 0.2 to the bounding area so we see all 
    % points
    maxx1 = max(I(:,2)) + 0.2;
    minx1 = min(I(:,2)) - 0.2;
    maxx2 = max(I(:,3)) + 0.2;
    minx2 = min(I(:,3)) - 0.2;
    axis([minx1 maxx1 minx2 maxx2]);
    
    % legend
    legend('Class 0','Class 1','Location','Best');
    title('Perceptron');
    
%    disp('Press any key to Start');
%    pause;
    
    % start the perceptron
    % NOTE: the book sets w0 to -1 automatically
    % such as w{1} = [-1 randn(1,cols-1)]';  
    Ip = I(:,1:end-1);      % Ip: the sample x's
    c  = I(:,end);          % c: vector of corresponding classes
    [rows,cols] = size(Ip); % cols: number of columns in Ip
    w{1} = randn(1,cols)';  % create random weight vector of size cols
    k = 2;                  % using 1-based indexing set k to 2
    
    % x1 and x2 for w
    x1 = 0;
    x2 = 0;
    
    % plot w{1}
    hold on
    x2 = minx2:.1:maxx2; % make the line cover the figure
    x1 = (-w{1}(1) - w{1}(3)*x2) / w{1}(2);
    h = plot(x1,x2,'k-');
    set(h,'EraseMode','xor','MarkerSize',18);
    hold off
        
    % while there exist input vectors in Ip that are missclassifed by
    % w{k-1} pick a missclassfiied Ij in Ip and adjust w{k-1} by delta w
    % to get w{k}
    i = is_misclassified(Ip,w{k-1},c,rows); % should combine these two
    M = misclassified(Ip,w{k-1},c,rows);
    hold on
    h1 = plot(M(:,1),M(:,2),'mo');
    set(h1,'EraseMode','xor','MarkerSize',8);

    % set the title
    set_title(w{k-1},k-1,length(M(:,1))); % assumes some are misclassified
    hold off
    
    while i        
        % compute new weight vector
        xk = (c(i)*Ip(i,1:end))';
        w{k} = w{k-1} + n*xk;
        k = k + 1;
        i = is_misclassified(Ip,w{k-1},c,rows);
        M = misclassified(Ip,w{k-1},c,rows);
        
        % draw the new computation
        drawnow;
        x1 = (-w{k-1}(1) - w{k-1}(3)*x2) / w{k-1}(2);
        pause(p);
        set(h,'XData',x1,'YData',x2);
        
        % circle misclassfied
        if ~isempty(M)
            set(h1,'XData',M(:,1),'YData',M(:,2));
            m = length(M(:,1));
        else
            set(h1,'XData',[],'YData',[]);
            m = 0;
        end
        
        % do the title
        set_title(w{k-1},k-1,m);
    end
    k = k-1;
    
    % result = is_misclassified(I,w,c)
    % returns the index of the first misclassified input vector 
    % in I if no input vectors in I are misclassifed returns 0
    function result = is_misclassified(I,w,c,r)
        result = 0;
        ij = I * w;
       
        for i = 1:r
            if (ij(i) <= 0 && c(i) ~= -1) || (ij(i) > 0 && c(i) ~= 1) 
                result = i;
                return;
            end
        end
    
    %NOTE: not the best way of doing but this is a quick fix
    % should combine this with is_misclassifed    
    % M = misclassified(I,w,c)
    % M is a list of missclassfied samples
    function M = misclassified(I,w,c,r)    
        ij = I * w;
        M = [];
        for i = 1:r
            if (ij(i) <= 0 && c(i) ~= -1) || (ij(i) > 0 && c(i) ~= 1) 
                M = [M ; I(i,2:end)];
            end
        end
        
    % set_title(w)
    % sets the title to the equation specified by w
    % and the next line, k = num iterations, m = num misclassifications
    function set_title(w,k,m)
        % given w = [w0 ,w1 w2], set the title to the equation  
        % w1x1 + w2x2 = w0 or w1x1 - w2x2 = w0
        % depending on whether w2 is > 0 or < 0
        op = ' + ';
        if w(3) < 0 
            op = ' - ';
        end
        
        % for w1 and w2: if they're 1 (-1) simplify
        % not worrying about 0 right now
        if abs(w(2)) == 1
            if w(2) > 0 
                w1 = '';
            else
                wi = '-';
            end
        else
            w1 = num2str(w(2));
        end
        
        % for w2
        if abs(w(3)) == 1
            w2 = '';
        else
            w2 = num2str(abs(w(3)));
        end
        
        % for w0, move w(1) to the right of the equation
        w0 = num2str(-w(1));
        
        title(['Perceptron: ',w1,'x_1',op,w2,'x_2 = ',w0,char(10), ...
               'k = ',num2str(k),'   m = ',num2str(m)]);
