Object-oriented Scientific Computing Library: Version 0.910
cern_mroot_root.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, 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_CERN_MROOT_ROOT_H
00024 #define O2SCL_CERN_MROOT_ROOT_H
00025 
00026 #include <string>
00027 
00028 #include <o2scl/root.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033 
00034   /** \brief One-dimensional version of cern_mroot
00035       
00036       This one-dimensional root-finding routine, based on cern_mroot,
00037       is probably slower than the more typical 1-d routines, but also
00038       tends to converge for a larger class of functions than
00039       cern_root, gsl_root_brent, or gsl_root_stef. It has been
00040       modified from cern_mroot and slightly optimized, but has the
00041       same basic behavior.
00042 
00043       If \f$ x_i \f$ denotes the current iteration, and \f$
00044       x^{\prime}_i \f$ denotes the previous iteration, then the
00045       calculation is terminated if either (or both) of the following
00046       tests is successful
00047       \f[
00048       1:\quad \mathrm{max} | f_i(x) | \leq \mathrm{tol\_rel}
00049       \f]
00050       \f[
00051       2:\quad \mathrm{max} |x_i-x^{\prime}_i| \leq
00052       \mathrm{tol\_abs} \times \mathrm{max} | x_i |
00053       \f]
00054       
00055       \note This code has not been checked to ensure that it cannot
00056       fail to solve the equations without calling the error handler
00057       and returning a non-zero value. Until then, the solution may
00058       need to be checked explicitly by the caller.
00059 
00060       \future Double-check this class to make sure it cannot fail
00061       while returning 0 for success.
00062   */
00063 #ifdef DOXYGENP
00064   template<class func_t=funct> class cern_mroot_root : public root
00065 #else
00066     template<class func_t=funct> class cern_mroot_root : 
00067   public root<func_t> 
00068 #endif
00069   {
00070     
00071     public:
00072     
00073     cern_mroot_root() {
00074       info=0;
00075       eps=0.1490116119384766e-07;
00076       scale=10.0;
00077       maxf=0;
00078     }
00079 
00080     virtual ~cern_mroot_root() {}
00081     
00082     /** \brief Get the value of \c INFO from the last call to solve() 
00083         (default 0)
00084         
00085         The value of info is assigned according to the following list.
00086         The values 1-8 are the standard behavior from CERNLIB.
00087         0 - The function solve() has not been called.
00088         1 - Test 1 was successful. \n
00089         2 - Test 2 was successful. \n
00090         3 - Both tests were successful. \n
00091         4 - Number of iterations is greater than cern_mroot_root::maxf. \n
00092         5 - Approximate (finite difference) Jacobian matrix is
00093         singular. \n
00094         6 - Iterations are not making good progress. \n
00095         7 - Iterations are diverging. \n
00096         8 - Iterations are converging, but either cern_mroot_root::tol_abs
00097         is too small or the Jacobian is nearly singular
00098         or the variables are badly scaled. \n
00099         9 - Either root::tol_rel or root::tol_abs is not greater than zero.
00100 
00101     */
00102     int get_info() { return info; }
00103 
00104     /** \brief Maximum number of function evaluations
00105         
00106         If \f$ \mathrm{maxf}\leq 0 \f$, then 200 (which is the CERNLIB
00107         default) is used.  The default value of \c maxf is zero which
00108         then implies the default from CERNLIB.
00109     */
00110     int maxf;
00111 
00112     /// Return the type, \c "cern_mroot_root".
00113     virtual const char *type() { return "cern_mroot_root"; }
00114 
00115     /** \brief The original scale parameter from CERNLIB (default 10.0)
00116      */
00117     double scale;
00118     
00119     /** \brief The smallest floating point number
00120         (default \f$ \sim 1.49012 \times 10^{-8} \f$)
00121 
00122         The original prescription from CERNLIB for \c eps is
00123         given below:
00124         \verbatim
00125         #if !defined(CERNLIB_DOUBLE)
00126         PARAMETER (EPS =  0.84293 69702 17878 97282 52636 392E-07)
00127         #endif
00128         #if defined(CERNLIB_IBM)
00129         PARAMETER (EPS =  0.14901 16119 38476 562D-07)
00130         #endif
00131         #if defined(CERNLIB_VAX)
00132         PARAMETER (EPS =  0.37252 90298 46191 40625D-08)
00133         #endif
00134         #if (defined(CERNLIB_UNIX))&&(defined(CERNLIB_DOUBLE))
00135         PARAMETER (EPS =  0.14901 16119 38476 600D-07)
00136         #endif
00137         \endverbatim
00138 
00139         \future This number should probably default to one of the
00140         GSL tolerances.
00141     */
00142     double eps;
00143     
00144     /// Solve \c func using \c x as an initial guess, returning \c x.
00145     virtual int solve(double &ux, func_t &func) {
00146       
00147       int it=0;
00148       double fky;
00149 
00150       this->last_conv=0;
00151         
00152       int lmaxf;
00153       if (maxf<=0) lmaxf=200;
00154       else lmaxf=maxf;
00155       
00156       info=0;
00157   
00158       if (this->tol_rel<=0.0 || this->tol_abs<=0.0) {
00159         info=9;
00160         std::string str="Invalid value of tol_rel ("+dtos(this->tol_rel)+
00161           ") or tol_abs ("+dtos(this->tol_abs)+") in cern_mroot_root::solve().";
00162         O2SCL_ERR_RET(str.c_str(),gsl_einval);
00163       }
00164   
00165       int iflag=0, numf=0, nfcall=0, nier6=-1, nier7=-1, nier8=0;
00166       double fnorm=0.0, difit=0.0, xnorm=0.0;
00167       bool set=false;
00168         
00169       if (xnorm<fabs(ux)) {
00170         xnorm=fabs(ux);
00171         set=true;
00172       }
00173 
00174       double delta=scale*xnorm;
00175       if (set==false) delta=scale;
00176         
00177       double wmat, farr, w0arr, w1arr, w2arr;
00178         
00179       bool solve_done=false;
00180       while (solve_done==false) {
00181     
00182         int nsing=1;
00183         double fnorm1=fnorm;
00184         double difit1=difit;
00185         fnorm=0.0;
00186     
00187         // Compute step H for the divided difference which approximates
00188         // the K-th row of the Jacobian matrix
00189         
00190         double h=eps*xnorm;
00191         if (h==0.0) h=eps;
00192 
00193         wmat=h;
00194         w1arr=ux;
00195 
00196         // Enter a subiteration
00197     
00198         iflag=0;
00199 
00200         farr=func(w1arr);
00201 
00202         fky=farr;
00203         nfcall++;
00204         numf=nfcall;
00205         if (fnorm<fabs(fky)) fnorm=fabs(fky);
00206       
00207         // Compute the K-th row of the Jacobian matrix
00208 
00209         w2arr=w1arr+wmat;
00210             
00211         farr=func(w2arr);
00212             
00213         double fkz=farr;
00214         nfcall++;
00215         numf=nfcall;
00216         w0arr=fkz-fky;
00217             
00218         farr=fky;
00219       
00220         // Compute the Householder transformation to reduce the K-th row
00221         // of the Jacobian matrix to a multiple of the K-th unit vector
00222 
00223         double eta=0.0;
00224         if (eta<fabs(w0arr)) eta=fabs(w0arr);
00225         
00226         if (eta!=0.0) {
00227           nsing--;
00228           double sknorm=0.0;
00229               
00230           w0arr/=eta;
00231           sknorm+=w0arr*w0arr;
00232 
00233           sknorm=sqrt(sknorm);
00234           if (w0arr<0.0) sknorm=-sknorm;
00235           w0arr+=sknorm;
00236           
00237           // Apply the transformation
00238 
00239           w2arr=0.0;
00240           w2arr+=w0arr*wmat;
00241           double temp=w0arr/(sknorm*w0arr);
00242           wmat-=temp*w2arr;
00243 
00244           // Compute the subiterate
00245 
00246           w0arr=sknorm*eta;
00247           double temp2=fky/w0arr;
00248           if (h*fabs(temp2)>delta) 
00249             temp2=(temp2>=0.0) ? fabs(delta/h) : -fabs(delta/h);
00250           w1arr+=temp2*wmat;
00251         }
00252 
00253         // Compute the norms of the iterate and correction vector
00254 
00255         xnorm=0.0;
00256         difit=0.0;
00257           
00258         if (xnorm<fabs(w1arr)) xnorm=fabs(w1arr);
00259         if (difit<fabs(ux-w1arr)) difit=fabs(ux-w1arr);
00260         ux=w1arr;
00261           
00262         // Update the bound on the correction vector
00263 
00264         if(delta<scale*xnorm) delta=scale*xnorm;
00265     
00266         // Determine the progress of the iteration
00267 
00268         bool lcv=(fnorm<fnorm1 && difit<difit1 && nsing==0);
00269         nier6++;
00270         nier7++;
00271         nier8++;
00272         if (lcv) nier6=0;
00273         if (fnorm<fnorm1 || difit<difit1) nier7=0;
00274         if (difit>eps*xnorm) nier8=0;
00275 
00276         // Print iteration information
00277           
00278         if (this->verbose>0) print_iter(ux,farr,++it,fnorm,this->tol_rel,
00279                                         "cern_mroot_root");
00280         
00281         // Tests for convergence
00282 
00283         if (fnorm<=this->tol_rel) info=1;
00284         if (difit<=this->tol_abs*xnorm && lcv) info=2;
00285         if (fnorm<=this->tol_rel && info==2) info=3;
00286         if (info!=0) {
00287           return 0;
00288         }
00289 
00290         // Tests for termination
00291 
00292         if (numf>=lmaxf) {
00293           info=4;
00294           this->last_conv=gsl_emaxiter;
00295           O2SCL_CONV_RET("Too many iterations in cern_mroot_root::solve().",
00296                          gsl_emaxiter,this->err_nonconv);
00297         }
00298         if (nsing==1) {
00299           info=5;
00300           this->last_conv=gsl_esing;
00301           O2SCL_CONV2_RET("Jacobian matrix singular in ",
00302                           "cern_mroot_root::solve().",
00303                           gsl_esing,this->err_nonconv);
00304         }
00305         if (nier6==5) {
00306           info=6;
00307           this->last_conv=gsl_enoprog;
00308           O2SCL_CONV_RET("No progress in cern_mroot_root::solve().",
00309                          gsl_enoprog,this->err_nonconv);
00310         }
00311         if (nier7==3) {
00312           info=7;
00313           this->last_conv=gsl_erunaway;
00314           O2SCL_CONV_RET("Iterations diverging in cern_mroot_root::solve().",
00315                          gsl_erunaway,this->err_nonconv);
00316         }
00317         if (nier8==4) {
00318           info=8;
00319           this->last_conv=gsl_efailed;
00320           std::string s2="Variable tol_abs too small, J singular, ";
00321           s2+="or bad scaling in cerm_mroot_root::solve().";
00322           O2SCL_CONV(s2.c_str(),gsl_efailed,this->err_nonconv);
00323         }
00324         
00325         // Exit if necessary
00326 
00327         if (info!=0) return gsl_efailed;
00328           
00329       }
00330         
00331       return 0;
00332     }
00333       
00334 #ifndef DOXYGEN_INTERNAL
00335 
00336     protected:
00337       
00338     /// Internal storage for the value of \c info
00339     int info;
00340       
00341 #endif
00342       
00343   };
00344   
00345 #ifndef DOXYGENP
00346 }
00347 #endif
00348   
00349 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.