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_MROOT_HYBRIDS_H 00024 #define O2SCL_GSL_MROOT_HYBRIDS_H 00025 00026 #include <gsl/gsl_multiroots.h> 00027 #include <gsl/gsl_linalg.h> 00028 00029 #include <o2scl/ovector_tlate.h> 00030 #include <o2scl/gsl_mroot_hybrids_b.h> 00031 #include <o2scl/mroot.h> 00032 #include <o2scl/jacobian.h> 00033 #include <o2scl/qr.h> 00034 00035 #ifndef DOXYGENP 00036 namespace o2scl { 00037 #endif 00038 00039 /** \brief State class for \ref gsl_mroot_hybrids 00040 00041 \todo Improve the documentation in this class 00042 */ 00043 template<class vec_t=ovector_view, class alloc_vec_t=ovector, 00044 class alloc_t=ovector_alloc, class mat_t=omatrix_view, 00045 class alloc_mat_t=omatrix, class mat_alloc_t=omatrix_alloc> 00046 class o2scl_hybrid_state_t { 00047 00048 public: 00049 00050 o2scl_hybrid_state_t() { 00051 dim2=0; 00052 } 00053 00054 /// Allocate memory for a solver with \c n variables 00055 int allocate(size_t n) { 00056 00057 ma.allocate(J,n,n); 00058 00059 q=gsl_matrix_calloc(n, n); 00060 if (q==0) { 00061 ma.free(J,n); 00062 O2SCL_ERR2_RET("Failed to allocate space for q", 00063 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00064 } 00065 00066 r=gsl_matrix_calloc(n, n); 00067 if (r==0) { 00068 ma.free(J,n); 00069 gsl_matrix_free(q); 00070 O2SCL_ERR2_RET("Failed to allocate space for r", 00071 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00072 } 00073 00074 tau=gsl_vector_calloc(n); 00075 if (tau==0) { 00076 ma.free(J,n); 00077 gsl_matrix_free(q); 00078 gsl_matrix_free(r); 00079 O2SCL_ERR2_RET("Failed to allocate space for tau", 00080 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00081 } 00082 00083 diag=gsl_vector_calloc(n); 00084 if (diag==0) { 00085 ma.free(J,n); 00086 gsl_matrix_free(q); 00087 gsl_matrix_free(r); 00088 gsl_vector_free(tau); 00089 O2SCL_ERR2_RET("Failed to allocate space for diag", 00090 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00091 } 00092 00093 qtf=gsl_vector_calloc(n); 00094 if (qtf==0) { 00095 ma.free(J,n); 00096 gsl_matrix_free(q); 00097 gsl_matrix_free(r); 00098 gsl_vector_free(tau); 00099 gsl_vector_free(diag); 00100 O2SCL_ERR2_RET("Failed to allocate space for qtf", 00101 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00102 } 00103 00104 newton=gsl_vector_calloc(n); 00105 if (newton==0) { 00106 ma.free(J,n); 00107 gsl_matrix_free(q); 00108 gsl_matrix_free(r); 00109 gsl_vector_free(tau); 00110 gsl_vector_free(diag); 00111 gsl_vector_free(qtf); 00112 O2SCL_ERR2_RET("Failed to allocate space for newton", 00113 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00114 } 00115 00116 gradient=gsl_vector_calloc(n); 00117 if (gradient==0) { 00118 ma.free(J,n); 00119 gsl_matrix_free(q); 00120 gsl_matrix_free(r); 00121 gsl_vector_free(tau); 00122 gsl_vector_free(diag); 00123 gsl_vector_free(qtf); 00124 gsl_vector_free(newton); 00125 O2SCL_ERR2_RET("Failed to allocate space for gradient", 00126 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00127 } 00128 00129 df=gsl_vector_calloc(n); 00130 if (df==0) { 00131 ma.free(J,n); 00132 gsl_matrix_free(q); 00133 gsl_matrix_free(r); 00134 gsl_vector_free(tau); 00135 gsl_vector_free(diag); 00136 gsl_vector_free(qtf); 00137 gsl_vector_free(newton); 00138 gsl_vector_free(gradient); 00139 O2SCL_ERR2_RET("Failed to allocate space for df", 00140 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00141 } 00142 00143 qtdf=gsl_vector_calloc(n); 00144 if (qtdf==0) { 00145 ma.free(J,n); 00146 gsl_matrix_free(q); 00147 gsl_matrix_free(r); 00148 gsl_vector_free(tau); 00149 gsl_vector_free(diag); 00150 gsl_vector_free(qtf); 00151 gsl_vector_free(newton); 00152 gsl_vector_free(gradient); 00153 gsl_vector_free(df); 00154 O2SCL_ERR2_RET("Failed to allocate space for qtdf", 00155 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00156 } 00157 00158 rdx=gsl_vector_calloc(n); 00159 if (rdx==0) { 00160 ma.free(J,n); 00161 gsl_matrix_free(q); 00162 gsl_matrix_free(r); 00163 gsl_vector_free(tau); 00164 gsl_vector_free(diag); 00165 gsl_vector_free(qtf); 00166 gsl_vector_free(newton); 00167 gsl_vector_free(gradient); 00168 gsl_vector_free(df); 00169 gsl_vector_free(qtdf); 00170 O2SCL_ERR2_RET("Failed to allocate space for rdx", 00171 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00172 } 00173 00174 w=gsl_vector_calloc(n); 00175 if (w==0) { 00176 ma.free(J,n); 00177 gsl_matrix_free(q); 00178 gsl_matrix_free(r); 00179 gsl_vector_free(tau); 00180 gsl_vector_free(diag); 00181 gsl_vector_free(qtf); 00182 gsl_vector_free(newton); 00183 gsl_vector_free(gradient); 00184 gsl_vector_free(df); 00185 gsl_vector_free(qtdf); 00186 gsl_vector_free(rdx); 00187 O2SCL_ERR2_RET("Failed to allocate space for w", 00188 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00189 } 00190 00191 v=gsl_vector_calloc(n); 00192 if (v==0) { 00193 ma.free(J,n); 00194 gsl_matrix_free(q); 00195 gsl_matrix_free(r); 00196 gsl_vector_free(tau); 00197 gsl_vector_free(diag); 00198 gsl_vector_free(qtf); 00199 gsl_vector_free(newton); 00200 gsl_vector_free(gradient); 00201 gsl_vector_free(df); 00202 gsl_vector_free(qtdf); 00203 gsl_vector_free(rdx); 00204 gsl_vector_free(w); 00205 O2SCL_ERR2_RET("Failed to allocate space for v", 00206 " in o2scl_hybrid_state_t::allocate().",gsl_enomem); 00207 } 00208 00209 dim2=n; 00210 return GSL_SUCCESS; 00211 } 00212 00213 /// Free allocated memory 00214 int free() { 00215 if (dim2>0) { 00216 gsl_vector_free(v); 00217 gsl_vector_free(w); 00218 gsl_vector_free(rdx); 00219 gsl_vector_free(qtdf); 00220 gsl_vector_free(df); 00221 gsl_vector_free(gradient); 00222 gsl_vector_free(newton); 00223 gsl_vector_free(qtf); 00224 gsl_vector_free(diag); 00225 gsl_vector_free(tau); 00226 gsl_matrix_free(r); 00227 gsl_matrix_free(q); 00228 ma.free(J,dim2); 00229 } 00230 return 0; 00231 } 00232 00233 /// Vector allocator 00234 alloc_t va; 00235 /// Matrix allocator 00236 mat_alloc_t ma; 00237 /// Number of iterations 00238 size_t iter; 00239 /// Desc 00240 size_t ncfail; 00241 /// Desc 00242 size_t ncsuc; 00243 /// Desc 00244 size_t nslow1; 00245 /// Desc 00246 size_t nslow2; 00247 /// Desc 00248 double fnorm; 00249 /// Desc 00250 double delta; 00251 /// Jacobian 00252 alloc_mat_t J; 00253 /// Q matrix from QR decomposition 00254 gsl_matrix *q; 00255 /// R matrix from QR decomposition 00256 gsl_matrix *r; 00257 /// tau vector from QR decomposition 00258 gsl_vector *tau; 00259 /// Desc 00260 gsl_vector *diag; 00261 /// Desc 00262 gsl_vector *qtf; 00263 /// Desc 00264 gsl_vector *newton; 00265 /// Desc 00266 gsl_vector *gradient; 00267 /// Desc 00268 gsl_vector *df; 00269 /// Desc 00270 gsl_vector *qtdf; 00271 /// Desc 00272 gsl_vector *rdx; 00273 /// Desc 00274 gsl_vector *w; 00275 /// Desc 00276 gsl_vector *v; 00277 /// Number of variables 00278 size_t dim2; 00279 //@} 00280 }; 00281 00282 /** 00283 \brief Multidimensional root-finding algorithm using 00284 Powell's Hybrid method (GSL) 00285 00286 This is a recasted version of the GSL routines which use a 00287 modified version of Powell's Hybrid method as implemented in the 00288 HYBRJ algorithm in MINPACK. Both the scaled and unscaled options 00289 are available by setting \ref int_scaling (the scaled version is 00290 the default). If derivatives are not provided, they will be 00291 computed automatically. This class provides the GSL-like 00292 interface using allocate(), set() (or set_de() in case where 00293 derivatives are available), iterate(), and free() and 00294 higher-level interfaces, msolve() and msolve_de(), which perform 00295 the solution and the memory allocation automatically. Some 00296 additional checking is performed in case the user calls the 00297 functions out of order (i.e. set() without allocate()). 00298 00299 The functions msolve() and msolve_de() use the condition \f$ 00300 \sum_i |f_i| < \f$ \ref mroot::tolf to determine if the solver has 00301 succeeded. 00302 00303 The original GSL algorithm has been modified to shrink the 00304 stepsize if a proposed step causes the function to return a 00305 non-zero value. This allows the routine to automatically try to 00306 avoid regions where the function is not defined. To return to 00307 the default GSL behavior, set \ref shrink_step to false. 00308 00309 The default method for numerically computing the Jacobian 00310 is from \ref simple_jacobian. This default is identical 00311 to the GSL approach, except that the default 00312 value of \ref simple_jacobian::epsmin is non-zero. See 00313 \ref simple_jacobian for more details. 00314 00315 There is an example for the usage of the multidimensional solver 00316 classes given in <tt>examples/ex_mroot.cpp</tt>, see \ref 00317 ex_mroot_sect . 00318 00319 */ 00320 template<class param_t, class func_t=mm_funct<param_t>, 00321 class vec_t=ovector_view, class alloc_vec_t=ovector, 00322 class alloc_t=ovector_alloc, class mat_t=omatrix_view, 00323 class alloc_mat_t=omatrix, class mat_alloc_t=omatrix_alloc, 00324 class jfunc_t=jac_funct<param_t,vec_t,mat_t> > 00325 class gsl_mroot_hybrids : 00326 public mroot<param_t,func_t,vec_t,jfunc_t>, public hybrids_base { 00327 00328 #ifndef DOXYGEN_INTERNAL 00329 00330 protected: 00331 00332 /// Desc 00333 void compute_Rg(size_t N, const gsl_matrix * r, 00334 const gsl_vector * gradient, vec_t &Rg) { 00335 size_t i, j; 00336 00337 for (i = 0; i < N; i++) { 00338 double sum = 0; 00339 00340 for (j = i; j < N; j++) { 00341 double gj = gsl_vector_get (gradient, j); 00342 double rij = gsl_matrix_get (r, i, j); 00343 sum += rij * gj; 00344 } 00345 00346 Rg[i]=sum; 00347 } 00348 } 00349 00350 /// Desc 00351 void compute_wv(size_t n, const gsl_vector * qtdf, 00352 const gsl_vector *rdx, const vec_t &dxx, 00353 const gsl_vector *diag, double pnorm, 00354 gsl_vector * w, gsl_vector * v) { 00355 00356 size_t i; 00357 00358 for (i = 0; i < n; i++) { 00359 00360 double qtdfi = gsl_vector_get (qtdf, i); 00361 double rdxi = gsl_vector_get (rdx, i); 00362 double dxi = dxx[i]; 00363 double diagi = gsl_vector_get (diag, i); 00364 00365 gsl_vector_set (w, i, (qtdfi - rdxi) / pnorm); 00366 gsl_vector_set (v, i, diagi * diagi * dxi / pnorm); 00367 } 00368 } 00369 00370 /// Desc 00371 void compute_rdx(size_t N, const gsl_matrix * r, 00372 const vec_t &dxx, gsl_vector * rdx) { 00373 size_t i, j; 00374 00375 for (i = 0; i < N; i++) { 00376 double sum = 0; 00377 for (j = i; j < N; j++) { 00378 sum += gsl_matrix_get (r, i, j) * dxx[j]; 00379 } 00380 gsl_vector_set (rdx, i, sum); 00381 } 00382 } 00383 00384 /// Desc 00385 double scaled_enorm_tvec(size_t n, const gsl_vector * d, const vec_t &ff) { 00386 double e2 = 0; 00387 size_t i; 00388 for (i = 0; i < n ; i++) { 00389 double fi=ff[i]; 00390 double di= gsl_vector_get(d, i); 00391 double u = di * fi; 00392 e2 += u * u ; 00393 } 00394 return sqrt(e2); 00395 } 00396 00397 /// Desc 00398 double compute_delta(size_t n, gsl_vector * diag, vec_t &xx) { 00399 double Dx = scaled_enorm_tvec(n,diag,xx); 00400 double factor = 100; 00401 00402 return (Dx > 0) ? factor * Dx : factor; 00403 } 00404 00405 /// Desc 00406 double enorm_tvec(const vec_t &ff) { 00407 double e2 = 0; 00408 size_t i; 00409 for (i = 0; i < dim ; i++) { 00410 double fi= ff[i]; 00411 e2 += fi * fi; 00412 } 00413 return sqrt(e2); 00414 } 00415 00416 /// Desc 00417 int compute_trial_step_tvec(size_t N, vec_t &xl, vec_t &dxl, 00418 vec_t &xx_trial) { 00419 size_t i; 00420 00421 for (i = 0; i < N; i++) { 00422 xx_trial[i]=xl[i]+dxl[i]; 00423 } 00424 return 0; 00425 } 00426 00427 /// Desc 00428 int compute_df_tvec(size_t n, const vec_t &ff_trial, 00429 const vec_t &fl, gsl_vector * dfl) { 00430 size_t i; 00431 00432 for (i = 0; i < n; i++) { 00433 double dfi=ff_trial[i]-fl[i]; 00434 gsl_vector_set(dfl,i,dfi); 00435 } 00436 00437 return 0; 00438 } 00439 00440 /// Desc 00441 void compute_diag_tvec(size_t n, const mat_t &J, gsl_vector *diag) { 00442 size_t i, j; 00443 00444 for (j = 0; j < n; j++) { 00445 double sum = 0; 00446 for (i = 0; i < n; i++) { 00447 double Jij = J[i][j]; 00448 sum += Jij * Jij; 00449 } 00450 if (sum == 0) { 00451 sum = 1.0; 00452 } 00453 00454 gsl_vector_set(diag,j,sqrt(sum)); 00455 } 00456 } 00457 00458 /// Desc 00459 void compute_qtf_tvec(size_t N, const gsl_matrix * q, const vec_t &ff, 00460 gsl_vector * qtf) { 00461 size_t i, j; 00462 00463 for (j = 0; j < N; j++) { 00464 double sum = 0; 00465 for (i = 0; i < N; i++) { 00466 sum += gsl_matrix_get (q, i, j)*ff[i]; 00467 } 00468 00469 gsl_vector_set (qtf, j, sum); 00470 } 00471 } 00472 00473 /// Desc 00474 void update_diag_tvec(size_t n, const mat_t &J, gsl_vector * diag) { 00475 size_t i, j; 00476 00477 for (j = 0; j < n; j++) { 00478 double cnorm, diagj, sum = 0; 00479 for (i = 0; i < n; i++) { 00480 double Jij = J[i][j]; 00481 sum += Jij * Jij; 00482 } 00483 if (sum == 0) { 00484 sum = 1.0; 00485 } 00486 00487 cnorm = sqrt (sum); 00488 diagj = gsl_vector_get (diag, j); 00489 00490 if (cnorm > diagj) { 00491 gsl_vector_set (diag, j, cnorm); 00492 } 00493 } 00494 } 00495 00496 /// Desc 00497 void scaled_addition_tvec(size_t N, double alpha, gsl_vector *newton, 00498 double beta, gsl_vector *gradient, vec_t &pp) { 00499 size_t i; 00500 00501 for (i = 0; i < N; i++) { 00502 double ni = gsl_vector_get (newton, i); 00503 double gi = gsl_vector_get (gradient, i); 00504 pp[i]=alpha*ni + beta*gi; 00505 } 00506 } 00507 00508 /// Take a dogleg step 00509 int dogleg(size_t n, const gsl_matrix *r, const gsl_vector *qtf, 00510 const gsl_vector *diag, double delta, 00511 gsl_vector *newton, gsl_vector *gradient, 00512 vec_t &p) { 00513 00514 double qnorm, gnorm, sgnorm, bnorm, temp; 00515 00516 newton_direction(r, qtf, newton); 00517 00518 qnorm = scaled_enorm (diag, newton); 00519 00520 if (qnorm <= delta) { 00521 for(size_t i=0;i<n;i++) p[i]=gsl_vector_get(newton,i); 00522 return GSL_SUCCESS; 00523 } 00524 00525 gradient_direction (r, qtf, diag, gradient); 00526 00527 gnorm = enorm (gradient); 00528 00529 if (gnorm == 0) { 00530 double alpha = delta / qnorm; 00531 double beta = 0; 00532 scaled_addition_tvec(n,alpha, newton, beta, gradient, p); 00533 return GSL_SUCCESS; 00534 } 00535 00536 minimum_step (gnorm, diag, gradient); 00537 00538 /* Use p as temporary space to compute Rg */ 00539 compute_Rg(n,r, gradient, p); 00540 00541 temp = enorm_tvec(p); 00542 sgnorm = (gnorm / temp) / temp; 00543 00544 if (sgnorm > delta) { 00545 double alpha = 0; 00546 double beta = delta; 00547 scaled_addition_tvec(n,alpha, newton, beta, gradient, p); 00548 return GSL_SUCCESS; 00549 } 00550 00551 bnorm = enorm (qtf); 00552 00553 double bg = bnorm / gnorm; 00554 double bq = bnorm / qnorm; 00555 double dq = delta / qnorm; 00556 double dq2 = dq * dq; 00557 double sd = sgnorm / delta; 00558 double sd2 = sd * sd; 00559 00560 double t1 = bg * bq * sd; 00561 double u = t1 - dq; 00562 double t2 = t1 - dq * sd2 + sqrt (u * u + (1-dq2) * (1 - sd2)); 00563 00564 double alpha = dq * (1 - sd2) / t2; 00565 double beta = (1 - alpha) * sgnorm; 00566 00567 scaled_addition_tvec(n,alpha, newton, beta, gradient, p); 00568 00569 return GSL_SUCCESS; 00570 } 00571 00572 /// Pointer to the user-specified Jacobian object 00573 jfunc_t *jac; 00574 00575 /// Pointer to the automatic Jacobian object 00576 jacobian<param_t,func_t,vec_t,mat_t> *ajac; 00577 00578 /// Memory allocator for objects of type \c alloc_vec_t 00579 alloc_t ao; 00580 00581 /// The value of the derivative 00582 alloc_vec_t dx; 00583 00584 /// Trial root 00585 alloc_vec_t x_trial; 00586 00587 /// Trial function value 00588 alloc_vec_t f_trial; 00589 00590 /// The solver state 00591 o2scl_hybrid_state_t<vec_t,alloc_vec_t,alloc_t, 00592 mat_t,alloc_mat_t,mat_alloc_t> state; 00593 00594 /// The function parameters 00595 param_t *params; 00596 00597 /// The number of equations and unknowns 00598 size_t dim; 00599 00600 /// True if the jacobian has been given 00601 bool jac_given; 00602 00603 /// Pointer to the user-specified function 00604 func_t *fnewp; 00605 00606 /// True if "set" has been called 00607 bool set_called; 00608 00609 /// Finish the solution after set() or set_de() has been called 00610 int solve_set(size_t nn, vec_t &xx, param_t &pa, func_t &ufunc) { 00611 int iter=0, status; 00612 00613 do { 00614 iter++; 00615 00616 status=iterate(); 00617 if (status) break; 00618 00619 // ------------------------------------------------------ 00620 // The effective equivalent of the statement: 00621 // 00622 // status=gsl_multiroot_test_residual(f,this->tolf); 00623 00624 double resid=0.0; 00625 for(size_t i=0;i<nn;i++) { 00626 resid+=fabs(f[i]); 00627 } 00628 if (resid<this->tolf) status=gsl_success; 00629 else status=gsl_continue; 00630 00631 // ------------------------------------------------------ 00632 00633 if (this->verbose>0) { 00634 this->print_iter(nn,x,f,iter,resid,this->tolf, 00635 "gsl_mroot_hybrids"); 00636 } 00637 00638 } while (status==GSL_CONTINUE && iter < this->ntrial); 00639 00640 for(size_t i=0;i<nn;i++) { 00641 xx[i]=x[i]; 00642 } 00643 00644 this->last_ntrial=iter; 00645 00646 if (iter>=this->ntrial) { 00647 if (this->last_conv==0) this->last_conv=gsl_emaxiter; 00648 O2SCL_CONV2_RET("Function gsl_mroot_hybrids::msolve() ", 00649 "exceeded max. number of iterations.", 00650 gsl_emaxiter,this->err_nonconv); 00651 } 00652 00653 if (status!=0) { 00654 O2SCL_ADD_ERR_RET("Function iterate() failed in msolve().", 00655 gsl_efailed); 00656 } 00657 00658 return gsl_success; 00659 } 00660 00661 #endif 00662 00663 public: 00664 00665 gsl_mroot_hybrids() { 00666 shrink_step=true; 00667 dim=0; 00668 ajac=&def_jac; 00669 def_jac.epsrel=GSL_SQRT_DBL_EPSILON; 00670 int_scaling=true; 00671 jac_given=false; 00672 set_called=false; 00673 } 00674 00675 virtual ~gsl_mroot_hybrids() {} 00676 00677 /** \brief If true, iterate() will shrink the step-size automatically if 00678 the function returns a non-zero value (default true) 00679 00680 The original GSL behavior can be obtained by setting 00681 this to \c false. 00682 */ 00683 bool shrink_step; 00684 00685 /// If true, use the internal scaling method (default true) 00686 bool int_scaling; 00687 00688 /// Default automatic Jacobian object 00689 simple_jacobian<param_t,func_t,vec_t,mat_t, 00690 alloc_vec_t,alloc_t> def_jac; 00691 00692 /// Set the automatic Jacobian object 00693 virtual int set_jacobian(jacobian<param_t,func_t,vec_t,mat_t> &j) { 00694 ajac=&j; 00695 return 0; 00696 } 00697 00698 /** 00699 \brief The value of the function at the present iteration 00700 00701 \comment 00702 We need this to be public so that the user can see if 00703 iterate() is working 00704 \endcomment 00705 00706 */ 00707 alloc_vec_t f; 00708 00709 /// The present solution 00710 alloc_vec_t x; 00711 00712 /** 00713 \brief Perform an iteration 00714 00715 At the end of the iteration, the current value of the solution 00716 is stored in \ref x. 00717 */ 00718 int iterate() { 00719 00720 if (!set_called) { 00721 O2SCL_ERR2_RET("Function set() not called or most recent call ", 00722 "failed in gsl_mroot_hybrids::iterate().", 00723 gsl_efailed); 00724 } 00725 00726 const double fnorm=state.fnorm; 00727 00728 this->last_conv=0; 00729 00730 gsl_matrix *q=state.q; 00731 gsl_matrix *r=state.r; 00732 gsl_vector *tau=state.tau; 00733 gsl_vector *diag=state.diag; 00734 gsl_vector *qtf=state.qtf; 00735 gsl_vector *df=state.df; 00736 gsl_vector *qtdf=state.qtdf; 00737 gsl_vector *rdx=state.rdx; 00738 gsl_vector *w=state.w; 00739 gsl_vector *v=state.v; 00740 00741 double prered,actred; 00742 double pnorm,fnorm1,fnorm1p; 00743 double ratio; 00744 double p1=0.1,p5=0.5,p001=0.001,p0001=0.0001; 00745 00746 /* Compute qtf=Q^T f */ 00747 00748 compute_qtf_tvec(dim,q,f,qtf); 00749 00750 /* Compute dogleg step */ 00751 00752 dogleg(dim,r,qtf,diag,state.delta,state.newton,state.gradient,dx); 00753 00754 /* Take a trial step */ 00755 00756 compute_trial_step_tvec(dim,x,dx,x_trial); 00757 pnorm=scaled_enorm_tvec(dim,diag,dx); 00758 if (state.iter==1) { 00759 if (pnorm < state.delta) { 00760 state.delta=pnorm; 00761 } 00762 } 00763 00764 /* Evaluate function at x + p */ 00765 00766 int status; 00767 00768 if (shrink_step==false) { 00769 00770 // Evaluate the function at the new point, exit if it fails 00771 00772 status=(*fnewp)(dim,x_trial,f_trial,*params); 00773 00774 if (status != gsl_success) { 00775 this->last_conv=gsl_ebadfunc; 00776 O2SCL_CONV_ADD_ERR_RET 00777 ("Returned non-zero value in gsl_mroot_hybrids::iterate().", 00778 o2scl::gsl_ebadfunc,this->err_nonconv); 00779 } 00780 00781 } else { 00782 00783 // Evaluate the function at the new point, try to recover 00784 // if it fails 00785 00786 status=(*fnewp)(dim,x_trial,f_trial,*params); 00787 00788 int bit=0; 00789 while(status!=0 && bit<20) { 00790 for(size_t ib=0;ib<dim;ib++) { 00791 x_trial[ib]=(x_trial[ib]+x[ib])/2.0; 00792 } 00793 status=(*fnewp)(dim,x_trial,f_trial,*params); 00794 bit++; 00795 } 00796 00797 // Exit if we weren't able to find a new good point 00798 00799 if (status != gsl_success) { 00800 this->last_conv=gsl_ebadfunc; 00801 O2SCL_CONV_ADD_ERR_RET 00802 ("No suitable step found in gsl_mroot_hybrids::iterate().", 00803 o2scl::gsl_ebadfunc,this->err_nonconv); 00804 } 00805 00806 } 00807 00808 /* Set df=f_trial-f */ 00809 00810 compute_df_tvec(dim,f_trial,f,df); 00811 00812 /* Compute the scaled actual reduction */ 00813 00814 fnorm1=enorm_tvec(f_trial); 00815 actred=compute_actual_reduction(fnorm,fnorm1); 00816 00817 /* Compute rdx=R dx */ 00818 00819 compute_rdx(dim,r,dx,rdx); 00820 00821 /* Compute the scaled predicted reduction phi1p=|Q^T f + R dx| */ 00822 00823 fnorm1p=enorm_sum(qtf,rdx); 00824 prered=compute_predicted_reduction(fnorm,fnorm1p); 00825 00826 /* Compute the ratio of the actual to predicted reduction */ 00827 00828 if (prered > 0) { 00829 ratio=actred / prered; 00830 } else { 00831 ratio=0; 00832 } 00833 00834 /* Update the step bound */ 00835 00836 if (ratio < p1) { 00837 state.ncsuc=0; 00838 state.ncfail++; 00839 state.delta *= p5; 00840 } else { 00841 state.ncfail=0; 00842 state.ncsuc++; 00843 00844 if (ratio >= p5 || state.ncsuc > 1) { 00845 state.delta=GSL_MAX (state.delta,pnorm / p5); 00846 } 00847 if (fabs (ratio - 1) <= p1) { 00848 state.delta=pnorm / p5; 00849 } 00850 } 00851 00852 /* Test for successful iteration */ 00853 00854 if (ratio >= p0001) { 00855 for(size_t i=0;i<dim;i++) { 00856 x[i]=x_trial[i]; 00857 f[i]=f_trial[i]; 00858 } 00859 state.fnorm=fnorm1; 00860 state.iter++; 00861 } 00862 00863 /* Determine the progress of the iteration */ 00864 00865 state.nslow1++; 00866 if (actred >= p001) { 00867 state.nslow1=0; 00868 } 00869 00870 if (actred >= p1) { 00871 state.nslow2=0; 00872 } 00873 00874 if (state.ncfail==2) { 00875 00876 int rx; 00877 00878 if (jac_given) rx=(*jac)(dim,x,f,state.J,*params); 00879 else rx=(*ajac)(dim,x,f,state.J,*params); 00880 00881 if (rx!=0) { 00882 this->last_conv=gsl_efailed; 00883 O2SCL_CONV_ADD_ERR_RET 00884 ("Jacobian failed in gsl_mroot_hybrids::iterate().", 00885 gsl_efailed,this->err_nonconv); 00886 } 00887 00888 state.nslow2++; 00889 00890 if (state.iter==1) { 00891 if (int_scaling) { 00892 compute_diag_tvec(dim,state.J,diag); 00893 } 00894 state.delta=compute_delta(dim,diag,x); 00895 } else { 00896 if (int_scaling) { 00897 update_diag_tvec(dim,state.J,diag); 00898 } 00899 } 00900 00901 /* Factorize J into QR decomposition */ 00902 ovector *otau=(ovector *)tau; 00903 omatrix *oq=(omatrix *)q; 00904 omatrix *oor=(omatrix *)r; 00905 o2scl_linalg::QR_decomp(dim,dim,state.J,*otau); 00906 o2scl_linalg::QR_unpack(dim,dim,state.J,*otau,*oq,*oor); 00907 00908 return gsl_success; 00909 } 00910 00911 /* Compute qtdf=Q^T df,w=(Q^T df - R dx)/|dx|, v=D^2 dx/|dx| */ 00912 00913 compute_qtf(q,df,qtdf); 00914 compute_wv(dim,qtdf,rdx,dx,diag,pnorm,w,v); 00915 00916 /* Rank-1 update of the jacobian Q'R'=Q(R + w v^T) */ 00917 00918 gsl_linalg_QR_update(q,r,w,v); 00919 00920 /* No progress as measured by jacobian evaluations */ 00921 00922 if (state.nslow2==5) { 00923 this->last_conv=gsl_enoprogj; 00924 O2SCL_CONV_RET 00925 ("No progress in Jacobian in gsl_mroot_hybrids::iterate().", 00926 gsl_enoprogj,this->err_nonconv); 00927 } 00928 00929 /* No progress as measured by function evaluations */ 00930 00931 if (state.nslow1==10) { 00932 this->last_conv=gsl_enoprog; 00933 O2SCL_CONV_RET 00934 ("No progress in function in gsl_mroot_hybrids::iterate().", 00935 gsl_enoprog,this->err_nonconv); 00936 } 00937 00938 return gsl_success; 00939 } 00940 00941 /// Allocate the memory 00942 int allocate(size_t n) { 00943 int status; 00944 00945 if (dim>0) free(); 00946 00947 ao.allocate(x,n); 00948 ao.allocate(dx,n); 00949 ao.allocate(f,n); 00950 ao.allocate(x_trial,n); 00951 ao.allocate(f_trial,n); 00952 status=state.allocate(n); 00953 00954 for(size_t i=0;i<n;i++) { 00955 x[i]=0.0; 00956 dx[i]=0.0; 00957 f[i]=0.0; 00958 } 00959 00960 dim=n; 00961 00962 return o2scl::gsl_success; 00963 } 00964 00965 /// Free the allocated memory 00966 int free() { 00967 if (dim>0) { 00968 state.free(); 00969 ao.free(x_trial); 00970 ao.free(f_trial); 00971 ao.free(dx); 00972 ao.free(x); 00973 ao.free(f); 00974 dim=0; 00975 } 00976 return o2scl::gsl_success; 00977 } 00978 00979 /// Return the type,\c "gsl_mroot_hybrids". 00980 virtual const char *type() { return "gsl_mroot_hybrids"; } 00981 00982 /** \brief Solve \c func with derivatives \c dfunc using \c x as 00983 an initial guess, returning \c x. 00984 00985 */ 00986 virtual int msolve_de(size_t nn, vec_t &xx, param_t &pa, func_t &ufunc, 00987 jfunc_t &dfunc) { 00988 int status; 00989 00990 status=set_de(nn,xx,ufunc,dfunc,pa); 00991 if (status!=0) { 00992 O2SCL_ADD_ERR_RET("Function set() failed in msolve().",gsl_efailed); 00993 } 00994 00995 return solve_set(nn,xx,pa,ufunc); 00996 } 00997 00998 /// Solve \c ufunc using \c xx as an initial guess, returning \c xx. 00999 virtual int msolve(size_t nn, vec_t &xx, param_t &pa, func_t &ufunc) { 01000 01001 int status; 01002 01003 status=set(nn,xx,ufunc,pa); 01004 if (status!=0) { 01005 O2SCL_ADD_ERR_RET("Function set() failed in msolve().",gsl_efailed); 01006 } 01007 01008 status=solve_set(nn,xx,pa,ufunc); 01009 for(size_t i=0;i<nn;i++) xx[i]=x[i]; 01010 01011 return status; 01012 } 01013 01014 /** \brief Set the function, the parameters, and the initial guess 01015 */ 01016 int set(size_t nn, vec_t &ax, func_t &ufunc, param_t &pa) { 01017 01018 int status; 01019 01020 if (nn!=dim) { 01021 status=allocate(nn); 01022 if (status!=0) { 01023 O2SCL_ADD_ERR_RET("Function allocate() failed in msolve().", 01024 gsl_efailed); 01025 } 01026 } 01027 01028 fnewp=&ufunc; 01029 01030 // Specify function for automatic Jacobian 01031 ajac->set_function(ufunc); 01032 01033 if (dim==0) { 01034 O2SCL_ERR_RET("Memory has not been allocated. Use allocate().", 01035 o2scl::gsl_ebadlen); 01036 } 01037 01038 params=&pa; 01039 01040 // Copy the user-specified solution 01041 for(size_t i=0;i<dim;i++) x[i]=ax[i]; 01042 01043 gsl_matrix *q=state.q; 01044 gsl_matrix *r=state.r; 01045 gsl_vector *tau=state.tau; 01046 gsl_vector *diag=state.diag; 01047 01048 status=ufunc(dim,ax,f,*params); 01049 if (status!=0) { 01050 O2SCL_ADD_ERR_RET("Function returned non-zero in set().", 01051 gsl_ebadfunc); 01052 } 01053 01054 if (jac_given) status=(*jac)(dim,ax,f,state.J,*params); 01055 else status=(*ajac)(dim,ax,f,state.J,*params); 01056 01057 if (status!=0) { 01058 O2SCL_ADD_ERR_RET("Jacobian failed in set().",gsl_efailed); 01059 } 01060 01061 state.iter=1; 01062 state.fnorm=enorm_tvec(f); 01063 state.ncfail=0; 01064 state.ncsuc=0; 01065 state.nslow1=0; 01066 state.nslow2=0; 01067 01068 for(size_t i=0;i<dim;i++) dx[i]=0.0; 01069 01070 /* Store column norms in diag */ 01071 01072 if (int_scaling) { 01073 compute_diag_tvec(dim,state.J,diag); 01074 } else { 01075 gsl_vector_set_all(diag,1.0); 01076 } 01077 01078 /* Set delta to factor |D x| or to factor if |D x| is zero */ 01079 01080 state.delta=compute_delta(dim,diag,x); 01081 01082 /* Factorize J into QR decomposition */ 01083 01084 ovector *otau=(ovector *)tau; 01085 omatrix *oq=(omatrix *)q; 01086 omatrix *oor=(omatrix *)r; 01087 01088 status=o2scl_linalg::QR_decomp(dim,dim,state.J,*otau); 01089 if (status!=0) { 01090 O2SCL_ADD_ERR_RET("QR decomposition failed in set().",gsl_efailed); 01091 } 01092 01093 status=o2scl_linalg::QR_unpack(dim,dim,state.J,*otau,*oq,*oor); 01094 if (status!=0) { 01095 O2SCL_ADD_ERR_RET("QR unpacking failed in set().",gsl_efailed); 01096 } 01097 01098 set_called=true; 01099 jac_given=false; 01100 01101 return gsl_success; 01102 } 01103 01104 /** \brief Set the function, the Jacobian, the parameters, 01105 and the initial guess 01106 */ 01107 int set_de(size_t nn, vec_t &ax, func_t &ufunc, jfunc_t &dfunc, 01108 param_t &pa) { 01109 01110 fnewp=&ufunc; 01111 jac=&dfunc; 01112 01113 // Make sure set() uses the right Jacobian 01114 jac_given=true; 01115 01116 int ret=set(nn,ax,ufunc,pa); 01117 01118 // Reset jac_given since set() will set it back to false 01119 jac_given=true; 01120 set_called=true; 01121 01122 return ret; 01123 } 01124 01125 }; 01126 01127 #ifndef DOXYGENP 01128 } 01129 #endif 01130 01131 #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