[root] / trunk / math / mathcore / src / FitResult.cxx Repository:
ViewVC logotype

View of /trunk/math/mathcore/src/FitResult.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25486 - (download) (as text) (annotate)
Mon Sep 22 12:43:03 2008 UTC (6 years, 4 months ago) by moneta
File size: 13097 byte(s)
import changes from math development branches for subdirectory math. List of changes in detail: 

mathcore: 
---------
  MinimizerOptions: 
	new  class for storing Minimizer option, with static default values that can be 
	changed by the user

  FitConfig: 
   	- use default values from MinimizerOption class
   	- rename method to create parameter settings from a function

  FitUtil.cxx:   
    	improve the derivative calculations used in the effective chi2 and in Fumili and 
	fix a bug for evaluation of likelihood or chi2 terms. 
	In  EvaluatePdf() work and return  the log of the pdf. 
      
  FitResult:
	- improve the class by adding extra information like, num. of free parameters, 
	minimizer status, global correlation coefficients, information about fixed 
	and bound parameters. 
   	- add method for getting fit confidence intervals 
  	- improve print method   

  DataRange: 
	add method SetRange to distinguish from AddRange. SetRange deletes the existing 
	ranges. 

  ParamsSettings: make few methods const

  FCN functions (Chi2FCN, LogLikelihoodFCN, etc..) 
	move some common methods and data members in base class (FitMethodFunction)

  RootFinder: add template Solve() for any callable function.  

mathmore:
--------
  minimizer classes: fill status information
  GSLNLSMinimizer: return error and covariance matrix 

minuit2: 
-------
  Minuit2Minimizer: fill  status information 
  DavidonErrorUpdator: check that delgam or gvg are not zero ( can happen when dg = 0)
  FumiliFCNAdapter: work on the log of pdf

minuit:
------- 
  TLinearMinimizer: add support for robust fitting
  TMinuitMinimizer: fill status information and fix a bug in filling the correlation matrix. 
 fumili:
 ------ 
  add TFumiliMinimizer: 
	wrapper class for TFumili using Minimizer interface

// @(#)root/mathcore:$Id$
// Author: L. Moneta Wed Aug 30 11:05:34 2006

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// Implementation file for class FitResult

#include "Fit/FitResult.h"

#include "Fit/FitConfig.h"

#include "Fit/BinData.h"

#include "Math/Minimizer.h"

#include "Math/IParamFunction.h"
#include "Math/OneDimFunctionAdapter.h"

#include "Math/DistFunc.h"

#include "TMath.h"  
#include "Math/RichardsonDerivator.h"
#include "Math/Error.h"

#include <cassert>
#include <cmath>
#include <iostream>
#include <iomanip>

namespace ROOT { 

   namespace Fit { 


FitResult::FitResult() : 
   fValid(false), fNormalized(false), fNFree(0), fNdf(0), fNCalls(0), 
   fStatus(-1), fVal(0), fEdm(0), fChi2(0), fFitFunc(0)
{
   // Default constructor implementation.
}

