Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 <cctype> // need to use c version of toupper defined here
67
68
69
70using namespace RooStats;
71
72
73////////////////////////////////////////////////////////////////////////////////
74/// Default constructor with name and title
75
77 ConfInterval(name), fBestFitParams(nullptr), fLikelihoodRatio(nullptr), fConfidenceLevel(0.95)
78{
79}
80
81////////////////////////////////////////////////////////////////////////////////
82/// Alternate constructor taking a pointer to the profile likelihood ratio, parameter of interest and
83/// optionally a snapshot of best parameter of interest for interval
84
87 fParameters(*params),
88 fBestFitParams(bestParams),
89 fLikelihoodRatio(lr),
90 fConfidenceLevel(0.95)
91{
92}
93
94
95////////////////////////////////////////////////////////////////////////////////
96/// Destructor
97
103
104
105////////////////////////////////////////////////////////////////////////////////
106/// This is the main method to satisfy the RooStats::ConfInterval interface.
107/// It returns true if the parameter point is in the interval.
108
110{
112 RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
113 // Method to determine if a parameter point is in the interval
114 if( !this->CheckParameters(parameterPoint) ) {
115 coutE(InputArguments) << "parameters don't match" << std::endl;
116 RooMsgService::instance().setGlobalKillBelow(msglevel);
117 return false;
118 }
119
120 // make sure likelihood ratio is set
121 if(!fLikelihoodRatio) {
122 coutE(Eval) << "likelihood ratio not set" << std::endl;
123 RooMsgService::instance().setGlobalKillBelow(msglevel);
124 return false;
125 }
126
127
128
129 // set parameters
130 SetParameters(&parameterPoint, std::unique_ptr<RooArgSet>{fLikelihoodRatio->getVariables()}.get());
131
132
133 // evaluate likelihood ratio, see if it's bigger than threshold
134 if (fLikelihoodRatio->getVal()<0){
135 coutW(Eval) << "The likelihood ratio is < 0, indicates a bad minimum or numerical precision problems. Will return true" << std::endl;
136 RooMsgService::instance().setGlobalKillBelow(msglevel);
137 return true;
138 }
139
140
141 // here we use Wilks' theorem.
143 RooMsgService::instance().setGlobalKillBelow(msglevel);
144 return false;
145 }
146
147
148 RooMsgService::instance().setGlobalKillBelow(msglevel);
149
150 return true;
151
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// returns list of parameters
156
161
162////////////////////////////////////////////////////////////////////////////////
163/// check that the parameters are correct
164
166{
167 if (parameterPoint.size() != fParameters.size() ) {
168 coutE(InputArguments) << "size is wrong, parameters don't match" << std::endl;
169 return false;
170 }
171 if ( ! parameterPoint.equals( fParameters ) ) {
172 coutE(InputArguments) << "size is ok, but parameters don't match" << std::endl;
173 return false;
174 }
175 return true;
176}
177
178
179
180////////////////////////////////////////////////////////////////////////////////
181/// Compute lower limit, check first if limit has been computed
182/// status is a boolean flag which will b set to false in case of error
183/// and is true if calculation is successful
184/// in case of error return also a lower limit value of zero
185
186double LikelihoodInterval::LowerLimit(const RooRealVar& param, bool & status)
187{
188 double lower = 0;
189 double upper = 0;
190 status = FindLimits(param, lower, upper);
191 return lower;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// Compute upper limit, check first if limit has been computed
196/// status is a boolean flag which will b set to false in case of error
197/// and is true if calculation is successful
198/// in case of error return also a lower limit value of zero
199
200double LikelihoodInterval::UpperLimit(const RooRealVar& param, bool & status)
201{
202 double lower = 0;
203 double upper = 0;
204 status = FindLimits(param, lower, upper);
205 return upper;
206}
207
208
210 // reset map with cached limits - called every time the test size or CL has been changed
211 fLowerLimits.clear();
212 fUpperLimits.clear();
213}
214
215
217 // internal function to create minimizer object needed to find contours or interval limits
218 // (running MINOS).
219 // Minimizer must be Minuit or Minuit2
220
222 if (!profilell) return false;
223
224 RooAbsReal & nll = profilell->nll();
225 // bind the nll function in the right interface for the Minimizer class
226 // as a function of only the parameters (poi + nuisance parameters)
227
228 std::unique_ptr<RooArgSet> partmp{profilell->getVariables()};
229 // need to remove constant parameters
231
232 RooArgList params(*partmp);
233
234 // need to restore values and errors for POI
235 if (fBestFitParams) {
236 for (auto *par : static_range_cast<RooRealVar *>(params)) {
237 RooRealVar * fitPar = static_cast<RooRealVar *> (fBestFitParams->find(par->GetName() ) );
238 if (fitPar) {
239 par->setVal( fitPar->getVal() );
240 par->setError( fitPar->getError() );
241 }
242 }
243 }
244
245 const auto& config = GetGlobalRooStatsConfig();
246
247 // now do binding of NLL with a functor for Minimizer
248 if (config.useLikelihoodOffset == "initial") {
249 ccoutI(InputArguments) << "LikelihoodInterval: using nll offset \"initial\" - set all RooAbsReal to hide the offset " << std::endl;
250 RooAbsReal::setHideOffset(false); // need to keep this false
251 }
252 fFunctor = std::make_shared<RooFunctor>(nll, RooArgSet(), params);
253
255 std::transform(minimType.begin(), minimType.end(), minimType.begin(), (int(*)(int)) tolower );
257
258 if (minimType != "Minuit" && minimType != "Minuit2") {
259 ccoutE(InputArguments) << minimType << " is wrong type of minimizer for getting interval limits or contours - must use Minuit or Minuit2" << std::endl;
260 return false;
261 }
262 // do not use static instance of TMInuit which could interfere with RooFit
263 if (minimType == "Minuit") TMinuitMinimizer::UseStaticMinuit(false);
264 // create minimizer class
265 fMinimizer = std::shared_ptr<ROOT::Math::Minimizer>(ROOT::Math::Factory::CreateMinimizer(minimType, "Migrad"));
266
267 if (!fMinimizer.get()) return false;
268
269 fMinFunc = std::static_pointer_cast<ROOT::Math::IMultiGenFunction>(
271 fMinimizer->SetFunction(*fMinFunc);
272
273 // set minimizer parameters
274 assert(params.size() == fMinFunc->NDim());
275
276 for (unsigned int i = 0; i < fMinFunc->NDim(); ++i) {
277 RooRealVar & v = static_cast<RooRealVar &>( params[i]);
278 fMinimizer->SetLimitedVariable( i, v.GetName(), v.getVal(), v.getError(), v.getMin(), v.getMax() );
279 }
280 // for finding the contour need to find first global minimum
281 bool iret = fMinimizer->Minimize();
282 if (!iret || fMinimizer->X() == nullptr) {
283 ccoutE(Minimization) << "Error: Minimization failed " << std::endl;
284 return false;
285 }
286
287 //std::cout << "print minimizer result..........." << std::endl;
288 //fMinimizer->PrintResults();
289
290 return true;
291}
292
293bool LikelihoodInterval::FindLimits(const RooRealVar & param, double &lower, double & upper)
294{
295 // Method to find both lower and upper limits using MINOS
296 // If cached values exist (limits have been already found) return them in that case
297 // check first if limit has been computed
298 // otherwise compute limit using MINOS
299 // in case of failure lower and upper will maintain previous value (will not be modified)
300
301 std::map<std::string, double>::const_iterator itrl = fLowerLimits.find(param.GetName());
302 std::map<std::string, double>::const_iterator itru = fUpperLimits.find(param.GetName());
303 if ( itrl != fLowerLimits.end() && itru != fUpperLimits.end() ) {
304 lower = itrl->second;
305 upper = itru->second;
306 return true;
307 }
308
309
310 std::unique_ptr<RooArgSet> partmp{fLikelihoodRatio->getVariables()};
312 RooArgList params(*partmp);
313 int iX = params.index(&param);
314 if (iX < 0 ) {
315 ccoutE(InputArguments) << "Error - invalid parameter " << param.GetName() << " specified for finding the interval limits " << std::endl;
316 return false;
317 }
318
319 bool ret = true;
320 if (!fMinimizer.get()) ret = CreateMinimizer();
321 if (!ret) {
322 ccoutE(Eval) << "Error returned from minimization of likelihood function - cannot find interval limits " << std::endl;
323 return false;
324 }
325
326 assert(fMinimizer.get());
327
328 // getting a 1D interval so ndf = 1
329 double err_level = TMath::ChisquareQuantile(ConfidenceLevel(),1); // level for -2log LR
330 err_level = err_level/2; // since we are using -log LR
331 fMinimizer->SetErrorDef(err_level);
332
333 unsigned int ivarX = iX;
334
335 double elow = 0;
336 double eup = 0;
337 ret = fMinimizer->GetMinosError(ivarX, elow, eup );
338
339 // WHEN error is zero normally is at limit
340 if (elow == 0) {
341 lower = param.getMin();
342 ccoutW(Minimization) << "Warning: lower value for " << param.GetName() << " is at limit " << lower << std::endl;
343 }
344 else
345 lower = fMinimizer->X()[ivarX] + elow; // elow is negative
346
347 if (eup == 0) {
348 ccoutW(Minimization) << "Warning: upper value for " << param.GetName() << " is at limit " << upper << std::endl;
349 upper = param.getMax();
350 }
351 else
352 upper = fMinimizer->X()[ivarX] + eup;
353
354 // store limits in the map
355 // minos return error limit = minValue +/- error
356 fLowerLimits[param.GetName()] = lower;
357 fUpperLimits[param.GetName()] = upper;
358
359 return true;
360}
361
362
364 // use Minuit to find the contour of the likelihood function at the desired CL
365
366 // check the parameters
367 // variable index in minimizer
368 // is index in the RooArgList obtained from the profileLL variables
369 std::unique_ptr<RooArgSet> partmp{fLikelihoodRatio->getVariables()};
371 RooArgList params(*partmp);
372 int iX = params.index(&paramX);
373 int iY = params.index(&paramY);
374 if (iX < 0 || iY < 0) {
375 coutE(InputArguments) << "LikelihoodInterval - Error - invalid parameters specified for finding the contours; parX = " << paramX.GetName()
376 << " parY = " << paramY.GetName() << std::endl;
377 return 0;
378 }
379
380 bool ret = true;
381 if (!fMinimizer.get()) ret = CreateMinimizer();
382 if (!ret) {
383 coutE(Eval) << "LikelihoodInterval - Error returned creating minimizer for likelihood function - cannot find contour points " << std::endl;
384 return 0;
385 }
386
387 assert(fMinimizer.get());
388
389 // getting a 2D contour so ndf = 2
390 double cont_level = TMath::ChisquareQuantile(ConfidenceLevel(),2); // level for -2log LR
391 cont_level = cont_level/2; // since we are using -log LR
392 fMinimizer->SetErrorDef(cont_level);
393
394 unsigned int ncp = npoints;
395 unsigned int ivarX = iX;
396 unsigned int ivarY = iY;
397 coutI(Minimization) << "LikelihoodInterval - Finding the contour of " << paramX.GetName() << " ( " << ivarX << " ) and " << paramY.GetName() << " ( " << ivarY << " ) " << std::endl;
398 ret = fMinimizer->Contour(ivarX, ivarY, ncp, x, y );
399 if (!ret) {
400 coutE(Minimization) << "LikelihoodInterval - Error finding contour for parameters " << paramX.GetName() << " and " << paramY.GetName() << std::endl;
401 return 0;
402 }
403 if (int(ncp) < npoints) {
404 coutW(Minimization) << "LikelihoodInterval -Warning - Less points calculated in contours np = " << ncp << " / " << npoints << std::endl;
405 }
406
407 return ncp;
408 }
#define coutI(a)
#define ccoutE(a)
#define coutW(a)
#define coutE(a)
#define ccoutW(a)
#define ccoutI(a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
char name[80]
Definition TGX11.cxx:145
static ROOT::Math::Minimizer * CreateMinimizer(const std::string &minimizerType="", const std::string &algoType="")
static method to create the corresponding 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-...
const_iterator begin() const
const_iterator end() const
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
Storage_t::size_type size() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
static void setHideOffset(bool flag)
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
static RooMsgService & instance()
Return reference to singleton instance.
Implements the profile likelihood estimator for a given likelihood and set of parameters of interest.
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
ConfInterval is an interface class for a generic interval in the RooStats framework.
double ConfidenceLevel() const override
return confidence level
double UpperLimit(const RooRealVar &param)
return the upper bound of the interval on a given parameter
Int_t GetContourPoints(const RooRealVar &paramX, const RooRealVar &paramY, double *x, double *y, Int_t npoints=30)
return the 2D-contour points for the given subset of parameters by default make the contour using 30 ...
void ResetLimits()
reset the cached limit values
bool CreateMinimizer()
internal function to create the minimizer for finding the contours
RooArgSet * GetParameters() const override
return a cloned list of parameters of interest. User manages the return object
RooArgSet * fBestFitParams
snapshot of the model parameters with best fit value (managed internally)
RooArgSet fParameters
parameters of interest for this interval
~LikelihoodInterval() override
destructor
double LowerLimit(const RooRealVar &param)
return the lower bound of the interval on a given parameter
std::shared_ptr< RooFunctor > fFunctor
! transient pointer to functor class used by the minimizer
bool 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 fConfidenceLevel
Requested confidence level (eg. 0.95 for 95% CL)
std::map< std::string, double > fLowerLimits
map with cached lower bound values
bool IsInInterval(const RooArgSet &) const override
check if given point is in the interval
bool CheckParameters(const RooArgSet &) const override
check if parameters are correct (i.e. they are the POI of this interval)
RooAbsReal * fLikelihoodRatio
likelihood ratio function used to make contours (managed internally)
std::map< std::string, double > fUpperLimits
map with cached upper bound values
std::shared_ptr< ROOT::Math::Minimizer > fMinimizer
! transient pointer to minimizer class used to find limits and contour
LikelihoodInterval(const char *name=nullptr)
default constructor
std::shared_ptr< ROOT::Math::IMultiGenFunction > fMinFunc
! transient pointer to the minimization function
static bool UseStaticMinuit(bool on=true)
static function to switch on/off usage of static global TMinuit instance (gMinuit) By default it is u...
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
Namespace for the RooStats classes.
Definition CodegenImpl.h:66
void SetParameters(const RooArgSet *desiredVals, RooArgSet *paramsToChange)
void RemoveConstantParameters(RooArgSet *set)
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:637
Double_t ChisquareQuantile(Double_t p, Double_t ndf)
Evaluate the quantiles of the chi-squared probability distribution function.
Definition TMath.cxx:2196