gsl_mmin_simp.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_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 vector, \c xc, 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         set_err_ret("Failed to allocate x in gsl_mmin_simp::allocate().",
00289                     gsl_enomem);
00290       }
00291   
00292       lstate.x1=gsl_matrix_alloc(n+1,n);
00293       if (lstate.x1 == NULL) {
00294         gsl_vector_free(x);
00295         set_err_ret("Failed to allocate x1 in gsl_mmin_simp::allocate().",
00296                 gsl_enomem);
00297       }
00298   
00299       lstate.y1=gsl_vector_alloc(n+1);
00300       if (lstate.y1 == NULL) {
00301         gsl_vector_free(x);
00302         gsl_matrix_free(lstate.x1);
00303         set_err_ret("Failed to allocate y1 in gsl_mmin_simp::allocate().",
00304                 gsl_enomem);
00305       }
00306   
00307       lstate.ws1=gsl_vector_alloc(n);
00308       if (lstate.ws1 == NULL) {
00309         gsl_vector_free(x);
00310         gsl_matrix_free(lstate.x1);
00311         gsl_vector_free(lstate.y1);
00312         set_err_ret("Failed to allocate ws1 in gsl_mmin_simp::allocate().",
00313                 gsl_enomem);
00314       }
00315   
00316       lstate.ws2=gsl_vector_alloc(n);
00317       if (lstate.ws2 == NULL) {
00318         gsl_vector_free(x);
00319         gsl_matrix_free(lstate.x1);
00320         gsl_vector_free(lstate.y1);
00321         gsl_vector_free(lstate.ws1);
00322         set_err_ret("Failed to allocate ws2 in gsl_mmin_simp::allocate().",
00323                 gsl_enomem);
00324       }
00325 
00326       return gsl_success;
00327     }
00328     
00329     /// Free the allocated memory
00330     virtual int free() {
00331 
00332       gsl_matrix_free(lstate.x1);
00333       gsl_vector_free(lstate.y1);
00334       gsl_vector_free(lstate.ws1);
00335       gsl_vector_free(lstate.ws2);
00336       gsl_vector_free(x);
00337 
00338       dim=0;
00339 
00340       return 0;
00341     }
00342     
00343     /// Set the function and initial guess
00344     virtual int set(func_t &ufunc, param_t &pa, vec_t &ax, 
00345                     vec_t &step_size) {
00346       size_t i;
00347                 
00348       if(dim==0) {
00349         set_err_ret("Memory not allocated in gsl_mmin_simp::set().",
00350                     gsl_ebadlen);
00351       }
00352       
00353       if(dim>ax.size()) {
00354         set_err_ret("Initial guess<solver size in gsl_mmin_simp::set().",
00355                     gsl_ebadlen);
00356       }
00357       
00358       params=&pa;
00359    
00360       // We can't use gsl_vector_memcpy here,since ax may have a
00361       // different size than dim.
00362       for (i=0;i<dim;i++) gsl_vector_set(x,i,ax[i]);
00363  
00364       func=&ufunc;
00365   
00366       double val;
00367       int status;
00368   
00369       gsl_vector *xtemp=lstate.ws1;
00370   
00371       /* first point is the original x0 */
00372         
00373       ufunc(dim,ax,val,pa);
00374       gsl_matrix_set_row(lstate.x1,0,x);
00375       gsl_vector_set(lstate.y1,0,val);
00376   
00377       /* following points are initialized to x0+step_size */
00378  
00379       for (i=0;i<x->size;i++) {
00380         status=gsl_vector_memcpy(xtemp,x);
00381  
00382         if (status != 0) {
00383           set_err_ret("Vector copy failed in gsl_mmin_simp::set().",
00384                       gsl_efailed);
00385         }
00386             
00387         val=gsl_vector_get(xtemp,i)+
00388           gsl_vector_get((gsl_vector *)(&step_size),i);
00389         gsl_vector_set(xtemp,i,val);
00390         ufunc(dim,*((ovector *)xtemp),val,pa);
00391         gsl_matrix_set_row(lstate.x1,i+1,xtemp);
00392         gsl_vector_set(lstate.y1,i+1,val);
00393       }
00394  
00395       /* Initialize simplex size */
00396         
00397       size=nmsimplex_size(&lstate);
00398         
00399       set_called=true;
00400  
00401       return gsl_success;
00402     }
00403 
00404     /// Perform an iteration
00405     virtual int iterate() {
00406         
00407       simp_state_t *nstate=&lstate;
00408       
00409       /* xc and xc2 vectors store tried corner point coordinates */
00410  
00411       gsl_vector *xc=nstate->ws1;
00412       gsl_vector *xc2=nstate->ws2;
00413       gsl_vector *y1=nstate->y1;
00414       gsl_matrix *x1=nstate->x1;
00415  
00416       size_t n=y1->size;
00417       size_t i;
00418       size_t hi=0,s_hi=0,lo=0;
00419       double dhi,ds_hi,dlo;
00420       int status;
00421       double val,val2;
00422  
00423       /* get index of highest,second highest and lowest point */
00424  
00425       dhi=ds_hi=dlo=gsl_vector_get(y1,0);
00426  
00427       for (i=1;i<n;i++) {
00428         val =(gsl_vector_get(y1,i));
00429         if(val<dlo) {
00430           dlo=val;
00431           lo=i;
00432         } else if (val > dhi) {
00433           ds_hi=dhi;
00434           s_hi=hi;
00435           dhi=val;
00436           hi=i;
00437         } else if(val > ds_hi) {
00438           ds_hi=val;
00439           s_hi=i;
00440         }
00441       }
00442  
00443       /* reflect the highest value */
00444         
00445       val=move_corner(-1.0,nstate,hi,xc,*func,dim,*params);
00446   
00447       if (val<gsl_vector_get(y1,lo)) {
00448       
00449         /* reflected point becomes lowest point,try expansion */
00450       
00451         val2=move_corner(-2.0,nstate,hi,xc2,*func,dim,*params);
00452         if (val2<gsl_vector_get(y1,lo)) {
00453           gsl_matrix_set_row(x1,hi,xc2);
00454           gsl_vector_set(y1,hi,val2);
00455         } else {
00456           gsl_matrix_set_row(x1,hi,xc);
00457           gsl_vector_set(y1,hi,val);
00458         }
00459 
00460       } else if (val > gsl_vector_get(y1,s_hi)) {
00461         
00462         /* reflection does not improve things enough */
00463         
00464         if(val <= gsl_vector_get(y1,hi)) {
00465             
00466           /* if trial point is better than highest point,replace
00467              highest point */
00468             
00469           gsl_matrix_set_row(x1,hi,xc);
00470           gsl_vector_set(y1,hi,val);
00471         }
00472       
00473         /* try one dimensional contraction */
00474           
00475         val2=move_corner(0.5,nstate,hi,xc2,*func,dim,*params);
00476       
00477         if(val2 <= gsl_vector_get(y1,hi)) {
00478 
00479           gsl_matrix_set_row(nstate->x1,hi,xc2);
00480           gsl_vector_set(y1,hi,val2);
00481 
00482         } else {
00483           
00484           /* contract the whole simplex in respect to the best point */
00485           
00486           status=contract_by_best(nstate,lo,xc,*func,dim,*params);
00487           if(status != 0) {
00488             set_err("Function contract_by_best() failed in iterate().",
00489                     gsl_efailed);
00490           }
00491         }
00492 
00493       } else {
00494       
00495         /* trial point is better than second highest point.
00496            Replace highest point by it */
00497       
00498         gsl_matrix_set_row(x1,hi,xc);
00499         gsl_vector_set(y1,hi,val);
00500       }
00501   
00502       /* return lowest point of simplex as x */
00503   
00504       lo=gsl_vector_min_index(y1);
00505       gsl_matrix_get_row(x,x1,lo);
00506       fval=gsl_vector_get(y1,lo);
00507   
00508       /* Update simplex size */
00509   
00510       size=nmsimplex_size(nstate);
00511 
00512       return gsl_success;
00513     }
00514       
00515     /** 
00516         \brief Print out iteration information.
00517           
00518         Depending on the value of the variable verbose, this prints out
00519         the iteration information. If verbose=0, then no information is
00520         printed, while if verbose>1, then after each iteration, the
00521         present values of x and y are output to std::cout along with the
00522         iteration number. If verbose>=2 then each iteration waits for a
00523         character.
00524     */
00525     virtual int print_iter(size_t nv, vec_t &xx, double y, int iter,
00526                            double value, double limit,
00527                            std::string comment) {
00528       if (this->verbose<=0) return 0;
00529       
00530       size_t i;
00531       char ch;
00532         
00533       std::cout << comment << " Iteration: " << iter << std::endl;
00534       text_out_file outs(&std::cout,79);
00535       outs.word_out("x:");
00536       for(i=0;i<nv;i++) outs.double_out(xx[i]);
00537       outs.end_line();
00538       if (print_simplex==1) {
00539         ovector_view *ov=(ovector_view *)(lstate.y1);
00540         outs.word_out("Simplex Values:");
00541         for(i=0;i<nv+1;i++) {
00542           outs.double_out((*ov)[i]);
00543         }
00544         outs.end_line();
00545       }
00546       std::cout << "y: " << y << " Val: " << value << " Lim: " 
00547       << limit << std::endl;
00548       if (this->verbose>1) {
00549         std::cout << "Press a key and type enter to continue. ";
00550         std::cin >> ch;
00551       }
00552         
00553       return 0;
00554     }
00555 
00556     /// Return string denoting type("gsl_mmin_simp")
00557     virtual const char *type() { return "gsl_mmin_simp";}
00558 
00559   };
00560   
00561 #ifndef DOXYGENP
00562 }
00563 #endif
00564 
00565 #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