function [ arg, status, a, b ] = local_min_rc ( a, b, status, value )

%*****************************************************************************80
%
%% LOCAL_MIN_RC seeks a minimizer of a scalar function of a scalar variable.
%
%  Discussion:
%
%    This routine seeks an approximation to the point where a function
%    F attains a minimum on the interval (A,B).
%
%    The method used is a combination of golden section search and
%    successive parabolic interpolation.  Convergence is never much
%    slower than that for a Fibonacci search.  If F has a continuous
%    second derivative which is positive at the minimum (which is not
%    at A or B), then convergence is superlinear, and usually of the
%    order of about 1.324...
%
%    The routine is a revised version of the Brent local minimization 
%    algorithm, using reverse communication.
%
%    It is worth stating explicitly that this routine will NOT be
%    able to detect a minimizer that occurs at either initial endpoint
%    A or B.  If this is a concern to the user, then the user must
%    either ensure that the initial interval is larger, or to check
%    the function value at the returned minimizer against the values
%    at either endpoint.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 October 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Richard Brent,
%    Algorithms for Minimization Without Derivatives,
%    Dover, 2002,
%    ISBN: 0-486-41998-3,
%    LC: QA402.5.B74.
%
%    David Kahaner, Cleve Moler, Steven Nash,
%    Numerical Methods and Software,
%    Prentice Hall, 1989,
%    ISBN: 0-13-627258-4,
%    LC: TA345.K34.
%
%  Parameters
%
%    Input, real A, B, the lower and upper bounds for an interval containing 
%    the minimizer.  It is required that A < B.
%
%    Input, integer STATUS, used to communicate between the user and the routine.  
%    The user only sets STATUS to zero on the first  call, to indicate that this
%    is a startup call.  On each subsequent call, the input value of STATUS
%    should be its output value from the previous call.
%
%    Input, real VALUE, the function value at ARG, as requested
%    by the routine on the previous call.
%
%    Output, real ARG, the currently estimate for the minimizer.  On return 
%    with STATUS positive, the user is requested to evaluate the function at ARG, 
%    and return the value in VALUE.  On return with STATUS zero, ARG is the routine's
%    estimate for the function minimizer.
%
%    Output, integer STATUS.  The routine returns STATUS positive to request 
%    that the function be evaluated at ARG, or returns STATUS as 0, to indicate 
%    that the iteration is complete and that ARG is the estimated minimizer.
%
%    Output, real A, B, the lower and upper bounds for an interval containing 
%    the minimizer.
%
%
%  Local parameters:
%
%    C is the squared inverse of the golden ratio.
%
%    EPS_SQRT is the square root of the relative machine precision.
%
  persistent arg_save
  persistent c
  persistent d
  persistent e
  persistent eps_sqrt
  persistent fu
  persistent fv
  persistent fw
  persistent fx
  persistent midpoint
  persistent p
  persistent q
  persistent r
  persistent tol
  persistent tol1
  persistent tol2
  persistent u
  persistent v
  persistent w
  persistent x
%
%  STATUS (INPUT) = 0, startup.
%
  if ( status == 0 )

    if ( b <= a )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'LOCAL_MIN_RC - Fatal error!\n' );
      fprintf ( 1, '  A < B is required, but\n' );
      fprintf ( 1, '  A = %f\n', a );
      fprintf ( 1, '  B = %f\n', b );
      status = -1;
      error ( 'LOCAL_MIN_RC - Fatal error!' )
    end

    c = 0.5 * ( 3.0 - sqrt ( 5.0 ) );

    eps_sqrt = sqrt ( eps );
    tol = eps;

    v = a + c * ( b - a );
    w = v;
    x = v;
    e = 0.0;

    status = 1;
    arg = x;
    arg_save = arg;

    return
%
%  STATUS (INPUT) = 1, return with initial function value of FX.
%
  elseif ( status == 1 )

    fx = value;
    fv = fx;
    fw = fx;
%
%  STATUS (INPUT) = 2 or more, update the data.
%
  elseif ( 2 <= status )

    fu = value;

    if ( fu <= fx )

      if ( x <= u )
        a = x;
      else
        b = x;
      end

      v = w;
      fv = fw;
      w = x;
      fw = fx;
      x = u;
      fx = fu;

    else

      if ( u < x )
        a = u;
      else
        b = u;
      end

      if ( fu <= fw || w == x )
        v = w;
        fv = fw;
        w = u;
        fw = fu;
      elseif ( fu <= fv || v == x || v == w )
        v = u;
        fv = fu;
      end

    end

  end
%
%  Take the next step.
%
  midpoint = 0.5 * ( a + b );
  tol1 = eps_sqrt * abs ( x ) + tol / 3.0;
  tol2 = 2.0 * tol1;
%
%  If the stopping criterion is satisfied, we can exit.
%
  if ( abs ( x - midpoint ) <= ( tol2 - 0.5 * ( b - a ) ) )
    status = 0;
    arg = arg_save;
    return
  end
%
%  Is golden-section necessary?
%
  if ( abs ( e ) <= tol1 )
    if ( midpoint <= x )
      e = a - x;
    else
      e = b - x;
    end

    d = c * e;
%
%  Consider fitting a parabola.
%
  else

    r = ( x - w ) * ( fx - fv );
    q = ( x - v ) * ( fx - fw );
    p = ( x - v ) * q - ( x - w ) * r;
    q = 2.0 * ( q - r );
    if ( 0.0 < q )
      p = - p;
    end
    q = abs ( q );
    r = e;
    e = d;
%
%  Choose a golden-section step if the parabola is not advised.
%
    if ( ...
      ( abs ( 0.5 * q * r ) <= abs ( p ) ) || ...
      ( p <= q * ( a - x ) ) || ...
      ( q * ( b - x ) <= p ) )

      if ( midpoint <= x )
        e = a - x;
      else
        e = b - x;
      end

      d = c * e;
%
%  Choose a parabolic interpolation step.
%
    else

      d = p / q;
      u = x + d;

      if ( ( u - a ) < tol2 )
        d = tol1 * r8_sign ( midpoint - x );
      end

      if ( ( b - u ) < tol2 )
        d = tol1 * r8_sign ( midpoint - x );
      end

    end

  end
%
%  F must not be evaluated too close to X.
%
  if ( tol1 <= abs ( d ) )
    u = x + d;
  end

  if ( abs ( d ) < tol1 )
    u = x + tol1 * r8_sign ( d );
  end
%
%  Request value of F(U).
%
  arg = u;
  arg_save = arg;
  status = status + 1;

  return
end
