LikelihoodInterval.cxx

Go to the documentation of this file.
00001 // @(#)root/roostats:$Id: LikelihoodInterval.cxx 38087 2011-02-16 10:49:52Z moneta $
00002 // Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
00003 /*************************************************************************
00004  * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
00005  * All rights reserved.                                                  *
00006  *                                                                       *
00007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00009  *************************************************************************/
00010 
00011 /*****************************************************************************
00012  * Project: RooStats
00013  * Package: RooFit/RooStats  
00014  * @(#)root/roofit/roostats:$Id: LikelihoodInterval.cxx 38087 2011-02-16 10:49:52Z moneta $
00015  * Authors:                     
00016  *   Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
00017  *
00018  *****************************************************************************/
00019 
00020 
00021 
00022 //_________________________________________________
00023 /*
00024 BEGIN_HTML
00025 <p>
00026 LikelihoodInterval is a concrete implementation of the RooStats::ConfInterval interface.  
00027 It implements a connected N-dimensional intervals based on the contour of a likelihood ratio.
00028 The boundary of the inteval is equivalent to a MINUIT/MINOS contour about the maximum likelihood estimator
00029 [<a href="#minuit">1</a>].
00030 The interval does not need to be an ellipse (eg. it is not the HESSE error matrix).
00031 The level used to make the contour is the same as that used in MINOS, eg. it uses Wilks' theorem, 
00032 which states that under certain regularity conditions the function -2* log (profile likelihood ratio) is asymptotically distributed as a chi^2 with N-dof, where 
00033 N is the number of parameters of interest.  
00034 </p>
00035 
00036 <p>
00037 Note, a boundary on the parameter space (eg. s>= 0) or a degeneracy (eg. mass of signal if Nsig = 0) can lead to violations of the conditions necessary for Wilks' theorem to be true.
00038 </p>
00039 
00040 <p>
00041 Also note, one can use any RooAbsReal as the function that will be used in the contour; however, the level of the contour
00042 is based on Wilks' theorem as stated above.
00043 </p>
00044 
00045 <P>References</P>
00046 
00047 <p><A NAME="minuit">1</A>
00048 F.&nbsp;James., Minuit.Long writeup D506, CERN, 1998.
00049 </p>
00050   
00051 END_HTML
00052 */
00053 //
00054 //
00055 
00056 #ifndef RooStats_LikelihoodInterval
00057 #include "RooStats/LikelihoodInterval.h"
00058 #endif
00059 #include "RooStats/RooStatsUtils.h"
00060 
00061 #include "RooAbsReal.h"
00062 #include "RooMsgService.h"
00063 
00064 #include "Math/WrappedFunction.h"
00065 #include "Math/Minimizer.h"
00066 #include "Math/Factory.h"
00067 #include "Math/MinimizerOptions.h"
00068 #include "RooFunctor.h"
00069 #include "RooProfileLL.h"
00070 
00071 #include <string>
00072 
00073 /*
00074 // for debugging
00075 #include "RooNLLVar.h"
00076 #include "RooProfileLL.h"
00077 #include "RooDataSet.h"
00078 #include "RooAbsData.h"
00079 */
00080 
00081 ClassImp(RooStats::LikelihoodInterval) ;
00082 
00083 using namespace RooStats;
00084 
00085 
00086 //____________________________________________________________________
00087 LikelihoodInterval::LikelihoodInterval(const char* name) :
00088    ConfInterval(name), fBestFitParams(0), fLikelihoodRatio(0), fConfidenceLevel(0.95)
00089 {
00090    // Default constructor with name and title
00091 }
00092 
00093 //____________________________________________________________________
00094 LikelihoodInterval::LikelihoodInterval(const char* name, RooAbsReal* lr, const RooArgSet* params,  RooArgSet * bestParams) :
00095    ConfInterval(name), 
00096    fParameters(*params), 
00097    fBestFitParams(bestParams), 
00098    fLikelihoodRatio(lr),
00099    fConfidenceLevel(0.95)
00100 {
00101    // Alternate constructor taking a pointer to the profile likelihood ratio, parameter of interest and 
00102    // optionally a snaphot of best parameter of interest for interval
00103 }
00104 
00105 
00106 //____________________________________________________________________
00107 LikelihoodInterval::~LikelihoodInterval()
00108 {
00109    // Destructor
00110    if (fBestFitParams) delete fBestFitParams; 
00111    if (fLikelihoodRatio) delete fLikelihoodRatio;
00112 }
00113 
00114 
00115 //____________________________________________________________________
00116 Bool_t LikelihoodInterval::IsInInterval(const RooArgSet &parameterPoint) const 
00117 {  
00118   // This is the main method to satisfy the RooStats::ConfInterval interface.  
00119   // It returns true if the parameter point is in the interval.
00120 
00121    RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
00122    RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
00123   // Method to determine if a parameter point is in the interval
00124   if( !this->CheckParameters(parameterPoint) ) {
00125     std::cout << "parameters don't match" << std::endl;
00126     RooMsgService::instance().setGlobalKillBelow(msglevel);
00127     return false; 
00128   }
00129 
00130   // make sure likelihood ratio is set
00131   if(!fLikelihoodRatio) {
00132     std::cout << "likelihood ratio not set" << std::endl;
00133     RooMsgService::instance().setGlobalKillBelow(msglevel);
00134     return false;
00135   }
00136 
00137   
00138 
00139   // set parameters
00140   SetParameters(&parameterPoint, fLikelihoodRatio->getVariables() );
00141 
00142 
00143   // evaluate likelihood ratio, see if it's bigger than threshold
00144   if (fLikelihoodRatio->getVal()<0){
00145     std::cout << "The likelihood ratio is < 0, indicates a bad minimum or numerical precision problems.  Will return true" << std::endl;
00146     RooMsgService::instance().setGlobalKillBelow(msglevel);
00147     return true;
00148   }
00149 
00150 
00151   // here we use Wilks' theorem.
00152   if ( TMath::Prob( 2* fLikelihoodRatio->getVal(), parameterPoint.getSize()) < (1.-fConfidenceLevel) ){
00153     RooMsgService::instance().setGlobalKillBelow(msglevel);
00154     return false;
00155   }
00156 
00157 
00158   RooMsgService::instance().setGlobalKillBelow(msglevel);
00159 
00160   return true;
00161   
00162 }
00163 
00164 //____________________________________________________________________
00165 RooArgSet* LikelihoodInterval::GetParameters() const
00166 {  
00167   // returns list of parameters
00168    return new RooArgSet(fParameters); 
00169 }
00170 
00171 //____________________________________________________________________
00172 Bool_t LikelihoodInterval::CheckParameters(const RooArgSet &parameterPoint) const
00173 {  
00174   // check that the parameters are correct
00175 
00176   if (parameterPoint.getSize() != fParameters.getSize() ) {
00177     std::cout << "size is wrong, parameters don't match" << std::endl;
00178     return false;
00179   }
00180   if ( ! parameterPoint.equals( fParameters ) ) {
00181     std::cout << "size is ok, but parameters don't match" << std::endl;
00182     return false;
00183   }
00184   return true;
00185 }
00186 
00187 
00188 
00189 //____________________________________________________________________
00190 Double_t LikelihoodInterval::LowerLimit(const RooRealVar& param, bool & status) 
00191 {  
00192    // Compute lower limit, check first if limit has been computed 
00193    // status is a boolean flag which will b set to false in case of error
00194    // and is true if calculation is succesfull
00195    // in case of error return also a lower limit value of zero
00196 
00197    double lower = 0; 
00198    double upper = 0; 
00199    status = FindLimits(param, lower, upper); 
00200    return lower; 
00201 }
00202 
00203 //____________________________________________________________________
00204 Double_t LikelihoodInterval::UpperLimit(const RooRealVar& param, bool & status) 
00205 {  
00206    // Compute upper limit, check first if limit has been computed 
00207    // status is a boolean flag which will b set to false in case of error
00208    // and is true if calculation is succesfull
00209    // in case of error return also a lower limit value of zero
00210 
00211    double lower = 0; 
00212    double upper = 0; 
00213    status = FindLimits(param, lower, upper); 
00214    return upper; 
00215 }
00216 
00217 
00218 void LikelihoodInterval::ResetLimits() { 
00219    // reset map with cached limits - called every time the test size or CL has been changed
00220    fLowerLimits.clear(); 
00221    fUpperLimits.clear(); 
00222 }
00223 
00224 
00225 bool LikelihoodInterval::CreateMinimizer() { 
00226    // internal function to create minimizer object needed to find contours or interval limits
00227    // (running MINOS). 
00228    // Minimizer must be Minuit or Minuit2
00229 
00230    RooProfileLL * profilell = dynamic_cast<RooProfileLL*>(fLikelihoodRatio);
00231    if (!profilell) return false; 
00232 
00233    RooAbsReal & nll  = profilell->nll(); 
00234    // bind the nll function in the right interface for the Minimizer class 
00235    // as a function of only the parameters (poi + nuisance parameters) 
00236 
00237    RooArgSet * partmp = profilell->getVariables();
00238    // need to remove constant parameters
00239    RemoveConstantParameters(partmp);
00240 
00241    RooArgList params(*partmp);
00242    delete partmp;
00243 
00244    // need to restore values and errors for POI
00245    if (fBestFitParams) { 
00246       for (int i = 0; i < params.getSize(); ++i) { 
00247          RooRealVar & par =  (RooRealVar &) params[i];
00248          RooRealVar * fitPar =  (RooRealVar *) (fBestFitParams->find(par.GetName() ) );
00249          if (fitPar) {
00250             par.setVal( fitPar->getVal() );
00251             par.setError( fitPar->getError() );
00252          }
00253       }
00254    }
00255 
00256    // now do binding of NLL with a functor for Minimizer 
00257    fFunctor = std::auto_ptr<RooFunctor>(new RooFunctor(nll, RooArgSet(), params )); 
00258 
00259    std::string minimType =  ROOT::Math::MinimizerOptions::DefaultMinimizerType();
00260 
00261    if (minimType != "Minuit" && minimType != "Minuit2") { 
00262       ccoutE(InputArguments) << minimType << "is wrong type of minimizer for getting interval limits or contours - must use Minuit or Minuit2" << std::endl;
00263       return false; 
00264    }
00265    // create minimizer class 
00266    fMinimizer = std::auto_ptr<ROOT::Math::Minimizer>(ROOT::Math::Factory::CreateMinimizer(minimType, "Migrad"));
00267 
00268    if (!fMinimizer.get()) return false;
00269 
00270    fMinFunc = std::auto_ptr<ROOT::Math::IMultiGenFunction>( new ROOT::Math::WrappedMultiFunction<RooFunctor &> (*fFunctor, fFunctor->nPar() ) );  
00271    fMinimizer->SetFunction(*fMinFunc); 
00272 
00273    // set minimizer parameters 
00274    assert( params.getSize() == int(fMinFunc->NDim()) ); 
00275 
00276    for (unsigned int i = 0; i < fMinFunc->NDim(); ++i) { 
00277       RooRealVar & v = (RooRealVar &) params[i]; 
00278       fMinimizer->SetLimitedVariable( i, v.GetName(), v.getVal(), v.getError(), v.getMin(), v.getMax() ); 
00279    }
00280    // for finding the contour need to find first global minimum
00281    bool iret = fMinimizer->Minimize();
00282    if (!iret || fMinimizer->X() == 0) { 
00283       ccoutE(Minimization) << "Error: Minimization failed  " << std::endl;
00284       return false; 
00285    }
00286 
00287    //std::cout << "print minimizer result..........." << std::endl;
00288    //fMinimizer->PrintResults();
00289 
00290    return true; 
00291 }
00292 
00293 bool LikelihoodInterval::FindLimits(const RooRealVar & param, double &lower, double & upper) 
00294 {
00295    // Method to find both lower and upper limits using MINOS
00296    // If cached values exist (limits have been already found) return them in that case
00297    // check first if limit has been computed 
00298    // otherwise compute limit using MINOS
00299    // in case of failure lower and upper will mantain previous value (will not be modified)
00300 
00301    std::map<std::string, double>::const_iterator itrl = fLowerLimits.find(param.GetName());
00302    std::map<std::string, double>::const_iterator itru = fUpperLimits.find(param.GetName());
00303    if ( itrl != fLowerLimits.end() && itru != fUpperLimits.end() ) { 
00304       lower = itrl->second;
00305       upper = itru->second; 
00306       return true; 
00307    }
00308       
00309 
00310    RooArgSet * partmp = fLikelihoodRatio->getVariables();
00311    RemoveConstantParameters(partmp);
00312    RooArgList params(*partmp);
00313    delete partmp;
00314    int ix = params.index(&param); 
00315    if (ix < 0 ) { 
00316       ccoutE(InputArguments) << "Error - invalid parameter " << param.GetName() << " specified for finding the interval limits " << std::endl;
00317       return false; 
00318    }
00319 
00320    bool ret = true;
00321    if (!fMinimizer.get()) ret = CreateMinimizer(); 
00322    if (!ret) { 
00323       ccoutE(Eval) << "Error returned from minimization of likelihood function - cannot find interval limits " << std::endl;
00324       return false; 
00325    }
00326 
00327    assert(fMinimizer.get());
00328         
00329    // getting a 1D interval so ndf = 1
00330    double err_level = TMath::ChisquareQuantile(ConfidenceLevel(),1); // level for -2log LR
00331    err_level = err_level/2; // since we are using -log LR
00332    fMinimizer->SetErrorDef(err_level);
00333    
00334    unsigned int ivarX = ix; 
00335 
00336    double elow = 0; 
00337    double eup = 0;
00338    ret = fMinimizer->GetMinosError(ivarX, elow, eup );
00339    if (!ret)  {
00340       ccoutE(Minimization) << "Error  running Minos for parameter " << param.GetName() << std::endl;
00341       return false; 
00342    }
00343 
00344    // WHEN error is zero normally is at limit
00345    if (elow == 0) { 
00346       lower = param.getMin();
00347       ccoutW(Minimization) << "Warning: lower value for " << param.GetName() << " is at limit " << lower << std::endl; 
00348    }
00349    else 
00350       lower = fMinimizer->X()[ivarX] + elow;  // elow is negative 
00351 
00352    if (eup == 0) { 
00353       ccoutW(Minimization) << "Warning: upper value for " << param.GetName() << " is at limit " << upper << std::endl; 
00354       upper = param.getMax();
00355    }
00356    else 
00357       upper = fMinimizer->X()[ivarX] + eup;
00358 
00359    // store limits in the map 
00360    // minos return error limit = minValue +/- error
00361    fLowerLimits[param.GetName()] = lower; 
00362    fUpperLimits[param.GetName()] = upper; 
00363       
00364    return true; 
00365 }
00366 
00367 
00368 Int_t LikelihoodInterval::GetContourPoints(const RooRealVar & paramX, const RooRealVar & paramY, Double_t * x, Double_t *y, Int_t npoints ) { 
00369    // use Minuit to find the contour of the likelihood function at the desired CL 
00370 
00371    // check the parameters 
00372    // variable index in minimizer
00373    // is index in the RooArgList obtained from the profileLL variables
00374    RooArgSet * partmp = fLikelihoodRatio->getVariables();
00375    RemoveConstantParameters(partmp);
00376    RooArgList params(*partmp);
00377    delete partmp;
00378    int ix = params.index(&paramX); 
00379    int iy = params.index(&paramY); 
00380    if (ix < 0 || iy < 0) { 
00381       ccoutE(InputArguments) << "Error - invalid parameters specified for finding the contours; parX = " << paramX.GetName() 
00382              << " parY = " << paramY.GetName() << std::endl;
00383          return 0; 
00384    }
00385 
00386    bool ret = true; 
00387    if (!fMinimizer.get()) ret = CreateMinimizer(); 
00388    if (!ret) { 
00389       ccoutE(Eval) << "Error returned creating minimizer for likelihood function - cannot find contour points " << std::endl;
00390       return 0; 
00391    }
00392 
00393    assert(fMinimizer.get());
00394         
00395    // getting a 2D contour so ndf = 2
00396    double cont_level = TMath::ChisquareQuantile(ConfidenceLevel(),2); // level for -2log LR
00397    cont_level = cont_level/2; // since we are using -log LR
00398    fMinimizer->SetErrorDef(cont_level);
00399   
00400    unsigned int ncp = npoints; 
00401    unsigned int ivarX = ix; 
00402    unsigned int ivarY = iy; 
00403    ret = fMinimizer->Contour(ivarX, ivarY, ncp, x, y );
00404    if (!ret) { 
00405       ccoutE(Minimization) << "Error finding contour for parameters " << paramX.GetName() << " and " << paramY.GetName()  << std::endl;
00406       return 0; 
00407    }
00408    if (int(ncp) < npoints) {
00409       ccoutW(Minimization) << "Warning - Less points calculated in contours np = " << ncp << " / " << npoints << std::endl;
00410    }
00411 
00412    return ncp;
00413  }

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