BayesianCalculator.cxx

Go to the documentation of this file.
00001 // @(#)root/roostats:$Id: BayesianCalculator.cxx 37487 2010-12-10 10:31:05Z moneta $
00002 // Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
00003 /*************************************************************************
00004  * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
00005  * All rights reserved.                                                  *
00006  *                                                                       *
00007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00009  *************************************************************************/
00010 
00011 /**
00012    BayesianCalculator class
00013 **/
00014 
00015 // include other header files
00016 
00017 #include "RooAbsFunc.h"
00018 #include "RooAbsReal.h"
00019 #include "RooRealVar.h"
00020 #include "RooArgSet.h"
00021 #include "RooBrentRootFinder.h"
00022 #include "RooFormulaVar.h"
00023 #include "RooGenericPdf.h"
00024 #include "RooPlot.h"
00025 #include "RooProdPdf.h"
00026 
00027 // include header file of this class 
00028 #include "RooStats/BayesianCalculator.h"
00029 #include "RooStats/ModelConfig.h"
00030 #include "RooStats/RooStatsUtils.h"
00031 
00032 #include "Math/IFunction.h"
00033 #include "Math/IntegratorMultiDim.h"
00034 #include "Math/Integrator.h"
00035 #include "Math/RootFinder.h"
00036 #include "Math/BrentMinimizer1D.h"
00037 #include "RooFunctor.h"
00038 #include "RooFunctor1DBinding.h"
00039 #include "RooTFnBinding.h"
00040 #include "RooMsgService.h"
00041 
00042 #include "TAxis.h"
00043 #include "TF1.h"
00044 #include "TH1.h"
00045 #include "TMath.h"
00046 #include "TCanvas.h"
00047 
00048 #include <map>
00049 #include <cmath>
00050 
00051 //#include "TRandom.h"
00052 #include "RConfigure.h"
00053 
00054 ClassImp(RooStats::BayesianCalculator)
00055 
00056 namespace RooStats { 
00057 
00058 
00059 // first some utility classes and functions 
00060 
00061 #ifdef R__HAS_MATHMORE
00062    const ROOT::Math::RootFinder::EType kRootFinderType = ROOT::Math::RootFinder::kGSL_BRENT; 
00063 #else 
00064    const ROOT::Math::RootFinder::EType kRootFinderType = ROOT::Math::RootFinder::kBRENT; 
00065 #endif
00066 
00067 
00068 
00069 
00070 struct  LikelihoodFunction { 
00071    LikelihoodFunction(RooFunctor & f, double offset = 0) : fFunc(f), fOffset(offset) {}
00072 
00073    double operator() (const double *x ) const { 
00074       double nll = fFunc(x) - fOffset;
00075       double likelihood =  std::exp(-nll);
00076 //       ooccoutD((TObject*)0,NumIntegration)  
00077 //      std::cout     << "x[0] = " << x[0] << " x[1] = " << x[1]  << " func " << fFunc(x) << " nll = " << nll << "offset " << fOffset << " likelihood = " << likelihood << std::endl;
00078       return likelihood; 
00079    }
00080 
00081    // for the 1D case
00082    double operator() (double x) const { 
00083       double tmp = x; 
00084       return (*this)(&tmp); 
00085    }
00086 
00087    RooFunctor & fFunc;     // functor representing the nll function 
00088    double fOffset;         //  offset used to bring the nll in a reasanble range for computing the exponent whch can be computed 
00089 };
00090 
00091 class PosteriorCdfFunction : public ROOT::Math::IGenFunction { 
00092 
00093 public:
00094    PosteriorCdfFunction(ROOT::Math::IntegratorMultiDim & ig, double * xmin, double * xmax) : 
00095       fIntegrator(ig), fXmin(xmin), fXmax(xmax), fNorm(1.0), fOffset(0.0), fMaxX(xmax[0]), 
00096       fHasNorm(false), fUseOldValues(true) 
00097    {
00098       // compute first the normalization with  the poi 
00099       fNorm = (*this)(xmax[0] );  
00100       fHasNorm = true; 
00101       fNormCdfValues.insert(std::make_pair(xmin[0], 0) );
00102       fNormCdfValues.insert(std::make_pair(xmax[0], 1.0) );
00103 
00104    }
00105 
00106 //    PosteriorCdfFunction(ROOT::Math::IntegratorMultiDim & ig, double * xmin, double * xmax, double norm) : 
00107 //       fIntegrator(ig), fXmin(xmin), fXmax(xmax), fNorm(norm), fOffset(0.0), fMaxX(xmax[0]), fHasNorm(true)  {
00108 //       // compute posterior cdf from a normalization given from outside 
00109 //    }
00110 
00111    ROOT::Math::IGenFunction * Clone() const { 
00112       ooccoutD((TObject*)0,NumIntegration) << " cloning function .........." << std::endl;
00113       return new PosteriorCdfFunction(*this); 
00114    }
00115 
00116    void SetOffset(double offset) { fOffset = offset; }
00117 
00118 private:
00119    double DoEval (double x) const { 
00120       // evaluate cdf at poi value x by integrating poi from [-xmin,x] and all the nuisances  
00121       fXmax[0] = x;
00122       if (x <= fXmin[0] ) return -fOffset; 
00123       // could also avoid a function evaluation at maximum
00124       if (x >= fMaxX && fHasNorm) return 1. - fOffset;  // cdf is bound to these values
00125 
00126       // computes the intergral using previous cdf estimate
00127       double  normcdf0 = 0; 
00128       if (fHasNorm && fUseOldValues) { 
00129          // look in the map of the stored cdf values the closes one
00130          std::map<double,double>::iterator itr = fNormCdfValues.upper_bound(x); 
00131          itr--;   // upper bound returns a poistion 1 up of the value we want
00132          if (itr != fNormCdfValues.end() ) { 
00133             fXmin[0] = itr->first; 
00134             normcdf0 = itr->second;
00135             ooccoutD((TObject*)0,NumIntegration) << "PosteriorCdfFunction:   position for x = " << x << " is  = " << itr->first << std::endl; 
00136          }
00137       }
00138 
00139 
00140       double cdf = fIntegrator.Integral(fXmin,fXmax);  
00141       double error = fIntegrator.Error(); 
00142       double normcdf =  cdf/fNorm;  // normalize the cdf 
00143       ooccoutD((TObject*)0,NumIntegration) << "PosteriorCdfFunction:   x0 = " << fXmin[0] << " x =  " 
00144                                           << x << " cdf(x) =  " << cdf << " +/- " << error 
00145                                           << "  norm-cdf(x) = " << normcdf << std::endl; 
00146       if (cdf != 0 && error/cdf > 0.2 ) 
00147          oocoutW((TObject*)0,NumIntegration) << "PosteriorCdfFunction: integration error  is larger than 20 %   x0 = " << fXmin[0]  
00148                                               << " x = " << x << " cdf(x) = " << cdf << " +/- " << error << std::endl;
00149 
00150       if (!fHasNorm) { 
00151          oocoutI((TObject*)0,NumIntegration) << "PosteriorCdfFunction - integral of posterior = " 
00152                                              << cdf << " +/- " << error << std::endl; 
00153          return cdf; 
00154       }
00155 
00156       normcdf += normcdf0;
00157 
00158       // store values in the map
00159       if (fUseOldValues) { 
00160          fNormCdfValues.insert(std::make_pair(x, normcdf) );
00161       }
00162 
00163       if (normcdf > 1. + 3 * error/fNorm) {
00164          oocoutW((TObject*)0,NumIntegration) << "PosteriorCdfFunction: normalized cdf values is larger than 1" 
00165                                               << " x = " << x << " normcdf(x) = " << normcdf << " +/- " << error/fNorm << std::endl;
00166       }
00167 
00168       return normcdf - fOffset;  // apply an offset (for finding the roots) 
00169    }
00170 
00171    ROOT::Math::IntegratorMultiDim & fIntegrator; 
00172    mutable double * fXmin; 
00173    mutable double * fXmax; 
00174    double fNorm; 
00175    double fOffset;
00176    double fMaxX;  // maxumum value of x 
00177    bool fHasNorm; // flag to control first call to the function 
00178    bool fUseOldValues;  // use old cdf values
00179    mutable std::map<double,double> fNormCdfValues; 
00180 };
00181 
00182 class PosteriorFunction : public ROOT::Math::IGenFunction { 
00183 
00184 public: 
00185 
00186 
00187    PosteriorFunction(RooAbsReal & nll, RooRealVar & poi, RooArgList & nuisParams, const char * integType = 0, double norm = 1.0, double nllOffset = 0) :
00188       fFunctor(nll, nuisParams, RooArgList() ),
00189       fLikelihood(fFunctor, nllOffset), 
00190       fPoi(&poi),
00191       fXmin(nuisParams.getSize() ),
00192       fXmax(nuisParams.getSize() ), 
00193       fNorm(norm)      
00194    { 
00195 
00196       for (unsigned int i = 0; i < fXmin.size(); ++i) { 
00197          RooRealVar & var = (RooRealVar &) nuisParams[i]; 
00198          fXmin[i] = var.getMin(); 
00199          fXmax[i] = var.getMax();
00200       }
00201       if (fXmin.size() == 1) { // 1D case  
00202          fIntegratorOneDim = std::auto_ptr<ROOT::Math::Integrator>(
00203             new ROOT::Math::Integrator(ROOT::Math::IntegratorOneDim::GetType(integType) ) );
00204          fIntegratorOneDim->SetFunction(fLikelihood);
00205          // interested only in relative tolerance
00206          //fIntegratorOneDim->SetAbsTolerance(1.E-300);
00207       }
00208       else if (fXmin.size() > 1) { // multiDim case          
00209          fIntegratorMultiDim = 
00210             std::auto_ptr<ROOT::Math::IntegratorMultiDim>(
00211                new ROOT::Math::IntegratorMultiDim(ROOT::Math::IntegratorMultiDim::GetType(integType) ) );
00212          fIntegratorMultiDim->SetFunction(fLikelihood, fXmin.size());
00213          //fIntegratorMultiDim->SetAbsTolerance(1.E-300);
00214       }
00215    }
00216       
00217       
00218    ROOT::Math::IGenFunction * Clone() const { 
00219       assert(1); 
00220       return 0; // cannot clone this function for integrator 
00221    } 
00222    
00223 private: 
00224    double DoEval (double x) const { 
00225       // evaluate posterior function at a poi value x by integrating all nuisance parameters
00226 
00227       fPoi->setVal(x);
00228       double f = 0; 
00229       double error = 0; 
00230       if (fXmin.size() == 1) { // 1D case  
00231          f = fIntegratorOneDim->Integral(fXmin[0],fXmax[0]); 
00232          error = fIntegratorOneDim->Error();
00233       }
00234       else if (fXmin.size() > 1) { // multi-dim case
00235          f = fIntegratorMultiDim->Integral(&fXmin[0],&fXmax[0]); 
00236          error = fIntegratorMultiDim->Error();
00237       } else { 
00238          // no integration to be done
00239          f = fLikelihood(&x);
00240       }
00241 
00242       if (f != 0 && error/f > 0.2 ) 
00243          ooccoutW((TObject*)0,NumIntegration) << "PosteriorFunction::DoEval - Error from integration in " 
00244                                               << fXmin.size() <<  " Dim is larger than 20 % " 
00245                                               << "x = " << x << " p(x) = " << f << " +/- " << error << std::endl;
00246 
00247       return f / fNorm;
00248    }
00249 
00250    RooFunctor fFunctor; 
00251    LikelihoodFunction fLikelihood; 
00252    RooRealVar * fPoi;
00253    std::auto_ptr<ROOT::Math::Integrator>  fIntegratorOneDim; 
00254    std::auto_ptr<ROOT::Math::IntegratorMultiDim>  fIntegratorMultiDim; 
00255    std::vector<double> fXmin; 
00256    std::vector<double> fXmax; 
00257    double fNorm;
00258 };
00259 
00260 
00261 
00262 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
00263 
00264 BayesianCalculator::BayesianCalculator() :
00265   fData(0),
00266   fPdf(0),
00267   fPriorPOI(0),
00268   fProductPdf (0), fLogLike(0), fLikelihood (0), fIntegratedLikelihood (0), fPosteriorPdf(0), 
00269   fPosteriorFunction(0), fApproxPosterior(0),
00270   fLower(0), fUpper(0),
00271   fNLLMin(0),
00272   fSize(0.05), fLeftSideFraction(0.5), 
00273   fBrfPrecision(0.00005), 
00274   fNScanBins(-1),
00275   fValidInterval(false)
00276 {
00277    // default constructor
00278 }
00279 
00280 BayesianCalculator::BayesianCalculator( /* const char* name,  const char* title, */                                                
00281                                                     RooAbsData& data,
00282                                                     RooAbsPdf& pdf,
00283                                                     const RooArgSet& POI,
00284                                                     RooAbsPdf& priorPOI,
00285                                                     const RooArgSet* nuisanceParameters ) :
00286    //TNamed( TString(name), TString(title) ),
00287   fData(&data),
00288   fPdf(&pdf),
00289   fPOI(POI),
00290   fPriorPOI(&priorPOI),
00291   fProductPdf (0), fLogLike(0), fLikelihood (0), fIntegratedLikelihood (0), fPosteriorPdf(0),
00292   fPosteriorFunction(0), fApproxPosterior(0),
00293   fLower(0), fUpper(0), 
00294   fNLLMin(0),
00295   fSize(0.05), fLeftSideFraction(0.5), 
00296   fBrfPrecision(0.00005), 
00297   fNScanBins(-1),
00298   fValidInterval(false)
00299 {
00300    // constructor
00301    if (nuisanceParameters) fNuisanceParameters.add(*nuisanceParameters); 
00302 }
00303 
00304 BayesianCalculator::BayesianCalculator( RooAbsData& data,
00305                        ModelConfig & model) : 
00306    fData(&data), 
00307    fPdf(model.GetPdf()),
00308    fPriorPOI( model.GetPriorPdf()),
00309    fProductPdf (0), fLogLike(0), fLikelihood (0), fIntegratedLikelihood (0), fPosteriorPdf(0),
00310    fPosteriorFunction(0), fApproxPosterior(0),
00311    fLower(0), fUpper(0), 
00312    fNLLMin(0),
00313    fSize(0.05), fLeftSideFraction(0.5), 
00314    fBrfPrecision(0.00005), 
00315    fNScanBins(-1),
00316    fValidInterval(false)
00317 {
00318    // constructor from Model Config
00319    SetModel(model);
00320 }
00321 
00322 
00323 BayesianCalculator::~BayesianCalculator()
00324 {
00325    // destructor
00326    ClearAll(); 
00327 }
00328 
00329 void BayesianCalculator::ClearAll() const { 
00330    // clear cached pdf objects
00331    if (fProductPdf) delete fProductPdf; 
00332    if (fLogLike) delete fLogLike; 
00333    if (fLikelihood) delete fLikelihood; 
00334    if (fIntegratedLikelihood) delete fIntegratedLikelihood; 
00335    if (fPosteriorPdf) delete fPosteriorPdf;    
00336    if (fPosteriorFunction) delete fPosteriorFunction; 
00337    if (fApproxPosterior) delete fApproxPosterior; 
00338    fPosteriorPdf = 0; 
00339    fPosteriorFunction = 0; 
00340    fProductPdf = 0;
00341    fLogLike = 0; 
00342    fLikelihood = 0; 
00343    fIntegratedLikelihood = 0; 
00344    fLower = 0;
00345    fUpper = 0;
00346    fNLLMin = 0; 
00347    fValidInterval = false;
00348 }
00349 
00350 void BayesianCalculator::SetModel(const ModelConfig & model) {
00351    // set the model
00352    fPdf = model.GetPdf();
00353    fPriorPOI =  model.GetPriorPdf(); 
00354    // assignment operator = does not do a real copy the sets (must use add method) 
00355    fPOI.removeAll();
00356    fNuisanceParameters.removeAll();
00357    if (model.GetParametersOfInterest()) fPOI.add( *(model.GetParametersOfInterest()) );
00358    if (model.GetNuisanceParameters())  fNuisanceParameters.add( *(model.GetNuisanceParameters() ) );
00359 
00360    // invalidate the cached pointers
00361    ClearAll(); 
00362 }
00363 
00364 
00365 
00366 RooAbsReal* BayesianCalculator::GetPosteriorFunction() const
00367 {
00368    // build and return the posterior function (not normalized) as a RooAbsReal
00369    // the posterior is obtained from the product of the likelihood function and the
00370    // prior pdf which is then intergated in the nuisance parameters (if existing).
00371    // A prior function for the nuisance can be specified either in the prior pdf object
00372    // or in the model itself. If no prior nuisance is specified, but prior parameters are then
00373    // the integration is performed assuming a flat prior for the nuisance parameters.        
00374 
00375    if (fIntegratedLikelihood) return fIntegratedLikelihood; 
00376    if (fLikelihood) return fLikelihood; 
00377 
00378    // run some sanity checks
00379    if (!fPdf ) {
00380       coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - missing pdf model" << std::endl;
00381       return 0;
00382    }
00383    if (!fPriorPOI) { 
00384       coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - missing prior pdf" << std::endl;
00385       return 0;
00386    }
00387    if (fPOI.getSize() == 0) {
00388       coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - missing parameter of interest" << std::endl;
00389       return 0;
00390    }
00391    if (fPOI.getSize() > 1) { 
00392       coutE(InputArguments) << "BayesianCalculator::GetPosteriorPdf - current implementation works only on 1D intervals" << std::endl;
00393       return 0; 
00394    }
00395 
00396    // create a unique name for the product pdf 
00397    TString prodName = TString("product_") + TString(fPdf->GetName()) + TString("_") + TString(fPriorPOI->GetName() );   
00398    fProductPdf = new RooProdPdf(prodName,"",RooArgList(*fPdf,*fPriorPOI));
00399 
00400    RooArgSet* constrainedParams = fProductPdf->getParameters(*fData);
00401    // remove the constant parameters
00402    RemoveConstantParameters(constrainedParams);
00403    
00404    //constrainedParams->Print("V");
00405 
00406    // use RooFit::Constrain() to make product of likelihood with prior pdf
00407    fLogLike = fProductPdf->createNLL(*fData, RooFit::Constrain(*constrainedParams) );
00408 
00409    ccoutD(Eval) <<  "BayesianCalculator::GetPosteriorFunction : " 
00410                 << " pdf x priors = " <<  fProductPdf->getVal() 
00411                 << " neglogLikelihood = " << fLogLike->getVal() << std::endl;
00412 
00413 
00414    // if pdf evaluates to zero, should be fixed, but this will
00415    // stop error messages.
00416    fLogLike->setEvalErrorLoggingMode(RooAbsReal::CountErrors);
00417 
00418 
00419 
00420    // need do find minimum of log-likelihood in the range to shift function 
00421    // to avoid numerical errors when we compute the likelihood (overflows in the exponent)
00422    // N.B.: this works for only 1 parameter of interest otherwise Minuit should be used for finding the minimum
00423    RooFunctor * nllFunc = fLogLike->functor(fPOI);
00424    ROOT::Math::Functor1D wnllFunc(*nllFunc);
00425    RooRealVar* poi = dynamic_cast<RooRealVar*>( fPOI.first() ); 
00426    assert(poi);
00427 
00428    ROOT::Math::BrentMinimizer1D minim; 
00429    minim.SetFunction(wnllFunc,poi->getMin(),poi->getMax() );
00430    bool ret  = minim.Minimize(100,1.E-3,1.E-3);
00431    fNLLMin = 0; 
00432    if (ret) fNLLMin = minim.FValMinimum();
00433 
00434    ccoutD(Eval) << "BayesianCalculator::GetPosteriorFunction : minimum of NLL vs POI for POI =  " 
00435           << poi->getVal() << " min NLL = " << fNLLMin << std::endl;
00436 
00437    delete nllFunc;
00438    delete constrainedParams;
00439 
00440    if ( fNuisanceParameters.getSize() == 0 ||  fIntegrationType.Contains("ROOFIT") ) { 
00441 
00442       ccoutD(Eval) << "BayesianCalculator::GetPosteriorFunction : use ROOFIT integration  " 
00443                    << std::endl;
00444 
00445 
00446       // case of no nuisance parameters 
00447       TString likeName = TString("likelihood_") + TString(fProductPdf->GetName());   
00448       TString formula; 
00449       formula.Form("exp(-@0+%f)",fNLLMin);
00450       fLikelihood = new RooFormulaVar(likeName,formula,RooArgList(*fLogLike));
00451       
00452       // if no nuisance parameter we can just return the likelihood funtion
00453       if (fNuisanceParameters.getSize() == 0) return fLikelihood; 
00454 
00455       // case of using RooFit for the integration
00456       fIntegratedLikelihood = fLikelihood->createIntegral(fNuisanceParameters);
00457    }
00458 
00459    else  { 
00460 
00461       // use ROOT integration method if there are nuisance parameters 
00462 
00463       RooArgList nuisParams(fNuisanceParameters); 
00464       fPosteriorFunction = new PosteriorFunction(*fLogLike, *poi, nuisParams, fIntegrationType, 1.,fNLLMin ); 
00465       
00466       TString name = "posteriorfunction_from_"; 
00467       name += fLogLike->GetName();  
00468       fIntegratedLikelihood = new RooFunctor1DBinding(name,name,*fPosteriorFunction,*poi);
00469 
00470    }
00471 
00472    fIntegratedLikelihood->setEvalErrorLoggingMode(RooAbsReal::CountErrors);
00473 
00474    ccoutD(Eval) << "BayesianCalculator::GetPosteriorFunction : use ROOT numerical integration algorithm. "; 
00475    ccoutD(Eval) << " Integrated log-likelihood = " << fIntegratedLikelihood->getVal() << std::endl;
00476 
00477 
00478    return fIntegratedLikelihood; 
00479 }
00480 
00481 RooAbsPdf* BayesianCalculator::GetPosteriorPdf() const
00482 {
00483    /// build and return the posterior pdf (i.e posterior function normalized to all range of poi
00484    ///NOTE: user must delete the returned object 
00485    
00486    RooAbsReal * plike = GetPosteriorFunction(); 
00487    
00488    // create a unique name on the posterior from the names of the components
00489    TString posteriorName = this->GetName() + TString("_posteriorPdf_") + plike->GetName(); 
00490 
00491    RooAbsPdf * posteriorPdf = new RooGenericPdf(posteriorName,"@0",*plike);
00492 
00493    return posteriorPdf;
00494 }
00495 
00496 
00497 RooPlot* BayesianCalculator::GetPosteriorPlot(bool norm, double precision ) const
00498 {
00499   /// return a RooPlot with the posterior  and the credibility region
00500 
00501    if (!fLikelihood) GetPosteriorFunction(); 
00502 
00503    // if a scan is requested approximate the posterior
00504    if (fNScanBins > 0) ApproximatePosterior();
00505 
00506    RooAbsReal * posterior = fIntegratedLikelihood; 
00507    if (norm) posterior = fPosteriorPdf; 
00508    if (!posterior) { 
00509       posterior = GetPosteriorFunction();
00510       if (norm) { 
00511          if (fPosteriorPdf) delete fPosteriorPdf;
00512          fPosteriorPdf = GetPosteriorPdf();
00513          posterior = fPosteriorPdf;
00514       }
00515    }
00516    if (!posterior) return 0;
00517 
00518    if (!fValidInterval) GetInterval();
00519 
00520    RooAbsRealLValue* poi = dynamic_cast<RooAbsRealLValue*>( fPOI.first() );
00521    assert(poi);
00522 
00523 
00524    RooPlot* plot = poi->frame();
00525 
00526    // try to reduce some error messages
00527    posterior->setEvalErrorLoggingMode(RooAbsReal::CountErrors);
00528 
00529    plot->SetTitle(TString("Posterior probability of parameter \"")+TString(poi->GetName())+TString("\""));  
00530    posterior->plotOn(plot,RooFit::Range(fLower,fUpper,kFALSE),RooFit::VLines(),RooFit::DrawOption("F"),RooFit::MoveToBack(),RooFit::FillColor(kGray),RooFit::Precision(precision));
00531    posterior->plotOn(plot);
00532    plot->GetYaxis()->SetTitle("posterior function");
00533    
00534    return plot; 
00535 }
00536 
00537 void BayesianCalculator::SetIntegrationType(const char * type) { 
00538    fIntegrationType = TString(type); 
00539    fIntegrationType.ToUpper(); 
00540 }
00541 
00542 
00543 
00544 SimpleInterval* BayesianCalculator::GetInterval() const
00545 {
00546   /// returns a SimpleInterval with lower and upper bounds on the
00547   /// parameter of interest specified in the constructor. 
00548   /// Using the method (to be called before SetInterval) SetLeftSideTailFraction the user can choose the type of interval.
00549   /// By default the returned interval is a central interval with the confidence level specified 
00550   /// previously in the constructor ( LeftSideTailFraction = 0.5). 
00551   ///  For lower limit use SetLeftSideTailFraction = 1
00552   ///  For upper limit use SetLeftSideTailFraction = 0
00553   ///  for shortest intervals use SetLeftSideTailFraction = -1 or call the method SetShortestInterval()
00554   /// NOTE: The BayesianCaluclator covers only the case with one
00555   /// single parameter of interest
00556 
00557    if (fValidInterval) 
00558       coutW(Eval) << "BayesianCalculator::GetInterval - recomputing interval for the same CL and same model" << std::endl;
00559 
00560    RooRealVar* poi = dynamic_cast<RooRealVar*>( fPOI.first() );
00561    if (!poi) { 
00562       coutE(Eval) << "BayesianCalculator::GetInterval - no parameter of interest is set " << std::endl;
00563       return 0; 
00564    } 
00565 
00566    if (fLeftSideFraction < 0 ) { 
00567       // compute short intervals
00568       ComputeShortestInterval(); 
00569    }
00570    else {
00571       // compute the other intervals
00572 
00573       double lowerCutOff = fLeftSideFraction * fSize; 
00574       double upperCutOff = 1. - (1.- fLeftSideFraction) * fSize; 
00575 
00576 
00577       if (fNScanBins > 0) { 
00578          ComputeIntervalFromApproxPosterior(lowerCutOff, upperCutOff);
00579       }
00580       
00581       else { 
00582          // use integration method if there are nuisance parameters 
00583          if (fNuisanceParameters.getSize() > 0) { 
00584             ComputeIntervalFromCdf(lowerCutOff, upperCutOff);      
00585             // case of no nuisance - just use createCdf from roofit
00586          }
00587          else { 
00588             ComputeIntervalUsingRooFit(lowerCutOff, upperCutOff);      
00589          }
00590       }
00591    }
00592 
00593    fValidInterval = true; 
00594    coutI(Eval) << "BayesianCalculator::GetInterval - found a valid interval : [" << fLower << " , " 
00595                 << fUpper << " ]" << std::endl;
00596    
00597    TString interval_name = TString("BayesianInterval_a") + TString(this->GetName());
00598    SimpleInterval * interval = new SimpleInterval(interval_name,*poi,fLower,fUpper,ConfidenceLevel());
00599    interval->SetTitle("SimpleInterval from BayesianCalculator");
00600    
00601    return interval;
00602 }
00603 
00604 double BayesianCalculator::GetMode() const { 
00605    /// Returns the value of the parameter for the point in
00606    /// parameter-space that is the most likely.
00607    ///  How do we do if there are points that are equi-probable?
00608    /// use approximate posterior
00609    /// t.b.d use real function to find the mode
00610 
00611    ApproximatePosterior(); 
00612    TH1 * h = fApproxPosterior->GetHistogram();
00613    return h->GetBinCenter(h->GetMaximumBin() );
00614    //return  fApproxPosterior->GetMaximumX();
00615 }
00616 
00617 void BayesianCalculator::ComputeIntervalUsingRooFit(double lowerCutOff, double upperCutOff ) const { 
00618    // compute the interval using RooFit
00619 
00620    coutI(Eval) <<  "BayesianCalculator: Compute interval using RooFit:  posteriorPdf + createCdf + RooBrentRootFinder " << std::endl;
00621 
00622    RooRealVar* poi = dynamic_cast<RooRealVar*>( fPOI.first() ); 
00623    assert(poi);
00624 
00625    if (!fPosteriorPdf) fPosteriorPdf = (RooAbsPdf*) GetPosteriorPdf();
00626          
00627    RooAbsReal* cdf = fPosteriorPdf->createCdf(fPOI,RooFit::ScanNoCdf());
00628          
00629    RooAbsFunc* cdf_bind = cdf->bindVars(fPOI,&fPOI);
00630    RooBrentRootFinder brf(*cdf_bind);
00631    brf.setTol(fBrfPrecision); // set the brf precision
00632    
00633    double tmpVal = poi->getVal();  // patch used because findRoot changes the value of poi
00634    
00635    bool ret = true; 
00636    if (lowerCutOff > 0) { 
00637       double y = lowerCutOff;
00638       ret &= brf.findRoot(fLower,poi->getMin(),poi->getMax(),y);
00639    } 
00640    else 
00641       fLower = poi->getMin(); 
00642 
00643    if (upperCutOff < 1.0) { 
00644       double y=upperCutOff;
00645       ret &= brf.findRoot(fUpper,poi->getMin(),poi->getMax(),y);
00646    }
00647    else 
00648       fUpper = poi->getMax();
00649    if (!ret) coutE(Eval) << "BayesianCalculator::GetInterval "
00650                          << "Error returned from Root finder, estimated interval is not fully correct" 
00651                          << std::endl;
00652 
00653    poi->setVal(tmpVal); // patch: restore the original value of poi
00654    
00655    delete cdf_bind;
00656    delete cdf;
00657 }
00658 
00659 void BayesianCalculator::ComputeIntervalFromCdf(double lowerCutOff, double upperCutOff ) const { 
00660    // compute the interval using Cdf integration
00661 
00662    coutI(Eval) <<  "BayesianCalculator: Compute the interval from the posterior cdf " << std::endl;
00663 
00664    RooRealVar* poi = dynamic_cast<RooRealVar*>( fPOI.first() ); 
00665    assert(poi);
00666    GetPosteriorFunction();
00667 
00668    // need to remove the constant parameters
00669    RooArgList bindParams; 
00670    bindParams.add(fPOI);
00671    bindParams.add(fNuisanceParameters);
00672    
00673    // this code could be put inside the PosteriorCdfFunction
00674          
00675    RooFunctor functor_nll(*fLogLike, bindParams, RooArgList());
00676          
00677    
00678    // compute the integral of the exp(-nll) function
00679    LikelihoodFunction fll(functor_nll, fNLLMin);
00680       
00681    ROOT::Math::IntegratorMultiDim ig(ROOT::Math::IntegratorMultiDim::GetType(fIntegrationType)); 
00682    ig.SetFunction(fll,bindParams.getSize()); 
00683    
00684    std::vector<double> pmin(bindParams.getSize());
00685    std::vector<double> pmax(bindParams.getSize());
00686    std::vector<double> par(bindParams.getSize());
00687    for (unsigned int i = 0; i < pmin.size(); ++i) { 
00688       RooRealVar & var = (RooRealVar &) bindParams[i]; 
00689       pmin[i] = var.getMin(); 
00690       pmax[i] = var.getMax();
00691       par[i] = var.getVal();
00692    } 
00693          
00694          
00695    //bindParams.Print("V");
00696          
00697    PosteriorCdfFunction cdf(ig, &pmin[0], &pmax[0] ); 
00698          
00699          
00700    //find the roots 
00701 
00702    ROOT::Math::RootFinder rf(kRootFinderType); 
00703          
00704    ccoutD(Eval) << "BayesianCalculator::GetInterval - finding roots of posterior using RF " << rf.Name() 
00705                 << " with precision = " << fBrfPrecision;
00706          
00707    if (lowerCutOff > 0) { 
00708       cdf.SetOffset(lowerCutOff);
00709       ccoutD(NumIntegration) << "Integrating posterior to get cdf and search lower limit at p =" << lowerCutOff << std::endl;
00710       bool ok = rf.Solve(cdf, poi->getMin(),poi->getMax() , 200,fBrfPrecision, fBrfPrecision); 
00711       if (!ok) 
00712          coutE(NumIntegration) << "BayesianCalculator::GetInterval - Error from root finder when searching lower limit !" << std::endl;
00713       fLower = rf.Root(); 
00714    }
00715    else { 
00716       fLower = poi->getMin(); 
00717    }
00718    if (upperCutOff < 1.0) {  
00719       cdf.SetOffset(upperCutOff);
00720       ccoutD(NumIntegration) << "Integrating posterior to get cdf and search upper interval limit at p =" << upperCutOff << std::endl;
00721       bool ok = rf.Solve(cdf, fLower,poi->getMax() , 200, fBrfPrecision, fBrfPrecision); 
00722       if (!ok) 
00723          coutE(NumIntegration) << "BayesianCalculator::GetInterval - Error from root finder when searching upper limit !" << std::endl;
00724       
00725       fUpper = rf.Root(); 
00726    }
00727    else { 
00728       fUpper = poi->getMax(); 
00729    }
00730 }
00731 
00732 void BayesianCalculator::ApproximatePosterior() const { 
00733    // approximate posterior in nbins using a TF1 and
00734    // scan the values
00735 
00736    if (fApproxPosterior) { 
00737       // if number of bins of existing function is >= requested one - no need to redo the scan
00738       if (fApproxPosterior->GetNpx() >= fNScanBins) return;  
00739       // otherwise redo the scan
00740       delete fApproxPosterior; 
00741       fApproxPosterior = 0;
00742    }      
00743 
00744    RooAbsReal * posterior = GetPosteriorFunction();
00745 
00746    // try to reduce some error messages
00747    posterior->setEvalErrorLoggingMode(RooAbsReal::CountErrors);
00748 
00749    TF1 * tmp = posterior->asTF(fPOI); 
00750    assert(tmp != 0);
00751    // binned the function in nbins and evaluate at thos points
00752    if (fNScanBins > 0)  tmp->SetNpx(fNScanBins);  // if not use default of TF1 (which is 100)
00753 
00754    coutI(Eval) << "BayesianCalculator - scan posterior function in nbins = " << tmp->GetNpx() << std::endl;
00755 
00756    fApproxPosterior = (TF1*) tmp->Clone();
00757    // save this function for future reuse 
00758    // I can delete now original posterior and use this approximated copy
00759    delete tmp;
00760    TString name = posterior->GetName() + TString("_approx");
00761    TString title = posterior->GetTitle() + TString("_approx");
00762    RooAbsReal * posterior2 = new RooTFnBinding(name,title,fApproxPosterior,fPOI);
00763    if (posterior == fIntegratedLikelihood) { 
00764       delete fIntegratedLikelihood;
00765       fIntegratedLikelihood = posterior2; 
00766    }
00767    else if (posterior == fLikelihood) { 
00768       delete fLikelihood; 
00769       fLikelihood = posterior2;
00770    }
00771    else {
00772       assert(1); // should never happen this case
00773    }
00774 }
00775 
00776 void BayesianCalculator::ComputeIntervalFromApproxPosterior(double lowerCutOff, double upperCutOff ) const { 
00777    // compute the interval using the approximate posterior function
00778 
00779    ccoutD(Eval) <<  "BayesianCalculator: Compute interval from the approximate posterior " << std::endl;
00780 
00781    ApproximatePosterior();
00782 
00783    double prob[2]; 
00784    double limits[2];
00785    prob[0] = lowerCutOff;
00786    prob[1] = upperCutOff; 
00787    fApproxPosterior->GetQuantiles(2,limits,prob);
00788    fLower = limits[0]; 
00789    fUpper = limits[1];
00790 }
00791 
00792 void BayesianCalculator::ComputeShortestInterval( ) const { 
00793    // compute the shortest interval
00794    coutI(Eval) << "BayesianCalculator - computing shortest interval with CL = " << 1.-fSize << std::endl;
00795 
00796    // compute via the approx posterior function
00797    ApproximatePosterior(); 
00798    TH1D * h1 = dynamic_cast<TH1D*>(fApproxPosterior->GetHistogram() );
00799    assert(h1 != 0);
00800    h1->SetName(fApproxPosterior->GetName());
00801    // get bins and sort them 
00802    double * bins = h1->GetArray(); 
00803    int n = h1->GetSize()-2; // exclude under/overflow bins
00804    std::vector<int> index(n);
00805    TMath::Sort(n, bins, &index[0]); 
00806    // find cut off as test size
00807    double sum = 0; 
00808    double actualCL = 0;
00809    double upper =  h1->GetXaxis()->GetXmin();
00810    double lower =  h1->GetXaxis()->GetXmax();
00811    double norm = h1->GetSumOfWeights();
00812 
00813    for (int i = 0; i < n; ++i)  {
00814       int idx = index[i]; 
00815       double p = bins[ idx] / norm;
00816       sum += p;
00817       if (sum > 1.-fSize ) { 
00818          actualCL = sum - p;
00819          break; 
00820       }
00821 
00822       if ( h1->GetBinLowEdge(idx) < lower) 
00823          lower = h1->GetBinLowEdge(idx);
00824       if ( h1->GetXaxis()->GetBinUpEdge(idx) > upper) 
00825          upper = h1->GetXaxis()->GetBinUpEdge(idx);
00826    }
00827 
00828    ccoutD(Eval) << "BayesianCalculator::ComputeShortestInterval - actual interval CL = " 
00829                 << actualCL << " difference from requested is " << (actualCL-(1.-fSize))/fSize*100. << "%  "
00830                 << " limits are [ " << lower << " , " << " upper ] " << std::endl;
00831 
00832 
00833    if (lower < upper) { 
00834       fLower = lower;
00835       fUpper = upper; 
00836 
00837 
00838 
00839       if ( std::abs(actualCL-(1.-fSize)) > 0.1*(1.-fSize) )
00840          coutW(Eval) << "BayesianCalculator::ComputeShortestInterval - actual interval CL = " 
00841                      << actualCL << " differs more than 10% from desired CL value - must increase nbins " 
00842                      << n << " to an higher value " << std::endl;
00843    }
00844    else 
00845       coutE(Eval) << "BayesianCalculator::ComputeShortestInterval " << n << " bins are not sufficient " << std::endl;
00846 
00847 
00848 }
00849 
00850 
00851 } // end namespace RooStats
00852 

Generated on Tue Jul 5 15:07:52 2011 for ROOT_528-00b_version by  doxygen 1.5.1