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 std::cout << "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 std::cout << "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 std::cout << "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 std::cout << "size is wrong, parameters don't match" << std::endl;
169 return false;
170 }
171 if ( ! parameterPoint.equals( fParameters ) ) {
172 std::cout << "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 (std::size_t i = 0; i < params.size(); ++i) {
237 RooRealVar & par = static_cast<RooRealVar &>( params[i]);
238 RooRealVar * fitPar = static_cast<RooRealVar *> (fBestFitParams->find(par.GetName() ) );
239 if (fitPar) {
240 par.setVal( fitPar->getVal() );
241 par.setError( fitPar->getError() );
242 }
243 }
244 }
245
246 const auto& config = GetGlobalRooStatsConfig();
247
248 // now do binding of NLL with a functor for Minimizer
249 if (config.useLikelihoodOffset == "initial") {
250 ccoutI(InputArguments) << "LikelihoodInterval: using nll offset \"initial\" - set all RooAbsReal to hide the offset " << std::endl;
251 RooAbsReal::setHideOffset(false); // need to keep this false
252 }
253 fFunctor = std::make_shared<RooFunctor>(nll, RooArgSet(), params);
254
256 std::transform(minimType.begin(), minimType.end(), minimType.begin(), (int(*)(int)) tolower );
258
259 if (minimType != "Minuit" && minimType != "Minuit2") {
260 ccoutE(InputArguments) << minimType << " is wrong type of minimizer for getting interval limits or contours - must use Minuit or Minuit2" << std::endl;
261 return false;
262 }
263 // do not use static instance of TMInuit which could interfere with RooFit
264 if (minimType == "Minuit") TMinuitMinimizer::UseStaticMinuit(false);
265 // create minimizer class
266 fMinimizer = std::shared_ptr<ROOT::Math::Minimizer>(ROOT::Math::Factory::CreateMinimizer(minimType, "Migrad"));
267
268 if (!fMinimizer.get()) return false;
269
270 fMinFunc = std::static_pointer_cast<ROOT::Math::IMultiGenFunction>(
272 fMinimizer->SetFunction(*fMinFunc);
273
274 // set minimizer parameters
275 assert(params.size() == fMinFunc->NDim());
276
277 for (unsigned int i = 0; i < fMinFunc->NDim(); ++i) {
278 RooRealVar & v = static_cast<RooRealVar &>( params[i]);
279 fMinimizer->SetLimitedVariable( i, v.GetName(), v.getVal(), v.getError(), v.getMin(), v.getMax() );
280 }
281 // for finding the contour need to find first global minimum
282 bool iret = fMinimizer->Minimize();
283 if (!iret || fMinimizer->X() == nullptr) {
284 ccoutE(Minimization) << "Error: Minimization failed " << std::endl;
285 return false;
286 }
287
288 //std::cout << "print minimizer result..........." << std::endl;
289 //fMinimizer->PrintResults();
290
291 return true;
292}
293
294bool LikelihoodInterval::FindLimits(const RooRealVar & param, double &lower, double & upper)
295{
296 // Method to find both lower and upper limits using MINOS
297 // If cached values exist (limits have been already found) return them in that case
298 // check first if limit has been computed
299 // otherwise compute limit using MINOS
300 // in case of failure lower and upper will maintain previous value (will not be modified)
301
302 std::map<std::string, double>::const_iterator itrl = fLowerLimits.find(param.GetName());
303 std::map<std::string, double>::const_iterator itru = fUpperLimits.find(param.GetName());
304 if ( itrl != fLowerLimits.end() && itru != fUpperLimits.end() ) {
305 lower = itrl->second;
306 upper = itru->second;
307 return true;
308 }
309
310
311 std::unique_ptr<RooArgSet> partmp{fLikelihoodRatio->getVariables()};
313 RooArgList params(*partmp);
314 int iX = params.index(&param);
315 if (iX < 0 ) {
316 ccoutE(InputArguments) << "Error - invalid parameter " << param.GetName() << " specified for finding the interval limits " << std::endl;
317 return false;
318 }
319
320 bool ret = true;
321 if (!fMinimizer.get()) ret = CreateMinimizer();
322 if (!ret) {
323 ccoutE(Eval) << "Error returned from minimization of likelihood function - cannot find interval limits " << std::endl;
324 return false;
325 }
326
327 assert(fMinimizer.get());
328
329 // getting a 1D interval so ndf = 1
330 double err_level = TMath::ChisquareQuantile(ConfidenceLevel(),1); // level for -2log LR
331 err_level = err_level/2; // since we are using -log LR
332 fMinimizer->SetErrorDef(err_level);
333
334 unsigned int ivarX = iX;
335
336 double elow = 0;
337 double eup = 0;
338 ret = fMinimizer->GetMinosError(ivarX, elow, eup );
339
340 // WHEN error is zero normally is at limit
341 if (elow == 0) {
342 lower = param.getMin();
343 ccoutW(Minimization) << "Warning: lower value for " << param.GetName() << " is at limit " << lower << std::endl;
344 }
345 else
346 lower = fMinimizer->X()[ivarX] + elow; // elow is negative
347
348 if (eup == 0) {
349 ccoutW(Minimization) << "Warning: upper value for " << param.GetName() << " is at limit " << upper << std::endl;
350 upper = param.getMax();
351 }
352 else
353 upper = fMinimizer->X()[ivarX] + eup;
354
355 // store limits in the map
356 // minos return error limit = minValue +/- error
357 fLowerLimits[param.GetName()] = lower;
358 fUpperLimits[param.GetName()] = upper;
359
360 return true;
361}
362
363
365 // use Minuit to find the contour of the likelihood function at the desired CL
366
367 // check the parameters
368 // variable index in minimizer
369 // is index in the RooArgList obtained from the profileLL variables
370 std::unique_ptr<RooArgSet> partmp{fLikelihoodRatio->getVariables()};
372 RooArgList params(*partmp);
373 int iX = params.index(&paramX);
374 int iY = params.index(&paramY);
375 if (iX < 0 || iY < 0) {
376 coutE(InputArguments) << "LikelihoodInterval - Error - invalid parameters specified for finding the contours; parX = " << paramX.GetName()
377 << " parY = " << paramY.GetName() << std::endl;
378 return 0;
379 }
380
381 bool ret = true;
382 if (!fMinimizer.get()) ret = CreateMinimizer();
383 if (!ret) {
384 coutE(Eval) << "LikelihoodInterval - Error returned creating minimizer for likelihood function - cannot find contour points " << std::endl;
385 return 0;
386 }
387
388 assert(fMinimizer.get());
389
390 // getting a 2D contour so ndf = 2
391 double cont_level = TMath::ChisquareQuantile(ConfidenceLevel(),2); // level for -2log LR
392 cont_level = cont_level/2; // since we are using -log LR
393 fMinimizer->SetErrorDef(cont_level);
394
395 unsigned int ncp = npoints;
396 unsigned int ivarX = iX;
397 unsigned int ivarY = iY;
398 coutI(Minimization) << "LikelihoodInterval - Finding the contour of " << paramX.GetName() << " ( " << ivarX << " ) and " << paramY.GetName() << " ( " << ivarY << " ) " << std::endl;
399 ret = fMinimizer->Contour(ivarX, ivarY, ncp, x, y );
400 if (!ret) {
401 coutE(Minimization) << "LikelihoodInterval - Error finding contour for parameters " << paramX.GetName() << " and " << paramY.GetName() << std::endl;
402 return 0;
403 }
404 if (int(ncp) < npoints) {
405 coutW(Minimization) << "LikelihoodInterval -Warning - Less points calculated in contours np = " << ncp << " / " << npoints << std::endl;
406 }
407
408 return ncp;
409 }
#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:110
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:59
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
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'.
void setError(double value)
Definition RooRealVar.h:60
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:58
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:2193