Logo ROOT  
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 const auto& config = GetGlobalRooStatsConfig();
257
258 // now do binding of NLL with a functor for Minimizer
259 if (config.useLikelihoodOffset) {
260 ccoutI(InputArguments) << "LikelihoodInterval: using nll offset - set all RooAbsReal to hide the offset " << std::endl;
261 RooAbsReal::setHideOffset(kFALSE); // need to keep this false
262 }
263 fFunctor = std::make_shared<RooFunctor>(nll, RooArgSet(), params);
264
266 std::transform(minimType.begin(), minimType.end(), minimType.begin(), (int(*)(int)) tolower );
267 *minimType.begin() = toupper( *minimType.begin());
268
269 if (minimType != "Minuit" && minimType != "Minuit2") {
270 ccoutE(InputArguments) << minimType << " is wrong type of minimizer for getting interval limits or contours - must use Minuit or Minuit2" << std::endl;
271 return false;
272 }
273 // do not use static instance of TMInuit which could interfere with RooFit
274 if (minimType == "Minuit") TMinuitMinimizer::UseStaticMinuit(false);
275 // create minimizer class
276 fMinimizer = std::shared_ptr<ROOT::Math::Minimizer>(ROOT::Math::Factory::CreateMinimizer(minimType, "Migrad"));
277
278 if (!fMinimizer.get()) return false;
279
280 fMinFunc = std::static_pointer_cast<ROOT::Math::IMultiGenFunction>(
282 fMinimizer->SetFunction(*fMinFunc);
283
284 // set minimizer parameters
285 assert( params.getSize() == int(fMinFunc->NDim()) );
286
287 for (unsigned int i = 0; i < fMinFunc->NDim(); ++i) {
288 RooRealVar & v = (RooRealVar &) params[i];
289 fMinimizer->SetLimitedVariable( i, v.GetName(), v.getVal(), v.getError(), v.getMin(), v.getMax() );
290 }
291 // for finding the contour need to find first global minimum
292 bool iret = fMinimizer->Minimize();
293 if (!iret || fMinimizer->X() == 0) {
294 ccoutE(Minimization) << "Error: Minimization failed " << std::endl;
295 return false;
296 }
297
298 //std::cout << "print minimizer result..........." << std::endl;
299 //fMinimizer->PrintResults();
300
301 return true;
302}
303
304bool LikelihoodInterval::FindLimits(const RooRealVar & param, double &lower, double & upper)
305{
306 // Method to find both lower and upper limits using MINOS
307 // If cached values exist (limits have been already found) return them in that case
308 // check first if limit has been computed
309 // otherwise compute limit using MINOS
310 // in case of failure lower and upper will maintain previous value (will not be modified)
311
312 std::map<std::string, double>::const_iterator itrl = fLowerLimits.find(param.GetName());
313 std::map<std::string, double>::const_iterator itru = fUpperLimits.find(param.GetName());
314 if ( itrl != fLowerLimits.end() && itru != fUpperLimits.end() ) {
315 lower = itrl->second;
316 upper = itru->second;
317 return true;
318 }
319
320
323 RooArgList params(*partmp);
324 delete partmp;
325 int ix = params.index(&param);
326 if (ix < 0 ) {
327 ccoutE(InputArguments) << "Error - invalid parameter " << param.GetName() << " specified for finding the interval limits " << std::endl;
328 return false;
329 }
330
331 bool ret = true;
332 if (!fMinimizer.get()) ret = CreateMinimizer();
333 if (!ret) {
334 ccoutE(Eval) << "Error returned from minimization of likelihood function - cannot find interval limits " << std::endl;
335 return false;
336 }
337
338 assert(fMinimizer.get());
339
340 // getting a 1D interval so ndf = 1
341 double err_level = TMath::ChisquareQuantile(ConfidenceLevel(),1); // level for -2log LR
342 err_level = err_level/2; // since we are using -log LR
343 fMinimizer->SetErrorDef(err_level);
344
345 unsigned int ivarX = ix;
346
347 double elow = 0;
348 double eup = 0;
349 ret = fMinimizer->GetMinosError(ivarX, elow, eup );
350 if (!ret) {
351 ccoutE(Minimization) << "Error running Minos for parameter " << param.GetName() << std::endl;
352 return false;
353 }
354
355 // WHEN error is zero normally is at limit
356 if (elow == 0) {
357 lower = param.getMin();
358 ccoutW(Minimization) << "Warning: lower value for " << param.GetName() << " is at limit " << lower << std::endl;
359 }
360 else
361 lower = fMinimizer->X()[ivarX] + elow; // elow is negative
362
363 if (eup == 0) {
364 ccoutW(Minimization) << "Warning: upper value for " << param.GetName() << " is at limit " << upper << std::endl;
365 upper = param.getMax();
366 }
367 else
368 upper = fMinimizer->X()[ivarX] + eup;
369
370 // store limits in the map
371 // minos return error limit = minValue +/- error
372 fLowerLimits[param.GetName()] = lower;
373 fUpperLimits[param.GetName()] = upper;
374
375 return true;
376}
377
378
380 // use Minuit to find the contour of the likelihood function at the desired CL
381
382 // check the parameters
383 // variable index in minimizer
384 // is index in the RooArgList obtained from the profileLL variables
387 RooArgList params(*partmp);
388 delete partmp;
389 int ix = params.index(&paramX);
390 int iy = params.index(&paramY);
391 if (ix < 0 || iy < 0) {
392 coutE(InputArguments) << "LikelihoodInterval - Error - invalid parameters specified for finding the contours; parX = " << paramX.GetName()
393 << " parY = " << paramY.GetName() << std::endl;
394 return 0;
395 }
396
397 bool ret = true;
398 if (!fMinimizer.get()) ret = CreateMinimizer();
399 if (!ret) {
400 coutE(Eval) << "LikelihoodInterval - Error returned creating minimizer for likelihood function - cannot find contour points " << std::endl;
401 return 0;
402 }
403
404 assert(fMinimizer.get());
405
406 // getting a 2D contour so ndf = 2
407 double cont_level = TMath::ChisquareQuantile(ConfidenceLevel(),2); // level for -2log LR
408 cont_level = cont_level/2; // since we are using -log LR
409 fMinimizer->SetErrorDef(cont_level);
410
411 unsigned int ncp = npoints;
412 unsigned int ivarX = ix;
413 unsigned int ivarY = iy;
414 coutI(Minimization) << "LikelihoodInterval - Finding the contour of " << paramX.GetName() << " ( " << ivarX << " ) and " << paramY.GetName() << " ( " << ivarY << " ) " << std::endl;
415 ret = fMinimizer->Contour(ivarX, ivarY, ncp, x, y );
416 if (!ret) {
417 coutE(Minimization) << "LikelihoodInterval - Error finding contour for parameters " << paramX.GetName() << " and " << paramY.GetName() << std::endl;
418 return 0;
419 }
420 if (int(ncp) < npoints) {
421 coutW(Minimization) << "LikelihoodInterval -Warning - Less points calculated in contours np = " << ncp << " / " << npoints << std::endl;
422 }
423
424 return ncp;
425 }
#define coutI(a)
Definition: RooMsgService.h:31
#define ccoutE(a)
Definition: RooMsgService.h:42
#define coutW(a)
Definition: RooMsgService.h:33
#define coutE(a)
Definition: RooMsgService.h:34
#define ccoutW(a)
Definition: RooMsgService.h:41
#define ccoutI(a)
Definition: RooMsgService.h:39
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:1917
Int_t getSize() const
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
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:59
static void setHideOffset(Bool_t flag)
Definition: RooAbsReal.cxx:117
Double_t getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:87
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgList.h:21
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 variable that can be changed from the outside.
Definition: RooRealVar.h:35
void setError(Double_t value)
Definition: RooRealVar.h:58
Double_t getError() const
Definition: RooRealVar.h:56
virtual void setVal(Double_t value)
Set value of variable to 'value'.
Definition: RooRealVar.cxx:278
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
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
Definition: RooGlobalFunc.h:65
@ Minimization
Definition: RooGlobalFunc.h:67
@ InputArguments
Definition: RooGlobalFunc.h:68
Namespace for the RooStats classes.
Definition: Asimov.h:20
void SetParameters(const RooArgSet *desiredVals, RooArgSet *paramsToChange)
Definition: RooStatsUtils.h:64
void RemoveConstantParameters(RooArgSet *set)
Definition: RooStatsUtils.h:68
RooStatsConfig & GetGlobalRooStatsConfig()
Retrieve the config object which can be used to set flags for things like offsetting the likelihood o...
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