C:/programs/UNCMIN/src/include/Uncmin.h

Go to the documentation of this file.
00001 /*! \file Uncmin.h
00002 
00003   \brief
00004   C++ implementation of UNCMIN routines for unconstrained minimization
00005   
00006   This software is available at 
00007   http://www.smallwaters.com/software/cpp/uncmin.html
00008  
00009   Version 0080309
00010   This release updates original work by Brad Hanson (http://www.b-a-h.com/) in 2001.
00011  
00012   The UNCMIN routines are based on Appendix A of:
00013  
00014   Dennis, J. E., & Schnabel, R. B. (1996). Numerical methods for
00015   unconstrained optimization and nonlinear equations. Philadelphia:
00016   Society for Industrual and Applied Mathematics.
00017  
00018   The original UNCMIN routines in FORTRAN are available from GAMS
00019   (http://gams.nist.gov/) as OPTIF9 and OPTIF0.
00020  
00021   FORTRAN UNCMIN routines were translated to java (Uncmin_f77.java) by
00022   Steve Verrill (steve@ws13.fpl.fs.fed.us).
00023   Uncmin_F77.java is available at http://www1.fpl.fs.fed.us/optimization.html
00024 
00025   The routines in Uncmin_f77.java were translated to C++ by
00026   Brad Hanson.
00027   
00028   (c) 2008, Werner Wothke, maintenance programming and documentation.
00029  
00030  
00031   Uncmin is a templated class with template parameters:
00032  
00033   V - A vector class of double precision numbers. Member functions
00034       that should be defined for class V are:
00035  
00036       V& operator=(const V &A); // assignment
00037  
00038       V& operator=(const double& scalar); // assign a value to all elements
00039  
00040       double& operator()(int i); // FORTRAN style one-offset subscripting
00041  
00042       int size(); // returns number of elements in vector
00043  
00044   M - A matrix class of double precision numbers. Member functions that
00045       should be defined for class M are:
00046  
00047       double operator()(int i, int j); // FORTRAN style one-offset subscripting
00048  
00049       int num_rows(); // returns number of rows in matrix
00050       int num_cols(); // returns number of columns in matrix
00051 
00052   FUNC - A class defining the function to minimize, its gradient and hessian.
00053          An example of how this class should be defined is:
00054   
00055     // V is vector class, M is matrix class
00056     template <class V, class M>
00057     class minclass
00058     {
00059        double f_to_minimize(V &x);
00060        // Returns value of function to minimize
00061  
00062        void gradient(V &x, V &g);
00063        // Returns gradient of function in g. This does not have
00064        // to be defined, in which case the gradient is approximated.
00065        // If the gradient is not defined Analytic_Gradient should 
00066        // return 0;
00067  
00068        void hessian(V &x, M &h);
00069        // Returns hessian of function in h. This does not have
00070        // to be defined, in which case the hessian is approximated.
00071        // If the hessian is not defined Analytic_Hessian should 
00072        // return 0;
00073  
00074        int HasAnalyticGradient();
00075        // Returns 1 if gradient is defined, otherwise returns 0
00076  
00077        int HasAnalyticHessian();
00078        // Returns 1 if hessian is defined, otherwise returns 0
00079  
00080        int ValidParameters(V &x);
00081        // Returns 1 if f_to_minimize(x) is defined for argument x.
00082  
00083        int dim();
00084        // Returns dimension of problem (number of elements in vector x
00085        // passed to f_to_minimize)
00086     }
00087  
00088     An example of how to use Uncmin to minimize a function defined in
00089     a class minclass with vector and matrix classes from the Simple
00090     C++ Numerical Toolkit (http://www.smallwaters.com/software/cpp/scppnt.html):
00091  
00092     #include "Uncmin.h"
00093     #include "vec.h"  // Simple C++ Numeric Toolkit (SCPPNT) vector class
00094     #include "cmat.h" // Simple C++ Numeric Toolkit (SCPPNT) matrix class
00095     #include <cstdio>
00096  
00097     using namespace SCPPNT;
00098  
00099     // Dimension of problem (number of parameters)
00100     const int dim = 4;
00101  
00102     // Create function object
00103     minclass<Vector<double>, Matrix<double> > test;
00104  
00105     // create Uncmin object
00106     Uncmin<Vector<double>, Matrix<double>, minclass> min(&test);
00107  
00108     // Starting values
00109     double start_values[4] = {1.0, 1.0, 1.0, 1.0}; // use some appropriate values here
00110     Vector<double> start(start_values, start_values+dim);
00111 
00112     // xpls will contain solution, gpls will contain
00113     // gradient at solution after call to min.Minimize
00114     Vector<double> xpls(dim), gpls(dim);
00115 
00116     // fpls contains the value of the function at
00117     // the solution given by xpls.
00118     double fpls;
00119  
00120     // Minimize function.
00121     // Minimize returns zero if successful (0, 1, 2, 3
00122     // returned by GetMessage), non-zero if not successful.
00123     if (min.Minimize(start, xpls,  fpls,  gpls))
00124     {
00125        int msg = min.GetMessage(); // find out what went wrong
00126        std::printf("\nMessage returned from Uncmin: %d\n", msg);
00127     }
00128 
00129     The GetMessage member function returns the status of the solution found
00130     by the last call to the Minimize member function.
00131     Possible values returned by GetMessage are:
00132  
00133     0 = Optimal solution found, terminated with gradient small
00134     1 = Terminated with gradient small, xpls is probably optimal.
00135     2 = Terminated with stepsize small, xpls is probably optimal.
00136     3 = Lower point cannot be found, xpls is probably optimal.
00137     4 = Iteration limit (default 150) exceeded.
00138     5 = Too many large steps, function may be unbounded.
00139     -1 = Analytic gradient check requested, but no analytic gradient supplied
00140     -2 = Analytic hessian check requested, but no analytic hessian supplied
00141     -3 = Illegal dimension
00142     -4 = Illegal tolerance
00143     -5 = Illegal iteration limit
00144     -6 = Minimization function has no good digits
00145     -7 = Iteration limit exceeded in lnsrch
00146     -20 = Function not defined at starting value
00147     -21 = Check of analytic gradient failed
00148     -22 = Check of analytic hessian failed
00149 
00150 
00151     The symbol BOOST_NO_STDC_NAMESPACE should be defined if the C++ compiler
00152     does not put the standard C library functions in the std namespace
00153     (this is needed for Visual C++ 6).
00154  
00155     The symbol BOOST_NO_LIMITS should be defined if the standard C++
00156     library header file <limits> is not available.
00157     (this is needed for Visual C++ 6).
00158 
00159  
00160     Version History
00161  
00162     Version 080309 (March 9, 2008)
00163     
00164     Edited doxygen-compatible documentation, second pass. Added descriptive comments,
00165     much as possible, incorporated any useful information from the existing FORTRAN 
00166     and Java documentation sets and removed these out-dated documentations afterwards. 
00167     
00168     Version 071226 (December 26, 2007)
00169  
00170     Refactored num_cols property to num_columns in UNCMIN::minimize().
00171     Tagged all public methods and properties with doxygen-compatible comments.
00172  
00173     Version 0.001206 (February 10, 2001)
00174  
00175     Added BOOST_NO_STDC_NAMESPACE and BOOST_NO_LIMITS symbols which
00176     need to be defined to compile Uncmin.h using Microsoft Visual C++ 6.
00177 
00178  */
00179 
00180 #ifndef UNCMIN_H_
00181 #define UNCMIN_H_
00182 
00183 #include <cstdio>
00184 #include <cmath>
00185 
00186 #ifdef BOOST_NO_STDC_NAMESPACE
00187 // If the standard C library functions are not in the std namespace (like Microsoft Visual C++ 6)
00188 namespace std
00189 { using ::sqrt; using ::pow; using ::fabs; using ::log; using ::FILE; using ::fprintf;}
00190 #endif
00191 
00192 #ifndef BOOST_NO_LIMITS
00193 // include limits for epsilon function used in SetTolerances.
00194 #include <limits>
00195 #else
00196 // If there is no limits header.
00197 #include <float.h>
00198 #endif
00199 
00200 /*! Documentation of member functions is given in their definitions which follow
00201  the Uncmin class definition */
00202 template<class V, class M, class FUNC> class Uncmin
00203 {
00204 
00205 public:
00206 
00207   typedef FUNC function_type;   //!< Type definition of function object to minimize.
00208 
00209   /* Constructor. */
00210   Uncmin(FUNC *f);
00211   
00212   /* Constructor. */
00213   Uncmin(int d = 1);
00214 
00215   /* Destructor */
00216   ~Uncmin();
00217 
00218   /* Calculate function minimum. */
00219   int Minimize(V &start, V &xpls, double &fpls, V &gpls, M &hpls);
00220 
00221   /* Version of Minimize where hessian matrix is allocated locally rather
00222    than passed as an argument to the function. */
00223   int Minimize(V &start, V &xpls, double &fpls, V &gpls);
00224 
00225   /* Get object containing function to minimize, gradient, and hessian. */
00226   FUNC *GetFunction();
00227 
00228   /* Set object containing function to minimize, gradient, and hessian. */
00229   void SetFunction(FUNC *f);
00230 
00231   /* Methods to set options. */
00232   void SetFuncExpensive(int iexp);
00233 
00234   /* Set typical magnitude of each argument to function. */
00235   int SetScaleArg(V typsiz);
00236 
00237   /* Set typical magnitude of function near minimum. */
00238   void SetScaleFunc(double fscale);
00239 
00240   /* Set the number of reliable digits returned by f_to_minimize. */
00241   void SetNumDigits(double ndigit);
00242 
00243   /* Set maximum number of iterations. */
00244   void SetMaxIter(int maxiter);
00245 
00246   /* Set step tolerance, gradient tolerance, and machine epsilon. */
00247   void SetTolerances(double step, double grad, double macheps = -1.0);
00248 
00249   /* Set maximum allowable scaled step length at any iteration. */
00250   void SetMaxStep(double stepmx);
00251 
00252   /* Set initial trust region radius. */
00253   void SetTrustRegionRadius(double dlt);
00254 
00255   /* Set flags to check analytic gradient and hessian. */
00256   void SetChecks(int check_gradient, int check_hessian = 0);
00257 
00258   /* Set flags to indicate whether results are printed. */
00259   void SetPrint(std::FILE *file, int print_results, int print_iterations = 0);
00260 
00261   /* Set method to use to solve minimization problem.
00262    1 = line search, 2 = double dogleg, 3 = More-Hebdon.  */
00263   void SetMethod(int method);
00264 
00265   /* Return stopping criteria computed at the end of the last call to Minimize. */
00266   void GetStoppingCriteria(double &gradtol, double &steptol, int &iterations);
00267 
00268   /*! Returns message generated in the last call to Minimize. */
00269   int GetMessage();
00270 
00271 private:
00272 
00273   FUNC *minclass; //!<  Class that contains function to miminize, gradient, and hessian. 
00274 
00275 
00276   int algorithm; //!<  Indicates algorithm to use to solve minimization problem: 1 = line search, 2 = double dogleg, 3 = More-Hebdon.
00277 
00278   std::FILE *mfile; //!< File to print messages to.
00279 
00280   int n; //!< Dimension of problem, provided in minclass by minclass->dim().
00281 
00282   double epsm; //!< Machine epsilon.
00283 
00284 
00285   double mLastGradCrit;  //!< Stopping criterion for gradient.
00286   
00287 
00288   double mLastStepCrit; //!<  Stopping criterion for argument change.
00289 
00290   
00291   int mLastIteration; //!<  Stopping criterion by number of iterations.
00292 
00293 
00294   int mLastMessage; //!<  Message generated by last call to Minimize.
00295 
00296   /* Options */
00297 
00298   int iexp;  //!< Flag indicating computational complexity. Set iexp = 1, for expensive calculations, iexp = 0 otherwise. If iexp = 1, the Hessian will be evaluated by secant (BFGS) update.
00299   
00300   /* These two flags are set from minclass using minclass.Analytic_Gradient() and
00301    minclass.Analytic_Methods() */
00302   int iagflg; //!< Flag: iagflag = 0 if an analytic gradient is not supplied, provided by minclass.
00303   int iahflg; //!< Flag: iahflag = 0 if an analytic Hessian is not supplied, provided by minclass.
00304 
00305   int fCheckGradient; //!< fCheckGradient = 0 if analytic gradient is not checked.
00306 
00307   int fCheckHessian; //!< fCheckHessian = 0 if analytic hessian is not checked.
00308 
00309   int fPrintResults; //!< fPrintResults = 0 if results are not printed to mfile.
00310 
00311   int fPrintIterationResults; //!< fPrintIterationResults = 0 if results of each iteration are not printed to mfile.
00312 
00313   /* Tolerances */
00314 
00315   V typsiz; //!< Typical size of of each argument of function to minimize.
00316 
00317   double fscale; //!< Estimate of scale of objective function.
00318 
00319   int ndigit; //!< Number of good digits in the minimization function. Special case, set ndigit = -1, for function providing within 1 or 2 of full number of significant digits.
00320 
00321   int itnlim; //!< Maximum number of allowable iterations.
00322 
00323   double mdlt; //!< Trust region radius. Special case,  mdlt = -1, uses length of initial scaled gradient instead.
00324 
00325   double gradtl; //!< Tolerance at which the gradient is considered close enough to zero to terminate the algorithm.
00326 
00327   double steptl; //!< Tolerance at which scaled distance between two successive iterates is considered close enough to zero to terminate algorithm. 
00328   
00329   double stepmx; //!< Maximum allowable step size.
00330 
00331   /* Private functions used in minimization. */
00332 
00333   void dfault();
00334 
00335   int optchk(V &x, V &sx, int &msg, int &method);
00336 
00337   void fstofd(V &xpls, double fpls, V &g, V &sx, double rnoise);
00338 
00339   void fstofd(V &xpls, V &fpls, M &a, V &sx, double rnoise, V &fhat);
00340 
00341   int grdchk(V &x, double f, V &g, V &typsiz, V &sx, double fscale, double rnf, double analtl,
00342       V &gest, int &msg);
00343 
00344   void optstp(V &xpls, double fpls, V &gpls, V &x, int &itncnt, int &icscmx, int &itrmcd, V &sx,
00345       double &fscale, int &itnlim, int &iretcd, bool &mxtake, int &msg);
00346 
00347   void hsnint(M &a, V &sx, int method);
00348 
00349   void sndofd(V &xpls, double &fpls, M &a, V &sx, double &rnoise, V &stepsz, V &anbr);
00350 
00351   int heschk(V &x, double &f, V &g, M &a, V &typsiz, V &sx, double rnf, double analtl, int &iagflg,
00352       V &udiag, V &wrk1, V &wrk2, int &msg);
00353 
00354   void result(V &x, double &f, V &g, M &a, V &p, int &itncnt, int iflg);
00355 
00356   void bakslv(M &a, V &x, V &b);
00357 
00358   void chlhsn(M &a, V &sx, V &udiag);
00359 
00360   void choldc(M &a, double diagmx, double tol, double &addmax);
00361 
00362   void dogdrv(V &x, double &f, V &g, M &a, V &p, V &xpls, double &fpls, V &sx, double &dlt,
00363       int &iretcd, bool &mxtake, V &sc, V &wrk1, V &wrk2, V &wrk3);
00364 
00365   void dogstp(V &g, M &a, V &p, V &sx, double rnwtln, double &dlt, bool &nwtake, bool &fstdog,
00366       V &ssd, V &v, double &cln, double &eta, V &sc);
00367 
00368   void forslv(M &a, V &x, V &b);
00369 
00370   void fstocd(V &x, V &sx, double rnoise, V &g);
00371 
00372   void hookdr(V &x, double &f, V &g, M &a, V &udiag, V &p, V &xpls, double &fpls, V &sx,
00373       double &dlt, int &iretcd, bool &mxtake, double &amu, double &dltp, double &phi,
00374       double &phip0, V &sc, V &xplsp, V &wrk0, int &itncnt);
00375 
00376   void hookst(V &g, M &a, V &udiag, V &p, V &sx, double rnwtln, double &dlt, double &amu,
00377       double &dltp, double &phi, double &phip0, bool &fstime, V &sc, bool &nwtake, V &wrk0);
00378 
00379   void lltslv(M &a, V &x, V &b);
00380 
00381   void lnsrch(V &x, double &f, V &g, V &p, V &xpls, double &fpls, bool &mxtake, int &iretcd, V &sx);
00382 
00383   void mvmltl(M &a, V &x, V &y);
00384 
00385   void mvmlts(M &a, V &x, V &y);
00386 
00387   void mvmltu(M &a, V &x, V &y);
00388 
00389   void qraux1(M &r, int i);
00390 
00391   void qraux2(M &r, int i, double a, double b);
00392 
00393   void qrupdt(M &a, V &u, V &v);
00394 
00395   void secfac(V &x, V &g, M &a, V &xpls, V &gpls, int &itncnt, double rnf, int &iagflg,
00396       bool &noupdt, V &s, V &y, V &u, V &w);
00397 
00398   void secunf(V &x, V &g, M &a, V &udiag, V &xpls, V &gpls, int &itncnt, double rnf, int &iagflg,
00399       bool &noupdt, V &s, V &y, V &t);
00400 
00401   void tregup(V &x, double &f, V &g, M &a, V &sc, V &sx, bool &nwtake, double &dlt, int &iretcd,
00402       V &xplsp, double &fplsp, V &xpls, double &fpls, bool &mxtake, int method, V &udiag);
00403 
00404   double ddot(V &x, V &y);
00405 
00406   double dnrm2(V &x);
00407 
00408   double max(double a, double b);
00409 
00410   double min(double a, double b);
00411 
00412 };
00413 
00414 /*!
00415   \brief 
00416   Constructor that sets dimension and function to minimize.
00417   
00418   The minclass function object must define:
00419                     
00420   1. a method, f_to_minimize, to minimize. f_to_minimize must have the form 
00421          public static double f_to_minimize(double x[])
00422      where x is the vector of arguments to the function and the return value is the 
00423      value of the function evaluated at x.  
00424 
00425   2. a method, gradient, that has the form
00426          public static void gradient(double x[], double g[])
00427      where g is the gradient of f evaluated at x.  This method will have an empty body if 
00428      the user does not wish to provide an analytic estimate of the gradient.
00429      
00430   3. a method, hessian, that has the form
00431          public static void hessian(double x[],double h[][])
00432      where h is the Hessian of f evaluated at x.  This method will have an empty body if the 
00433      user does not wish to provide an analytic estimate of the Hessian. If the user wants 
00434      Uncmin++ to check the Hessian, then the hessian method should only fill the lower 
00435      triangle (and diagonal)of h.
00436   
00437    Minimization parameters are set at default values.
00438   
00439   \section template_args Template Parameters
00440   
00441   \param M  SCPPNT Matrix type.
00442   \param V  SCPPNT Vector type.
00443   \param FUNC Type of function to minimize.
00444   
00445   \section function_args Function Parameters
00446    
00447   \param[in]  *f  Pointer to function object f.
00448  */
00449 template<class V, class M, class FUNC> Uncmin<V, M, FUNC>::Uncmin(FUNC *f) :
00450   minclass(f)
00451 {
00452   if (minclass)
00453     n = minclass->dim();
00454   else
00455     n = 0;
00456 
00457   mfile = 0;
00458 
00459   mLastGradCrit = 0.0;
00460   mLastStepCrit = 0.0;
00461   mLastIteration = 0;
00462   mLastMessage = 0;
00463 
00464   /* Set default parameter values */
00465   dfault();
00466 }
00467 
00468 /*!
00469   \brief 
00470   Constructor that sets dimension, but not function to minimize.
00471   
00472   Note: Function to minimize must be set by calling SetFunction. 
00473   Minimization parameters are set to default values.
00474   
00475   \section template_args Template Parameters
00476   
00477   \param M  SCPPNT Matrix type.
00478   \param V  SCPPNT Vector type.
00479   \param FUNC Type of function to minimize.
00480   
00481   \section function_args Function Parameters
00482    
00483   \param[in]  d  Dimension d (number of function arguments).
00484  */
00485 template<class V, class M, class FUNC> Uncmin<V, M, FUNC>::Uncmin(int d) :
00486   minclass(0), typsiz(d)
00487 {
00488 
00489   n = d;
00490 
00491   mfile = 0;
00492 
00493   mLastGradCrit = 0.0;
00494   mLastStepCrit = 0.0;
00495   mLastIteration = 0;
00496   mLastMessage = 0;
00497 
00498   /* Set default parameter values */
00499   dfault();
00500 
00501 }
00502 
00503 /*!
00504   \brief Destructor of uncmin.
00505  */
00506 template<class V, class M, class FUNC> Uncmin<V, M, FUNC>::~Uncmin()
00507 {
00508 
00509 }
00510 
00511 /*!
00512   \brief 
00513   Assigns flag indicating whether function is expensive to evaluate.
00514   
00515   Set iexp =1 if function is expensive to evaluate, = 0 otherwise.  
00516   If iexp = 1, then the Hessian will be evaluated by secant (BFGS) update 
00517   rather than analytically or by finite differences.
00518 
00519   Default value is 0 if this function is not called.
00520   
00521   \section template_args Template Parameters
00522   
00523   \param M  SCPPNT Matrix type.
00524   \param V  SCPPNT Vector type.
00525   \param FUNC Type of function to minimize.
00526   
00527   \section function_args Function Parameters
00528    
00529   \param[in]  iexp  Set iexp =1 if function is expensive to evaluate, iexp = 0 otherwise.
00530  */
00531 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetFuncExpensive(int iexp)
00532 {
00533   this->iexp = iexp;
00534 }
00535 
00536 /*!
00537   \brief
00538   Assigns typical magnitude of each argument to function.
00539 
00540   Returns zero if dimension matches, otherwise returns 1.
00541  
00542   The default is to set all elements of typsiz to 1 if this function is not called.
00543   
00544   \section template_args Template Parameters
00545   
00546   \param M  SCPPNT Matrix type.
00547   \param V  SCPPNT Vector type.
00548   \param FUNC Type of function to minimize.
00549   
00550   \section function_args Function Parameters
00551    
00552   \param[in]  typsiz  Vector describing the magnitude of all function arguments.
00553  */
00554 template<class V, class M, class FUNC> int Uncmin<V, M, FUNC>::SetScaleArg(V typsiz)
00555 {
00556   if (typsiz.size() != n)
00557     return 1;
00558 
00559   this->typsiz = typsiz;
00560 
00561   return 0;
00562 }
00563 
00564 /*!
00565   \brief
00566   Assigns typical magnitude of function near minimum.
00567   
00568   \section template_args Template Parameters
00569   
00570   \param M  SCPPNT Matrix type.
00571   \param V  SCPPNT Vector type.
00572   \param FUNC Type of function to minimize.
00573   
00574   \section function_args Function Parameters
00575    
00576   \param[in]  fscale  Magnitude of function values near minimum.
00577                       A default value of 1 is used for fscale if this
00578                       function is not called.
00579  */
00580 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetScaleFunc(double fscale)
00581 {
00582   this->fscale = fscale;
00583 }
00584 
00585 /*!
00586   \brief
00587   Assigns the number of reliable digits returned by f_to_minimize.
00588   
00589   If the argument to the function is -1 this
00590   means that f_to_minimize is expected to
00591   provide within one or two of the full number of
00592   significant digits available.
00593  
00594   The default value of -1 is used for ndigit when
00595   this function is not called.
00596 
00597   \section template_args Template Parameters
00598   
00599   \param M  SCPPNT Matrix type.
00600   \param V  SCPPNT Vector type.
00601   \param FUNC Type of function to minimize.
00602   
00603   \section function_args Function Parameters
00604    
00605   \param[in]  ndigit  Number of digits precision required for the solution.
00606  */
00607 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetNumDigits(double ndigit)
00608 {
00609   this->ndigit = ndigit;
00610 }
00611 
00612 /*!
00613   \brief
00614   Assigns the maximum number of iterations.
00615   
00616   The default value of 150 is used if this function is not called.
00617 
00618   \section template_args Template Parameters
00619   
00620   \param M  SCPPNT Matrix type.
00621   \param V  SCPPNT Vector type.
00622   \param FUNC Type of function to minimize.
00623   
00624   \section function_args Function Parameters
00625    
00626   \param[in]  maxiter  Maximum number of iterations.
00627  */
00628 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetMaxIter(int maxiter)
00629 {
00630   this->itnlim = maxiter;
00631 }
00632 
00633 /*!
00634   \brief
00635   Assigns step tolerance, gradient tolerance, and the machine epsilon.
00636   
00637   Note: For any of these values <= zero, default values are used.
00638   
00639   \section template_args Template Parameters
00640   
00641   \param M  SCPPNT Matrix type.
00642   \param V  SCPPNT Vector type.
00643   \param FUNC Type of function to minimize.
00644   
00645   \section function_args Function Parameters
00646    
00647   \param[in]  step  Tolerance at which scaled distance between two successive iterates
00648     is considered close enough to zero to terminate algorithm. If the value of
00649     step is <= zero a default value is used.
00650   \param[in]  grad  Tolerance at which gradient is considered close enough
00651     to zero to terminate algorithm. If the value of
00652     grad is <= zero a default value is used.
00653   \param[in]  macheps Largest relative spacing. Machine epsilon == 2**(-T+1) where
00654     (1 + 2**-T) == 1. This argument has a default value of -1 if not included
00655     in function call.
00656  */
00657 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetTolerances(double step,
00658     double grad, double macheps)
00659 {
00660   if (macheps <= 0.0) // use default value
00661   {
00662 
00663 #ifdef BOOST_NO_LIMITS
00664     epsm = DBL_EPSILON; // from float.h
00665 #else
00666     // use epsilon from numeric_limits in standard C++ library
00667     epsm = std::numeric_limits<double>::epsilon();
00668 #endif
00669 
00670   }
00671   else
00672   {
00673     epsm = macheps;
00674   }
00675 
00676   if (grad <= 0.0)
00677   {
00678     gradtl = std::pow(epsm, 1.0/3.0); // default value
00679   }
00680   else
00681   {
00682     gradtl = grad;
00683   }
00684 
00685   if (step <= 0.0)
00686   {
00687     steptl = std::sqrt(epsm); // default value
00688   }
00689   else
00690   {
00691     steptl = step;
00692   }
00693 
00694 }
00695 
00696 /*!
00697   \brief
00698   Assigns maximum allowable scaled step length at any iteration.
00699   
00700   The maximum step length is used to prevent steps that would cause the 
00701   optimization algorithm to overflow or leave the domain of iterest,
00702   as well as to detect divergence. It should be chosen small enough
00703   to prevent the first two of these occurrences, but larger
00704   than any anticipated reasonable step size. The algorithm will
00705   halt if it takes steps larger than the maximum allowable step
00706   length on 5 consecutive iterations.
00707  
00708   If the argument to the function is <= 0 then a default value of
00709   stepmx will be computed in optchk.
00710  
00711   A default value of 0 is used for stepmx when this function is
00712   not called.
00713 
00714   \section template_args Template Parameters
00715   
00716   \param M  SCPPNT Matrix type.
00717   \param V  SCPPNT Vector type.
00718   \param FUNC Type of function to minimize.
00719   
00720   \section function_args Function Parameters
00721    
00722   \param[in]  stepmx  Maximum (scaled) step size.
00723  */
00724 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetMaxStep(double stepmx)
00725 {
00726   this->stepmx = stepmx;
00727 }
00728 
00729 /*!
00730   \brief
00731   Assigns initial trust region radius.
00732   
00733   Used when method = 2 or 3, ignored when method = 1. 
00734   The value should be what the user considers a reasonable 
00735   scaled step length for the first iteration, and should be 
00736   less than the maximum step length.
00737  
00738   If dlt = -1, then the length of the initial scaled gradient is used instead.
00739  
00740   A default value of -1 is used if this function is not called.
00741  
00742   \section template_args Template Parameters
00743   
00744   \param M  SCPPNT Matrix type.
00745   \param V  SCPPNT Vector type.
00746   \param FUNC Type of function to minimize.
00747   
00748   \section function_args Function Parameters
00749    
00750   \param[in]  dlt  Maximum (scaled) step size of first iteration.
00751  */
00752 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetTrustRegionRadius(double dlt)
00753 {
00754   this->mdlt = dlt;
00755 }
00756 
00757 /*!
00758   \brief
00759   Returns pointer to object containing function to minimize, gradient, and hessian.
00760  
00761   \section template_args Template Parameters
00762   
00763   \param M  SCPPNT Matrix type.
00764   \param V  SCPPNT Vector type.
00765   \param FUNC Type of function to minimize.
00766  */
00767 template<class V, class M, class FUNC> FUNC * Uncmin<V, M, FUNC>::GetFunction()
00768 {
00769   return minclass;
00770 }
00771 
00772 
00773 /*!
00774   \brief
00775   Assigns pointer to object containing function to minimize, gradient, and hessian.
00776 
00777   \section template_args Template Parameters
00778   
00779   \param M  SCPPNT Matrix type.
00780   \param V  SCPPNT Vector type.
00781   \param FUNC Type of function to minimize.
00782   
00783   \section function_args Function Parameters
00784    
00785   \param[in]  *f  Pointer to function object f.
00786  */
00787 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetFunction(FUNC *f)
00788 {
00789   minclass = f;
00790 
00791   /* If dimension does not match change n and re-intialize typsiz */
00792   if (n != f->dim())
00793   {
00794     n = f->dim();
00795     V defaultTypSiz(n, 1.0);
00796     typsiz = defaultTypSiz;
00797   }
00798 }
00799 
00800 /*!
00801   \brief
00802   Assigns flags to check analytic gradient and hessian.
00803 
00804   The default is to not check the gradient and hessian, if this function is not called
00805   (fCheckGradient = 0 and fCheckHessian = 0).
00806  
00807   Note that check_hessian can be left off function call in which case default value of
00808   0 is used.
00809   
00810   \section template_args Template Parameters
00811   
00812   \param M  SCPPNT Matrix type.
00813   \param V  SCPPNT Vector type.
00814   \param FUNC Type of function to minimize.
00815   
00816   \section function_args Function Parameters
00817    
00818   \param[in]  check_gradient  Flag to check analytic gradient of function: 1 = yes, 0 = no.
00819   \param[in]  check_hessian  Flag to check analytic hessian of function: 1 = yes, 0 = no.
00820  */
00821 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetChecks(int check_gradient,
00822     int check_hessian)
00823 {
00824   fCheckGradient = check_gradient;
00825   fCheckHessian = check_hessian;
00826 }
00827 
00828 /*!
00829   \brief
00830   Assigns flags to indicate whether results are printed and specify which file is 
00831   receive the print output.
00832 
00833   Printing is done to open file indicated by first argument.
00834 
00835   The default action is not to print any output.
00836   
00837   \section template_args Template Parameters
00838   
00839   \param M  SCPPNT Matrix type.
00840   \param V  SCPPNT Vector type.
00841   \param FUNC Type of function to minimize.
00842   \param FILE Type of file for writing print output to.
00843   
00844   \section function_args Function Parameters
00845    
00846   \param[in]  *file  Pointer to the open file that will receive the printed results.
00847   \param[in]  print_results  Flag (if non-zero) to print standard results.
00848   \param[in]  print_iterations  Flag (if non-zero) to print intermediate results at each 
00849       iteration (this argument can be left off function call in which case the
00850       default value of 0 is used).
00851   */
00852 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetPrint(std::FILE *file,
00853     int print_results, int print_iterations)
00854 {
00855 
00856   mfile = file;
00857 
00858   if (!file)
00859   {
00860     fPrintResults = 0;
00861     fPrintIterationResults = 0;
00862   }
00863   else
00864   {
00865     fPrintResults = print_results;
00866     fPrintIterationResults = print_iterations;
00867   }
00868 
00869 }
00870 
00871 /*!
00872   \brief
00873   Assigns method to use to solve minimization problem.
00874   
00875   A default value is 1 (line search) if SetMethod is not called.
00876 
00877   \section template_args Template Parameters
00878   
00879   \param M  SCPPNT Matrix type.
00880   \param V  SCPPNT Vector type.
00881   \param FUNC Type of function to minimize.
00882   
00883   \section function_args Function Parameters
00884    
00885   \param[in]  method  Method indicator: 1 = line search, 2 = double dogleg, 3 = More-Hebdon.
00886  */
00887 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::SetMethod(int method)
00888 {
00889   if (method == 2 || method == 3)
00890     algorithm = method;
00891   else
00892     algorithm = 1; // use default value of 1 for any values of argument other than 2 or 3
00893 }
00894 
00895 /*!
00896   \brief
00897   Returns stopping criteria computed at the end of the last call to Minimize.
00898 
00899   \section template_args Template Parameters
00900   
00901   \param M  SCPPNT Matrix type.
00902   \param V  SCPPNT Vector type.
00903   \param FUNC Type of function to minimize.
00904   
00905   \section function_args Function Parameters
00906    
00907   \param[out]  &gradtol  Address of gradient tolerance, i.e., how close the gradient is to zero.
00908   \param[out]  &steptol  Address of maximum scaled difference between function parameters in 
00909       consecutive iterations.
00910   \param[out]  &iterations  Address of number of iterations used.
00911  */
00912 template<class V, class M, class FUNC> void Uncmin<V, M, FUNC>::GetStoppingCriteria(
00913     double &gradtol, double &steptol, int &iterations)
00914 {
00915   gradtol = mLastGradCrit;
00916   steptol = mLastStepCrit;
00917   iterations = mLastIteration;
00918 }
00919 
00920 /*!
00921   \brief
00922   Returns message index generated in the last call to Minimize.
00923  
00924   Possible values of message are:
00925  
00926     0 = Optimal solution found, terminated with gradient small.
00927     1 = Terminated with gradient small, xpls is probably optimal.
00928     2 = Terminated with stepsize small, xpls is probably optimal.
00929     3 = Lower point cannot be found, xpls is probably optimal.
00930     4 = Iteration limit (default 150) exceeded.
00931     5 = Too many large steps, function may be unbounded.
00932    -1 = Analytic gradient check requested, but no analytic gradient supplied
00933    -2 = Analytic hessian check requested, but no analytic hessian supplied
00934    -3 = Illegal dimension
00935    -4 = Illegal tolerance
00936    -5 = Illegal iteration limit
00937    -6 = Minimization function has no good digits
00938    -7 = Iteration limit exceeded in lnsrch
00939   -20 = Function not defined at starting value
00940   -21 = Check of analytic gradient failed
00941   -22 = Check of analytic hessian failed
00942 
00943   \section template_args Template Parameters
00944   
00945   \param M  SCPPNT Matrix type.
00946   \param V  SCPPNT Vector type.
00947   \param FUNC Type of function to minimize.
00948  */
00949 template<class V, class M, class FUNC> inline int Uncmin<V, M, FUNC>::GetMessage()
00950 {
00951   return mLastMessage;
00952 }
00953 
00954 /*!
00955   \brief
00956   Method to compute values that minimize the function.
00957 
00958   Translated by Brad Hanson from optdrv_f77 by Steve Verrill.
00959   
00960   Returns 0 if mLastMessage is 0, 1, 2, or 3 (indicating optimal solution probably found), 
00961   otherwise returns non-zero.
00962   
00963   On exit data member mLastMessage is set to indicate status of solution.
00964 
00965   Possible values of mLastMessage are:
00966     0 = Optimal solution found, terminated with gradient small.
00967     1 = Terminated with gradient small, xpls is probably optimal.
00968     2 = Terminated with stepsize small, xpls is probably optimal.
00969     3 = Lower point cannot be found, xpls is probably optimal.
00970     4 = Iteration limit (default 150) exceeded.
00971     5 = Too many large steps, function may be unbounded.
00972    -1 = Analytic gradient check requested, but no analytic gradient supplied.
00973    -2 = Analytic hessian check requested, but no analytic hessian supplied.
00974    -3 = Illegal dimension.
00975    -4 = Illegal tolerance.
00976    -5 = Illegal iteration limit.
00977    -6 = Minimization function has no good digits. 
00978    -7 = Iteration limit exceeded in lnsrch.
00979   -20 = Function not defined at starting value.
00980   -21 = Check of analytic gradient failed.
00981   -22 = Check of analytic hessian failed.
00982 
00983   \section template_args Template Parameters
00984   
00985   \param M  SCPPNT Matrix type.
00986   \param V  SCPPNT Vector type.
00987   \param FUNC Type of function to minimize.
00988   
00989   \section function_args Function Parameters
00990    
00991   \param[in]   &start  Address of vector containing initial estimate of location of minimum.
00992   \param[out]  &xpls  Address of vector containing local minimum (size must be n on input).
00993   \param[out]  &fpls  Address of function value at local minimum.
00994   \param[out]  &gpls  Address of vector containing gradient at local minimum (size must be 
00995       n on input). 
00996   \param[out]  &hpls  Address of matrix containing hessian at local minimum (size must be 
00997       n X n on input). Only the lower half should be input; the upper off-diagonal entries 
00998       can be set to zero. On return, the lower half of hpls contains the Cholesky factor 
00999       of the Hessian, evaluated at the solution (i.e., H = LL').
01000  */
01001 template<class V, class M, class FUNC> int Uncmin<V, M, FUNC>::Minimize(V &start, V &xpls,
01002     double &fpls, V &gpls, M &hpls)
01003 {
01004 
01005   bool noupdt;
01006   bool mxtake;
01007 
01008   int i, j, num5, remain, ilow, ihigh;
01009   int icscmx;
01010   int iretcd;
01011   int itncnt;
01012 
01013   /*
01014     Return code.
01015       itrmcd =  0:    Optimal solution found
01016       itrmcd =  1:    Terminated with gradient small, X is probably optimal
01017       itrmcd =  2:    Terminated with stepsize small, X is probably optimal
01018       itrmcd =  3:    Lower point cannot be found, X is probably optimal
01019       itrmcd =  4:    Iteration limit (150) exceeded
01020       itrmcd =  5:    Too many large steps, function may be unbounded.
01021    */
01022   int itrmcd;
01023 
01024   double rnf, analtl, dltsav, amusav, dlpsav, phisav, phpsav;
01025 
01026   double f;
01027 
01028   double amu = 0.0;
01029   double dltp = 0.0;
01030   double phi = 0.0;
01031   double phip0 = 0.0;
01032 
01033   int method = algorithm;
01034 
01035   mLastGradCrit = 0.0;
01036   mLastStepCrit = 0.0;
01037   mLastIteration = 0;
01038   mLastMessage = -9999;
01039 
01040   iagflg = minclass->HasAnalyticGradient();
01041   iahflg = minclass->HasAnalyticHessian();
01042 
01043   /*
01044     msg
01045     Flag to set various options.
01046     Bits which indicate flags which control checks of gradient and hessian and what output is printed.
01047     msg should be zero or a sum of the following values which indicate which flags to set or not set.
01048 
01049       1 = Turn off check of analytic gradient.
01050       2 = Turn off check of analytic hessian.
01051       4 = Turn off printing of results.
01052       8 = Turn on printing of results at each iteration.
01053    */
01054   int msg = (fCheckGradient == 0) * 1 + (fCheckHessian == 0) * 2 + (fPrintResults == 0) * 4
01055       + (fPrintIterationResults != 0) * 8;
01056 
01057   /* Check that dimensions match */
01058   if (start.size() != n || xpls.size() != n || gpls.size() != n || hpls.num_rows() != n
01059       || hpls.num_columns() != n) // Refactored function "num_columns", ww, 12-22-2007
01060   {
01061     mLastMessage = -3;
01062     return -1;
01063   }
01064 
01065   /* Check that starting values are valid */
01066   if (!(minclass->ValidParameters(start)))
01067   {
01068     mLastMessage = -20;
01069     return -1;
01070   }
01071 
01072   /* Workspace */
01073   M &a = hpls;
01074   V udiag(n); //workspace (for diagonal of Hessian)
01075   V g(n); // workspace (for gradient at current iterate)
01076   V p(n); // workspace for step
01077   V sx(n); // workspace (for scaling vector)
01078   V wrk0(n), wrk1(n), wrk2(n), wrk3(n);
01079 
01080   V x(start);
01081 
01082   double dlt = mdlt;
01083 
01084   dltsav = amusav = dlpsav = phisav = phpsav = 0.0;
01085 
01086   // INITIALIZATION
01087 
01088   for (i = 1; i <= n; i++)
01089   {
01090     p(i) = 0.0;
01091   }
01092 
01093   itncnt = 0;
01094   iretcd = -1;
01095 
01096   /* Check for valid options */
01097   if (optchk(x, sx, msg, method))
01098   {
01099     mLastMessage = msg;
01100     return -1;
01101   }
01102 
01103   rnf = max(std::pow(10.0, -ndigit), epsm);
01104   analtl = max(.01, std::sqrt(rnf));
01105 
01106   if (!(msg & 4))
01107   {
01108     num5 = n/5;
01109     remain = n%5;
01110 
01111     std::fprintf(mfile, "\n\nOPTDRV          Typical x\n\n");
01112 
01113     ilow = -4;
01114     ihigh = 0;
01115 
01116     for (i = 1; i <= num5; i++)
01117     {
01118       ilow += 5;
01119       ihigh += 5;
01120 
01121       std::fprintf(mfile, "%d--%d     ", ilow, ihigh);
01122 
01123       for (j = 1; j <= 5; j++)
01124       {
01125         std::fprintf(mfile, "%lf  ", (double) typsiz(ilow+j-1));
01126       }
01127       std::fprintf(mfile, "\n");
01128     }
01129 
01130     ilow += 5;
01131     ihigh = ilow + remain - 1;
01132 
01133     std::fprintf(mfile, "%d--%d     ", ilow, ihigh);
01134 
01135     for (j = 1; j <= remain; j++)
01136     {
01137       std::fprintf(mfile, "%lf  ", (double) typsiz(ilow+j-1));
01138     }
01139 
01140     std::fprintf(mfile, "\n");
01141 
01142     std::fprintf(mfile, "\n\nOPTDRV      Scaling vector for x\n\n");
01143 
01144     ilow = -4;
01145     ihigh = 0;
01146 
01147     for (i = 1; i <= num5; i++)
01148     {
01149       ilow += 5;
01150       ihigh += 5;
01151 
01152       std::fprintf(mfile, "%d--%d     ", ilow, ihigh);
01153 
01154       for (j = 1; j <= 5; j++)
01155       {
01156         std::fprintf(mfile, "%lf  ", (double) sx(ilow+j-1));
01157       }
01158       std::fprintf(mfile, "\n");
01159     }
01160 
01161     ilow += 5;
01162     ihigh = ilow + remain - 1;
01163 
01164     std::fprintf(mfile, "%d--%d     ", ilow, ihigh);
01165 
01166     for (j = 1; j <= remain; j++)
01167     {
01168       std::fprintf(mfile, "%lf  ", (double) sx(ilow+j-1));
01169     }
01170 
01171     std::fprintf(mfile, "\n");
01172 
01173     std::fprintf(mfile, "\n\nOPTDRV      Typical f = %f\n", fscale);
01174     std::fprintf(mfile, "OPTDRV      Number of good digits in");
01175     std::fprintf(mfile, " f_to_minimize = %d\n", ndigit);
01176     std::fprintf(mfile, "OPTDRV      Gradient flag");
01177     std::fprintf(mfile, " = %d\n", iagflg);
01178     std::fprintf(mfile, "OPTDRV      Hessian flag");
01179     std::fprintf(mfile, " = %d\n", iahflg);
01180     std::fprintf(mfile, "OPTDRV      Expensive function calculation flag");
01181     std::fprintf(mfile, " = %d\n", iexp);
01182     std::fprintf(mfile, "OPTDRV      Method to use");
01183     std::fprintf(mfile, " = %d\n", method);
01184     std::fprintf(mfile, "OPTDRV      Iteration limit");
01185     std::fprintf(mfile, " = %d\n", itnlim);
01186     std::fprintf(mfile, "OPTDRV      Machine epsilon");
01187     std::fprintf(mfile, " = %e\n", epsm);
01188     std::fprintf(mfile, "OPTDRV      Maximum step size");
01189     std::fprintf(mfile, " = %f\n", stepmx);
01190     std::fprintf(mfile, "OPTDRV      Step tolerance");
01191     std::fprintf(mfile, " = %e\n", steptl);
01192     std::fprintf(mfile, "OPTDRV      Gradient tolerance");
01193     std::fprintf(mfile, " = %e\n", gradtl);
01194     std::fprintf(mfile, "OPTDRV      Trust region radius");
01195     std::fprintf(mfile, " = %f\n", dlt);
01196     std::fprintf(mfile, "OPTDRV      Relative noise in");
01197     std::fprintf(mfile, " f_to_minimize = %e\n", rnf);
01198     std::fprintf(mfile, "OPTDRV      Analytical fd tolerance");
01199     std::fprintf(mfile, " = %e\n", analtl);
01200   }
01201 
01202   // EVALUATE FCN(X)
01203   f = minclass->f_to_minimize(x);
01204 
01205   // EVALUATE ANALYTIC OR FINITE DIFFERENCE GRADIENT AND CHECK ANALYTIC
01206   // GRADIENT, IF REQUESTED.
01207   if (iagflg == 0)
01208   {
01209     fstofd(x, f, g, sx, rnf);
01210   }
01211   else
01212   {
01213     minclass->gradient(x, g);
01214 
01215     if (!(msg & 1))
01216     {
01217       if (grdchk(x, f, g, typsiz, sx, fscale, rnf, analtl, wrk1, msg))
01218       {
01219         mLastMessage = msg;
01220         return -1; // msg = -21
01221       }
01222     }
01223   }
01224 
01225   optstp(x, f, g, wrk1, itncnt, icscmx, itrmcd, sx, fscale, itnlim, iretcd, mxtake, msg);
01226 
01227   if (itrmcd != 0)
01228   {
01229     fpls = f;
01230 
01231     for (i = 1; i <= n; i++)
01232     {
01233       xpls(i) = x(i);
01234       gpls(i) = g(i);
01235     }
01236   }
01237   else
01238   {
01239     if (iexp == 1)
01240     {
01241       // IF OPTIMIZATION FUNCTION EXPENSIVE TO EVALUATE (IEXP=1), THEN
01242       // HESSIAN WILL BE OBTAINED BY SECANT (BFGS) UPDATES.  GET INITIAL HESSIAN.
01243 
01244       hsnint(a, sx, method);
01245     }
01246     else
01247     {
01248       // EVALUATE ANALYTIC OR FINITE DIFFERENCE HESSIAN AND CHECK ANALYTIC
01249       // HESSIAN IF REQUESTED (ONLY IF USER-SUPPLIED ANALYTIC HESSIAN
01250       // ROUTINE minclass->hessian FILLS ONLY LOWER TRIANGULAR PART AND DIAGONAL OF A).
01251 
01252       if (iahflg == 0)
01253       {
01254         if (iagflg == 1)
01255         {
01256           fstofd(x, g, a, sx, rnf, wrk1);
01257         }
01258         else
01259         {
01260           sndofd(x, f, a, sx, rnf, wrk1, wrk2);
01261         }
01262       }
01263       else
01264       {
01265         if (msg & 2)
01266         {
01267           minclass->hessian(x, a);
01268         }
01269         else
01270         {
01271           if (heschk(x, f, g, a, typsiz, sx, rnf, analtl, iagflg, udiag, wrk1, wrk2, msg))
01272           {
01273             mLastMessage = msg;
01274             return -1; // msg = -22
01275           }
01276           // HESCHK EVALUATES minclass->hessian AND CHECKS IT AGAINST THE FINITE
01277           // DIFFERENCE HESSIAN WHICH IT CALCULATES BY CALLING FSTOFD
01278           // (IF IAGFLG .EQ. 1) OR SNDOFD (OTHERWISE).
01279         }
01280       }
01281     }
01282 
01283     if (!(msg & 4))
01284       result(x, f, g, a, p, itncnt, 1);
01285 
01286     // ITERATION
01287     while (itrmcd == 0)
01288     {
01289       itncnt++;
01290       mLastIteration = itncnt; // BAH
01291 
01292       // FIND PERTURBED LOCAL MODEL HESSIAN AND ITS LL+ DECOMPOSITION
01293       // (SKIP THIS STEP IF LINE SEARCH OR DOGSTEP TECHNIQUES BEING USED WITH
01294       // SECANT UPDATES.  CHOLESKY DECOMPOSITION L ALREADY OBTAINED FROM
01295       // SECFAC.)
01296       if (iexp != 1 || method == 3)
01297       {
01298         chlhsn(a, sx, udiag);
01299       }
01300 
01301       // SOLVE FOR NEWTON STEP:  AP=-G
01302       for (i = 1; i <= n; i++)
01303       {
01304         wrk1(i) = -g(i);
01305       }
01306 
01307       lltslv(a, p, wrk1);
01308 
01309       // DECIDE WHETHER TO ACCEPT NEWTON STEP  XPLS=X + P
01310       // OR TO CHOOSE XPLS BY A GLOBAL STRATEGY.
01311       if (iagflg == 0 && method != 1)
01312       {
01313         dltsav = dlt;
01314 
01315         if (method != 2)
01316         {
01317           amusav = amu;
01318           dlpsav = dltp;
01319           phisav = phi;
01320           phpsav = phip0;
01321         }
01322       }
01323 
01324       if (method == 1)
01325       {
01326         lnsrch(x, f, g, p, xpls, fpls, mxtake, iretcd, sx);
01327         if (iretcd == -7) // BAH
01328         {
01329           mLastMessage = iretcd;
01330           return -1;
01331         }
01332       }
01333       else if (method == 2)
01334       {
01335         dogdrv(x, f, g, a, p, xpls, fpls, sx, dlt, iretcd, mxtake, wrk0, wrk1, wrk2, wrk3);
01336       }
01337       else
01338       {
01339         hookdr(x, f, g, a, udiag, p, xpls, fpls, sx, dlt, iretcd, mxtake, amu, dltp, phi, phip0,
01340             wrk0, wrk1, wrk2, itncnt);
01341       }
01342 
01343       // IF COULD NOT FIND SATISFACTORY STEP AND FORWARD DIFFERENCE
01344       // GRADIENT WAS USED, RETRY USING CENTRAL DIFFERENCE GRADIENT.
01345       if (iretcd == 1 && iagflg == 0)
01346       {
01347         // SET IAGFLG FOR CENTRAL DIFFERENCES
01348         iagflg = -1;
01349 
01350         if (!(msg & 4))
01351         {
01352           std::fprintf(mfile, "\nOPTDRV      Shift from forward to central");
01353           std::fprintf(mfile, " differences");
01354           std::fprintf(mfile, "\nOPTDRV      in iteration %d", itncnt);
01355           std::fprintf(mfile, "\n");
01356         }
01357 
01358         fstocd(x, sx, rnf, g);
01359 
01360         if (method == 1)
01361         {
01362           // SOLVE FOR NEWTON STEP:  AP=-G
01363           for (i = 1; i <= n; i++)
01364           {
01365             wrk1(i) = -g(i);
01366           }
01367 
01368           lltslv(a, p, wrk1);
01369 
01370           lnsrch(x, f, g, p, xpls, fpls, mxtake, iretcd, sx);
01371           if (iretcd == -7) // BAH
01372           {
01373             mLastMessage = iretcd;
01374             return -1;
01375           }
01376         }
01377         else
01378         {
01379           dlt = dltsav;
01380           if (method == 2)
01381           {
01382             // SOLVE FOR NEWTON STEP:  AP=-G
01383             for (i = 1; i <= n; i++)
01384             {
01385               wrk1(i) = -g(i);
01386             }
01387 
01388             lltslv(a, p, wrk1);
01389 
01390             dogdrv(x, f, g, a, p, xpls, fpls, sx, dlt, iretcd, mxtake, wrk0, wrk1, wrk2, wrk3);
01391           }
01392           else
01393           {
01394             amu = amusav;
01395             dltp = dlpsav;
01396             phi = phisav;
01397             phip0 = phpsav;
01398 
01399             chlhsn(a, sx, udiag);
01400 
01401             // SOLVE FOR NEWTON STEP:  AP=-G
01402             for (i = 1; i <= n; i++)
01403             {
01404               wrk1(i) = -g(i);
01405             }
01406 
01407             lltslv(a, p, wrk1);
01408 
01409             hookdr(x, f, g, a, udiag, p, xpls, fpls, sx, dlt, iretcd, mxtake, amu, dltp, phi,
01410                 phip0, wrk0, wrk1, wrk2, itncnt);
01411           }
01412         }
01413       }
01414       // CALCULATE STEP FOR OUTPUT
01415       for (i = 1; i <= n; i++)
01416       {
01417         p(i) = xpls(i) - x(i);
01418       }
01419 
01420       // CALCULATE GRADIENT AT XPLS
01421       if (iagflg == -1)
01422       {
01423         // CENTRAL DIFFERENCE GRADIENT
01424         fstocd(xpls, sx, rnf, gpls);
01425       }
01426       else if (iagflg == 0)
01427       {
01428         // FORWARD DIFFERENCE GRADIENT
01429         fstofd(xpls, fpls, gpls, sx, rnf);
01430       }
01431       else
01432       {
01433         // ANALYTIC GRADIENT
01434         minclass->gradient(xpls, gpls);
01435       }
01436 
01437       // CHECK WHETHER STOPPING CRITERIA SATISFIED
01438       optstp(xpls, fpls, gpls, x, itncnt, icscmx, itrmcd, sx, fscale, itnlim, iretcd, mxtake, msg);
01439 
01440       if (itrmcd == 0)
01441       {
01442         // EVALUATE HESSIAN AT XPLS
01443         if (iexp != 0)
01444         {
01445           if (method == 3)
01446           {
01447             secunf(x, g, a, udiag, xpls, gpls, itncnt, rnf, iagflg, noupdt, wrk1, wrk2, wrk3);
01448           }
01449           else
01450           {
01451             secfac(x, g, a, xpls, gpls, itncnt, rnf, iagflg, noupdt, wrk0, wrk1, wrk2, wrk3);
01452           }
01453         }
01454         else
01455         {
01456           if (iahflg == 1)
01457           {
01458             minclass->hessian(xpls, a);
01459           }
01460           else
01461           {
01462             if (iagflg == 1)
01463             {
01464               fstofd(xpls, gpls, a, sx, rnf, wrk1);
01465             }
01466             else
01467             {
01468               sndofd(xpls, fpls, a, sx, rnf, wrk1, wrk2);
01469             }
01470           }
01471         }
01472 
01473         if