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