function perceptron ( )

%*****************************************************************************80
%
%% perceptron demonstrates the perceptron algorithm.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 April 2019
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'perceptron\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  The Perceptron.\n' );
  fprintf ( 1, '  Data file: index, rpm, vibration, rating\n' );
  fprintf ( 1, '  Rating is 0 for bad, 1 for good.\n' );
  fprintf ( 1, '  Use the perceptron algorithm to determine a\n' );
  fprintf ( 1, '  classifier f(rpm,vibration) -> {0, 1}\n' );

  data = load ( 'generators.txt' );
  
  rpm = data(:,2);
  vib = data(:,3);
  grade = data(:,4);

  n = length ( rpm );
%
%  Part 1.
%
  rpm_min = min ( rpm );
  rpm_max = max ( rpm );
  vib_min = min ( vib );
  vib_max = max ( vib );
  good = find ( grade == +1.0 );
  bad = find ( grade == 0.0 );
  grade(bad) = 0;
  n_good = length ( good );
  n_bad = length ( bad );
  bad_rpm_mean = mean ( rpm(bad) );
  bad_vib_mean = mean ( vib(bad) );
  good_rpm_mean = mean ( rpm(good) );
  good_vib_mean = mean ( vib(good) );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Generator Ratings\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of generators = %d\n', n );
  fprintf ( 1, '  %d good generators, and %d bad generators\n', n_good, n_bad );
  fprintf ( 1, '  %g <= RPM <= %g\n', rpm_min, rpm_max );
  fprintf ( 1, '  %g <= VIB <= %g\n', vib_min, vib_max );
  fprintf ( 1, '  GOOD: mean RPM = %g, mean VIB = %g\n', good_rpm_mean, good_vib_mean );
  fprintf ( 1, '  BAD:  mean RPM = %g, mean VIB = %g\n', bad_rpm_mean, bad_vib_mean );
  fprintf ( 1, '  %g <= VIB <= %g\n', vib_min, vib_max );

  figure ( 1 )
  plot ( rpm(good), vib(good), 'b+', rpm(bad), vib(bad), 'ro' )
  xlabel ( '<-- RPM -->' );
  ylabel ( '<-- VIB -->' );
  title ( 'Generator Ratings' );
  grid ( 'on' );
  axis ( 'equal' );
  filename = 'perceptron_data.png';
  print ( '-dpng', filename );
  fprintf ( 1, '  Graphics saved as "%s"\n', filename );
%
%  Part 2.
%

%
%  Work with standardized data.
%
  r = ( rpm - min ( rpm ) ) / ( max ( rpm ) - min ( rpm ) );
  v = ( vib - min ( vib ) ) / ( max ( vib ) - min ( vib ) );
%
%  Perceptron algorithm.
%
  alpha = 0.01;
  m = 3;
  w = ones(m,1) / m;
  x = [ ones(n,1), r, v ];

  e = 1;
  step = 0;

  while ( e ~= 0 && step < 100 )

    e = 0;
    step = step + 1;

    for i = 1 : n
      f = ( 0 < x(i,1:3) * w(1:3) );
      e = e + ( grade(i) ~= f );
      w(1:3,1) = w(1:3,1) + alpha * x(i,1:3)' * ( grade(i) - f );
    end

    w = w / norm ( w );

  end

  if ( e == 0 )
    fprintf ( 1, '  All training data classified on step %d\n', step );
  else
    fprintf ( 1, '  Iteration terminated without convergence on step %d\n', step );
  end
%
%  Report.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Perceptron weights:\n' );
  fprintf ( 1, '  f(x) = %g + %g * r + %g * v\n', w );
  fprintf ( 1, '\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Index    x*w  (0<x*w)  Rating\n' );
  fprintf ( 1, '\n' );
  c = x * w;
  f = ( 0 < c );
  for j = 1 : n
    fprintf ( 1,'     %2d  %6.2f      %g      %g\n', j, c(j), f(j), grade(j) );
  end
%
%  Plot.
%
  px = [];
  py = [];

  rv = 0.0;
  vv = ( - w(1) - w(2) * rv ) / w(3);
  if ( 0.0 <= vv && vv <= +1.0 )
    px = [ px, rv ];
    py = [ py, vv ];
  end

  vv = 0.0;
  rv = ( - w(1) - w(3) * vv ) / w(2);
  if ( 0.0 <= rv && rv <= +1.0 )
    px = [ px, rv ];
    py = [ py, vv ];
  end

  vv = +1.0;
  rv = ( - w(1) - w(3) * vv ) / w(2);
  if ( 0.0 <= rv && rv <= +1.0 )
    px = [ px, rv ];
    py = [ py, vv ];
  end

  rv = +1.0;
  vv = ( - w(1) - w(2) * rv ) / w(3);
  if ( 0.0 <= vv && vv <= +1.0 )
    px = [ px, rv ];
    py = [ py, vv ];
  end

  figure ( 2 )
  hold on
  plot ( r(good), v(good), 'b+', r(bad), v(bad), 'ro' );
  plot ( px, py, 'k-', 'linewidth', 3 );
  hold off
  xlabel ( '<-- RPM -->' );
  ylabel ( '<-- VIB -->' );
  title ( 'Generator Ratings Classifier' );
  grid ( 'on' );
  axis ( 'equal' );
  filename = 'perceptron_classifier.png';
  print ( '-dpng', filename );
  fprintf ( 1, '  Graphics saved as "%s"\n', filename );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'perceptron\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end
