% iterations = plot_adaline(Input,
%                           TrainingRate,
%                           SatisfactoryMSE,
%                           Pause)
% shows the process of lms adaline 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_adaline(I,n,smse,p)
    if nargin == 3 
        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('LMS-Adaline');
    
%    disp('Press any key to Start');
%    pause;
    
    % start the adaline
    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 the mean squared error is unsatisfactory and the computational
    % bounds are not exceeded
    % NOTE: for mean squared error, find the mean of the vector of the 
    % of the squared errors where c = desired output, net = Ip * w{k-1}  
    % => use .^ 2 to compute squared errors of (c - Ip * w{k-1}) and take 
    % the mean of this vector
    mse = mean((c-Ip*w{k-1}).^2);
    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},mse,k-1,length(M(:,1))); % assumes some are misclassified
    hold off
    
    while k < 100000 && mean((c-Ip*w{k-1}).^2) > smse
        % we'll selct Ij in a sequence Ij1 - Ij-n
        Ij = Ip(mod(k,rows)+1,1:end);
        dj = c(mod(k,rows)+1);
        
        % update the weight vector to
        % n * (dj - netj)*ij
        w{k} = w{k-1} + (n * (dj - Ij*w{k-1}) * Ij)';
        k = k + 1;
        mse = mean((c-Ip*w{k-1}).^2);
        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},mse,k-1,m);
    end
    k = k-1;
    
    % 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,mse,k,m)
    % sets the title to the equation specified by w
    % and the next line, mse = MSE, k = num iterations, 
    % m = num misclassifications
    function set_title(w,mse,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(['Adaline: ',w1,'x_1',op,w2,'x_2 = ',w0,char(10), ...
               'mse = ',num2str(mse) '    k = ',num2str(k), ... 
               '   m = ',num2str(m)]);
