Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
BayesianCalculator.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/** \class RooStats::BayesianCalculator
13 \ingroup Roostats
14
15BayesianCalculator is a concrete implementation of IntervalCalculator, providing the computation
16of a credible interval using a Bayesian method.
17The class works only for one single parameter of interest and it integrates the likelihood function with the given prior
18probability density function to compute the posterior probability. The result of the class is a one dimensional interval
19(class SimpleInterval ), which is obtained from inverting the cumulative posterior distribution.
20This calculator works then only for model with a single parameter of interest.
21The model can instead have several nuisance parameters which are integrated (marginalized) in the computation of the posterior function.
22The integration and normalization of the posterior is computed using numerical integration methods provided by ROOT.
23See the MCMCCalculator for model with multiple parameters of interest.
24
25The interface allows one to construct the class by passing the data set, probability density function for the model, the prior
26functions and then the parameter of interest to scan. The nuisance parameters can also be passed to be marginalized when
27computing the posterior. Alternatively, the class can be constructed by passing the data and the ModelConfig containing
28all the needed information (model pdf, prior pdf, parameter of interest, nuisance parameters, etc..)
29
30After configuring the calculator, one only needs to ask GetInterval(), which
31will return an SimpleInterval object. By default the extreme of the integral are obtained by inverting directly the
32cumulative posterior distribution. By using the method SetScanOfPosterior(nbins) the interval is then obtained by
33scanning the posterior function in the given number of points. The first method is in general faster but it requires an
34integration one extra dimension ( in the poi in addition to the nuisance parameters), therefore in some case it can be
35less robust.
36
37The class can also return the posterior function (method GetPosteriorFunction) or if needed the normalized
38posterior function (the posterior pdf) (method GetPosteriorPdf). A posterior plot is also obtained using
39the GetPosteriorPlot method.
40
41The class allows to use different integration methods for integrating in (marginalizing) the nuisances and in the poi. All the numerical
42integration methods of ROOT can be used via the method SetIntegrationType (see more in the documentation of
43this method).
44
45Calculator estimating a credible interval using the Bayesian procedure.
46The calculator computes given the model the posterior distribution and estimates the
47credible interval from the given function.
48*/
49
50
51// include other header files
52
53#include "RooAbsFunc.h"
54#include "RooAbsReal.h"
55#include "RooRealVar.h"
56#include "RooArgSet.h"
57#include "RooBrentRootFinder.h"
58#include "RooFormulaVar.h"
59#include "RooGenericPdf.h"
60#include "RooPlot.h"
61#include "RooProdPdf.h"
62#include "RooDataSet.h"
63
64// include header file of this class
68
69#include "Math/IFunction.h"
71#include "Math/Integrator.h"
72#include "Math/RootFinder.h"
74#include "RooFunctor.h"
75#include "RooFunctor1DBinding.h"
76#include "RooTFnBinding.h"
77#include "RooMsgService.h"
78
79#include "TAxis.h"
80#include "TF1.h"
81#include "TH1.h"
82#include "TMath.h"
83
84#include <map>
85#include <cmath>
86#include <memory>
87
88#include "RConfigure.h"
89
90
91namespace RooStats {
92
93
94// first some utility classes and functions
95
96#ifdef R__HAS_MATHMORE
98#else
100#endif
101
102
103
104
106 LikelihoodFunction(RooFunctor & f, RooFunctor * prior = nullptr, double offset = 0) :
107 fFunc(f), fPrior(prior),
109 {
111 }
112
114
115 double operator() (const double *x ) const {
116 double nll = fFunc(x) - fOffset;
117 double likelihood = std::exp(-nll);
118
119 if (fPrior) likelihood *= (*fPrior)(x);
120
121 int nCalls = fFunc.binding().numCall();
122 if (nCalls > 0 && nCalls % 1000 == 0) {
123 ooccoutD(nullptr,Eval) << "Likelihood evaluation ncalls = " << nCalls
124 << " x0 " << x[0] << " nll = " << nll+fOffset;
125 if (fPrior) ooccoutD(nullptr,Eval) << " prior(x) = " << (*fPrior)(x);
126 ooccoutD(nullptr,Eval) << " likelihood " << likelihood
127 << " max Likelihood " << fMaxL << std::endl;
128 }
129
130 if (likelihood > fMaxL ) {
131 fMaxL = likelihood;
132 if ( likelihood > 1.E10) {
133 ooccoutW(nullptr,Eval) << "LikelihoodFunction::() WARNING - Huge likelihood value found for parameters ";
134 for (int i = 0; i < fFunc.nObs(); ++i)
135 ooccoutW(nullptr,Eval) << " x[" << i << " ] = " << x[i];
136 ooccoutW(nullptr,Eval) << " nll = " << nll << " L = " << likelihood << std::endl;
137 }
138 }
139
140 return likelihood;
141 }
142
143 // for the 1D case
144 double operator() (double x) const {
145 // just call the previous method
146 assert(fFunc.nObs() == 1); // check nobs = 1
147 double tmp = x;
148 return (*this)(&tmp);
149 }
150
151 RooFunctor & fFunc; // functor representing the nll function
152 RooFunctor * fPrior; // functor representing the prior function
153 double fOffset; // offset used to bring the nll in a reasonable range for computing the exponent
154 mutable double fMaxL = 0;
155};
156
157
158// Posterior CDF Function class
159// for integral of posterior function in nuisance and POI
160// 1-Dim function as function of the poi
161
163
164public:
165
166 PosteriorCdfFunction(RooAbsReal & nll, RooArgList & bindParams, RooAbsReal * prior = nullptr, const char * integType = nullptr, double nllMinimum = 0) :
167 fFunctor(nll, bindParams, RooArgList() ), // functor
168 fPriorFunc(nullptr),
169 fLikelihood(fFunctor, nullptr, nllMinimum), // integral of exp(-nll) function
170 fIntegrator(ROOT::Math::IntegratorMultiDim::GetType(integType) ), // integrator
171 fXmin(bindParams.size()), // vector of parameters (min values)
173 {
174 if (prior) {
175 fPriorFunc = std::make_shared<RooFunctor>(*prior, bindParams, RooArgList());
177 }
178
180
181 ooccoutD(nullptr,NumIntegration) << "PosteriorCdfFunction::Compute integral of posterior in nuisance and poi. "
182 << " nllMinimum is " << nllMinimum << std::endl;
183
184 std::vector<double> par(bindParams.size());
185 for (unsigned int i = 0; i < fXmin.size(); ++i) {
186 RooRealVar & var = static_cast<RooRealVar &>( bindParams[i]);
187 fXmin[i] = var.getMin();
188 fXmax[i] = var.getMax();
189 par[i] = var.getVal();
190 ooccoutD(nullptr,NumIntegration) << "PosteriorFunction::Integrate" << var.GetName()
191 << " in interval [ " << fXmin[i] << " , " << fXmax[i] << " ] " << std::endl;
192 }
193
194 fIntegrator.Options().Print(ooccoutD(nullptr,NumIntegration));
195
196 // store max POI value because it will be changed when evaluating the function
197 fMaxPOI = fXmax[0];
198
199 // compute first the normalization with the poi
200 fNorm = (*this)( fMaxPOI );
201 if (fError) ooccoutE(nullptr,NumIntegration) << "PosteriorFunction::Error computing normalization - norm = " << fNorm << std::endl;
202 fHasNorm = true;
203 fNormCdfValues.insert(std::make_pair(fXmin[0], 0) );
204 fNormCdfValues.insert(std::make_pair(fXmax[0], 1.0) );
205
206 }
207
208 // copy constructor (needed for Cloning the object)
209 // need special treatment because integrator
210 // has no copy constructor
212 ROOT::Math::IGenFunction(),
214 //fPriorFunc(std::shared_ptr<RooFunctor>((RooFunctor*)0)),
217 fIntegrator(ROOT::Math::IntegratorMultiDim::GetType( rhs.fIntegrator.Name().c_str() ) ), // integrator
218 fXmin( rhs.fXmin),
219 fXmax( rhs.fXmax),
220 fNorm( rhs.fNorm),
228 {
230 // need special treatment for the smart pointer
231 // if (rhs.fPriorFunc.get() ) {
232 // fPriorFunc = std::shared_ptr<RooFunctor>(new RooFunctor(*(rhs.fPriorFunc) ) );
233 // fLikelihood.SetPrior( fPriorFunc.get() );
234 // }
235 }
236
237
238 bool HasError() const { return fError; }
239
240
241 ROOT::Math::IGenFunction * Clone() const override {
242 ooccoutD(nullptr,NumIntegration) << " cloning function .........." << std::endl;
243 return new PosteriorCdfFunction(*this);
244 }
245
246 // offset value for computing the root
247 void SetOffset(double offset) { fOffset = offset; }
248
249private:
250
251 // make assignment operator private
253 return *this;
254 }
255
256 double DoEval (double x) const override {
257
258 // evaluate cdf at poi value x by integrating poi from [xmin,x] and all the nuisances
259 fXmax[0] = x;
260 if (x <= fXmin[0] ) return -fOffset;
261 // could also avoid a function evaluation at maximum
262 if (x >= fMaxPOI && fHasNorm) return 1. - fOffset; // cdf is bound to these values
263
264 // computes the integral using a previous cdf estimate
265 double normcdf0 = 0;
266 if (fHasNorm && fUseOldValues) {
267 // look in the map of the stored cdf values the closes one
268 std::map<double,double>::iterator itr = fNormCdfValues.upper_bound(x);
269 --itr; // upper bound returns a position 1 up of the value we want
270 if (itr != fNormCdfValues.end() ) {
271 fXmin[0] = itr->first;
272 normcdf0 = itr->second;
273 // ooccoutD(nullptr,NumIntegration) << "PosteriorCdfFunction: computing integral between in poi interval : "
274 // << fXmin[0] << " - " << fXmax[0] << std::endl;
275 }
276 }
277
278 fFunctor.binding().resetNumCall(); // reset number of calls for debug
279
280 double cdf = fIntegrator.Integral(&fXmin[0],&fXmax[0]);
281 double error = fIntegrator.Error();
282 double normcdf = cdf/fNorm; // normalize the cdf
283
284 ooccoutD(nullptr,NumIntegration) << "PosteriorCdfFunction: poi = [" << fXmin[0] << " , "
285 << fXmax[0] << "] integral = " << cdf << " +/- " << error
286 << " norm-integ = " << normcdf << " cdf(x) = " << normcdf+normcdf0
287 << " ncalls = " << fFunctor.binding().numCall() << std::endl;
288
289 if (TMath::IsNaN(cdf) || cdf > std::numeric_limits<double>::max()) {
290 ooccoutE(nullptr,NumIntegration) << "PosteriorFunction::Error computing integral - cdf = "
291 << cdf << std::endl;
292 fError = true;
293 }
294
295 if (cdf != 0 && error / cdf > 0.2) {
296 oocoutW(nullptr, NumIntegration)
297 << "PosteriorCdfFunction: integration error is larger than 20 % x0 = " << fXmin[0] << " x = " << x
298 << " cdf(x) = " << cdf << " +/- " << error << std::endl;
299 }
300
301 if (!fHasNorm) {
302 oocoutI(nullptr,NumIntegration) << "PosteriorCdfFunction - integral of posterior = "
303 << cdf << " +/- " << error << std::endl;
304 fNormErr = error;
305 return cdf;
306 }
307
308 normcdf += normcdf0;
309
310 // store values in the map
311 if (fUseOldValues) {
312 fNormCdfValues.insert(std::make_pair(x, normcdf) );
313 }
314
315 double errnorm = sqrt( error*error + normcdf*normcdf * fNormErr * fNormErr )/fNorm;
316 if (normcdf > 1. + 3 * errnorm) {
317 oocoutW(nullptr,NumIntegration) << "PosteriorCdfFunction: normalized cdf values is larger than 1"
318 << " x = " << x << " normcdf(x) = " << normcdf << " +/- " << error/fNorm << std::endl;
319 }
320
321 return normcdf - fOffset; // apply an offset (for finding the roots)
322 }
323
324 mutable RooFunctor fFunctor; // functor binding nll
325 mutable std::shared_ptr<RooFunctor> fPriorFunc; // functor binding the prior
326 LikelihoodFunction fLikelihood; // likelihood function
327 mutable ROOT::Math::IntegratorMultiDim fIntegrator; // integrator (mutable because Integral() is not const
328 mutable std::vector<double> fXmin; // min value of parameters (poi+nuis) -
329 mutable std::vector<double> fXmax; // max value of parameters (poi+nuis) - max poi changes so it is mutable
330 double fNorm = 1.0; // normalization value (computed in constructor)
331 mutable double fNormErr = 0.0; // normalization error value (computed in constructor)
332 double fOffset = 0; // offset for computing the root
333 double fMaxPOI = 0; // maximum value of POI
334 bool fHasNorm = false; // flag to control first call to the function
335 bool fUseOldValues = true; // use old cdf values
336 mutable bool fError = false; // flag to indicate if a numerical evaluation error occurred
337 mutable std::map<double,double> fNormCdfValues;
338};
339
340//__________________________________________________________________
341// Posterior Function class
342// 1-Dim function as function of the poi
343// and it integrated all the nuisance parameters
344
346
347public:
348
349
350 PosteriorFunction(RooAbsReal & nll, RooRealVar & poi, RooArgList & nuisParams, RooAbsReal * prior = nullptr, const char * integType = nullptr, double
351 norm = 1.0, double nllOffset = 0, int niter = 0) :
353 fPriorFunc(nullptr),
354 fLikelihood(fFunctor, nullptr, nllOffset),
355 fPoi(&poi),
358 fNorm(norm)
359 {
360
361 if (prior) {
362 fPriorFunc = std::make_shared<RooFunctor>(*prior, nuisParams, RooArgList());
364 }
365
366 ooccoutD(nullptr,NumIntegration) << "PosteriorFunction::Evaluate the posterior function by integrating the nuisances: " << std::endl;
367 for (unsigned int i = 0; i < fXmin.size(); ++i) {
368 RooRealVar & var = static_cast<RooRealVar &>( nuisParams[i]);
369 fXmin[i] = var.getMin();
370 fXmax[i] = var.getMax();
371 ooccoutD(nullptr,NumIntegration) << "PosteriorFunction::Integrate " << var.GetName()
372 << " in interval [" << fXmin[i] << " , " << fXmax[i] << " ] " << std::endl;
373 }
374 if (fXmin.size() == 1) { // 1D case
375 fIntegratorOneDim = std::make_unique<ROOT::Math::Integrator>( ROOT::Math::IntegratorOneDim::GetType(integType) );
376
377 fIntegratorOneDim->SetFunction(fLikelihood);
378 // interested only in relative tolerance
379 //fIntegratorOneDim->SetAbsTolerance(1.E-300);
380 fIntegratorOneDim->Options().Print(ooccoutD(nullptr,NumIntegration) );
381 }
382 else if (fXmin.size() > 1) { // multiDim case
383 fIntegratorMultiDim = std::make_unique<ROOT::Math::IntegratorMultiDim>(ROOT::Math::IntegratorMultiDim::GetType(integType));
384 fIntegratorMultiDim->SetFunction(fLikelihood, fXmin.size());
386 if (niter > 0) {
387 opt.SetNCalls(niter);
388 fIntegratorMultiDim->SetOptions(opt);
389 }
390 //fIntegratorMultiDim->SetAbsTolerance(1.E-300);
391 // print the options
392 opt.Print(ooccoutD(nullptr,NumIntegration) );
393 }
394 }
395
396
397 ROOT::Math::IGenFunction * Clone() const override {
398 assert(1);
399 return nullptr; // cannot clone this function for integrator
400 }
401
402 double Error() const { return fError;}
403
404
405private:
406 double DoEval (double x) const override {
407
408 // evaluate posterior function at a poi value x by integrating all nuisance parameters
409
410 fPoi->setVal(x);
411 fFunctor.binding().resetNumCall(); // reset number of calls for debug
412
413 double f = 0;
414 double error = 0;
415 if (fXmin.size() == 1) { // 1D case
416 f = fIntegratorOneDim->Integral(fXmin[0],fXmax[0]);
417 error = fIntegratorOneDim->Error();
418 }
419 else if (fXmin.size() > 1) { // multi-dim case
420 f = fIntegratorMultiDim->Integral(&fXmin[0],&fXmax[0]);
421 error = fIntegratorMultiDim->Error();
422 } else {
423 // no integration to be done
424 f = fLikelihood(x);
425 }
426
427 // debug
428 ooccoutD(nullptr,NumIntegration) << "PosteriorFunction: POI value = "
429 << x << "\tf(x) = " << f << " +/- " << error
430 << " norm-f(x) = " << f/fNorm
431 << " ncalls = " << fFunctor.binding().numCall() << std::endl;
432
433 if (f != 0 && error / f > 0.2) {
434 ooccoutW(nullptr, NumIntegration)
435 << "PosteriorFunction::DoEval - Error from integration in " << fXmin.size() << " Dim is larger than 20 % "
436 << "x = " << x << " p(x) = " << f << " +/- " << error << std::endl;
437 }
438
439 fError = error / fNorm;
440 return f / fNorm;
441 }
442
444 mutable std::shared_ptr<RooFunctor> fPriorFunc; // functor binding the prior
447 std::unique_ptr<ROOT::Math::Integrator> fIntegratorOneDim;
448 std::unique_ptr<ROOT::Math::IntegratorMultiDim> fIntegratorMultiDim;
449 std::vector<double> fXmin;
450 std::vector<double> fXmax;
451 double fNorm;
452 mutable double fError = 0;
453};
454
455////////////////////////////////////////////////////////////////////////////////
456/// Posterior function obtaining sampling toy MC for the nuisance according to their pdf
457
459
460public:
462 RooAbsReal *prior = nullptr, double nllOffset = 0, int niter = 0, bool redoToys = true)
463 : fFunctor(nll, nuisParams, RooArgList()),
464 fPriorFunc(nullptr),
465 fLikelihood(fFunctor, nullptr, nllOffset),
466 fPdf(&pdf),
467 fPoi(&poi),
470
472 {
473 if (niter == 0) fNumIterations = 100; // default value
474
475 if (prior) {
476 fPriorFunc = std::make_shared<RooFunctor>(*prior, nuisParams, RooArgList());
478 }
479
480 ooccoutI(nullptr,InputArguments) << "PosteriorFunctionFromToyMC::Evaluate the posterior function by randomizing the nuisances: niter " << fNumIterations << std::endl;
481
482 ooccoutI(nullptr,InputArguments) << "PosteriorFunctionFromToyMC::Pdf used for randomizing the nuisance is " << fPdf->GetName() << std::endl;
483 // check that pdf contains the nuisance
484 std::unique_ptr<RooArgSet> vars{fPdf->getVariables()};
485 for (std::size_t i = 0; i < fNuisParams.size(); ++i) {
486 if (!vars->find( fNuisParams[i].GetName() ) ) {
487 ooccoutW(nullptr,InputArguments) << "Nuisance parameter " << fNuisParams[i].GetName()
488 << " is not part of sampling pdf. "
489 << "they will be treated as constant " << std::endl;
490 }
491 }
492
493 if (!fRedoToys) {
494 ooccoutI(nullptr,InputArguments) << "PosteriorFunctionFromToyMC::Generate nuisance toys only one time (for all POI points)" << std::endl;
495 GenerateToys();
496 }
497 }
498
499 // generate first n-samples of the nuisance parameters
500 void GenerateToys() const {
501 fGenParams = std::unique_ptr<RooDataSet>{fPdf->generate(fNuisParams, fNumIterations)};
502 if(fGenParams==nullptr) {
503 ooccoutE(nullptr,InputArguments) << "PosteriorFunctionFromToyMC - failed to generate nuisance parameters" << std::endl;
504 }
505 }
506
507 double Error() const { return fError;}
508
509 ROOT::Math::IGenFunction * Clone() const override {
510 // use default copy constructor
511 //return new PosteriorFunctionFromToyMC(*this);
512 // clone not implemented
513 assert(1);
514 return nullptr;
515 }
516
517private:
518 // evaluate the posterior at the poi value x
519 double DoEval( double x) const override {
520
521 int npar = fNuisParams.size();
522 assert (npar > 0);
523
524
525 // generate the toys
526 if (fRedoToys) GenerateToys();
527 if (!fGenParams) return 0;
528
529 // evaluate posterior function at a poi value x by integrating all nuisance parameters
530
531 fPoi->setVal(x);
532
533 // loop over all of the generate data
534 double sum = 0;
535 double sum2 = 0;
536
537 for(int iter=0; iter<fNumIterations; ++iter) {
538
539 // get the set of generated parameters and set the nuisance parameters to the generated values
540 std::vector<double> p(npar);
541 for (int i = 0; i < npar; ++i) {
542 const RooArgSet* genset=fGenParams->get(iter);
543 RooAbsArg * arg = genset->find( fNuisParams[i].GetName() );
544 RooRealVar * var = dynamic_cast<RooRealVar*>(arg);
545 assert(var != nullptr);
546 p[i] = var->getVal();
547 (static_cast<RooRealVar &>( fNuisParams[i])).setVal(p[i]);
548 }
549
550 // evaluate now the likelihood function
551 double fval = fLikelihood( &p.front() );
552
553 // likelihood already must contained the pdf we have sampled
554 // so we must divided by it. The value must be normalized on all
555 // other parameters
557 double nuisPdfVal = fPdf->getVal(&arg);
558 fval /= nuisPdfVal;
559
560
561 if( fval > std::numeric_limits<double>::max() ) {
562 ooccoutE(nullptr,Eval) << "BayesianCalculator::EvalPosteriorFunctionFromToy : "
563 << "Likelihood evaluates to infinity " << std::endl;
564 ooccoutE(nullptr,Eval) << "poi value = " << x << std::endl;
565 ooccoutE(nullptr,Eval) << "Nuisance parameter values : ";
566 for (int i = 0; i < npar; ++i)
567 ooccoutE(nullptr,Eval) << fNuisParams[i].GetName() << " = " << p[i] << " ";
568 ooccoutE(nullptr,Eval) << " - return 0 " << std::endl;
569
570 fError = 1.E30;
571 return 0;
572 }
573 if( TMath::IsNaN(fval) ) {
574 ooccoutE(nullptr,Eval) << "BayesianCalculator::EvalPosteriorFunctionFromToy : "
575 << "Likelihood is a NaN " << std::endl;
576 ooccoutE(nullptr,Eval) << "poi value = " << x << std::endl;
577 ooccoutE(nullptr,Eval) << "Nuisance parameter values : ";
578 for (int i = 0; i < npar; ++i)
579 ooccoutE(nullptr,Eval) << fNuisParams[i].GetName() << " = " << p[i] << " ";
580 ooccoutE(nullptr,Eval) << " - return 0 " << std::endl;
581 fError = 1.E30;
582 return 0;
583 }
584
585
586
587 sum += fval;
588 sum2 += fval*fval;
589 }
590
591 // compute the average and variance
592 double val = sum/double(fNumIterations);
593 double dval2 = std::max( sum2/double(fNumIterations) - val*val, 0.0);
594 fError = std::sqrt( dval2 / fNumIterations);
595
596 // debug
597 ooccoutD(nullptr,NumIntegration) << "PosteriorFunctionFromToyMC: POI value = "
598 << x << "\tp(x) = " << val << " +/- " << fError << std::endl;
599
600
601 if (val != 0 && fError/val > 0.2 ) {
602 ooccoutW(nullptr,NumIntegration) << "PosteriorFunctionFromToyMC::DoEval"
603 << " - Error in estimating posterior is larger than 20% ! "
604 << "x = " << x << " p(x) = " << val << " +/- " << fError << std::endl;
605 }
606
607
608 return val;
609 }
610
612 mutable std::shared_ptr<RooFunctor> fPriorFunc; // functor binding the prior
614 mutable RooAbsPdf * fPdf;
617 mutable std::unique_ptr<RooDataSet> fGenParams;
619 mutable double fError = -1;
620 bool fRedoToys; // do toys every iteration
621
622};
623
624////////////////////////////////////////////////////////////////////////////////
625// Implementation of BayesianCalculator
626////////////////////////////////////////////////////////////////////////////////
627
628////////////////////////////////////////////////////////////////////////////////
629/// default constructor
630
632 fData(nullptr),
633 fPdf(nullptr),
634 fPriorPdf(nullptr),
635 fNuisancePdf(nullptr),
636 fProductPdf (nullptr), fLikelihood (nullptr), fIntegratedLikelihood (nullptr), fPosteriorPdf(nullptr),
637 fPosteriorFunction(nullptr), fApproxPosterior(nullptr),
638 fLower(0), fUpper(0),
639 fNLLMin(0),
640 fSize(0.05), fLeftSideFraction(0.5),
641 fBrfPrecision(0.00005),
642 fNScanBins(-1),
643 fNumIterations(0),
644 fValidInterval(false)
645{
646}
647
648////////////////////////////////////////////////////////////////////////////////
649/// Constructor from data set, model pdf, parameter of interests and prior pdf
650/// If nuisance parameters are given they will be integrated according either to the prior or
651/// their constraint term included in the model
652
653BayesianCalculator::BayesianCalculator( /* const char* name, const char* title, */
655 RooAbsPdf& pdf,
656 const RooArgSet& POI,
659 fData(&data),
660 fPdf(&pdf),
661 fPOI(POI),
662 fPriorPdf(&priorPdf),
663 fNuisancePdf(nullptr),
664 fProductPdf (nullptr), fLikelihood (nullptr), fIntegratedLikelihood (nullptr), fPosteriorPdf(nullptr),
665 fPosteriorFunction(nullptr), fApproxPosterior(nullptr),
666 fLower(0), fUpper(0),
667 fNLLMin(0),
668 fSize(0.05), fLeftSideFraction(0.5),
669 fBrfPrecision(0.00005),
670 fNScanBins(-1),
671 fNumIterations(0),
672 fValidInterval(false)
673{
674
676 // remove constant nuisance parameters
678}
679
680////////////////////////////////////////////////////////////////////////////////
681/// Constructor from a data set and a ModelConfig
682/// model pdf, poi and nuisances will be taken from the ModelConfig
683
685 ModelConfig & model) :
686 fData(&data),
687 fPdf(model.GetPdf()),
688 fPriorPdf( model.GetPriorPdf()),
689 fNuisancePdf(nullptr),
690 fProductPdf (nullptr), fLikelihood (nullptr), fIntegratedLikelihood (nullptr), fPosteriorPdf(nullptr),
691 fPosteriorFunction(nullptr), fApproxPosterior(nullptr),
692 fLower(0), fUpper(0),
693 fNLLMin(0),
694 fSize(0.05), fLeftSideFraction(0.5),
695 fBrfPrecision(0.00005),
696 fNScanBins(-1),
697 fNumIterations(0),
698 fValidInterval(false)
699{
700 SetModel(model);
701}
702
703
705{
706 // destructor
707 ClearAll();
708}
709
710////////////////////////////////////////////////////////////////////////////////
711/// clear all cached pdf objects
712
714 if (fProductPdf) delete fProductPdf;
715 fLogLike.reset();
716 if (fLikelihood) delete fLikelihood;
718 if (fPosteriorPdf) delete fPosteriorPdf;
721 fPosteriorPdf = nullptr;
722 fPosteriorFunction = nullptr;
723 fProductPdf = nullptr;
724 fLikelihood = nullptr;
725 fIntegratedLikelihood = nullptr;
726 fLower = 0;
727 fUpper = 0;
728 fNLLMin = 0;
729 fValidInterval = false;
730}
731
732////////////////////////////////////////////////////////////////////////////////
733/// set the model to use
734/// The model pdf, prior pdf, parameter of interest and nuisances
735/// will be taken according to the model
736
738
739 fPdf = model.GetPdf();
740 fPriorPdf = model.GetPriorPdf();
741 // assignment operator = does not do a real copy the sets (must use add method)
742 fPOI.removeAll();
746 if (model.GetParametersOfInterest()) fPOI.add( *(model.GetParametersOfInterest()) );
749 if (model.GetGlobalObservables()) fGlobalObs.add( *(model.GetGlobalObservables() ) );
750 // remove constant nuisance parameters
752
753 // invalidate the cached pointers
754 ClearAll();
755}
756
757////////////////////////////////////////////////////////////////////////////////
758/// Build and return the posterior function (not normalized) as a RooAbsReal
759/// the posterior is obtained from the product of the likelihood function and the
760/// prior pdf which is then integrated in the nuisance parameters (if existing).
761/// A prior function for the nuisance can be specified either in the prior pdf object
762/// or in the model itself. If no prior nuisance is specified, but prior parameters are then
763/// the integration is performed assuming a flat prior for the nuisance parameters.
764///
765/// NOTE: the return object is managed by the BayesianCalculator class, users do not need to delete it,
766/// but the object will be deleted when the BayesiabCalculator object is deleted
767
769{
770
772 if (fLikelihood) return fLikelihood;
773
774 // run some sanity checks
775 if (!fPdf ) {
776 coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - missing pdf model" << std::endl;
777 return nullptr;
778 }
779 if (fPOI.empty()) {
780 coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - missing parameter of interest" << std::endl;
781 return nullptr;
782 }
783 if (fPOI.size() > 1) {
784 coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - current implementation works only on 1D intervals" << std::endl;
785 return nullptr;
786 }
787
788
789 std::unique_ptr<RooArgSet> constrainedParams{fPdf->getParameters(*fData)};
790 // remove the constant parameters
792
793 //constrainedParams->Print("V");
794
795 // use RooFit::Constrain() to be sure constraints terms are taken into account
797
798
799
800 ccoutD(Eval) << "BayesianCalculator::GetPosteriorFunction : "
801 << " pdf value " << fPdf->getVal()
802 << " neglogLikelihood = " << fLogLike->getVal() << std::endl;
803
804 if (fPriorPdf)
805 ccoutD(Eval) << "\t\t\t priorPOI value " << fPriorPdf->getVal() << std::endl;
806
807 // check that likelihood evaluation is not infinity
808 double nllVal = fLogLike->getVal();
809 if ( nllVal > std::numeric_limits<double>::max() ) {
810 coutE(Eval) << "BayesianCalculator::GetPosteriorFunction : "
811 << " Negative log likelihood evaluates to infinity " << std::endl
812 << " Non-const Parameter values : ";
814 for (std::size_t i = 0; i < p.size(); ++i) {
815 RooRealVar * v = dynamic_cast<RooRealVar *>(&p[i] );
816 if (v!=nullptr) ccoutE(Eval) << v->GetName() << " = " << v->getVal() << " ";
817 }
818 ccoutE(Eval) << std::endl;
819 ccoutE(Eval) << "-- Perform a full likelihood fit of the model before or set more reasonable parameter values"
820 << std::endl;
821 coutE(Eval) << "BayesianCalculator::GetPosteriorFunction : " << " cannot compute posterior function " << std::endl;
822 return nullptr;
823 }
824
825
826
827 // need do find minimum of log-likelihood in the range to shift function
828 // to avoid numerical errors when we compute the likelihood (overflows in the exponent)
829 // N.B.: this works for only 1 parameter of interest otherwise Minuit should be used for finding the minimum
830 RooFunctor * nllFunc = fLogLike->functor(fPOI);
833 RooRealVar* poi = dynamic_cast<RooRealVar*>(fPOI.first() );
834 assert(poi);
835
836 // try to reduce some error messages
837 //bool silentMode = (RooMsgService::instance().globalKillBelow() >= RooFit::ERROR || RooMsgService::instance().silentMode()) ;
839
840
841 coutI(Eval) << "BayesianCalculator::GetPosteriorFunction : "
842 << " nll value " << nllVal << " poi value = " << poi->getVal() << std::endl;
843
844
846 minim.SetFunction(wnllFunc,poi->getMin(),poi->getMax() );
847 bool ret = minim.Minimize(100,1.E-3,1.E-3);
848 fNLLMin = 0;
849 if (ret) fNLLMin = minim.FValMinimum();
850
851 coutI(Eval) << "BayesianCalculator::GetPosteriorFunction : minimum of NLL vs POI for POI = "
852 << poi->getVal() << " min NLL = " << fNLLMin << std::endl;
853
854 delete nllFunc;
855
856
857 if ( fNuisanceParameters.empty() || fIntegrationType.Contains("ROOFIT") ) {
858
859 ccoutD(Eval) << "BayesianCalculator::GetPosteriorFunction : use ROOFIT integration "
860 << std::endl;
861
862#ifdef DOLATER // (not clear why this does not work)
863 // need to make in this case a likelihood from the nll and make the product with the prior
864 TString likeName = TString("likelihood_times_prior_") + TString(fPriorPdf->GetName());
865 TString formula;
866 formula.Form("exp(-@0+%f+log(@1))",fNLLMin);
868#else
869 // here use RooProdPdf (not very nice) but working
870
871 if (fLogLike) fLogLike.reset();
872 if (fProductPdf) {
873 delete fProductPdf;
874 fProductPdf = nullptr;
875 }
876
877 // // create a unique name for the product pdf
879 if (fPriorPdf) {
880 TString prodName = TString("product_") + TString(fPdf->GetName()) + TString("_") + TString(fPriorPdf->GetName() );
881 // save this as data member since it needs to be deleted afterwards
884 }
885
886 std::unique_ptr<RooArgSet> constrParams{fPdf->getParameters(*fData)};
887 // remove the constant parameters
890
891 TString likeName = TString("likelihood_times_prior_") + TString(pdfAndPrior->GetName());
892 TString formula;
893 formula.Form("exp(-@0+%f)",fNLLMin);
895#endif
896
897
898 // if no nuisance parameter we can just return the likelihood function
901 fLikelihood = nullptr;
902 } else {
903 // case of using RooFit for the integration
905 std::unique_ptr<RooAbsReal>{fLikelihood->createIntegral(fNuisanceParameters)}.release();
906 }
907
908 }
909
910 else if ( fIntegrationType.Contains("TOYMC") ) {
911 // compute the posterior as expectation values of the likelihood function
912 // sampling on the nuisance parameters
913
915
916 bool doToysEveryIteration = true;
917 // if type is 1-TOYMC or TOYMC-1
919
921 if (!fNuisancePdf) {
922 ccoutI(Eval) << "BayesianCalculator::GetPosteriorFunction : no nuisance pdf is provided, try using global pdf (this will be slower)"
923 << std::endl;
924 }
927
928 TString name = "toyposteriorfunction_from_";
929 name += fLogLike->GetName();
931
932 // need to scan likelihood in this case
933 if (fNScanBins <= 0) fNScanBins = 100;
934
935 }
936
937 else {
938
939 // use ROOT integration method if there are nuisance parameters
940
943
944 TString name = "posteriorfunction_from_";
945 name += fLogLike->GetName();
947
948 }
949
950 if (RooAbsReal::numEvalErrors() > 0) {
951 coutW(Eval) << "BayesianCalculator::GetPosteriorFunction : " << RooAbsReal::numEvalErrors()
952 << " errors reported in evaluating log-likelihood function " << std::endl;
953 }
956
958
959}
960
961////////////////////////////////////////////////////////////////////////////////
962/// Build and return the posterior pdf (i.e posterior function normalized to all range of poi)
963/// Note that an extra integration in the POI is required for the normalization
964/// NOTE: user must delete the returned object
965
967{
968
970 if (!plike) return nullptr;
971
972
973 // create a unique name on the posterior from the names of the components
974 TString posteriorName = this->GetName() + TString("_posteriorPdf_") + plike->GetName();
975
977
978 return posteriorPdf;
979}
980
981////////////////////////////////////////////////////////////////////////////////
982/// When am approximate posterior is computed binninig the parameter of interest (poi) range
983/// (see SetScanOfPosteriors) an histogram is created and can be returned to the user
984/// A nullptr is instead returned when the posterior is computed without binning the poi.
985///
986/// NOTE: the returned object is managed by the BayesianCalculator class,
987/// if the user wants to take ownership of the returned histogram, he needs to clone
988/// or copy the return object.
989
994
995
996////////////////////////////////////////////////////////////////////////////////
997/// return a RooPlot with the posterior and the credibility region
998/// NOTE: User takes ownership of the returned object
999
1001{
1002
1004
1005 // if a scan is requested approximate the posterior
1006 if (fNScanBins > 0)
1008
1010 if (norm) {
1011 // delete and re-do always posterior pdf (could be invalid after approximating it)
1012 if (fPosteriorPdf) delete fPosteriorPdf;
1015 }
1016 if (!posterior) return nullptr;
1017
1019
1020 RooAbsRealLValue* poi = dynamic_cast<RooAbsRealLValue*>(fPOI.first() );
1021 assert(poi);
1022
1023
1024 RooPlot* plot = poi->frame();
1025 if (!plot) return nullptr;
1026
1027 // try to reduce some error messages
1029
1030 plot->SetTitle(TString("Posterior probability of parameter \"")+TString(poi->GetName())+TString("\""));
1032 posterior->plotOn(plot);
1033 plot->GetYaxis()->SetTitle("posterior function");
1034
1035 // reset the counts and default mode
1038
1039 return plot;
1040}
1041
1042////////////////////////////////////////////////////////////////////////////////
1043/// set the integration type (possible type are) :
1044///
1045/// - 1D integration ( used when only one nuisance and when the posterior is scanned):
1046/// adaptive , gauss, nonadaptive
1047/// - multidim:
1048/// - ADAPTIVE, adaptive numerical integration
1049/// The parameter numIters (settable with SetNumIters) is the max number of function calls.
1050/// It can be reduced to make the integration faster but it will be difficult to reach the required tolerance
1051/// - VEGAS MC integration method based on importance sampling - numIters is number of function calls
1052/// Extra Vegas parameter can be set using IntegratorMultiDimOptions class
1053/// - MISER MC integration method based on stratified sampling
1054/// See also http://en.wikipedia.org/wiki/Monte_Carlo_integration for VEGAS and MISER description
1055/// - PLAIN simple MC integration method, where the max number of calls can be specified using SetNumIters(numIters)
1056///
1057/// Extra integration types are:
1058///
1059/// - TOYMC:
1060/// evaluate posterior by generating toy MC for the nuisance parameters. It is a MC
1061/// integration, where the function is sampled according to the nuisance. It is convenient to use when all
1062/// the nuisance are uncorrelated and it is efficient to generate them
1063/// The toy are generated by default for each poi values
1064/// (this method has been proposed and provided by J.P Chou)
1065/// - 1-TOYMC : same method as before but in this case the toys are generated only one time and then used for
1066/// each poi value. It can be convenient when the generation time is much larger than the evaluation time,
1067/// otherwise it is recommended to re-generate the toy for each poi scanned point of the posterior function
1068/// - ROOFIT:
1069/// use roofit default integration methods which will produce a nested integral (not recommended for more
1070/// than 1 nuisance parameters)
1071
1073 // if type = 0 use default specified via class IntegratorMultiDimOptions::SetDefaultIntegrator
1076}
1077
1078////////////////////////////////////////////////////////////////////////////////
1079/// Compute the interval. By Default a central interval is computed
1080/// and the result is a SimpleInterval object.
1081///
1082/// Using the method (to be called before SetInterval) SetLeftSideTailFraction the user can choose the type of interval.
1083/// By default the returned interval is a central interval with the confidence level specified
1084/// previously in the constructor ( LeftSideTailFraction = 0.5).
1085/// - For lower limit use SetLeftSideTailFraction = 1
1086/// - For upper limit use SetLeftSideTailFraction = 0
1087/// - for shortest intervals use SetLeftSideTailFraction = -1 or call the method SetShortestInterval()
1088///
1089/// NOTE: The BayesianCalculator covers only the case with one
1090/// single parameter of interest
1091///
1092/// NOTE: User takes ownership of the returned object
1093
1095{
1096
1097 if (fValidInterval)
1098 coutW(Eval) << "BayesianCalculator::GetInterval - recomputing interval for the same CL and same model" << std::endl;
1099
1100 RooRealVar* poi = dynamic_cast<RooRealVar*>(fPOI.first() );
1101 if (!poi) {
1102 coutE(Eval) << "BayesianCalculator::GetInterval - no parameter of interest is set " << std::endl;
1103 return nullptr;
1104 }
1105
1106
1107
1108 // get integrated likelihood (posterior function)
1110
1111 //bool silentMode = (RooMsgService::instance().globalKillBelow() >= RooFit::ERROR || RooMsgService::instance().silentMode()) ;
1113
1114 if (fLeftSideFraction < 0 ) {
1115 // compute short intervals
1117 }
1118 else {
1119 // compute the other intervals
1120
1122 double upperCutOff = 1. - (1.- fLeftSideFraction) * fSize;
1123
1124
1125 if (fNScanBins > 0) {
1127 }
1128
1129 else {
1130 // use integration method if there are nuisance parameters
1131 if (!fNuisanceParameters.empty()) {
1133 }
1134 else {
1135 // case of no nuisance - just use createCdf from roofit
1137 }
1138 // case cdf failed (scan then the posterior)
1139 if (!fValidInterval) {
1140 fNScanBins = 100;
1141 coutW(Eval) << "BayesianCalculator::GetInterval - computing integral from cdf failed - do a scan in "
1142 << fNScanBins << " nbins " << std::endl;
1144 }
1145 }
1146 }
1147
1148
1149 // reset the counts and default mode
1150 if (RooAbsReal::numEvalErrors() > 0) {
1151 coutW(Eval) << "BayesianCalculator::GetInterval : " << RooAbsReal::numEvalErrors()
1152 << " errors reported in evaluating log-likelihood function " << std::endl;
1153 }
1154
1157
1158 if (!fValidInterval) {
1159 fLower = 1; fUpper = 0;
1160 coutE(Eval) << "BayesianCalculator::GetInterval - cannot compute a valid interval - return a dummy [1,0] interval"
1161 << std::endl;
1162 }
1163 else {
1164 coutI(Eval) << "BayesianCalculator::GetInterval - found a valid interval : [" << fLower << " , "
1165 << fUpper << " ]" << std::endl;
1166 }
1167
1168 TString interval_name = TString("BayesianInterval_a") + TString(this->GetName());
1170 interval->SetTitle("SimpleInterval from BayesianCalculator");
1171
1172 return interval;
1173}
1174
1175////////////////////////////////////////////////////////////////////////////////
1176/// Returns the value of the parameter for the point in
1177/// parameter-space that is the most likely.
1178/// How do we do if there are points that are equi-probable?
1179/// use approximate posterior
1180/// t.b.d use real function to find the mode
1181
1183
1186 return h->GetBinCenter(h->GetMaximumBin() );
1187 //return fApproxPosterior->GetMaximumX();
1188}
1189
1190////////////////////////////////////////////////////////////////////////////////
1191/// internal function compute the interval using RooFit
1192
1194
1195 coutI(Eval) << "BayesianCalculator: Compute interval using RooFit: posteriorPdf + createCdf + RooBrentRootFinder " << std::endl;
1196
1197 RooRealVar* poi = dynamic_cast<RooRealVar*>(fPOI.first() );
1198 assert(poi);
1199
1200 fValidInterval = false;
1202 if (!fPosteriorPdf) return;
1203
1204 std::unique_ptr<RooAbsReal> cdf{fPosteriorPdf->createCdf(fPOI,RooFit::ScanNoCdf())};
1205 if (!cdf) return;
1206
1207 std::unique_ptr<RooAbsFunc> cdf_bind{cdf->bindVars(fPOI,&fPOI)};
1208 if (!cdf_bind) return;
1209
1211 brf.setTol(fBrfPrecision); // set the brf precision
1212
1213 double tmpVal = poi->getVal(); // patch used because findRoot changes the value of poi
1214
1215 bool ret = true;
1216 if (lowerCutOff > 0) {
1217 double y = lowerCutOff;
1218 ret &= brf.findRoot(fLower,poi->getMin(),poi->getMax(),y);
1219 }
1220 else
1221 fLower = poi->getMin();
1222
1223 if (upperCutOff < 1.0) {
1224 double y=upperCutOff;
1225 ret &= brf.findRoot(fUpper,poi->getMin(),poi->getMax(),y);
1226 }
1227 else
1228 fUpper = poi->getMax();
1229 if (!ret) {
1230 coutE(Eval) << "BayesianCalculator::GetInterval "
1231 << "Error returned from Root finder, estimated interval is not fully correct" << std::endl;
1232 } else {
1233 fValidInterval = true;
1234 }
1235
1236 poi->setVal(tmpVal); // patch: restore the original value of poi
1237}
1238
1239////////////////////////////////////////////////////////////////////////////////
1240/// internal function compute the interval using Cdf integration
1241
1243
1244 fValidInterval = false;
1245
1246 coutI(InputArguments) << "BayesianCalculator:GetInterval Compute the interval from the posterior cdf " << std::endl;
1247
1248 RooRealVar* poi = dynamic_cast<RooRealVar*>(fPOI.first() );
1249 assert(poi);
1250 if (GetPosteriorFunction() == nullptr) {
1251 coutE(InputArguments) << "BayesianCalculator::GetInterval() cannot make posterior Function " << std::endl;
1252 return;
1253 }
1254
1255 // need to remove the constant parameters
1257 bindParams.add(fPOI);
1259
1260 // this code could be put inside the PosteriorCdfFunction
1261
1262 //bindParams.Print("V");
1263
1265 if( cdf.HasError() ) {
1266 coutE(Eval) << "BayesianCalculator: Numerical error computing CDF integral - try a different method " << std::endl;
1267 return;
1268 }
1269
1270 //find the roots
1271
1273
1274 ccoutD(Eval) << "BayesianCalculator::GetInterval - finding roots of posterior using RF " << rf.Name()
1275 << " with precision = " << fBrfPrecision;
1276
1277 if (lowerCutOff > 0) {
1278 cdf.SetOffset(lowerCutOff);
1279 ccoutD(NumIntegration) << "Integrating posterior to get cdf and search lower limit at p =" << lowerCutOff << std::endl;
1280 bool ok = rf.Solve(cdf, poi->getMin(),poi->getMax() , 200,fBrfPrecision, fBrfPrecision);
1281 if( cdf.HasError() )
1282 coutW(Eval) << "BayesianCalculator: Numerical error integrating the CDF " << std::endl;
1283 if (!ok) {
1284 coutE(NumIntegration) << "BayesianCalculator::GetInterval - Error from root finder when searching lower limit !" << std::endl;
1285 return;
1286 }
1287 fLower = rf.Root();
1288 }
1289 else {
1290 fLower = poi->getMin();
1291 }
1292 if (upperCutOff < 1.0) {
1293 cdf.SetOffset(upperCutOff);
1294 ccoutD(NumIntegration) << "Integrating posterior to get cdf and search upper interval limit at p =" << upperCutOff << std::endl;
1295 bool ok = rf.Solve(cdf, fLower,poi->getMax() , 200, fBrfPrecision, fBrfPrecision);
1296 if( cdf.HasError() )
1297 coutW(Eval) << "BayesianCalculator: Numerical error integrating the CDF " << std::endl;
1298 if (!ok) {
1299 coutE(NumIntegration) << "BayesianCalculator::GetInterval - Error from root finder when searching upper limit !" << std::endl;
1300 return;
1301 }
1302 fUpper = rf.Root();
1303 }
1304 else {
1305 fUpper = poi->getMax();
1306 }
1307
1308 fValidInterval = true;
1309}
1310
1311////////////////////////////////////////////////////////////////////////////////
1312/// approximate posterior in nbins using a TF1
1313/// scan the poi values and evaluate the posterior at each point
1314/// and save the result in a cloned TF1
1315/// For each point the posterior is evaluated by integrating the nuisance
1316/// parameters
1317
1319
1320 if (fApproxPosterior) {
1321 // if number of bins of existing function is >= requested one - no need to redo the scan
1322 if (fApproxPosterior->GetNpx() >= fNScanBins) return;
1323 // otherwise redo the scan
1324 delete fApproxPosterior;
1325 fApproxPosterior = nullptr;
1326 }
1327
1328
1330 if (!posterior) return;
1331
1332
1333 TF1 * tmp = posterior->asTF(fPOI);
1334 assert(tmp != nullptr);
1335 // binned the function in nbins and evaluate at those points
1336 if (fNScanBins > 0) tmp->SetNpx(fNScanBins); // if not use default of TF1 (which is 100)
1337
1338 coutI(Eval) << "BayesianCalculator - scan posterior function in nbins = " << tmp->GetNpx() << std::endl;
1339
1340 fApproxPosterior = static_cast<TF1*>(tmp->Clone());
1341 // save this function for future reuse
1342 // I can delete now original posterior and use this approximated copy
1343 delete tmp;
1344 TString name = posterior->GetName() + TString("_approx");
1345 TString title = posterior->GetTitle() + TString("_approx");
1348 delete fIntegratedLikelihood;
1350 }
1351 else if (posterior == fLikelihood) {
1352 delete fLikelihood;
1354 }
1355 else {
1356 assert(1); // should never happen this case
1357 }
1358}
1359
1360////////////////////////////////////////////////////////////////////////////////
1361/// compute the interval using the approximate posterior function
1362
1364
1365 ccoutD(Eval) << "BayesianCalculator: Compute interval from the approximate posterior " << std::endl;
1366
1368 if (!fApproxPosterior) return;
1369
1370 double prob[2];
1371 double limits[2] = {0,0};
1372 prob[0] = lowerCutOff;
1373 prob[1] = upperCutOff;
1375 fLower = limits[0];
1376 fUpper = limits[1];
1377 fValidInterval = true;
1378}
1379
1380////////////////////////////////////////////////////////////////////////////////
1381/// compute the shortest interval from the histogram representing the posterior
1382
1383
1385 coutI(Eval) << "BayesianCalculator - computing shortest interval with CL = " << 1.-fSize << std::endl;
1386
1387 // compute via the approx posterior function
1389 if (!fApproxPosterior) return;
1390
1391 TH1D * h1 = dynamic_cast<TH1D*>(fApproxPosterior->GetHistogram() );
1392 assert(h1 != nullptr);
1394 // get bins and sort them
1395 double * bins = h1->GetArray();
1396 // exclude under/overflow bins
1397 int n = h1->GetSize()-2;
1398 std::vector<int> index(n);
1399 // exclude bins[0] (the underflow bin content)
1400 TMath::Sort(n, bins+1, &index[0]);
1401 // find cut off as test size
1402 double sum = 0;
1403 double actualCL = 0;
1404 double upper = h1->GetXaxis()->GetXmin();
1405 double lower = h1->GetXaxis()->GetXmax();
1406 double norm = h1->GetSumOfWeights();
1407
1408 for (int i = 0; i < n; ++i) {
1409 int idx = index[i];
1410 double p = bins[ idx] / norm;
1411 sum += p;
1412 if (sum > 1.-fSize ) {
1413 actualCL = sum - p;
1414 break;
1415 }
1416
1417 // histogram bin content starts from 1
1418 if ( h1->GetBinLowEdge(idx+1) < lower)
1419 lower = h1->GetBinLowEdge(idx+1);
1420 if ( h1->GetXaxis()->GetBinUpEdge(idx+1) > upper)
1421 upper = h1->GetXaxis()->GetBinUpEdge(idx+1);
1422 }
1423
1424 ccoutD(Eval) << "BayesianCalculator::ComputeShortestInterval - actual interval CL = "
1425 << actualCL << " difference from requested is " << (actualCL-(1.-fSize))/fSize*100. << "% "
1426 << " limits are [ " << lower << " , " << " upper ] " << std::endl;
1427
1428
1429 if (lower < upper) {
1430 fLower = lower;
1431 fUpper = upper;
1432
1433 if (std::abs(actualCL - (1. - fSize)) > 0.1 * (1. - fSize)) {
1434 coutW(Eval) << "BayesianCalculator::ComputeShortestInterval - actual interval CL = " << actualCL
1435 << " differs more than 10% from desired CL value - must increase nbins " << n
1436 << " to an higher value " << std::endl;
1437 }
1438 }
1439 else
1440 coutE(Eval) << "BayesianCalculator::ComputeShortestInterval " << n << " bins are not sufficient " << std::endl;
1441
1442 fValidInterval = true;
1443
1444}
1445
1446
1447
1448
1449} // end namespace RooStats
dim_t fSize
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define coutI(a)
#define ccoutE(a)
#define oocoutW(o, a)
#define coutW(a)
#define oocoutI(o, a)
#define coutE(a)
#define ooccoutW(o, a)
#define ooccoutI(o, a)
#define ooccoutD(o, a)
#define ccoutI(a)
#define ccoutD(a)
#define ooccoutE(o, a)
@ kGray
Definition Rtypes.h:65
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
winID h TVirtualViewer3D TVirtualGLPainter char TVirtualGLPainter plot
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
User class for performing function minimization.
Functor1D class for one-dimensional functions.
Definition Functor.h:95
Interface (abstract class) for generic functions objects of one-dimension Provides a method to evalua...
Definition IFunction.h:114
Numerical multi dimensional integration options.
void Print(std::ostream &os=std::cout) const
print all the options
void SetNCalls(unsigned int calls)
set maximum number of function calls
User class for performing multidimensional integration.
double Integral(const double *xmin, const double *xmax)
evaluate the integral with the previously given function between xmin[] and xmax[]
void SetFunction(Function &f, unsigned int dim)
set integration function using a generic function implementing the operator()(double *x) The dimensio...
static IntegrationMultiDim::Type GetType(const char *name)
static function to get the enumeration from a string
ROOT::Math::IntegratorMultiDimOptions Options() const
retrieve the options
double Error() const
return integration error
static IntegrationOneDim::Type GetType(const char *name)
static function to get the enumeration from a string
User Class to find the Root of one dimensional functions.
Definition RootFinder.h:73
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
const char * GetName() const override
Returns name of object.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
RooAbsArg * first() const
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
void resetNumCall() const
Reset function call counter.
Definition RooAbsFunc.h:52
Int_t numCall() const
Return number of function calls since last reset.
Definition RooAbsFunc.h:47
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
RooFit::OwningPtr< RooAbsReal > createNLL(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Construct representation of -log(L) of PDF with given dataset.
Definition RooAbsPdf.h:163
RooFit::OwningPtr< RooAbsReal > createCdf(const RooArgSet &iset, const RooArgSet &nset=RooArgSet())
Create a cumulative distribution function of this p.d.f in terms of the observables listed in iset.
RooFit::OwningPtr< RooDataSet > generate(const RooArgSet &whatVars, Int_t nEvents, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={})
See RooAbsPdf::generate(const RooArgSet&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,...
Definition RooAbsPdf.h:57
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
RooPlot * frame(const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create a new RooPlot on the heap with a drawing frame initialized for this object,...
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 Int_t numEvalErrors()
Return the number of logged evaluation errors since the last clearing.
static void setEvalErrorLoggingMode(ErrorLoggingMode m)
Set evaluation error logging mode.
static void clearEvalErrorLog()
Clear the stack of evaluation error messages.
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create an object that represents the integral of the function over one or more observables listed in ...
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
Implement the abstract 1-dimensional root finding interface using the Brent-Decker method.
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
RooCFunction1Binding is a templated implementation of class RooAbsReal that binds generic C(++) funct...
Lightweight interface adaptor that exports a RooAbsPdf as a functor.
Definition RooFunctor.h:25
Int_t nObs() const
Definition RooFunctor.h:34
RooAbsFunc & binding()
Definition RooFunctor.h:51
Implementation of a probability density function that takes a RooArgList of servers and a C++ express...
Plot frame and a container for graphics objects within that frame.
Definition RooPlot.h:43
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:36
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
ROOT::Math::IGenFunction * fPosteriorFunction
function representing the posterior
RooAbsReal * fLikelihood
internal pointer to likelihood function
double fNLLMin
minimum value of Nll
int fNumIterations
number of iterations (when using ToyMC)
RooAbsPdf * GetPosteriorPdf() const
return posterior pdf (object is managed by the user)
RooPlot * GetPosteriorPlot(bool norm=false, double precision=0.01) const
get the plot with option to get it normalized
int fNScanBins
number of bins to scan, if = -1 no scan is done (default)
void ClearAll() const
clear all cached pdf objects
void ComputeShortestInterval() const
compute the shortest interval from the histogram representing the posterior
RooAbsPdf * fNuisancePdf
nuisance pdf (needed when using nuisance sampling technique)
RooArgSet fConditionalObs
conditional observables
double fBrfPrecision
root finder precision
RooAbsReal * fIntegratedLikelihood
integrated likelihood function, i.e - unnormalized posterior function
void ApproximatePosterior() const
approximate posterior in nbins using a TF1 scan the poi values and evaluate the posterior at each poi...
double fSize
size used for getting the interval
RooArgSet fNuisanceParameters
nuisance parameters
double fLeftSideFraction
fraction of probability content on left side of interval
RooArgSet fGlobalObs
global observables
double GetMode() const
return the mode (most probable value of the posterior function)
RooAbsPdf * fPdf
model pdf (could contain the nuisance pdf as constraint term)
SimpleInterval * GetInterval() const override
compute the interval.
RooAbsPdf * fProductPdf
internal pointer to model * prior
TF1 * fApproxPosterior
TF1 representing the scanned posterior function.
RooAbsReal * GetPosteriorFunction() const
return posterior function (object is managed by the BayesianCalculator class)
void SetIntegrationType(const char *type)
set the integration type (possible type are) :
RooAbsPdf * fPosteriorPdf
normalized (on the poi) posterior pdf
double fUpper
upper interval bound
double fLower
computer lower interval bound
TH1 * GetPosteriorHistogram() const
return the approximate posterior as histogram (TH1 object). Note the object is managed by the Bayesia...
void ComputeIntervalFromApproxPosterior(double c1, double c2) const
compute the interval using the approximate posterior function
void SetModel(const ModelConfig &model) override
set the model via the ModelConfig
RooAbsPdf * fPriorPdf
prior pdf (typically for the POI)
std::unique_ptr< RooAbsReal > fLogLike
internal pointer to log likelihood function
double ConfidenceLevel() const override
Get the Confidence level for the test.
~BayesianCalculator() override
destructor
void ComputeIntervalUsingRooFit(double c1, double c2) const
internal function compute the interval using RooFit
void ComputeIntervalFromCdf(double c1, double c2) const
internal function compute the interval using Cdf integration
ModelConfig is a simple class that holds configuration information specifying how a model should be u...
Definition ModelConfig.h:35
const RooArgSet * GetConditionalObservables() const
get RooArgSet for conditional observables (return nullptr if not existing)
const RooArgSet * GetGlobalObservables() const
get RooArgSet for global observables (return nullptr if not existing)
const RooArgSet * GetParametersOfInterest() const
get RooArgSet containing the parameter of interest (return nullptr if not existing)
const RooArgSet * GetNuisanceParameters() const
get RooArgSet containing the nuisance parameters (return nullptr if not existing)
RooAbsPdf * GetPdf() const
get model PDF (return nullptr if pdf has not been specified or does not exist)
RooAbsPdf * GetPriorPdf() const
get parameters prior pdf (return nullptr if not existing)
std::shared_ptr< RooFunctor > fPriorFunc
PosteriorCdfFunction & operator=(const PosteriorCdfFunction &)
PosteriorCdfFunction(const PosteriorCdfFunction &rhs)
ROOT::Math::IntegratorMultiDim fIntegrator
PosteriorCdfFunction(RooAbsReal &nll, RooArgList &bindParams, RooAbsReal *prior=nullptr, const char *integType=nullptr, double nllMinimum=0)
double DoEval(double x) const override
implementation of the evaluation function. Must be implemented by derived classes
std::map< double, double > fNormCdfValues
ROOT::Math::IGenFunction * Clone() const override
Clone a function.
Posterior function obtaining sampling toy MC for the nuisance according to their pdf.
std::shared_ptr< RooFunctor > fPriorFunc
std::unique_ptr< RooDataSet > fGenParams
double DoEval(double x) const override
implementation of the evaluation function. Must be implemented by derived classes
PosteriorFunctionFromToyMC(RooAbsReal &nll, RooAbsPdf &pdf, RooRealVar &poi, RooArgList &nuisParams, RooAbsReal *prior=nullptr, double nllOffset=0, int niter=0, bool redoToys=true)
ROOT::Math::IGenFunction * Clone() const override
Clone a function.
PosteriorFunction(RooAbsReal &nll, RooRealVar &poi, RooArgList &nuisParams, RooAbsReal *prior=nullptr, const char *integType=nullptr, double norm=1.0, double nllOffset=0, int niter=0)
std::shared_ptr< RooFunctor > fPriorFunc
std::unique_ptr< ROOT::Math::IntegratorMultiDim > fIntegratorMultiDim
ROOT::Math::IGenFunction * Clone() const override
Clone a function.
double DoEval(double x) const override
implementation of the evaluation function. Must be implemented by derived classes
std::unique_ptr< ROOT::Math::Integrator > fIntegratorOneDim
SimpleInterval is a concrete implementation of the ConfInterval interface.
Use TF1, TF2, TF3 functions as RooFit objects.
const Float_t * GetArray() const
Definition TArrayF.h:43
Int_t GetSize() const
Definition TArray.h:47
Double_t GetXmax() const
Definition TAxis.h:142
Double_t GetXmin() const
Definition TAxis.h:141
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition TAxis.cxx:523
1-Dim function class
Definition TF1.h:233
virtual TH1 * GetHistogram() const
Return a pointer to the histogram used to visualise the function Note that this histogram is managed ...
Definition TF1.cxx:1584
virtual Int_t GetQuantiles(Int_t n, Double_t *xp, const Double_t *p)
Compute Quantiles for density distribution of this function.
Definition TF1.cxx:1994
virtual Int_t GetNpx() const
Definition TF1.h:518
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:693
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
TAxis * GetXaxis()
Definition TH1.h:340
virtual Double_t GetBinLowEdge(Int_t bin) const
Return bin lower edge for 1D histogram.
Definition TH1.cxx:9154
void SetName(const char *name) override
Change the name of this histogram.
Definition TH1.cxx:8962
virtual Double_t GetSumOfWeights() const
Return the sum of weights excluding under/overflows.
Definition TH1.cxx:7919
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Basic string class.
Definition TString.h:139
void ToUpper()
Change string to upper case.
Definition TString.cxx:1195
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
RooCmdArg ScanNoCdf()
RooCmdArg Constrain(const RooArgSet &params)
RooCmdArg GlobalObservables(Args_t &&... argsOrArgSet)
RooCmdArg ConditionalObservables(Args_t &&... argsOrArgSet)
Create a RooCmdArg to declare conditional observables.
RooCmdArg FillColor(TColorNumber color)
RooCmdArg Precision(double prec)
RooCmdArg DrawOption(const char *opt)
RooCmdArg Range(const char *rangeName, bool adjustNorm=true)
RooCmdArg MoveToBack()
RooCmdArg VLines()
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TH1F * h1
Definition legend1.C:5
Namespace for new Math classes and functions.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Namespace for the RooStats classes.
Definition CodegenImpl.h:58
void RemoveConstantParameters(RooArgSet *set)
const ROOT::Math::RootFinder::EType kRootFinderType
Bool_t IsNaN(Double_t x)
Definition TMath.h:896
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Sort the n elements of the array a of generic templated type Element.
Definition TMathBase.h:431
void SetPrior(RooFunctor *prior)
LikelihoodFunction(RooFunctor &f, RooFunctor *prior=nullptr, double offset=0)
double operator()(const double *x) const
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345