ROOT logo
// @(#)root/tmva $Id: RootFinder.cxx 29195 2009-06-24 10:39:49Z brun $   
// Author: Andreas Hoecker, Joerg Stelzer, Helge Voss

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : RootFinder                                                            *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation (see header file for description)                          *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland              *
 *      Helge Voss      <Helge.Voss@cern.ch>     - MPI-K Heidelberg, Germany      *
 *      Kai Voss        <Kai.Voss@cern.ch>       - U. of Victoria, Canada         *
 *                                                                                *
 * Copyright (c) 2005:                                                            *
 *      CERN, Switzerland                                                         * 
 *      U. of Victoria, Canada                                                    * 
 *      MPI-K Heidelberg, Germany                                                 * 
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

#include "TMath.h"

#include "TMVA/RootFinder.h"
#include "TMVA/MsgLogger.h"

ClassImp(TMVA::RootFinder)

//_______________________________________________________________________
TMVA::RootFinder::RootFinder( Double_t (*rootVal)( Double_t ),
                              Double_t rootMin, 
                              Double_t rootMax,
                              Int_t maxIterations, 
                              Double_t absTolerance )
   : fRootMin( rootMin ),
     fRootMax( rootMax ),
     fMaxIter( maxIterations ),
     fAbsTol ( absTolerance  ),
     fLogger ( new MsgLogger("RootFinder") )
{
   // constructor
   fGetRootVal = rootVal;
}

//_______________________________________________________________________
TMVA::RootFinder::~RootFinder( void )
{
   // destructor
   delete fLogger;
}

