multi_min.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_MULTI_MIN_H
00024 #define O2SCL_MULTI_MIN_H
00025 
00026 #include <o2scl/text_file.h>
00027 #include <o2scl/ovector_tlate.h>
00028 #include <o2scl/multi_funct.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033 
00034   /// Base class for a gradient function
00035   template<class param_t, class vec_t=ovector_view>
00036     class grad_funct {
00037 
00038     public:
00039 
00040     virtual ~grad_funct() {}
00041 
00042     /// Compute the gradient \c g at the point \c x
00043     virtual int operator()(size_t nv, vec_t &x, vec_t &g, param_t &pa) {
00044       return 0;
00045     }
00046 
00047   };
00048 
00049   /** \brief Function pointer to a gradient
00050    */
00051   template <class param_t, class vec_t=ovector_view>
00052     class grad_funct_fptr : public grad_funct<param_t,vec_t> {
00053     
00054     public:
00055 
00056     /** \brief Specify the function pointer
00057      */
00058     grad_funct_fptr(int (*fp)(size_t nv, vec_t &x, vec_t &g, param_t &pa)) {
00059       fptr=fp;
00060     }
00061     
00062     virtual ~grad_funct_fptr() {};
00063 
00064     /** \brief Compute the gradient \c g at the point \c x
00065      */
00066     virtual int operator()(size_t nv, vec_t &x, vec_t &g, param_t &pa) {
00067       return (*fptr)(nv,x,g,pa);
00068     }
00069 
00070 #ifndef DOXYGEN_INTERNAL
00071 
00072     protected:
00073 
00074     /// The function pointer
00075     int (*fptr)(size_t nv, vec_t &x, vec_t &g, param_t &pa);
00076 
00077 #endif
00078 
00079 #ifndef DOXYGENP
00080 
00081     private:
00082 
00083     grad_funct_fptr(const grad_funct_fptr &);
00084     grad_funct_fptr& operator=(const grad_funct_fptr&);
00085 
00086 #endif
00087 
00088   };
00089 
00090   /** \brief Member function pointer to a gradient
00091    */
00092   template <class tclass, class param_t, class vec_t=ovector_view>
00093     class grad_funct_mfptr : public grad_funct<param_t,vec_t> {
00094     
00095     public:
00096 
00097     /** \brief Specify the member function pointer
00098      */
00099     grad_funct_mfptr(tclass *tp, int (tclass::*fp)
00100                      (size_t nv, vec_t &x, vec_t &g, param_t &pa)) {
00101       tptr=tp;
00102       fptr=fp;
00103     }
00104     
00105     virtual ~grad_funct_mfptr() {};
00106 
00107     /** \brief Compute the gradient \c g at the point \c x
00108      */
00109     virtual int operator()(size_t nv, vec_t &x, vec_t &g, param_t &pa) {
00110       return (*tptr.*fptr)(nv,x,g,pa);
00111     }
00112 
00113 #ifndef DOXYGEN_INTERNAL
00114 
00115     protected:
00116 
00117     /// Member function pointer
00118     int (tclass::*fptr)(size_t nv, vec_t &x, vec_t &g, param_t &pa);
00119     
00120     /// Class pointer
00121     tclass *tptr;
00122 
00123 #endif
00124 
00125 #ifndef DOXYGENP
00126 
00127     private:
00128 
00129     grad_funct_mfptr(const grad_funct_mfptr &);
00130     grad_funct_mfptr& operator=(const grad_funct_mfptr&);
00131 
00132 #endif
00133 
00134   };
00135 
00136   /// Base class for automatically computing gradients
00137   template<class param_t, class func_t, class vec_t=ovector_view> 
00138     class gradient : public grad_funct<param_t,vec_t> {
00139 
00140     public:
00141 
00142     virtual ~gradient() {}
00143 
00144     /// Set the function to compute the gradient of
00145     virtual int set_function(func_t &f) {
00146       func=&f;
00147       return 0;
00148     }
00149 
00150     /** \brief Compute the gradient \c g at the point \c x
00151      */
00152     virtual int operator()(size_t nv, vec_t &x, vec_t &g, param_t &pa) {
00153       return 0;
00154     }
00155 
00156 #ifndef DOXYGEN_INTERNAL
00157 
00158     protected:
00159 
00160     /// A pointer to the user-specified function
00161     func_t *func;
00162 
00163 #endif
00164 
00165   };
00166 
00167   /// Simple automatic computation of gradient by finite differencing
00168   template<class param_t, class func_t, class vec_t> class simple_grad :
00169   public gradient<param_t,func_t,vec_t> {
00170 
00171   public:
00172 
00173     simple_grad() {
00174       epsrel=1.0e-4;
00175       epsmin=1.0e-15;
00176     }
00177     
00178     virtual ~simple_grad() {}
00179 
00180     /** \brief The relative stepsize for finite-differencing
00181         (default \f$ 10^{-4} \f$ )
00182     */
00183     double epsrel;
00184 
00185     /// The minimum stepsize (default \f$ 10^{-15} \f$)
00186     double epsmin;
00187 
00188     /** \brief Compute the gradient \c g at the point \c x
00189      */
00190     virtual int operator()(size_t nv, vec_t &x, vec_t &g, param_t &pa) {
00191       double fv1, fv2, h;
00192 
00193       (*this->func)(nv,x,fv1,pa);
00194       
00195       for(size_t i=0;i<nv;i++) {
00196         
00197         h=epsrel*fabs(x[i]);
00198         if (fabs(h)<=epsmin) h=epsrel;
00199 
00200         x[i]+=h;
00201         (*this->func)(nv,x,fv2,pa);
00202         x[i]-=h;
00203         g[i]=(fv2-fv1)/h;
00204       }
00205       
00206       return 0;
00207     }
00208 
00209   };
00210     
00211   /// Base class for a gradient function using arrays
00212   template<class param_t, size_t nv> class grad_vfunct {
00213 
00214     public:
00215 
00216     virtual ~grad_vfunct() {}
00217 
00218     /** \brief Compute the gradient \c g at the point \c x
00219      */
00220     virtual int operator()(size_t nvar, double x[nv], double g[nv], 
00221                            param_t &pa) {
00222       return 0;
00223     }
00224 
00225   };
00226 
00227   /** \brief Function pointer to a gradient
00228    */
00229   template <class param_t, size_t nv>
00230     class grad_vfunct_fptr : public grad_vfunct<param_t,nv> {
00231     
00232     public:
00233 
00234     /** \brief Specify the member function pointer
00235      */
00236     grad_vfunct_fptr(int (*fp)(size_t nv, double x[nv], double g[nv], 
00237                                param_t &pa)) {
00238       fptr=fp;
00239     }
00240     
00241     virtual ~grad_vfunct_fptr() {};
00242 
00243     /** \brief Compute the gradient \c g at the point \c x
00244      */
00245     virtual int operator()(size_t nvar, double x[nv], double g[nv], 
00246                            param_t &pa) {
00247       return (*fptr)(nvar,x,g,pa);
00248     }
00249 
00250 #ifndef DOXYGEN_INTERNAL
00251 
00252     protected:
00253 
00254     /// Function pointer
00255     int (*fptr)(size_t nvar, double x[nv], double g[nv], param_t &pa);
00256 
00257 #endif
00258 
00259 #ifndef DOXYGENP
00260 
00261     private:
00262 
00263     grad_vfunct_fptr(const grad_vfunct_fptr &);
00264     grad_vfunct_fptr& operator=(const grad_vfunct_fptr&);
00265 
00266 #endif
00267 
00268   };
00269 
00270   /** \brief Member function pointer to a gradient
00271    */
00272   template <class tclass, class param_t, size_t nv>
00273     class grad_vfunct_mfptr : public grad_vfunct<param_t,nv> {
00274     
00275     public:
00276 
00277     /** \brief Specify the member function pointer
00278      */
00279     grad_vfunct_mfptr(tclass *tp, int (tclass::*fp)
00280                       (size_t nvar, double x[nv], double g[nv], param_t &pa)) {
00281       tptr=tp;
00282       fptr=fp;
00283     }
00284     
00285     virtual ~grad_vfunct_mfptr() {};
00286 
00287     /** \brief Compute the gradient \c g at the point \c x
00288      */
00289     virtual int operator()(size_t nvar, double x[nv], double g[nv], 
00290                            param_t &pa) {
00291       return (*tptr.*fptr)(nvar,x,g,pa);
00292     }
00293 
00294 #ifndef DOXYGEN_INTERNAL
00295 
00296     protected:
00297 
00298     /// Member function pointer
00299     int (tclass::*fptr)(size_t nvar, double x[nv], double g[nv], param_t &pa);
00300     
00301     /// Class pointer
00302     tclass *tptr;
00303 
00304 #endif
00305 
00306 #ifndef DOXYGENP
00307 
00308     private:
00309 
00310     grad_vfunct_mfptr(const grad_vfunct_mfptr &);
00311     grad_vfunct_mfptr& operator=(const grad_vfunct_mfptr&);
00312 
00313 #endif
00314 
00315   };
00316 
00317   /// Base class for automatically computing gradients with arrays
00318   template<class param_t, class func_t, size_t nv> 
00319     class gradient_array : public grad_vfunct<param_t,nv> {
00320 
00321     public:
00322 
00323     virtual ~gradient_array() {}
00324 
00325     /// Set the function to compute the gradient of
00326     virtual int set_function(func_t &f) {
00327       func=&f;
00328       return 0;
00329     }
00330 
00331     /** \brief Compute the gradient \c g at the point \c x
00332      */
00333     virtual int operator()(size_t nvar, double x[nv], double g[nv], 
00334                            param_t &pa) {
00335       return 0;
00336     }
00337 
00338 #ifndef DOXYGEN_INTERNAL
00339 
00340     protected:
00341 
00342     /// A pointer to the user-specified function
00343     func_t *func;
00344 
00345 #endif
00346 
00347   };
00348 
00349   /** \brief Simple automatic computation of gradient by finite 
00350       differencing with arrays
00351   */
00352   template<class param_t, class func_t, size_t nv> class simple_grad_array :
00353   public gradient_array<param_t,func_t,nv> {
00354 
00355   public:
00356 
00357     simple_grad_array() {
00358       epsrel=1.0e-4;
00359       epsmin=1.0e-15;
00360     }
00361     
00362     virtual ~simple_grad_array() {}
00363 
00364     /** \brief The relative stepsize for finite-differencing
00365         (default \f$ 10^{-4} \f$ )
00366     */
00367     double epsrel;
00368 
00369     /// The minimum stepsize (default \f$ 10^{-15} \f$)
00370     double epsmin;
00371 
00372     /** \brief Compute the gradient \c g at the point \c x
00373      */
00374     virtual int operator()(size_t nvar, double x[nv], double g[nv], 
00375                            param_t &pa) {
00376       double fv1, fv2, h;
00377 
00378       (*this->func)(nv,x,fv1,pa);
00379       
00380       for(size_t i=0;i<nvar;i++) {
00381         
00382         h=epsrel*fabs(x[i]);
00383         if (fabs(h)<=epsmin) h=epsrel;
00384 
00385         x[i]+=h;
00386         (*this->func)(nvar,x,fv2,pa);
00387         x[i]-=h;
00388         g[i]=(fv2-fv1)/h;
00389       }
00390       
00391       return 0;
00392     }
00393 
00394   };
00395     
00396   /** 
00397       \brief Multidimensional minimization base
00398 
00399       <b>The template parameters:</b>
00400       The template parameter \c func_t specifies the function to 
00401       minimize and should be a class containing a definition 
00402       \code
00403       func_t::operator()(size_t nv, const vec_t &x, double &f, param_t &pa);
00404       \endcode
00405       where \c f is the value of the function at \c x with parameter \c pa
00406       where \c x is a array-like class defining \c operator[] of size \c nv.
00407       The parameter \c dfunc_t (if used) should provide the gradient with
00408       \code
00409       func_t::operator()(size_t nv, const vec_t &x, vec_t &g, param_t &pa);
00410       \endcode
00411       where \c g is the gradient of the function at \c x. 
00412   */
00413   template<class param_t, class func_t, class dfunc_t=func_t, 
00414     class vec_t=ovector_view> class multi_min {
00415       
00416       public:
00417       
00418       /// Output control
00419       int verbose;
00420       
00421       /// Maximum number of iterations
00422       int ntrial;
00423       
00424       /// Tolerance
00425       double tolf;
00426       
00427       /// The minimum allowable stepsize
00428       double tolx;
00429 
00430       /// The number of iterations for in the most recent minimization
00431       int last_ntrial;
00432       
00433       multi_min() {
00434         verbose=0;
00435         ntrial=100;
00436         tolf=1.0e-4;
00437         tolx=1.0e-4;
00438         last_ntrial=0;
00439       }
00440 
00441       virtual ~multi_min() {}
00442       
00443       /** \brief Calculate the minimum \c min of \c func w.r.t. the
00444           array \c x of size \c nvar.
00445       */
00446       virtual int mmin(size_t nvar, vec_t &x, double &fmin, param_t &pa,
00447                        func_t &func) 
00448       {
00449         return 0;
00450       }
00451       
00452       /** \brief Calculate the minimum \c min of \c func
00453           w.r.t. the array \c x of size \c nvar with gradient
00454           \c dfunc
00455       */
00456       virtual int mmin_de(size_t nvar, vec_t &x, double &fmin, param_t &pa,
00457                           func_t &func, dfunc_t &dfunc)
00458       {
00459         return mmin(nvar,x,fmin,pa,func);
00460       }
00461       
00462       /** 
00463           \brief Print out iteration information.
00464           
00465           Depending on the value of the variable verbose, this prints out
00466           the iteration information. If verbose=0, then no information is
00467           printed, while if verbose>1, then after each iteration, the
00468           present values of x and y are output to std::cout along with the
00469           iteration number. If verbose>=2 then each iteration waits for a
00470           character.
00471       */
00472       template<class vec2_t> 
00473       int print_iter(size_t nv, vec2_t &x, double y, int iter,
00474                      double value, double limit,
00475                      std::string comment) 
00476       {
00477         if (verbose<=0) return 0;
00478         
00479         int i;
00480         char ch;
00481         
00482         std::cout << comment << " Iteration: " << iter << std::endl;
00483         text_out_file outs(&std::cout,79);
00484         outs.word_out("x:");
00485         for(i=0;i<((int)nv);i++) outs.double_out(x[i]);
00486         outs.end_line();
00487         std::cout << "y: " << y << " Val: " << value << " Lim: " 
00488         << limit << std::endl;
00489         if (verbose>1) {
00490           std::cout << "Press a key and type enter to continue. ";
00491           std::cin >> ch;
00492         }
00493         
00494         return 0;
00495       }
00496       
00497       /// Return string denoting type ("multi_min")
00498       const char *type() { return "multi_min"; }
00499       
00500   };
00501   
00502 #ifndef DOXYGENP
00503 }
00504 #endif
00505 
00506 #endif
00507 

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page