Follow this link to skip to the main content

1d_function_solver.cc

Go to the documentation of this file.
00001 // -*-c++-*-
00002 //---------------------------< /-/ CLARAty /-/ >------------------------------
00003 /**
00004  * @file  1d_function_solver.cc
00005  *
00006  * Provides algorithms to (a) find the roots for a single variable
00007  * math function (i.e. zero crossings), and (b) the local
00008  * minimum/maximum of a single variable function over a specified
00009  * interval. (a) roots is implemented using a Newton Raphson
00010  * minimization iterative technique.
00011  *
00012  * <br>@b Designer(s):  Hari Nayar
00013  * <br>@b Author(s):    Issa A.D. Nesnas
00014  * <br>@b Date:         May 15, 2001
00015  *
00016  * <b>Software License:</b><br>
00017  * <code>  http://claraty.jpl.nasa.gov/license/open_src/  or
00018  *         file: license/open_src.txt  </code>
00019  *
00020  * &copy; 2006, Jet Propulsion Laboratory, California Institute of Technology<br>
00021  *
00022  * $Revision: 1.4 $
00023  */
00024 //-----------------------------------------------------------------------------
00025 
00026 #include "claraty/1d_function_solver.h"
00027 #include <iostream>
00028 #include <math.h>
00029 
00030 using namespace std;
00031 
00032 namespace claraty {
00033 
00034 //-----------------------------------------------------------------------------
00035 /**
00036  * 1-D function solver.
00037  *
00038  * @param[in]   function  Function which accepts double arguments
00039  * @param[in]   guess
00040  * @param[in]   max_iterations
00041  * @param[in]   tolerance
00042  * @param[in]   perturbation
00043  * @param[in]   step_size
00044  */
00045 
00046 N_1D_Function_Solver::
00047 N_1D_Function_Solver(double (*function)(double x),
00048                       double guess,
00049                       int    max_iterations,
00050                       double tolerance,
00051                       double perturbation,
00052                       double step_size)
00053   :
00054   _function1(NULL)
00055 { 
00056   set_function(function);
00057   set_initial_guess(guess);
00058   set_maximum_iterations(max_iterations);
00059   set_solution_tolerance(tolerance);
00060   set_perturbation(perturbation);
00061   set_step_size(step_size);
00062 }
00063 
00064 //-----------------------------------------------------------------------------
00065 /**
00066  * 1-D generic function solver.
00067  *
00068  * @param[in]   function  Function which accepts <> arguments.
00069  * @param[in]   guess
00070  * @param[in]   max_iterations
00071  * @param[in]   tolerance
00072  * @param[in]   perturbation
00073  * @param[in]   step_size
00074  */
00075 N_1D_Function_Solver::
00076 N_1D_Function_Solver(Function<> * function,
00077                      double       guess,
00078                      int          max_iterations,
00079                      double       tolerance,
00080                      double       perturbation,
00081                      double       step_size)
00082   :
00083   _function2(NULL)
00084 {
00085   set_function(function);
00086   set_initial_guess(guess);
00087   set_maximum_iterations(max_iterations);
00088   set_solution_tolerance(tolerance);
00089   set_perturbation(perturbation);
00090   set_step_size(step_size);
00091 }
00092 
00093 //-----------------------------------------------------------------------------
00094 /**
00095  * Find root of a function.
00096  *
00097  * @param [out] result
00098  * @return      Return code.
00099  */
00100 int N_1D_Function_Solver::
00101 find_root(double& result)
00102 {
00103   int  iterations = 0;
00104   bool terminate  = false;
00105   int return_code = CONTINUE_ITERATION;
00106   double current_value, next_value=0, delta_value;
00107   double derivative;
00108   
00109   while (!terminate)
00110     {
00111       // Compute the function value at the current guess
00112       current_value = _function(_guess);
00113       
00114       // If the current value is below the threshold,
00115       // set termination condition and quit the loop
00116       
00117       if (fabs(current_value) < _error_tolerance)
00118         {
00119           terminate = true;
00120           return_code = SOLVED;
00121         }
00122       else
00123         {
00124           // Compute the function value at a delta perturbation from
00125           // the current guess to determine the derivative of the function
00126           next_value = _function(_guess+_perturbation);
00127           delta_value = next_value - current_value;
00128             
00129           // Compute the derivative 
00130           derivative = delta_value/_perturbation;
00131           
00132           // Use the derivative to determine the next guess
00133           _guess -= current_value / derivative;
00134           
00135           // Increment iteration counter
00136           iterations++;
00137           
00138           // Check for termination
00139           if (iterations > _max_iterations)
00140             {
00141               terminate = true;
00142               return_code = MAX_ITERATIONS_EXCEEDED;
00143             }
00144         }
00145 #ifdef DEBUG
00146       cout << "Iteration #: "      << iterations
00147            << "  Current guess = " << _guess 
00148            << "  Current value = " << current_value
00149            << "  Next value = "    << next_value;
00150            << endl;
00151 #endif // DEBUG
00152     }
00153     result = _guess;
00154     return return_code;
00155 }
00156 
00157 //-----------------------------------------------------------------------------
00158 /**
00159  * Bisection.
00160  *
00161  * @param[out]  x0
00162  * @param[out]  x2
00163  * @param[out]  x4
00164  * @param[out]  y0
00165  * @param[out]  y2
00166  * @param[out]  y4
00167  */
00168 void N_1D_Function_Solver::
00169 _bisect(double &x0, double &y0,
00170         double &x2, double &y2,
00171         double &x4, double &y4)
00172 {
00173   // Bisect the first interval
00174   double x1 = ( x0 + x2 )/2;
00175   double y1 = _function(x1);
00176   
00177   // if new point is lower, use as new middle
00178   if(y1 < y2)
00179     {
00180       x4 = x2; y4 = y2; x2 = x1; y2 = y1;
00181       return;
00182     }
00183     
00184   // if it's higher, move in left limit
00185   if(y1 > y2)
00186     {
00187       x0 = x1; y0 = y1;
00188     }
00189     
00190   // Bisect the second interval
00191   double x3 = ( x2 + x4 )/2;
00192   double y3 = _function(x3);
00193     
00194   // if new point is lower, use as new middle
00195   if(y3 < y2)
00196     {
00197       x0 = x2; y0 = y2; x2 = x3; y2 = y3;
00198       return;
00199     }
00200   
00201   // if it's higher, move in right limit
00202   if(y3 > y2)
00203     {
00204       x4 = x3; y4 = y3;
00205     }
00206   
00207   // if y1 was equal to y2, replace y2
00208   if(y1 == y2)
00209     {
00210       x2 = x1; y2 = y1;
00211     }
00212 }
00213 
00214 /*
00215  * Solve for minimum of function, using n successive bisections.
00216  * Initial points _MUST_ represent legal  configuration, i.e.,
00217  * y0 > y1, y2 > y1.
00218  * The points need not be evenly spaced.
00219  *
00220  * Example of usage of the minimization function:
00221  *  double x0 = 0;
00222  *  double y0 = f(x0);
00223  *  double x1 = 0.5;
00224  *  double y1 = f(x1);
00225  *  double x2 = 1;
00226  *  double y2 = f(x2);
00227  *  cout << minimize(x0, y0, x1, y1, x2, y2, 20);
00228  */
00229 
00230 int N_1D_Function_Solver::
00231 minimize(double &x0, double &y0,
00232          double &x1, double &y1,
00233          double &x2, double &y2,
00234          long n, double &result)
00235 {
00236   for(long i=0; i<n; i++) _bisect(x0, y0, x1, y1, x2, y2);
00237   
00238   result = x1; 
00239   return SOLVED;
00240 }
00241 
00242 } // namespace claraty