TFumiliFCN.cxx

Go to the documentation of this file.
00001 // @(#)root/minuit2:$Id: TFumiliFCN.cxx 29198 2009-06-24 13:05:43Z brun $
00002 // Author: L. Moneta    10/2005  
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2005 ROOT Foundation,  CERN/PH-SFT                   *
00007  *                                                                    *
00008  **********************************************************************/
00009 
00010 #include "TFumiliFCN.h"
00011 #include "TChi2FCN.h"
00012 #include "TBinLikelihoodFCN.h"
00013 #include "TChi2FitData.h"
00014 #include "FitterUtil.h"
00015 
00016 #include "TF1.h"
00017 #include "TVirtualFitter.h"
00018 
00019 
00020 //#define DEBUG
00021 
00022 #ifdef DEBUG
00023 #include <iostream>
00024 #endif
00025 
00026 #include <cmath>
00027 
00028 static const double kPrecision = 1.E-16; 
00029 static const double kEpsilon = 1.E-300; 
00030 
00031 
00032 
00033 
00034 TFumiliFCN::TFumiliFCN( const TVirtualFitter & fitter, double up, int strategy, bool skipEmptyBins) : 
00035 FumiliFCNBase()
00036 {
00037    // constructor for a class with a FumiliFCNBase interface.
00038    // Need to use default constructor for FumiliFCNBase (don't know number of parameters at this stage)
00039    // Create also FitData class. 
00040 
00041    fUp = up;
00042    fFunc = dynamic_cast<TF1 *> ( fitter.GetUserFunc() );
00043    assert(fFunc != 0);
00044    // default skip empty bins
00045    fData = new TChi2FitData(fitter, skipEmptyBins); 
00046    //std::cout << "Created FitData with size = " << fData->Size() << std::endl;
00047    
00048    // need to set the size so ROOT can calculate ndf.
00049    fFunc->SetNumberFitPoints(fData->Size());
00050    
00051    fStrategy = strategy; 
00052    
00053    //std::cout << "created FumiliFCN  with dimension " << dimension() << std::endl;
00054 }
00055 
00056 
00057 TFumiliFCN::~TFumiliFCN() {  
00058    //  this class manages the fit data class. Delete it at the end
00059 
00060    if (fData) { 
00061       //std::cout << "deleting the data - size is " << fData->Size() << std::endl; 
00062       delete fData; 
00063    }
00064 }
00065 
00066 
00067 void TFumiliFCN::Initialize(unsigned int nPar) { 
00068    // need an initialize method with number of fit parameters to make space for cached 
00069    // quantities (gradient , etc..)
00070 
00071    fParamCache = std::vector<double>(nPar);
00072    fFunctionGradient = std::vector<double>( nPar );
00073    // call init function on FumiliFCN
00074    InitAndReset(nPar);
00075 }
00076 
00077 
00078 void  TFumiliFCN::EvaluateAll( const std::vector<double> & p) { 
00079    // evaluate at same time function, gradient and hessian for parameter p. FumiliFCN interface
00080    Calculate_gradient_and_hessian(p);
00081 }
00082 
00083 
00084 void TFumiliFCN::Calculate_gradient_and_hessian(const std::vector<double> & p)  {
00085    // evaluate at same time function, gradient and hessian for parameter p
00086       
00087    unsigned int npar = p.size(); 
00088    if (npar != Dimension() ) { 
00089       // re-initialize the store gradient
00090       //std::cout << "initialize FumiliFCN and cache" << std::endl;
00091       Initialize(npar);
00092    }
00093    
00094    const FumiliFitData & points = *fData; 
00095    
00096    
00097    // set parameters
00098    fFunc->SetParameters( &p.front() );
00099    fParamCache = p;
00100    
00101    std::vector<double> & grad = Gradient(); 
00102    std::vector<double> & hess = Hessian(); 
00103    
00104    // dimension of hessian symmetric matrix  
00105    unsigned int nhdim = static_cast<int>( 0.5*npar*(npar + 1) ); 
00106    assert( npar == fFunctionGradient.size() ); 
00107    assert( npar == grad.size() ); 
00108    assert( nhdim == hess.size() );
00109    // reset  
00110    grad.assign( npar, 0.0); 
00111    hess.assign( nhdim, 0.0);
00112    
00113    double sum = 0; 
00114    
00115    
00116    // loop on measurements
00117    unsigned int nMeasurements = points.Size();
00118    unsigned int nRejected = 0; 
00119    for (unsigned int i = 0; i < nMeasurements; ++i) {
00120       
00121       fFunc->RejectPoint(false); 
00122       
00123       const std::vector<double> & x =  points.Coords(i); 
00124       fFunc->InitArgs( &x.front(), &fParamCache.front() ); 
00125       
00126       // one should implement integral option (in TFumili is not correct)
00127       double fval; 
00128       if ( fData->UseIntegral()) {
00129          const std::vector<double> & x2 = fData->Coords(i+1); 
00130          // need to implement derivatives of integral
00131          fval = FitterUtil::EvalIntegral(fFunc,x,x2,fParamCache); 
00132          if (fFunc->RejectedPoint() ) { 
00133             nRejected++; 
00134             continue;
00135          }
00136          Calculate_numerical_gradient_of_integral( x, x2, fval);        
00137          
00138       }
00139       else { 
00140          
00141          fval = fFunc->EvalPar(&x.front(), &fParamCache.front() ); 
00142          if (fFunc->RejectedPoint() ) { 
00143             nRejected++; 
00144             continue;
00145          }
00146          Calculate_numerical_gradient( x, fval); 
00147       }
00148       
00149       // calculate gradient 
00150       // eventually use function if provides it 
00151       
00152       Calculate_element(i, points, fval, sum, grad, hess); 
00153       
00154       // calculate i -element contribution to the chi2
00155       // add contributions to previous one 
00156       
00157       
00158    }
00159    
00160 #ifdef DEBUG
00161    std::cout << "Calculated Gradient and hessian " << std::endl; 
00162    for (unsigned int i = 0; i < npar; ++i) 
00163       std::cout << " par " << i << " = " << fParamCache[i] << " grad = " << grad[i] << std::endl;
00164    for (unsigned int i = 0; i < npar; ++i) {
00165       for (unsigned int j = 0; j < npar; ++j) 
00166          std::cout << hess[i*npar+j]; 
00167       
00168       std::cout << std::endl; 
00169    }
00170 #endif
00171    
00172    // set value of Obj function to be used by Minuit
00173    SetFCNValue(sum);
00174    
00175    // reset the number of fitting data points
00176    if (nRejected != 0)  fFunc->SetNumberFitPoints(nMeasurements-nRejected);
00177    
00178         
00179 }
00180 
00181 
00182 void TFumiliFCN::Calculate_numerical_gradient( const std::vector<double> & x, double f0) {   
00183    // calculate the numerical gradient for f(f). 
00184    // Different method (5 point r 2 points) according to the strategy set
00185    
00186    // use a cache for parameters to avoid to copy parameters each time this function is called
00187    
00188    int n = fParamCache.size();
00189    //std::cout << "Model function Gradient " << std::endl;
00190    for (int ipar = 0; ipar < n ; ++ipar) { 
00191       double p0 = fParamCache[ipar]; 
00192       // use 0.001 of par 
00193       double h = std::max( 0.001* std::fabs(p0), 8.0*kPrecision*(std::fabs(p0) + kPrecision) );  
00194       fParamCache[ipar] = p0 + h;  
00195       double f2 =  fFunc->EvalPar( &x.front(), &fParamCache.front() ); 
00196       
00197       
00198       if (fStrategy == 2) { 
00199          //  USE 5 POINT_RULE
00200          fParamCache[ipar] = p0 - h;  
00201          double f1 =  fFunc->EvalPar( &x.front(), &fParamCache.front() ); 
00202          fParamCache[ipar] = p0 + h/2; 
00203          double g1 =  fFunc->EvalPar( &x.front(), &fParamCache.front() ); 
00204          fParamCache[ipar] = p0 - h/2; 
00205          double g2 =  fFunc->EvalPar( &x.front(), &fParamCache.front() ); 
00206          
00207          double h2    = 1/(2.*h);
00208          double d0    = f1 - f2;
00209          double d2    = 2*(g1 - g2);
00210          
00211          //fFunctionGradient[ipar] =  0.5*( f2 - f1)/h;
00212          fFunctionGradient[ipar] =  h2*(4*d2 - d0)/3.;
00213          
00214       }
00215       else { 
00216          //default 2  point rule
00217          fFunctionGradient[ipar] =  (f2 - f0)/h;
00218       }
00219       
00220       // reset to old value
00221       fParamCache[ipar] = p0; 
00222       //std::cout << " i " << ipar << par[ipar] << "  " << fFunctionGradient[ipar] << " xi = " << x[0] << " fval " << f0 << std::endl; 
00223    }
00224    
00225 }
00226 
00227 
00228 void TFumiliFCN::Calculate_numerical_gradient_of_integral( const std::vector<double> & x1, const std::vector<double> & x2, double f0) {   
00229    // calculate the numerical gradient when the integral of the model function is used in the fit
00230     // Different method (5 point r 2 points) according to the strategy set
00231    // use a cache for parameters to avoid to copy parameters each time this function is called
00232    
00233    int n = fParamCache.size();
00234    //std::cout << "Model function Gradient " << std::endl;
00235    for (int ipar = 0; ipar < n ; ++ipar) { 
00236       double p0 = fParamCache[ipar]; 
00237       // use 0.001 of par 
00238       double h = std::max( 0.001* std::fabs(p0), 8.0*kPrecision*(std::fabs(p0) + kPrecision) );  
00239       fParamCache[ipar] = p0 + h;  
00240       double f2 =   FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00241       
00242       
00243       if (fStrategy == 2) { 
00244          //  USE 5 POINT_RULE
00245          fParamCache[ipar] = p0 - h;  
00246          double f1 =  FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00247          fParamCache[ipar] = p0 + h/2; 
00248          double g1 =  FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00249          fParamCache[ipar] = p0 - h/2; 
00250          double g2 =  FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache); 
00251          
00252          double h2    = 1/(2.*h);
00253          double d0    = f1 - f2;
00254          double d2    = 2*(g1 - g2);
00255          
00256          //fFunctionGradient[ipar] =  0.5*( f2 - f1)/h;
00257          fFunctionGradient[ipar] =  h2*(4*d2 - d0)/3.;
00258          
00259       }
00260       else { 
00261          //default 2  point rule
00262          fFunctionGradient[ipar] =  (f2 - f0)/h;
00263       }
00264       
00265       // reset to old value
00266       fParamCache[ipar] = p0; 
00267       //std::cout << " i " << ipar << par[ipar] << "  " << fFunctionGradient[ipar] << " xi = " << x[0] << " fval " << f0 << std::endl; 
00268    }
00269    
00270 }
00271 
00272 
00273 
00274 void TFumiliChi2FCN::Calculate_element(int i, const FumiliFitData & points, double fval, double & chi2, std::vector<double> & grad,   std::vector<double> & hess ) {
00275    // calculate the element i : grad(i) and hessian(i) for a chi2 FCN
00276    
00277    double invError =  points.InvError(i); 
00278    double value = points.Value(i);
00279    double element = invError*( fval - value );
00280    unsigned int npar = grad.size();
00281    
00282    chi2 += element*element;
00283    
00284    for (unsigned int j = 0; j < npar; ++j) { 
00285       
00286       double fj =  invError * fFunctionGradient[j]; 
00287       grad[j] += 2.0 * element * fj; 
00288       
00289       //std::cout << " ---------j " << " j  " <<  fFunctionGradient[j] << "  " << grad[j] << std::endl; 
00290       
00291       for (unsigned int k = j; k < npar; ++ k) { 
00292          int idx =  j + k*(k+1)/2; 
00293          hess[idx] += 2.0 * fj * invError * fFunctionGradient[k]; 
00294       }
00295    }
00296    //      std::cout << "element " << i << " x " << x[0] << " val = " << value << " sig = " << 1/invError << " f(x) " << fval << " element " << element << " gradients:  " << grad[0] << "  " << grad[1] << "  " << grad[2] << std::endl; 
00297    
00298 }
00299 
00300 
00301 void TFumiliBinLikelihoodFCN::Calculate_element(int i, const FumiliFitData & points, double fval, double & logLike, std::vector<double> & grad,   std::vector<double> & hess ) {
00302    // calculate the element i : grad(i) and hessian(i) for a binned log-likelihood FCN
00303    
00304    unsigned int npar = grad.size();
00305    
00306    // kEpsilon is smalles number ( 10-300) 
00307    double logtmp, invFval; 
00308    if(fval<=kEpsilon) { 
00309       logtmp = fval/kEpsilon + std::log(kEpsilon) - 1; 
00310       invFval = 1.0/kEpsilon; 
00311    } else {        
00312       logtmp = std::log(fval);
00313       invFval = 1.0/fval;
00314    }
00315    
00316    double value =  points.Value(i); 
00317    logLike +=  2.*( fval - value*logtmp );
00318    
00319    
00320    for (unsigned int j = 0; j < npar; ++j) {
00321       
00322       double fj; 
00323       if ( fval < kPrecision &&  std::fabs(fFunctionGradient[j]) < kPrecision ) 
00324          fj = 2.0; 
00325       else 
00326          fj =  2.* fFunctionGradient[j] * ( 1.0 - value*invFval); 
00327       
00328       
00329       //            if ( ( ! (fj <= 0) )  && ( ! ( fj > 0) ) ) { 
00330       //              std::cout << "fj is nan -- " << fj << "  " << j << " x " << x[0] << " f(x) = " << fval << "  inv =  " << invFval << "gradient = " 
00331       //                        << fFunctionGradient[j] << "  " << fFunctionGradient[j]/fval << std::endl;
00332       //              fj = 0; 
00333       
00334       //            }
00335       
00336       grad[j] += fj;
00337       
00338       for (unsigned int k = j; k < npar; ++ k) { 
00339          int idx =  j + k*(k+1)/2; 
00340          double fk; 
00341          if ( fval < kPrecision &&  std::fabs(fFunctionGradient[k]) < kPrecision ) 
00342             fk = 1.0; 
00343          else 
00344             fk =  fFunctionGradient[k]* ( 1.0 - value*invFval); 
00345          
00346          
00347          hess[idx] += fj * fk;
00348       }
00349    }
00350    
00351 }
00352 
00353 
00354 void TFumiliUnbinLikelihoodFCN::Calculate_element(int , const FumiliFitData &, double fval, double & logLike, std::vector<double> & grad,   std::vector<double> & hess ) {
00355    // calculate the element i : grad(i) and hessian(i) for an unbinned log-likelihood FCN
00356    
00357    unsigned int npar = grad.size();
00358    // likelihood
00359    //if (fval < 1.0E-16) fval = 1.0E-16; // truncate for precision
00360    
00361    // kEpsilon is smalles number ( 10-300) 
00362    double logtmp, invFval; 
00363    if(fval<=kEpsilon) { 
00364       logtmp = fval/kEpsilon + std::log(kEpsilon) - 1; 
00365       invFval = 1.0/kEpsilon; 
00366    } else {        
00367       logtmp = std::log(fval);
00368       invFval = 1.0/fval;
00369    }
00370    
00371    logLike += logtmp;
00372    for (unsigned int j = 0; j < npar; ++j) {
00373       
00374       double fj; 
00375       if ( fval < kPrecision &&  std::fabs(fFunctionGradient[j]) < kPrecision ) 
00376          fj = 2.0; 
00377       else 
00378          fj =  2.* invFval * fFunctionGradient[j]; 
00379         
00380       grad[j] -= fj;
00381       
00382       for (unsigned int k = j; k < npar; ++ k) { 
00383          int idx =  j + k*(k+1)/2; 
00384          double fk; 
00385          if ( fval < kPrecision &&  std::fabs(fFunctionGradient[k]) < kPrecision ) 
00386             fk = 1.0; 
00387          else 
00388             fk =  invFval * fFunctionGradient[k]; 
00389          
00390          
00391          hess[idx] += fj * fk;
00392       }
00393    }
00394 }
00395 
00396 
00397 //  
00398 double TFumiliChi2FCN::operator()(const std::vector<double>& par) const {
00399    // implement chi2 function 
00400    assert(fData != 0); 
00401    assert(fFunc != 0); 
00402    
00403    TChi2FCN  fcn(fData,fFunc); 
00404    return fcn(par); 
00405 }
00406 
00407 
00408 double TFumiliBinLikelihoodFCN::operator()(const std::vector<double>& par) const {
00409     // implement binned-likelihood function 
00410    assert(fData != 0); 
00411    assert(fFunc != 0); 
00412    
00413    TBinLikelihoodFCN  fcn(fData,fFunc); 
00414    return fcn(par); 
00415 }
00416 
00417 double TFumiliBinLikelihoodFCN::Chi2(const std::vector<double>& par) const {
00418    // implement function to evaluate chi2 equivalent
00419    TChi2FCN chi2Fcn(fData,fFunc);
00420    return chi2Fcn(par);
00421 }
00422 
00423 
00424 double TFumiliUnbinLikelihoodFCN::operator()(const std::vector<double>& /*par */) const {
00425    // not yet implemented (to be done)
00426    assert(fData != 0); 
00427    assert(fFunc != 0); 
00428    
00429    //TUnbinLikelihoodFCN  fcn(*fData,*fFunc); 
00430    //return fcn(par);
00431    // to be implemented
00432    return 0; 
00433 }

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