function [w,bias,runw,numokw] = pocket(negative,positive,w,bias,runw,numokw,iterations)

% pocket.m
%
% Train a perceptron with the pocket algorithm with rachet, a variant 
% of the perceptron learning algorithm that works on data that isn't
% linearly separable. (Stephen Gallant, 1990)
%
% Initially:
%
% w = zeros(1,size(negative,2))
% bias = 0
% runw = 0
% numokw = 0
%
% You should only pass in non-zero values when you are continuing after
% having done some iterations.
%
% Binary feature vectors in negative and positive can be built
% with feature.pl or a similar program.
%
% Suggestions from Gallant 1990:
%
%   If the pocket weights were changed in the last (.8 * iterations) 
%   steps continue, passing in the new weight vector, bias, runw, and 
%   numokw that were output last time. Increase the number of iterations 
%   to (1.5 * iterations). Stop when the weights have remained unchanged
%   for the last 4/5 of the run.
%
%   Initially, interations = 10000 is suggested.
%
% Perform (Perceptron Classifier in Inform) v1.0
% Nick Montfort  http://nickm.com  2004-06-25

% Error if data isn't all of the same dimension.
if (size(negative,2) != size(positive,2))
  printf("Dimensions of positive and negative examples don't match.\n");
  break;
end

printf("Data looks good. Beginning training...\n");
fflush(stdout);

numpoints = size(negative,1) + size(positive,1);

% The current weights are set to 0 if we're beginning, or whatever
% w is if we're continuing.
c = w;  
biasc = bias;

% Current weights have classified 0 correctly so far.
runc = 0;

% Main loop.
lastchanged = 0;
i = 0;
while (i < iterations)
  i++;

  % Print a message every 100 iterations, so that we maintain hope.
  if (mod(i,100) == 0)
    printf("Iteration %i beginning: %i misclassified, run of %i correct.\n", i, numpoints - numokw , runw);
    fflush(stdout);
  end

  % Pick a random point.
  pt = floor(rand(1) * numpoints) + 1;

  % Assume we picked a positive point.
  class = 1;

  % If it's in the range of negative examples, correct that.
  if (pt <= size(negative,1))
    class = -1;
  end;

  % Check to see if our random point is classified correctly by current.
  if (class == -1)
    point = negative(pt,:);
    right = ((sum(point * c') + biasc) <= 0);
  else
    point = positive((pt-size(negative,1)),:);
    right = ((sum(point * c') + biasc) > 0);
  end

  % If right, check to see if current has a longer run than the pocket.
  if (right)
    runc++;
    if (runc > runw)

      % Count how many of the whole training set current gets right.
      numokc = 0;
      for j=(1:size(negative,1));
        numokc += ((sum(negative(j,:) * c') + biasc) <= 0);
      end
      for j=(1:size(positive,1));
        numokc += ((sum(positive(j,:) * c') + biasc) > 0);
      end

      % If it does better than pocket, replace pocket with current.
      if (numokc > numokw)
        lastchanged = i;
        w = c;
        biasw = biasc;
        runw = runc;
        numokw = numokc;
        printf("Pocket weights changed at iteration %i.\n", i);

        % Check to see if we got them all, and stop if so.
        if (numokw == numpoints)
          printf("Finished, data was linearly separable.\n");
          break;
        end
      end
    end

  % If not right, update current weights. Current now have no consecutive
  % correct classifications.
  else
    c += class * point;
    runc = 0;
  end
end
printf("Finished: %i misclassified and a run of %i correct for these weights,\nlast updated at iteration %i.\n", numpoints - numokw , runw, lastchanged);
