BrentMethods.cxx

Go to the documentation of this file.
00001 // @(#)root/mathcore:$Id: BrentMethods.cxx 36905 2010-11-24 15:44:34Z moneta $
00002 // Authors: David Gonzalez Maline    01/2008 
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006 , LCG ROOT MathLib Team                         *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 #include "Math/BrentMethods.h"
00012 #include "Math/IFunction.h"
00013 
00014 #include <cmath>
00015 #include <algorithm>
00016 
00017 #ifndef ROOT_Math_Error
00018 #include "Math/Error.h"
00019 #endif
00020 
00021 #include <iostream>
00022 
00023 namespace ROOT {
00024 namespace Math {
00025 
00026 namespace BrentMethods { 
00027 
00028    double MinimStep(const IGenFunction* function, int type, double &xmin, double &xmax, double fy, int npx,bool logStep)
00029 {
00030    //   Grid search implementation, used to bracket the minimum and later
00031    //   use Brent's method with the bracketed interval
00032    //   The step of the search is set to (xmax-xmin)/npx
00033    //   type: 0-returns MinimumX
00034    //         1-returns Minimum
00035    //         2-returns MaximumX
00036    //         3-returns Maximum
00037    //         4-returns X corresponding to fy
00038 
00039    if (logStep) { 
00040       xmin = std::log(xmin);
00041       xmax = std::log(xmax);
00042    }
00043 
00044 
00045    if (npx < 2) return 0.5*(xmax-xmin); // no bracketing - return just mid-point
00046    double dx = (xmax-xmin)/(npx-1);
00047    double xxmin = (logStep) ? std::exp(xmin) : xmin; 
00048    double yymin;
00049    if (type < 2)
00050       yymin = (*function)(xxmin);
00051    else if (type < 4)
00052       yymin = -(*function)(xxmin);
00053    else
00054       yymin = std::fabs((*function)(xxmin)-fy);
00055 
00056    for (int i=1; i<=npx-1; i++) {
00057       double x = xmin + i*dx;
00058       if (logStep) x = std::exp(x); 
00059       double y = 0;
00060       if (type < 2)
00061          y = (*function)(x);
00062       else if (type < 4)
00063          y = -(*function)(x);
00064       else
00065          y = std::fabs((*function)(x)-fy);
00066       if (y < yymin) {
00067          xxmin = x; 
00068          yymin = y;
00069       }
00070    }
00071 
00072    if (logStep) {
00073       xmin = std::exp(xmin); 
00074       xmax = std::exp(xmax); 
00075    }
00076 
00077 
00078    xmin = std::max(xmin,xxmin-dx);
00079    xmax = std::min(xmax,xxmin+dx);
00080 
00081    return std::min(xxmin, xmax);
00082 }
00083 
00084    double MinimBrent(const IGenFunction* function, int type, double &xmin, double &xmax, double xmiddle, double fy,  bool &ok, int &niter, double epsabs, double epsrel, int itermax)
00085 {
00086    //Finds a minimum of a function, if the function is unimodal  between xmin and xmax
00087    //This method uses a combination of golden section search and parabolic interpolation
00088    //Details about convergence and properties of this algorithm can be
00089    //found in the book by R.P.Brent "Algorithms for Minimization Without Derivatives"
00090    //or in the "Numerical Recipes", chapter 10.2
00091    // convergence is reached using  tolerance = 2 *( epsrel * abs(x) + epsabs)
00092    //
00093    //type: 0-returns MinimumX
00094    //      1-returns Minimum
00095    //      2-returns MaximumX
00096    //      3-returns Maximum
00097    //      4-returns X corresponding to fy
00098    //if ok=true the method has converged
00099 
00100    const double c = 3.81966011250105097e-01; //  (3.-std::sqrt(5.))/2.  (comes from golden section)
00101    double u, v, w, x, fv, fu, fw, fx, e, p, q, r, t2, d=0, m, tol;
00102    v = w = x = xmiddle;
00103    e=0;
00104 
00105    double a=xmin;
00106    double b=xmax;
00107    if (type < 2)
00108       fv = fw = fx = (*function)(x);
00109    else if (type < 4)
00110       fv = fw = fx = -(*function)(x);
00111    else
00112       fv = fw = fx = std::fabs((*function)(x)-fy);
00113 
00114    for (int i=0; i<itermax; i++){
00115       m=0.5*(a + b);
00116       tol = epsrel*(std::fabs(x))+epsabs;
00117       t2 = 2*tol;
00118 
00119       if (std::fabs(x-m) <= (t2-0.5*(b-a))) {
00120          //converged, return x
00121          ok=true;
00122          niter = i-1; 
00123          if (type==1)
00124             return fx;
00125          else if (type==3)
00126             return -fx;
00127          else
00128             return x;
00129       }
00130 
00131       if (std::fabs(e)>tol){
00132          //fit parabola
00133          r = (x-w)*(fx-fv);
00134          q = (x-v)*(fx-fw);
00135          p = (x-v)*q - (x-w)*r;
00136          q = 2*(q-r);
00137          if (q>0) p=-p;
00138          else q=-q;
00139          r=e;   // Deltax before last
00140          e=d;   // last delta x
00141          // current Deltax = p/q
00142          // take a parabolic  step only if: 
00143          // Deltax < 0.5* (DeltaX before last) && Deltax > a && Deltax < b
00144          // (a BUG in testing this condition is fixed 11/3/2010 (with revision  32544)
00145          if (std::fabs(p) >= std::fabs(0.5*q*r) || p <= q*(a-x) || p >= q*(b-x)) {
00146             //  condition fails - do not take parabolic step 
00147             e=(x>=m ? a-x : b-x);
00148             d = c*e;
00149          } else { 
00150             // take a parabolic interpolation step
00151             d = p/q;
00152             u = x+d;
00153             if (u-a < t2 || b-u < t2)
00154                //d=TMath::Sign(tol, m-x);
00155                d=(m-x >= 0) ? std::fabs(tol) : -std::fabs(tol);
00156          } 
00157       } else {
00158          e=(x>=m ? a-x : b-x);
00159          d = c*e;
00160       }
00161       u = (std::fabs(d)>=tol ? x+d : x+ ((d >= 0) ? std::fabs(tol) : -std::fabs(tol)) );
00162       if (type < 2)
00163          fu = (*function)(u);
00164       else if (type < 4)
00165          fu = -(*function)(u);
00166       else
00167          fu = std::fabs((*function)(u)-fy);
00168       //update a, b, v, w and x
00169       if (fu<=fx){
00170          if (u<x) b=x;
00171          else a=x;
00172          v=w; fv=fw; w=x; fw=fx; x=u; fx=fu;
00173       } else {
00174          if (u<x) a=u;
00175          else b=u;
00176          if (fu<=fw || w==x){
00177             v=w; fv=fw; w=u; fw=fu;
00178          }
00179          else if (fu<=fv || v==x || v==w){
00180             v=u; fv=fu;
00181          }
00182       }
00183    }
00184    //didn't converge
00185    ok = false;
00186    xmin = a;
00187    xmax = b;
00188    niter = itermax;
00189    return x;
00190 
00191 }
00192 
00193 } // end namespace BrentMethods
00194 } // end namespace Math
00195 } // ned namespace ROOT

Generated on Tue Jul 5 14:33:22 2011 for ROOT_528-00b_version by  doxygen 1.5.1