      FitResult::FitResult(ROOT::Math::Minimizer & min, const FitConfig & fconfig, IModelFunction & func,  bool isValid,  unsigned int sizeOfData, const  ROOT::Math::IMultiGenFunction * chi2func, bool minosErr, unsigned int ncalls ) : 
   fValid(isValid),
   fNormalized(false),
   fNFree(min.NFree() ),
   fNCalls(min.NCalls()),
   fStatus(min.Status() ),
   fVal (min.MinValue()),  
   fEdm (min.Edm()),  
   fFitFunc(&func), 
   fParams(std::vector<double>(min.X(), min.X() + min.NDim() ) )
{
   // Constructor from a minimizer, fill the data. ModelFunction  is passed as non const 
   // since it will be managed by the FitResult

   if (sizeOfData > 0) fNdf = sizeOfData - min.NFree(); 

   // set right parameters in function (in case minimizer did not do before)
   // do also when fit is not valid
   fFitFunc->SetParameters(&fParams.front());

   if (min.Errors() != 0) 
      fErrors = std::vector<double>(min.Errors(), min.Errors() + min.NDim() ) ; 

   // check for fixed or limited parameters
   for (unsigned int ipar = 0; ipar < fParams.size(); ++ipar) { 
      const ParameterSettings & par = fconfig.ParSettings(ipar); 
      if (par.IsFixed() ) fFixedParams.push_back(ipar); 
      if (par.IsBound() ) fBoundParams.push_back(ipar); 
   } 

   if (chi2func == 0) 
      fChi2 = fVal;
   else { 
      // compute chi2 equivalent
      fChi2 = (*chi2func)(&fParams[0]); 
   }

   // replace ncalls if given (they are taken from the FitMethodFunction)
   if (ncalls !=0) fNCalls = ncalls;

   unsigned int n  = min.NDim(); 
      
//    // fill error matrix
   // cov matrix rank 
   if (fValid) { 

      unsigned int r = n * (  n + 1 )/2;  
      fCovMatrix.reserve(r);
      for (unsigned int i = 0; i < n; ++i) 
         for (unsigned int j = 0; j <= i; ++j)
            fCovMatrix.push_back(min.CovMatrix(i,j) );
      
      assert (fCovMatrix.size() == r ); 

      // normalize errors if requested in configuration
      if (fconfig.NormalizeErrors() ) NormalizeErrors();

      // minos errors 
      if (minosErr) { 
         fMinosErrors.reserve(n);
         for (unsigned int i = 0; i < n; ++i) { 
            double elow, eup; 
            bool ret = min.GetMinosError(0, elow, eup); 
            if (ret) fMinosErrors.push_back(std::make_pair(elow,eup) );
            else fMinosErrors.push_back(std::make_pair(0.,0.) );
         }
      }

      // globalCC
      fGlobalCC.reserve(n);
      for (unsigned int i = 0; i < n; ++i) { 
         double globcc = min.GlobalCC(i); 
         if (globcc < 0) break; // it is not supported by that minimizer
         fGlobalCC.push_back(globcc); 
      }
      
   }

   fMinimType = fconfig.MinimizerType();

   // append algorithm name for minimizer that support it  
   if ( (fMinimType.find("Fumili") == std::string::npos) &&
        (fMinimType.find("GSLMultiFit") == std::string::npos) 
      ) { 
      if (fconfig.MinimizerAlgoType() != "") fMinimType += " / " + fconfig.MinimizerAlgoType(); 
   }

}

FitResult::FitResult(const FitResult &rhs) { 
   // Implementation of copy constructor
   (*this) = rhs; 
}

FitResult & FitResult::operator = (const FitResult &rhs) { 
   // Implementation of assignment operator.
   if (this == &rhs) return *this;  // time saving self-test

   // Manages the fitted function 
   if (fFitFunc) delete fFitFunc;
   fFitFunc = 0; 
   if (rhs.fFitFunc != 0 ) {
      fFitFunc = dynamic_cast<IModelFunction *>( (rhs.fFitFunc)->Clone() ); 
      assert(fFitFunc != 0); 
   }

   // copy all other data members 
   fValid = rhs.fValid; 
   fNormalized = rhs.fNormalized;
   fNFree = rhs.fNFree; 
   fNdf = rhs.fNdf; 
   fNCalls = rhs.fNCalls; 
   fStatus = rhs.fStatus; 
   fVal = rhs.fVal;  
   fEdm = rhs.fEdm; 
   fChi2 = rhs.fChi2;

   fFixedParams = rhs.fFixedParams;
   fBoundParams = rhs.fBoundParams;
   fParams = rhs.fParams; 
   fErrors = rhs.fErrors; 
   fCovMatrix = rhs.fCovMatrix; 
   fGlobalCC = rhs.fGlobalCC;
   fMinosErrors = rhs.fMinosErrors; 

   fMinimType = rhs.fMinimType; 
   
   return *this; 

}  


void FitResult::NormalizeErrors() { 
   // normalize errors and covariance matrix according to chi2 value
   if (fNdf == 0 || fChi2 <= 0) return; 
   double s2 = fChi2/fNdf; 
   double s = std::sqrt(fChi2/fNdf); 
   for (unsigned int i = 0; i < fErrors.size() ; ++i) 
      fErrors[i] *= s; 
   for (unsigned int i = 0; i < fCovMatrix.size() ; ++i) 
      fCovMatrix[i] *= s2; 

   fNormalized = true; 
} 

double FitResult::Prob() const { 
   // fit probability
   return ROOT::Math::chisquared_cdf_c(fChi2, static_cast<double>(fNdf) ); 
}

int FitResult::Index(const std::string & name) const { 
   // find index for given parameter name
   unsigned int npar = fParams.size(); 
   for (unsigned int i = 0; i < npar; ++i) 
      if ( fFitFunc->ParameterName(i) == name) return i; 
   
   return -1; // case name is not found
} 

bool FitResult::IsParameterBound(unsigned int ipar) const { 
   for (unsigned int i = 0; i < fBoundParams.size() ; ++i) 
      if ( fBoundParams[i] == ipar) return true; 
   return false; 
}

bool FitResult::IsParameterFixed(unsigned int ipar) const { 
   for (unsigned int i = 0; i < fFixedParams.size() ; ++i) 
      if ( fFixedParams[i] == ipar) return true; 
   return false; 
}

void FitResult::Print(std::ostream & os, bool doCovMatrix) const { 
   // print the result in the given stream 
   // need to add minos errors , globalCC, etc..
   if (!fValid) { 
      os << "\n****************************************\n";
      os << "            Invalid FitResult            ";
      os << "\n****************************************\n";
      return; 
   }

   os << "\n****************************************\n";
   //os << "            FitResult                   \n\n";
   os << "Minimizer is " << fMinimType << std::endl;
   unsigned int npar = fParams.size(); 
   const unsigned int nw = 25; 
   if (fVal != fChi2) 
      os << std::setw(nw) << std::left << "Likelihood" << " =\t" << fVal << std::endl;
   os << std::setw(nw) << std::left <<  "Chi2"  << " =\t" << fChi2<< std::endl;
   os << std::setw(nw) << std::left << "NDf"    << " =\t" << fNdf << std::endl; 
   if (fMinimType.find("Linear") == std::string::npos) {  // no need to print this for linear fits
      os << std::setw(nw) << std::left << "Edm"    << " =\t" << fEdm << std::endl; 
      os << std::setw(nw) << std::left << "NCalls" << " =\t" << fNCalls << std::endl; 
   }
   assert(fFitFunc != 0); 
   for (unsigned int i = 0; i < npar; ++i) { 
      os << std::setw(nw) << std::left << fFitFunc->ParameterName(i) << " =\t" << fParams[i]; 
      if (IsParameterFixed(i) ) 
         os << " \t(fixed)";
      else {
         if (fErrors.size() != 0)
            os << " \t+/-\t" << fErrors[i]; 
         if (IsParameterBound(i) ) 
            os << " \t (limited)"; 
      }
      os << std::endl; 
   }

   if (doCovMatrix) PrintCovMatrix(os); 
}

void FitResult::PrintCovMatrix(std::ostream &os) const { 
   // print the covariance and correlation matrix 
   if (!fValid) return;
   if (fCovMatrix.size() == 0) return; 
//   os << "****************************************\n";
   os << "\n            Covariance Matrix            \n\n";
   unsigned int npar = fParams.size(); 
   const int kPrec = 5; 
   const int kWidth = 10; 
   const int parw = 12; 
   const int matw = kWidth+4;
   os << std::setw(parw) << " " << "\t"; 
   for (unsigned int i = 0; i < npar; ++i) 
      if (!IsParameterFixed(i) ) { 
         os << std::setw(matw)  << fFitFunc->ParameterName(i) ;
      }
   os << std::endl;   
   for (unsigned int i = 0; i < npar; ++i) {
      if (!IsParameterFixed(i) ) { 
         os << std::setw(parw) << std::left << fFitFunc->ParameterName(i) << "\t";
         for (unsigned int j = 0; j < npar; ++j) {
            if (!IsParameterFixed(j) ) { 
               os.precision(kPrec); os.width(kWidth);  os << std::setw(matw) << CovMatrix(i,j); 
            }
         }
         os << std::endl;
      }
   }
//   os << "****************************************\n";
   os << "\n            Correlation Matrix         \n\n";
   os << std::setw(parw) << " " << "\t"; 
   for (unsigned int i = 0; i < npar; ++i) 
      if (!IsParameterFixed(i) ) { 
         os << std::setw(matw)  << fFitFunc->ParameterName(i) ;
      }
   os << std::endl;   
   for (unsigned int i = 0; i < npar; ++i) {
      if (!IsParameterFixed(i) ) { 
         os << std::setw(parw) << std::left << fFitFunc->ParameterName(i) << "\t";
         for (unsigned int j = 0; j < npar; ++j) {
            if (!IsParameterFixed(j) ) {
               os.precision(kPrec); os.width(kWidth);  os << std::setw(matw) << Correlation(i,j); 
            }
         }
         os << std::endl;
      }
   }
}

void FitResult::GetConfidenceIntervals(unsigned int n, unsigned int stride1, unsigned int stride2, const double * x, double * ci, double cl ) const {     
   // stride1 stride in coordinate  stride2 stride in dimension space
   // i.e. i-th point in k-dimension is x[ stride1 * i + stride2 * k]
   // compute the confidence interval of the fit on the given data points
   // the dimension of the data points must match the dimension of the fit function
   // confidence intervals are returned in array ci

   // use student quantile
   //double t = - TMath::StudentQuantile((1.-cl)/2, f->GetNDF()); 
   double t = TMath::StudentQuantile(0.5 + cl/2, fNdf); 
   double chidf = TMath::Sqrt(fChi2/fNdf);

   if (!fFitFunc) {
      MATH_ERROR_MSG("FitResult::GetConfidenceIntervals","cannot compute Confidence Intervals without fitter function");
      return;
   }

   unsigned int ndim = fFitFunc->NDim(); 
   unsigned int npar = fFitFunc->NPar(); 

   std::vector<double> xpoint(ndim); 
   std::vector<double> grad(npar); 
   std::vector<double> vsum(npar); 

   // loop on the points
   for (unsigned int ipoint = 0; ipoint < n; ++ipoint) { 

      for (unsigned int kdim = 0; kdim < ndim; ++kdim) { 
         unsigned int i = ipoint * stride1 + kdim * stride2; 
         assert(i < ndim*n); 
         xpoint[kdim] = x[ipoint * stride1 + kdim * stride2]; 
      }

      // calculate gradient of fitted function w.r.t the parameters

      // check first if fFitFunction provides parameter gradient or not 
      
      // does not provide gradient
      // t.b.d : skip calculation for fixed parameters
      ROOT::Math::RichardsonDerivator d; 
      for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
         ROOT::Math::OneDimParamFunctionAdapter<const ROOT::Math::IParamMultiFunction &> fadapter(*fFitFunc,&xpoint.front(),&fParams.front(),ipar);
         d.SetFunction(fadapter); 
         grad[ipar] = d(fParams[ipar] ); // evaluate df/dp
      }

      // multiply covariance matrix with gradient
      vsum.assign(npar,0.0);
      for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
         for (unsigned int jpar = 0; jpar < npar; ++jpar) {
            vsum[ipar] += CovMatrix(ipar,jpar) * grad[jpar]; 
         }
      }
      // multiply gradient by vsum
      double r2 = 0; 
      for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
         r2 += grad[ipar] * vsum[ipar]; 
      }
      double r = std::sqrt(r2); 
      ci[ipoint] = r * t * chidf; 
   }
}

void FitResult::GetConfidenceIntervals(const BinData & data, double * ci, double cl ) const { 
   // implement confidence intervals from a given bin data sets
   // currently copy the data from Bindata. 
   // could implement otherwise directly
   unsigned int ndim = data.NDim(); 
   unsigned int np = data.NPoints(); 
   std::vector<double> xdata( ndim * np ); 
   for (unsigned int i = 0; i < np ; ++i) { 
      const double * x = data.Coords(i); 
      std::vector<double>::iterator itr = xdata.begin()+ ndim * i;
      std::copy(x,x+ndim,itr);
   }
   // points are arraned as x0,y0,z0, ....xN,yN,zN  (stride1=ndim, stride2=1)
   GetConfidenceIntervals(np,ndim,1,&xdata.front(),ci,cl);
}

   } // end namespace Fit

} // end namespace ROOT


Subversion Admin
ViewVC Help
Powered by ViewVC 1.0.9