function [ x, fx, k ] = compass_search ( function_handle, m, x, delta_tol, ...
  delta, k_max )

%*****************************************************************************80
%
%% compass_search() carries out a direct search minimization algorithm.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    04 January 2012
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Tamara Kolda, Robert Michael Lewis, Virginia Torczon,
%    Optimization by Direct Search: New Perspectives on Some 
%    Classical and Modern Methods,
%    SIAM Review,
%    Volume 45, Number 3, 2003, pages 385-482. 
%
%  Input:
%
%    function handle FUNCTION_HANDLE ( M, X ), a handle for the function
%    to be minimized.
%
%    integer M, the number of variables.
%
%    real X(M), a starting estimate for the minimizer.
%
%    real DELTA_TOL, the smallest step size that is allowed.
%
%    real DELTA, the starting stepsize.  
%
%    integer K_MAX, the maximum number of steps allowed.
%
%  Output:
%
%    real X(M), the estimated minimizer.
%
%    real FX, the function value at X.
%
%    integer K, the number of steps taken.
%
  k = 0;
  x = x(:);
  fx = function_handle ( m, x );

  if ( delta_tol <= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'compass_search - Fatal error!\n' );
    fprintf ( 1, '  DELTA_TOL <= 0.0.\n' );
    error ( 'compass_search - Fatal error!' );
  end

  if ( delta <= delta_tol )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'compass_search - Fatal error!\n' );
    fprintf ( 1, '  DELTA < DELTA_TOL.\n' );
    error ( 'compass_search - Fatal error!' );
  end

  while ( k < k_max )

    k = k + 1;
%
%  For each coordinate direction I, seek a lower function value
%  by increasing or decreasing X(I) by DELTA.
%
    decrease = 0;
    s = + 1.0;
    i = 1;

    for ii = 1 : 2 * m

      xd = x;
      xd(i) = xd(i) + s * delta;
      fxd = function_handle ( m, xd );
%
%  As soon as a decrease is noticed, accept the new point.
%
      if ( fxd < fx )
        x = xd;
        fx = fxd;
        decrease = 1;
        break;
      end

      s = - s;
      if ( s == + 1.0 )
        i = i + 1;
      end

    end
%
%  If no decrease occurred, reduce DELTA.
%
    if ( ~ decrease )
      delta = delta / 2.0;
      if ( delta < delta_tol )
        break;
      end
    end

  end

  return
end
 
