RooNonCentralChiSquare.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitModels                                                     *
00004  * @(#)root/roofit:$Id: RooNonCentralChiSquare                               *
00005  * Authors:                                                                  *
00006  *   Kyle Cranmer
00007  *                                                                           *
00008  *****************************************************************************/
00009 
00010 //////////////////////////////////////////////////////////////////////////////
00011 //
00012 // BEGIN_HTML
00013 // The PDF of the Non-Central Chi Square distribution for n degrees of freedom.  
00014 // It is the asymptotic distribution of the profile likeihood ratio test q_mu 
00015 // when a different mu' is true.  It is Wald's generalization of Wilks' Theorem.
00016 //
00017 // See:
00018 //  Asymptotic formulae for likelihood-based tests of new physics
00019 //     By Glen Cowan, Kyle Cranmer, Eilam Gross, Ofer Vitells
00020 //     http://arXiv.org/abs/arXiv:1007.1727
00021 //
00022 //  Wikipedia:
00023 //    http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution#Approximation
00024 //
00025 // It requires MathMore to evaluate for non-integer degrees of freedom, k.
00026 //
00027 // When the Mathmore library is available we can use the MathMore libraries impelmented using GSL. 
00028 // It makes use of the modified Bessel function of the first kind (for k > 2). For k < 2 it uses 
00029 // the hypergeometric function 0F1. 
00030 // When is not available we use explicit summation of normal chi-squared distributions
00031 // The usage of the sum can be forced by calling SetForceSum(true);
00032 //
00033 // This implementation could be improved.  BOOST has a nice implementation:
00034 // http://live.boost.org/doc/libs/1_42_0/libs/math/doc/sf_and_dist/html/math_toolkit/dist/dist_ref/dists/nc_chi_squared_dist.html
00035 // http://wesnoth.repositoryhosting.com/trac/wesnoth_wesnoth/browser/trunk/include/boost/math/distributions/non_central_chi_squared.hpp?rev=6
00036 // END_HTML
00037 //
00038 
00039 #include "Riostream.h" 
00040 
00041 #include "RooNonCentralChiSquare.h" 
00042 #include "RooAbsReal.h" 
00043 #include "RooAbsCategory.h" 
00044 #include <math.h> 
00045 #include "TMath.h" 
00046 //#include "RooNumber.h"
00047 #include "Math/DistFunc.h"
00048 
00049 
00050 #include "RooMsgService.h"
00051 
00052 ClassImp(RooNonCentralChiSquare) 
00053 
00054 RooNonCentralChiSquare::RooNonCentralChiSquare(const char *name, const char *title, 
00055                                                RooAbsReal& _x,
00056                                                RooAbsReal& _k,
00057                                                RooAbsReal& _lambda) :
00058    RooAbsPdf(name,title), 
00059    x("x","x",this,_x),
00060    k("k","k",this,_k),
00061    lambda("lambda","lambda",this,_lambda),
00062    fErrorTol(1E-3),
00063    fMaxIters(10),
00064    fHasIssuedConvWarning(false),
00065    fHasIssuedSumWarning(false)
00066 { 
00067 #ifdef R__HAS_MATHMORE  
00068    ccoutD(InputArguments) << "RooNonCentralChiSquare::ctor(" << GetName() << 
00069       "MathMore Available, will use Bessel function expressions unless SetForceSum(true) "<< endl ;
00070    fForceSum = false;
00071 #else 
00072    fForceSum = true;
00073 #endif
00074 } 
00075 
00076 RooNonCentralChiSquare::RooNonCentralChiSquare(const RooNonCentralChiSquare& other, const char* name) :  
00077    RooAbsPdf(other,name), 
00078    x("x",this,other.x),
00079    k("k",this,other.k),
00080    lambda("lambda",this,other.lambda),
00081    fErrorTol(other.fErrorTol),
00082    fMaxIters(other.fMaxIters),
00083    fHasIssuedConvWarning(false),
00084    fHasIssuedSumWarning(false)
00085 { 
00086 #ifdef R__HAS_MATHMORE  
00087    ccoutD(InputArguments) << "RooNonCentralChiSquare::ctor(" << GetName() << 
00088      "MathMore Available, will use Bessel function expressions unless SetForceSum(true) "<< endl ;
00089    fForceSum = other.fForceSum;
00090 #else 
00091    fForceSum = true;
00092 #endif
00093 } 
00094 
00095 
00096 void RooNonCentralChiSquare::SetForceSum(Bool_t flag) { 
00097    fForceSum = flag; 
00098 #ifndef R__HAS_MATHMORE
00099    if (!fForceSum) { 
00100       ccoutD(InputArguments) << "RooNonCentralChiSquare::SetForceSum" << GetName() << 
00101          "MathMore is not available- ForceSum must be on "<< endl ;
00102       fForceSum = true; 
00103    }
00104 #endif
00105 
00106 }
00107 
00108 
00109 Double_t RooNonCentralChiSquare::evaluate() const 
00110 { 
00111    // ENTER EXPRESSION IN TERMS OF VARIABLE ARGUMENTS HERE 
00112 
00113 
00114    // chi^2(0,k) gives inf and causes various problems
00115    // truncate
00116    Double_t xmin = x.min(); 
00117    Double_t xmax = x.max();
00118    double _x = x;
00119    if(_x<=0){
00120      // options for dealing with this
00121      //     return 0; // gives a funny dip
00122      //     _x = 1./RooNumber::infinity(); // too tall
00123      _x = xmin + 1e-3*(xmax-xmin); // very small fraction of range
00124    }
00125 
00126    // special case (form below doesn't work when lambda==0)
00127    if(lambda==0){
00128       return ROOT::Math::chisquared_pdf(_x,k);
00129    }
00130 
00131    // three forms
00132    // FIRST FORM
00133    // \sum_i=0^\infty exp(-lambda/2) (\lamda/2)^i chi2(x,k+2i) / i!
00134    // could truncate sum
00135 
00136    if ( fForceSum  ){
00137       if(!fHasIssuedSumWarning){
00138          coutI(InputArguments) << "RooNonCentralChiSquare sum being forced" << endl ;
00139          fHasIssuedSumWarning=true;
00140       }
00141       double sum = 0;
00142       double ithTerm = 0;
00143       double errorTol = fErrorTol;
00144       int MaxIters = fMaxIters;
00145       int iDominant = (int) TMath::Floor(lambda/2);     
00146       //     cout <<"iDominant: " << iDominant << endl;
00147     
00148       // do 0th term last
00149       //     if(iDominant==0) iDominant = 1;
00150       for(int i = iDominant; ; ++i){
00151          ithTerm =exp(-lambda/2.)*pow(lambda/2.,i)*ROOT::Math::chisquared_pdf(_x,k+2*i)/TMath::Gamma(i+1);
00152          sum+=ithTerm;
00153          //       cout <<"progress: " << i << " " << ithTerm/sum << endl;
00154          if(ithTerm/sum < errorTol)
00155             break;
00156 
00157          if( i>iDominant+MaxIters){
00158             if(!fHasIssuedConvWarning){
00159                fHasIssuedConvWarning=true;
00160                coutW(Eval) << "RooNonCentralChiSquare did not converge: for x=" << x <<" k="<<k
00161                            << ", lambda="<<lambda << " fractional error = " << ithTerm/sum 
00162                            << "\n either adjust tolerance with SetErrorTolerance(tol) or max_iter with SetMaxIter(max_it)"  
00163                            << endl;
00164             }
00165             break;
00166          }
00167       }
00168 
00169       for(int i = iDominant - 1; i >= 0; --i){
00170          //       cout <<"Progress: " << i << " " << ithTerm/sum << endl;
00171          ithTerm =exp(-lambda/2.)*pow(lambda/2.,i)*ROOT::Math::chisquared_pdf(_x,k+2*i)/TMath::Gamma(i+1);
00172          sum+=ithTerm;
00173       }
00174 
00175 
00176       return sum;
00177    }
00178 
00179    // SECOND FORM (use MathMore function based on Bessel function (if k>2) or 
00180    // or  regularized confluent hypergeometric limit function.
00181 #ifdef R__HAS_MATHMORE
00182    return  ROOT::Math::noncentral_chisquared_pdf(_x,k,lambda);
00183 #else 
00184    coutF(Eval) << "RooNonCentralChisquare: ForceSum must be set" << endl;
00185    return 0; 
00186 #endif
00187 
00188 } 
00189 
00190 //_____________________________________________________________________________
00191 Int_t RooNonCentralChiSquare::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const 
00192 {
00193    if (matchArgs(allVars,analVars,x)) return 1 ;
00194    return 0 ;
00195 }
00196 
00197 
00198 
00199 //_____________________________________________________________________________
00200 Double_t RooNonCentralChiSquare::analyticalIntegral(Int_t code, const char* rangeName) const 
00201 {
00202    assert(code==1 );
00203    //  cout << "evaluating analytic integral" << endl;
00204    Double_t xmin = x.min(rangeName); 
00205    Double_t xmax = x.max(rangeName);
00206 
00207    // if xmin~0 and xmax big, then can return 1. b/c evaluate is normalized.  
00208 
00209    // special case (form below doesn't work when lambda==0)
00210    if(lambda==0){
00211       return (ROOT::Math::chisquared_cdf(xmax,k) - ROOT::Math::chisquared_cdf(xmin,k));
00212    }
00213 
00214    // three forms
00215    // FIRST FORM
00216    // \sum_i=0^\infty exp(-lambda/2) (\lamda/2)^i chi2(x,k+2i) / i!
00217    // could truncate sum
00218 
00219   
00220    double sum = 0;
00221    double ithTerm = 0;
00222    double errorTol = fErrorTol; // for nomralization allow slightly larger error
00223    int MaxIters = fMaxIters; // for normalization use more terms
00224 
00225    int iDominant = (int) TMath::Floor(lambda/2);     
00226    //     cout <<"iDominant: " << iDominant << endl;
00227    //   iDominant=0;
00228    for(int i = iDominant; ; ++i){
00229       ithTerm =exp(-lambda/2.)*pow(lambda/2.,i)
00230          *( ROOT::Math::chisquared_cdf(xmax,k+2*i)/TMath::Gamma(i+1)
00231             - ROOT::Math::chisquared_cdf(xmin,k+2*i)/TMath::Gamma(i+1) );
00232       sum+=ithTerm;
00233       //     cout <<"progress: " << i << " " << ithTerm << " " << sum << endl;
00234       if(ithTerm/sum < errorTol)
00235          break;
00236      
00237       if( i>iDominant+MaxIters){
00238          if(!fHasIssuedConvWarning){
00239             fHasIssuedConvWarning=true;
00240             coutW(Eval) << "RooNonCentralChiSquare Normalization did not converge: for k="<<k
00241                         << ", lambda="<<lambda << " fractional error = " << ithTerm/sum 
00242                         << "\n either adjust tolerance with SetErrorTolerance(tol) or max_iter with SetMaxIter(max_it)"  
00243                         << endl;
00244          }
00245          break;
00246       }
00247    }
00248    
00249    for(int i = iDominant - 1; i >= 0; --i){
00250       ithTerm =exp(-lambda/2.)*pow(lambda/2.,i)
00251          *( ROOT::Math::chisquared_cdf(xmax,k+2*i)/TMath::Gamma(i+1)
00252             -ROOT::Math::chisquared_cdf(xmin,k+2*i)/TMath::Gamma(i+1) );
00253       sum+=ithTerm;
00254    }
00255    return sum;
00256 }
00257 
00258 
00259 
00260 
00261 

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