gsl_mmin_simp.h

00001 /*
00002   -------------------------------------------------------------------
00003 
00004   Copyright (C) 2006, 2007, 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_GSL_MMIN_SIMP_H
00024 #define O2SCL_GSL_MMIN_SIMP_H
00025 
00026 #include <o2scl/multi_min.h>
00027 #include <o2scl/gsl_mmin_simp_b.h>
00028 
00029 #ifndef DOXYGENP
00030 namespace o2scl {
00031 #endif
00032 
00033   /** 
00034       \brief Multidimensional minimization by the Simplex method (GSL)
00035 
00036       \todo Not properly generalized to non-GSL vectors (to do this,
00037       I'll have to store the simplex as a vec_t array rather than a 
00038       gsl_matrix). Right now, this only works with \c vec_t \c = 
00039       \ref ovector_view.
00040       \todo Add a minimize function which allows specification
00041       of the entire simplex.
00042       \todo Gracefully ensure memory allocation and deallocation 
00043       is performed automatically.
00044       \todo Test mmin_twovec().
00045       \todo Document how set() chooses the simplex from the initial
00046       guess and step size
00047   */
00048   template<class param_t,class func_t=multi_funct<param_t>,
00049     class vec_t=ovector_view> class gsl_mmin_simp :
00050   public multi_min<param_t,func_t,func_t,vec_t>, public gsl_mmin_simp_b 
00051   {
00052     
00053 #ifndef DOXYGEN_INTERNAL
00054     
00055     protected:
00056     
00057     /** 
00058         \brief Move a corner of a simplex
00059 
00060         Moves a simplex corner scaled by coeff (negative value
00061         represents mirroring by the middle point of the "other" corner
00062         points) and gives new corner in xc and function value at xc as
00063         a return value.
00064     */
00065     virtual double move_corner(const double coeff, const simp_state_t *state,
00066                                size_t corner, gsl_vector *xc, func_t &f, 
00067                                size_t nvar, param_t &pa) {
00068       
00069       gsl_matrix *x1=state->x1;
00070         
00071       size_t i,j;
00072       double newval,mp;
00073         
00074       if(x1->size1<2) {
00075         set_err("Simplex too small in gsl_mmin_simp::move_corner().",
00076                 gsl_efailed);
00077         return 0.0;
00078       }
00079         
00080       for (j=0;j<x1->size2;j++) {
00081         mp=0.0;
00082         for (i=0;i<x1->size1;i++) {
00083           if (i!=corner) {
00084             mp+=(gsl_matrix_get(x1,i,j));
00085           }
00086         }
00087         mp/=(double)(x1->size1-1);
00088         newval=mp-coeff*(mp-gsl_matrix_get(x1,corner,j));
00089         gsl_vector_set(xc,j,newval);
00090       }
00091       
00092       f(nvar,*((ovector *)xc),newval,pa);
00093         
00094       return newval;
00095     }
00096       
00097     /** 
00098         \brief Contract the simplex towards the best point
00099           
00100         Function contracts the simplex in respect to best valued
00101         corner. All corners besides the best corner are moved.
00102         
00103         The xc vector is used as work space.
00104     */
00105     virtual int contract_by_best(simp_state_t *state, size_t best, 
00106                                  gsl_vector *xc, func_t &f,
00107                                  size_t nvar, param_t &pa) {
00108         
00109       gsl_matrix *x1=state->x1;
00110       gsl_vector *y1=state->y1;
00111   
00112       size_t i,j;
00113       double newval;
00114   
00115       for (i=0;i<x1->size1;i++) {
00116         if (i!=best) {
00117           for (j=0;j<x1->size2;j++) {
00118             newval=0.5*(gsl_matrix_get(x1,i,j)
00119                         +gsl_matrix_get(x1,best,j));
00120             gsl_matrix_set(x1,i,j,newval);
00121           }
00122             
00123           /* evaluate function in the new point */
00124           gsl_matrix_get_row(xc,x1,i);
00125           f(nvar,*((ovector *)xc),newval,pa);
00126           gsl_vector_set(y1,i,newval);
00127         }
00128       }
00129   
00130       return gsl_success;
00131     }
00132 
00133     /// Number of variables to be minimized over
00134     size_t dim;
00135 
00136     /// Present minimum vector
00137     gsl_vector *x;
00138 
00139     /// Function value at minimum
00140     double fval;
00141 
00142     /// Function
00143     func_t *func;
00144 
00145     /// Parameters
00146     param_t *params;
00147 
00148     /// True if set() has been called
00149     bool set_called;
00150 
00151     /// Size of simplex
00152     double size;
00153 
00154     /// Simplex state storage
00155     simp_state_t lstate;
00156 
00157 #endif
00158 
00159     public:
00160 
00161     gsl_mmin_simp() {
00162       dim=0;
00163       initial_step=1.0;
00164       print_simplex=0;
00165     }
00166     
00167     virtual ~gsl_mmin_simp() {}
00168     
00169     /// The initial stepsize (default 1.0)
00170     double initial_step;
00171     
00172     /** 
00173         \brief Print simplex information in print_iter() (default 0)
00174         
00175         If this is 1 and \ref verbose is greater than 0, 
00176         then print_iter() will print the function values at all 
00177         the simplex points. 
00178     */
00179     int print_simplex;
00180 
00181     /** \brief Calculate the minimum \c min of \c func w.r.t the
00182         array \c x of size \c nvar.
00183     */
00184     virtual int mmin(size_t nn, vec_t &xx, double &fmin, param_t &pa,
00185                      func_t &ufunc) {
00186       
00187       int ret=0,status,iter=0;
00188       
00189       allocate(nn);
00190       
00191       ovector ss(nn);
00192       for (size_t is=0;is<nn;is++) ss[is]=initial_step;
00193       ret=set(ufunc,pa,xx,ss);
00194       if(ret!=0) {
00195         free();
00196         return ret;
00197       }
00198   
00199       do {
00200         iter++;
00201           
00202         status=iterate();
00203         if(status) break;
00204 
00205         if(this->verbose>0) {
00206           ovector *tx=(ovector *)(x);
00207           print_iter(nn,*tx,fval,iter,size,this->tolx,
00208                      "gsl_mmin_nmsimplex");
00209         }
00210     
00211         status=gsl_multimin_test_size(size,this->tolx);
00212           
00213       } while(status == GSL_CONTINUE && iter<this->ntrial);
00214         
00215       for (size_t i=0;i<nn;i++) xx[i]=gsl_vector_get(x,i);      
00216       fmin=fval;
00217   
00218       if(iter>=this->ntrial) {
00219         set_err_ret("Exceeded max # of iterations in gsl_mmin_simp::mmin().",
00220                     gsl_emaxiter);
00221       }
00222 
00223       free();
00224       this->last_ntrial=iter;
00225       
00226       return status;
00227     }
00228     
00229     /** \brief Calculate the minimum \c min of \c func w.r.t the
00230         array \c x of size \c nvar, using \c xx and \c xx2 to specify
00231         the simplex
00232     */
00233     virtual int mmin_twovec(size_t nn, vec_t &xx, vec_t &xx2, double &fmin, 
00234                             param_t &pa, func_t &ufunc) {
00235       
00236       int ret=0,i,status,iter=0;
00237       
00238       allocate(nn);
00239         
00240       ovector ss(nn);
00241       for (size_t is=0;is<nn;is++) ss[is]=xx2[is]-xx[is];
00242       ret=set(ufunc,pa,xx,ss);
00243       if(ret!=0) {
00244         free();
00245         return ret;
00246       }
00247   
00248       do {
00249         iter++;
00250           
00251         status=iterate();
00252         if(status) break;
00253 
00254         if(this->verbose>0) {
00255           ovector *tx=(ovector *)(x);
00256           print_iter(nn,*tx,fval,iter,size,this->tolx,
00257                      "gsl_mmin_nmsimplex");
00258         }
00259     
00260         status=gsl_multimin_test_size(size,this->tolx);
00261           
00262       } while(status == GSL_CONTINUE && iter<this->ntrial);
00263         
00264       for (i=0;i<((int)nn);i++) xx[i]=gsl_vector_get(x,i);
00265       fmin=fval;
00266   
00267       if(iter>=this->ntrial) {
00268         set_err_ret
00269           ("Exceeded max # of iterations in gsl_mmin_simp::mmin_twovec().",
00270            gsl_emaxiter);
00271       }
00272 
00273       free();
00274       this->last_ntrial=iter;
00275 
00276       return status;
00277     }
00278     
00279     /// Allocate the memory
00280     virtual int allocate(size_t n) {
00281       int status;
00282       if(dim!=0) free();
00283       set_called=false;
00284       dim=n;
00285 
00286       x=gsl_vector_calloc(n);
00287       if(x == 0) {
00288         GSL_ERROR_VAL("failed to allocate space for x",GSL_ENOMEM,0);
00289       }
00290   
00291       lstate.x1=gsl_matrix_alloc(n+1,n);
00292       if(lstate.x1 == NULL) {
00293         set_err("Failed to allocate x1 in gsl_mmin_nmsimplex::allocate().",
00294                 gsl_enomem);
00295       }
00296   
00297       lstate.y1=gsl_vector_alloc(n+1);
00298       if(lstate.y1 == NULL) {
00299         set_err("Failed to allocate y1 in gsl_mmin_nmsimplex::allocate().",
00300                 gsl_enomem);
00301       }
00302   
00303       lstate.ws1=gsl_vector_alloc(n);
00304       if(lstate.ws1 == NULL) {
00305         set_err("Failed to allocate ws1 in gsl_mmin_nmsimplex::allocate().",
00306                 gsl_enomem);
00307       }
00308   
00309       lstate.ws2=gsl_vector_alloc(n);
00310       if(lstate.ws2 == NULL) {
00311         set_err("Failed to allocate ws2 in gsl_mmin_nmsimplex::allocate().",
00312                 gsl_enomem);
00313       }
00314 
00315       return gsl_success;
00316     }
00317     
00318     /// Free the allocated memory
00319     virtual int free() {
00320 
00321       gsl_matrix_free(lstate.x1);
00322       gsl_vector_free(lstate.y1);
00323       gsl_vector_free(lstate.ws1);
00324       gsl_vector_free(lstate.ws2);
00325       gsl_vector_free(x);
00326 
00327       dim=0;
00328 
00329       return 0;
00330     }
00331     
00332     /// Set the function and initial guess
00333     virtual int set(func_t &ufunc, param_t &pa, vec_t &ax, 
00334                     vec_t &step_size) {
00335       size_t i;
00336                 
00337       if(dim==0) {
00338         set_err_ret("Memory not allocated in gsl_mmin_nmsimplex::set().",
00339                     gsl_ebadlen);
00340       }
00341       
00342       if(dim>ax.size()) {
00343         set_err_ret("Initial guess<solver size in gsl_mmin_nmsimplex::set().",
00344                     gsl_ebadlen);
00345       }
00346       
00347       params=&pa;
00348    
00349       // We can't use gsl_vector_memcpy here,since ax may have a
00350       // different size than dim.
00351       for (i=0;i<dim;i++) gsl_vector_set(x,i,ax[i]);
00352  
00353       func=&ufunc;
00354   
00355       double val;
00356       int status;
00357   
00358       gsl_vector *xtemp=lstate.ws1;
00359   
00360       /* first point is the original x0 */
00361         
00362       ufunc(dim,ax,val,pa);
00363       gsl_matrix_set_row(lstate.x1,0,x);
00364       gsl_vector_set(lstate.y1,0,val);
00365   
00366       /* following points are initialized to x0+step_size */
00367  
00368       for (i=0;i<x->size;i++) {
00369         status=gsl_vector_memcpy(xtemp,x);
00370  
00371         if(status != 0)      {
00372           GSL_ERROR("vector memcopy failed",GSL_EFAILED);
00373         }
00374             
00375         val=gsl_vector_get(xtemp,i)+
00376           gsl_vector_get((gsl_vector *)(&step_size),i);
00377         gsl_vector_set(xtemp,i,val);
00378         ufunc(dim,*((ovector *)xtemp),val,pa);
00379         gsl_matrix_set_row(lstate.x1,i+1,xtemp);
00380         gsl_vector_set(lstate.y1,i+1,val);
00381       }
00382  
00383       /* Initialize simplex size */
00384         
00385       size=nmsimplex_size(&lstate);
00386         
00387       set_called=true;
00388  
00389       return gsl_success;
00390     }
00391 
00392     /// Perform an iteration
00393     virtual int iterate() {
00394         
00395       simp_state_t *nstate=&lstate;
00396       
00397       /* xc and xc2 vectors store tried corner point coordinates */
00398  
00399       gsl_vector *xc=nstate->ws1;
00400       gsl_vector *xc2=nstate->ws2;
00401       gsl_vector *y1=nstate->y1;
00402       gsl_matrix *x1=nstate->x1;
00403  
00404       size_t n=y1->size;
00405       size_t i;
00406       size_t hi=0,s_hi=0,lo=0;
00407       double dhi,ds_hi,dlo;
00408       int status;
00409       double val,val2;
00410  
00411       /* get index of highest,second highest and lowest point */
00412  
00413       dhi=ds_hi=dlo=gsl_vector_get(y1,0);
00414  
00415       for (i=1;i<n;i++) {
00416         val =(gsl_vector_get(y1,i));
00417         if(val<dlo) {
00418           dlo=val;
00419           lo=i;
00420         } else if (val > dhi) {
00421           ds_hi=dhi;
00422           s_hi=hi;
00423           dhi=val;
00424           hi=i;
00425         } else if(val > ds_hi) {
00426           ds_hi=val;
00427           s_hi=i;
00428         }
00429       }
00430  
00431       /* reflect the highest value */
00432         
00433       val=move_corner(-1.0,nstate,hi,xc,*func,dim,*params);
00434   
00435       if (val<gsl_vector_get(y1,lo)) {
00436       
00437         /* reflected point becomes lowest point,try expansion */
00438       
00439         val2=move_corner(-2.0,nstate,hi,xc2,*func,dim,*params);
00440         if (val2<gsl_vector_get(y1,lo)) {
00441           gsl_matrix_set_row(x1,hi,xc2);
00442           gsl_vector_set(y1,hi,val2);
00443         } else {
00444           gsl_matrix_set_row(x1,hi,xc);
00445           gsl_vector_set(y1,hi,val);
00446         }
00447 
00448       } else if (val > gsl_vector_get(y1,s_hi)) {
00449         
00450         /* reflection does not improve things enough */
00451         
00452         if(val <= gsl_vector_get(y1,hi)) {
00453             
00454           /* if trial point is better than highest point,replace
00455              highest point */
00456             
00457           gsl_matrix_set_row(x1,hi,xc);
00458           gsl_vector_set(y1,hi,val);
00459         }
00460       
00461         /* try one dimensional contraction */
00462           
00463         val2=move_corner(0.5,nstate,hi,xc2,*func,dim,*params);
00464       
00465         if(val2 <= gsl_vector_get(y1,hi)) {
00466 
00467           gsl_matrix_set_row(nstate->x1,hi,xc2);
00468           gsl_vector_set(y1,hi,val2);
00469 
00470         } else {
00471           
00472           /* contract the whole simplex in respect to the best point */
00473           
00474           status=contract_by_best(nstate,lo,xc,*func,dim,*params);
00475           if(status != 0) {
00476             set_err("Function contract_by_best() failed in iterate().",
00477                     gsl_efailed);
00478           }
00479         }
00480 
00481       } else {
00482       
00483         /* trial point is better than second highest point.
00484            Replace highest point by it */
00485       
00486         gsl_matrix_set_row(x1,hi,xc);
00487         gsl_vector_set(y1,hi,val);
00488       }
00489   
00490       /* return lowest point of simplex as x */
00491   
00492       lo=gsl_vector_min_index(y1);
00493       gsl_matrix_get_row(x,x1,lo);
00494       fval=gsl_vector_get(y1,lo);
00495   
00496       /* Update simplex size */
00497   
00498       size=nmsimplex_size(nstate);
00499 
00500       return gsl_success;
00501     }
00502       
00503     /** 
00504         \brief Print out iteration information.
00505           
00506         Depending on the value of the variable verbose, this prints out
00507         the iteration information. If verbose=0, then no information is
00508         printed, while if verbose>1, then after each iteration, the
00509         present values of x and y are output to std::cout along with the
00510         iteration number. If verbose>=2 then each iteration waits for a
00511         character.
00512     */
00513     virtual int print_iter(size_t nv, vec_t &xx, double y, int iter,
00514                            double value, double limit,
00515                            std::string comment) {
00516       if (this->verbose<=0) return 0;
00517       
00518       int i;
00519       char ch;
00520         
00521       std::cout << comment << " Iteration: " << iter << std::endl;
00522       text_out_file outs(&std::cout,79);
00523       outs.word_out("x:");
00524       for(i=0;i<((int)nv);i++) outs.double_out(xx[i]);
00525       outs.end_line();
00526       if (print_simplex==1) {
00527         ovector_view *ov=(ovector_view *)(lstate.y1);
00528         outs.word_out("simp vals:");
00529         for(i=0;i<((int)nv+1);i++) {
00530           outs.double_out((*ov)[i]);
00531         }
00532         outs.end_line();
00533       }
00534       std::cout << "y: " << y << " Val: " << value << " Lim: " 
00535       << limit << std::endl;
00536       if (this->verbose>1) {
00537         std::cout << "Press a key and type enter to continue. ";
00538         std::cin >> ch;
00539       }
00540         
00541       return 0;
00542     }
00543 
00544     /// Return string denoting type("gsl_mmin_simp")
00545     virtual const char *type() { return "gsl_mmin_simp";}
00546 
00547   };
00548   
00549 #ifndef DOXYGENP
00550 }
00551 #endif
00552 
00553 #endif

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