//_______________________________________________________________________
Double_t TMVA::RootFinder::Root( Double_t refValue  )
{
   // Root finding using Brents algorithm; taken from CERNLIB function RZERO
   Double_t a  = fRootMin, b = fRootMax;
   Double_t fa = (*fGetRootVal)( a ) - refValue;
   Double_t fb = (*fGetRootVal)( b ) - refValue;
   if (fb*fa > 0) {
      Log() << kWARNING << "<Root> initial interval w/o root: "
              << "(a=" << a << ", b=" << b << "),"
              << " (Eff_a=" << (*fGetRootVal)( a ) 
              << ", Eff_b=" << (*fGetRootVal)( b ) << "), "
              << "(fa=" << fa << ", fb=" << fb << "), "
              << "refValue = " << refValue << Endl;
      return 1;
   }

   Bool_t   ac_equal(kFALSE);
   Double_t fc = fb;
   Double_t c  = 0, d = 0, e = 0;
   for (Int_t iter= 0; iter <= fMaxIter; iter++) {
      if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) {

         // Rename a,b,c and adjust bounding interval d
         ac_equal = kTRUE;
         c  = a; fc = fa;
         d  = b - a; e  = b - a;
      }
  
      if (TMath::Abs(fc) < TMath::Abs(fb)) {
         ac_equal = kTRUE;
         a  = b;  b  = c;  c  = a;
         fa = fb; fb = fc; fc = fa;
      }

      Double_t tol = 0.5 * 2.2204460492503131e-16 * TMath::Abs(b);
      Double_t m   = 0.5 * (c - b);
      if (fb == 0 || TMath::Abs(m) <= tol || TMath::Abs(fb) < fAbsTol) return b;
  
      // Bounds decreasing too slowly: use bisection
      if (TMath::Abs (e) < tol || TMath::Abs (fa) <= TMath::Abs (fb)) { d = m; e = m; }      
      else {
         // Attempt inverse cubic interpolation
         Double_t p, q, r;
         Double_t s = fb / fa;
      
         if (ac_equal) { p = 2 * m * s; q = 1 - s; }
         else {
            q = fa / fc; r = fb / fc;
            p = s * (2 * m * q * (q - r) - (b - a) * (r - 1));
            q = (q - 1) * (r - 1) * (s - 1);
         }
         // Check whether we are in bounds
         if (p > 0) q = -q;
         else       p = -p;
      
         Double_t min1 = 3 * m * q - TMath::Abs (tol * q);
         Double_t min2 = TMath::Abs (e * q);
         if (2 * p < (min1 < min2 ? min1 : min2)) {
            // Accept the interpolation
            e = d;        d = p / q;
         }
         else { d = m; e = m; } // Interpolation failed: use bisection.
      }
      // Move last best guess to a
      a  = b; fa = fb;
      // Evaluate new trial root
      if (TMath::Abs(d) > tol) b += d;
      else                     b += (m > 0 ? +tol : -tol);

      fb = (*fGetRootVal)( b ) - refValue;

   }

   // Return our best guess if we run out of iterations
   Log() << kWARNING << "<Root> maximum iterations (" << fMaxIter 
           << ") reached before convergence" << Endl;

   return b;
}

 RootFinder.cxx:1
 RootFinder.cxx:2
 RootFinder.cxx:3
 RootFinder.cxx:4
 RootFinder.cxx:5
 RootFinder.cxx:6
 RootFinder.cxx:7
 RootFinder.cxx:8
 RootFinder.cxx:9
 RootFinder.cxx:10
 RootFinder.cxx:11
 RootFinder.cxx:12
 RootFinder.cxx:13
 RootFinder.cxx:14
 RootFinder.cxx:15
 RootFinder.cxx:16
 RootFinder.cxx:17
 RootFinder.cxx:18
 RootFinder.cxx:19
 RootFinder.cxx:20
 RootFinder.cxx:21
 RootFinder.cxx:22
 RootFinder.cxx:23
 RootFinder.cxx:24
 RootFinder.cxx:25
 RootFinder.cxx:26
 RootFinder.cxx:27
 RootFinder.cxx:28
 RootFinder.cxx:29
 RootFinder.cxx:30
 RootFinder.cxx:31
 RootFinder.cxx:32
 RootFinder.cxx:33
 RootFinder.cxx:34
 RootFinder.cxx:35
 RootFinder.cxx:36
 RootFinder.cxx:37
 RootFinder.cxx:38
 RootFinder.cxx:39
 RootFinder.cxx:40
 RootFinder.cxx:41
 RootFinder.cxx:42
 RootFinder.cxx:43
 RootFinder.cxx:44
 RootFinder.cxx:45
 RootFinder.cxx:46
 RootFinder.cxx:47
 RootFinder.cxx:48
 RootFinder.cxx:49
 RootFinder.cxx:50
 RootFinder.cxx:51
 RootFinder.cxx:52
 RootFinder.cxx:53
 RootFinder.cxx:54
 RootFinder.cxx:55
 RootFinder.cxx:56
 RootFinder.cxx:57
 RootFinder.cxx:58
 RootFinder.cxx:59
 RootFinder.cxx:60
 RootFinder.cxx:61
 RootFinder.cxx:62
 RootFinder.cxx:63
 RootFinder.cxx:64
 RootFinder.cxx:65
 RootFinder.cxx:66
 RootFinder.cxx:67
 RootFinder.cxx:68
 RootFinder.cxx:69
 RootFinder.cxx:70
 RootFinder.cxx:71
 RootFinder.cxx:72
 RootFinder.cxx:73
 RootFinder.cxx:74
 RootFinder.cxx:75
 RootFinder.cxx:76
 RootFinder.cxx:77
 RootFinder.cxx:78
 RootFinder.cxx:79
 RootFinder.cxx:80
 RootFinder.cxx:81
 RootFinder.cxx:82
 RootFinder.cxx:83
 RootFinder.cxx:84
 RootFinder.cxx:85
 RootFinder.cxx:86
 RootFinder.cxx:87
 RootFinder.cxx:88
 RootFinder.cxx:89
 RootFinder.cxx:90
 RootFinder.cxx:91
 RootFinder.cxx:92
 RootFinder.cxx:93
 RootFinder.cxx:94
 RootFinder.cxx:95
 RootFinder.cxx:96
 RootFinder.cxx:97
 RootFinder.cxx:98
 RootFinder.cxx:99
 RootFinder.cxx:100
 RootFinder.cxx:101
 RootFinder.cxx:102
 RootFinder.cxx:103
 RootFinder.cxx:104
 RootFinder.cxx:105
 RootFinder.cxx:106
 RootFinder.cxx:107
 RootFinder.cxx:108
 RootFinder.cxx:109
 RootFinder.cxx:110
 RootFinder.cxx:111
 RootFinder.cxx:112
 RootFinder.cxx:113
 RootFinder.cxx:114
 RootFinder.cxx:115
 RootFinder.cxx:116
 RootFinder.cxx:117
 RootFinder.cxx:118
 RootFinder.cxx:119
 RootFinder.cxx:120
 RootFinder.cxx:121
 RootFinder.cxx:122
 RootFinder.cxx:123
 RootFinder.cxx:124
 RootFinder.cxx:125
 RootFinder.cxx:126
 RootFinder.cxx:127
 RootFinder.cxx:128
 RootFinder.cxx:129
 RootFinder.cxx:130
 RootFinder.cxx:131
 RootFinder.cxx:132
 RootFinder.cxx:133
 RootFinder.cxx:134
 RootFinder.cxx:135
 RootFinder.cxx:136
 RootFinder.cxx:137
 RootFinder.cxx:138