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
,
O2scl Sourceforge Project Page