Logo ROOT   6.18/05
Reference Guide
LikelihoodInterval.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
3/*************************************************************************
4 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/*****************************************************************************
12 * Project: RooStats
13 * Package: RooFit/RooStats
14 * @(#)root/roofit/roostats:$Id$
15 * Authors:
16 * Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
17 *
18 *****************************************************************************/
19
20
21/** \class RooStats::LikelihoodInterval
22 \ingroup Roostats
23
24 LikelihoodInterval is a concrete implementation of the RooStats::ConfInterval interface.
25 It implements a connected N-dimensional intervals based on the contour of a likelihood ratio.
26 The boundary of the interval is equivalent to a MINUIT/MINOS contour about the maximum likelihood estimator
27
28 The interval does not need to be an ellipse (eg. it is not the HESSE error matrix).
29 The level used to make the contour is the same as that used in MINOS, eg. it uses Wilks' theorem,
30 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
31 N is the number of parameters of interest.
32
33
34 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'
35 theorem to be true.
36
37 Also note, one can use any RooAbsReal as the function that will be used in the contour; however, the level of the contour
38 is based on Wilks' theorem as stated above.
39
40
41#### References
42
43* 1. F. James., Minuit.Long writeup D506, CERN, 1998.
44
45*/
46
47
50
51#include "RooAbsReal.h"
52#include "RooMsgService.h"
53
55#include "Math/Minimizer.h"
56#include "Math/Factory.h"
58#include "RooFunctor.h"
59#include "RooProfileLL.h"
60
61#include "TMinuitMinimizer.h"
62
63#include <string>
64#include <algorithm>
65#include <functional>
66#include <ctype.h> // need to use c version of toupper defined here
67
68/*
69// for debugging
70#include "RooNLLVar.h"
71#include "RooProfileLL.h"
72#include "RooDataSet.h"
73#include "RooAbsData.h"
74*/
75
77
78using namespace RooStats;
79using namespace std;
80
81
82////////////////////////////////////////////////////////////////////////////////
83/// Default constructor with name and title
84
85LikelihoodInterval::LikelihoodInterval(const char* name) :
86 ConfInterval(name), fBestFitParams(0), fLikelihoodRatio(0), fConfidenceLevel(0.95)
87{
88}
89
90////////////////////////////////////////////////////////////////////////////////
91/// Alternate constructor taking a pointer to the profile likelihood ratio, parameter of interest and
92/// optionally a snapshot of best parameter of interest for interval
93
94LikelihoodInterval::LikelihoodInterval(const char* name, RooAbsReal* lr, const RooArgSet* params, RooArgSet * bestParams) :
96 fParameters(*params),
97 fBestFitParams(bestParams),
98 fLikelihoodRatio(lr),
99 fConfidenceLevel(0.95)
100{
101}
102
103
104////////////////////////////////////////////////////////////////////////////////
105/// Destructor
106
108{
109 if (fBestFitParams) delete fBestFitParams;
111}
112
113
114////////////////////////////////////////////////////////////////////////////////
115/// This is the main method to satisfy the RooStats::ConfInterval interface.
116/// It returns true if the parameter point is in the interval.
117
119{
122 // Method to determine if a parameter point is in the interval
123 if( !this->CheckParameters(parameterPoint) ) {
124 std::cout << "parameters don't match" << std::endl;
126 return false;
127 }
128
129 // make sure likelihood ratio is set
130 if(!fLikelihoodRatio) {
131 std::cout << "likelihood ratio not set" << std::endl;
133 return false;
134 }
135
136
137
138 // set parameters
139 SetParameters(&parameterPoint, fLikelihoodRatio->getVariables() );
140
141
142 // evaluate likelihood ratio, see if it's bigger than threshold
143 if (fLikelihoodRatio->getVal()<0){
144 std::cout << "The likelihood ratio is < 0, indicates a bad minimum or numerical precision problems. Will return true" << std::endl;
146 return true;
147 }
148
149
150 // here we use Wilks' theorem.
151 if ( TMath::Prob( 2* fLikelihoodRatio->getVal(), parameterPoint.getSize()) < (1.-fConfidenceLevel) ){
153 return false;
154 }
155
156
158
159 return true;
160
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// returns list of parameters
165
167{
168 return new RooArgSet(fParameters);
169}
170
171////////////////////////////////////////////////////////////////////////////////
172/// check that the parameters are correct
173
175{
176 if (parameterPoint.getSize() != fParameters.getSize() ) {
177 std::cout << "size is wrong, parameters don't match" << std::endl;
178 return false;
179 }
180 if ( ! parameterPoint.equals( fParameters ) ) {
181 std::cout << "size is ok, but parameters don't match" << std::endl;
182 return false;
183 }
184 return true;
185}
186
187
188
189////////////////////////////////////////////////////////////////////////////////
190/// Compute lower limit, check first if limit has been computed
191/// status is a boolean flag which will b set to false in case of error
192/// and is true if calculation is successful
193/// in case of error return also a lower limit value of zero
194
196{
197 double lower = 0;
198 double upper = 0;
199 status = FindLimits(param, lower, upper);
200 return lower;
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Compute upper limit, check first if limit has been computed
205/// status is a boolean flag which will b set to false in case of error
206/// and is true if calculation is successful
207/// in case of error return also a lower limit value of zero
208
210{
211 double lower = 0;
212 double upper = 0;
213 status = FindLimits(param, lower, upper);
214 return upper;
215}
216
217
219 // reset map with cached limits - called every time the test size or CL has been changed
220 fLowerLimits.clear();
221 fUpperLimits.clear();
222}
223
224
226 // internal function to create minimizer object needed to find contours or interval limits
227 // (running MINOS).
228 // Minimizer must be Minuit or Minuit2
229
230 RooProfileLL * profilell = dynamic_cast<RooProfileLL*>(fLikelihoodRatio);
231 if (!profilell) return false;
232
233 RooAbsReal & nll = profilell->nll();
234 // bind the nll function in the right interface for the Minimizer class
235 // as a function of only the parameters (poi + nuisance parameters)
236
237 RooArgSet * partmp = profilell->getVariables();
238 // need to remove constant parameters
240
241 RooArgList params(*partmp);
242 delete partmp;
243
244 // need to restore values and errors for POI
245 if (fBestFitParams) {
246 for (int i = 0; i < params.getSize(); ++i) {
247 RooRealVar & par = (RooRealVar &) params[i];
248 RooRealVar * fitPar = (RooRealVar *) (fBestFitParams->find(par.GetName() ) );
249 if (fitPar) {
250 par.setVal( fitPar->getVal() );
251 par.setError( fitPar->getError() );
252 }
253 }
254 }
255
256 // now do binding of NLL with a functor for Minimizer
257 if (RooStats::IsNLLOffset() ) {
258 ccoutI(InputArguments) << "LikelihoodInterval: using nll offset - set all RooAbsReal to hide the offset " << std::endl;
259 RooAbsReal::setHideOffset(kFALSE); // need to keep this false
260 }
261 fFunctor = std::make_shared<RooFunctor>(nll, RooArgSet(), params);
262
264 std::transform(minimType.begin(), minimType.end(), minimType.begin(), (int(*)(int)) tolower );
265 *minimType.begin() = toupper( *minimType.begin());
266
267 if (minimType != "Minuit" && minimType != "Minuit2") {
268 ccoutE(InputArguments) << minimType << " is wrong type of minimizer for getting interval limits or contours - must use Minuit or Minuit2" << std::endl;
269 return false;
270 }
271 // do not use static instance of TMInuit which could interfere with RooFit
272 if (minimType == "Minuit") TMinuitMinimizer::UseStaticMinuit(false);
273 // create minimizer class
274 fMinimizer = std::shared_ptr<ROOT::Math::Minimizer>(ROOT::Math::Factory::CreateMinimizer(minimType, "Migrad"));
275
276 if (!fMinimizer.get()) return false;
277
278 fMinFunc = std::static_pointer_cast<ROOT::Math::IMultiGenFunction>(
280 fMinimizer->SetFunction(*fMinFunc);
281
282 // set minimizer parameters
283 assert( params.getSize() == int(fMinFunc->NDim()) );
284
285 for (unsigned int i = 0; i < fMinFunc->NDim(); ++i) {
286 RooRealVar & v = (RooRealVar &) params[i];
287 fMinimizer->SetLimitedVariable( i, v.GetName(), v.getVal(), v.getError(), v.getMin(), v.getMax() );
288 }
289 // for finding the contour need to find first global minimum
290 bool iret = fMinimizer->Minimize();
291 if (!iret || fMinimizer->X() == 0) {
292 ccoutE(Minimization) << "Error: Minimization failed " << std::endl;
293 return false;
294 }
295
296 //std::cout << "print minimizer result..........." << std::endl;
297 //fMinimizer->PrintResults();
298
299 return true;
300}
301
302bool LikelihoodInterval::FindLimits(const RooRealVar & param, double &lower, double & upper)
303{
304 // Method to find both lower and upper limits using MINOS
305 // If cached values exist (limits have been already found) return them in that case
306 // check first if limit has been computed
307 // otherwise compute limit using MINOS
308 // in case of failure lower and upper will maintain previous value (will not be modified)
309
310 std::map<std::string, double>::const_iterator itrl = fLowerLimits.find(param.GetName());
311 std::map<std::string, double>::const_iterator itru = fUpperLimits.find(param.GetName());
312 if ( itrl != fLowerLimits.end() && itru != fUpperLimits.end() ) {
313 lower = itrl->second;
314 upper = itru->second;
315 return true;
316 }
317
318
321 RooArgList params(*partmp);
322 delete partmp;
323 int ix = params.index(&param);
324 if (ix < 0 ) {
325 ccoutE(InputArguments) << "Error - invalid parameter " << param.GetName() << " specified for finding the interval limits " << std::endl;
326 return false;
327 }
328
329 bool ret = true;
330 if (!fMinimizer.get()) ret = CreateMinimizer();
331 if (!ret) {
332 ccoutE(Eval) << "Error returned from minimization of likelihood function - cannot find interval limits " << std::endl;
333 return false;
334 }
335
336 assert(fMinimizer.get());
337
338 // getting a 1D interval so ndf = 1
339 double err_level = TMath::ChisquareQuantile(ConfidenceLevel(),1); // level for -2log LR
340 err_level = err_level/2; // since we are using -log LR
341 fMinimizer->SetErrorDef(err_level);
342
343 unsigned int ivarX = ix;
344
345 double elow = 0;
346 double eup = 0;
347 ret = fMinimizer->GetMinosError(ivarX, elow, eup );
348 if (!ret) {
349 ccoutE(Minimization) << "Error running Minos for parameter " << param.GetName() << std::endl;
350 return false;
351 }
352
353 // WHEN error is zero normally is at limit
354 if (elow == 0) {
355 lower = param.getMin();
356 ccoutW(Minimization) << "Warning: lower value for " << param.GetName() << " is at limit " << lower << std::endl;
357 }
358 else
359 lower = fMinimizer->X()[ivarX] + elow; // elow is negative
360
361 if (eup == 0) {
362 ccoutW(Minimization) << "Warning: upper value for " << param.GetName() << " is at limit " << upper << std::endl;
363 upper = param.getMax();
364 }
365 else
366 upper = fMinimizer->X()[ivarX] + eup;
367
368 // store limits in the map
369 // minos return error limit = minValue +/- error
370 fLowerLimits[param.GetName()] = lower;
371 fUpperLimits[param.GetName()] = upper;
372
373 return true;
374}
375
376
378 // use Minuit to find the contour of the likelihood function at the desired CL
379
380 // check the parameters
381 // variable index in minimizer
382 // is index in the RooArgList obtained from the profileLL variables
385 RooArgList params(*partmp);
386 delete partmp;
387 int ix = params.index(&paramX);
388 int iy = params.index(&paramY);
389 if (ix < 0 || iy < 0) {
390 coutE(InputArguments) << "LikelihoodInterval - Error - invalid parameters specified for finding the contours; parX = " << paramX.GetName()
391 << " parY = " << paramY.GetName() << std::endl;
392 return 0;
393 }
394
395 bool ret = true;
396 if (!fMinimizer.get()) ret = CreateMinimizer();
397 if (!ret) {
398 coutE(Eval) << "LikelihoodInterval - Error returned creating minimizer for likelihood function - cannot find contour points " << std::endl;
399 return 0;
400 }
401
402 assert(fMinimizer.get());
403
404 // getting a 2D contour so ndf = 2
405 double cont_level = TMath::ChisquareQuantile(ConfidenceLevel(),2); // level for -2log LR
406 cont_level = cont_level/2; // since we are using -log LR
407 fMinimizer->SetErrorDef(cont_level);
408
409 unsigned int ncp = npoints;
410 unsigned int ivarX = ix;
411 unsigned int ivarY = iy;
412 coutI(Minimization) << "LikelihoodInterval - Finding the contour of " << paramX.GetName() << " ( " << ivarX << " ) and " << paramY.GetName() << " ( " << ivarY << " ) " << std::endl;
413 ret = fMinimizer->Contour(ivarX, ivarY, ncp, x, y );
414 if (!ret) {
415 coutE(Minimization) << "LikelihoodInterval - Error finding contour for parameters " << paramX.GetName() << " and " << paramY.GetName() << std::endl;
416 return 0;
417 }
418 if (int(ncp) < npoints) {
419 coutW(Minimization) << "LikelihoodInterval -Warning - Less points calculated in contours np = " << ncp << " / " << npoints << std::endl;
420 }
421
422 return ncp;
423 }
SVector< double, 2 > v
Definition: Dict.h:5
#define coutI(a)
Definition: RooMsgService.h:31
#define ccoutE(a)
Definition: RooMsgService.h:41
#define coutW(a)
Definition: RooMsgService.h:33
#define coutE(a)
Definition: RooMsgService.h:34
#define ccoutW(a)
Definition: RooMsgService.h:40
#define ccoutI(a)
Definition: RooMsgService.h:38
int Int_t
Definition: RtypesCore.h:41
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
#define ClassImp(name)
Definition: Rtypes.h:365
char name[80]
Definition: TGX11.cxx:109
static ROOT::Math::Minimizer * CreateMinimizer(const std::string &minimizerType="", const std::string &algoType="")
static method to create the corrisponding Minimizer given the string Supported Minimizers types are: ...
Definition: Factory.cxx:63
static const std::string & DefaultMinimizerType()
Template class to wrap any C++ callable object implementing operator() (const double * x) in a multi-...
RooArgSet * getVariables(Bool_t stripDisconnected=kTRUE) const
Return RooArgSet with all variables (tree leaf nodes of expresssion tree)
Definition: RooAbsArg.cxx:2034
Int_t getSize() const
Bool_t equals(const RooAbsCollection &otherColl) const
Check if this and other collection have identically-named contents.
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual Double_t getMax(const char *name=0) const
Get maximum of currently defined range.
virtual Double_t getMin(const char *name=0) const
Get miniminum of currently defined range.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:53
static void setHideOffset(Bool_t flag)
Definition: RooAbsReal.cxx:117
Double_t getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:81
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgList.h:21
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in list.
Definition: RooArgList.h:73
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:28
static RooMsgService & instance()
Return reference to singleton instance.
void setGlobalKillBelow(RooFit::MsgLevel level)
RooFit::MsgLevel globalKillBelow() const
Class RooProfileLL implements the profile likelihood estimator for a given likelihood and set of para...
Definition: RooProfileLL.h:26
RooAbsReal & nll()
Definition: RooProfileLL.h:39
RooRealVar represents a fundamental (non-derived) real valued object.
Definition: RooRealVar.h:36
void setError(Double_t value)
Definition: RooRealVar.h:56
Double_t getError() const
Definition: RooRealVar.h:54
virtual void setVal(Double_t value)
Set value of variable to 'value'.
Definition: RooRealVar.cxx:233
ConfInterval is an interface class for a generic interval in the RooStats framework.
Definition: ConfInterval.h:35
LikelihoodInterval is a concrete implementation of the RooStats::ConfInterval interface.
virtual RooArgSet * GetParameters() const
return a cloned list of parameters of interest. User manages the return object
Double_t LowerLimit(const RooRealVar &param)
return the lower bound of the interval on a given parameter
void ResetLimits()
reset the cached limit values
bool CreateMinimizer()
internal function to create the minimizer for finding the contours
Int_t GetContourPoints(const RooRealVar &paramX, const RooRealVar &paramY, Double_t *x, Double_t *y, Int_t npoints=30)
return the 2D-contour points for the given subset of parameters by default make the contour using 30 ...
Bool_t CheckParameters(const RooArgSet &) const
check if parameters are correct (i.e. they are the POI of this interval)
Double_t fConfidenceLevel
likelihood ratio function used to make contours (managed internally)
RooArgSet * fBestFitParams
parameters of interest for this interval
virtual Double_t ConfidenceLevel() const
return confidence level
std::shared_ptr< RooFunctor > fFunctor
transient pointer to minimizer class used to find limits and contour
Bool_t FindLimits(const RooRealVar &param, double &lower, double &upper)
find both lower and upper interval boundaries for a given parameter return false if the bounds have n...
Double_t UpperLimit(const RooRealVar &param)
return the upper bound of the interval on a given parameter
std::map< std::string, double > fLowerLimits
Requested confidence level (eg. 0.95 for 95% CL)
LikelihoodInterval(const char *name=0)
default constructor
RooAbsReal * fLikelihoodRatio
snapshot of the model parameters with best fit value (managed internally)
std::map< std::string, double > fUpperLimits
map with cached lower bound values
std::shared_ptr< ROOT::Math::Minimizer > fMinimizer
map with cached upper bound values
virtual ~LikelihoodInterval()
destructor
virtual Bool_t IsInInterval(const RooArgSet &) const
check if given point is in the interval
std::shared_ptr< ROOT::Math::IMultiGenFunction > fMinFunc
transient pointer to functor class used by the minimizer
static bool UseStaticMinuit(bool on=true)
static function to switch on/off usage of static global TMinuit instance (gMinuit) By default it is u...
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
@ Minimization
Definition: RooGlobalFunc.h:57
@ InputArguments
Definition: RooGlobalFunc.h:58
Namespace for the RooStats classes.
Definition: Asimov.h:20
void SetParameters(const RooArgSet *desiredVals, RooArgSet *paramsToChange)
Definition: RooStatsUtils.h:58
void RemoveConstantParameters(RooArgSet *set)
Definition: RooStatsUtils.h:62
bool IsNLLOffset()
Double_t Prob(Double_t chi2, Int_t ndf)
Computation of the probability for a certain Chi-squared (chi2) and number of degrees of freedom (ndf...
Definition: TMath.cxx:621
Double_t ChisquareQuantile(Double_t p, Double_t ndf)
Evaluate the quantiles of the chi-squared probability distribution function.
Definition: TMath.cxx:2164