gsl_mroot_hybrids.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_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 SourceForge.net Logo, O2scl Sourceforge Project Page