Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooHistError.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooHistError.cxx
19\class RooHistError
20\ingroup Roofitcore
21
22Singleton class used to calculate the error bars
23for each bin of a RooHist object. Errors are calculated by integrating
24a specified area of a Poisson or Binomail error distribution.
25**/
26
27#include "RooHistError.h"
28#include "RooBrentRootFinder.h"
29#include "RooMsgService.h"
30
31#include "Math/QuantFuncMathCore.h" // ROOT::Math::chisquared_quantile, chisquared_quantile_c
32
33#include "Riostream.h"
34
35#include <cassert>
36#include <cmath>
37
38using std::endl;
39
40
41////////////////////////////////////////////////////////////////////////////////
42/// Return a reference to a singleton object that is created the
43/// first time this method is called. Only one object will be
44/// constructed per ROOT session.
45
51
52
53////////////////////////////////////////////////////////////////////////////////
54/// Calculate a confidence interval for the expected number of events given n
55/// observed (unweighted) events. The interval will contain the same probability
56/// as nSigma of a Gaussian. Uses a central interval unless this does not enclose
57/// the point estimate n (ie, for small n) in which case the interval is adjusted
58/// to start at n.
59
60bool RooHistError::getPoissonInterval(Int_t n, double &mu1, double &mu2, double nSigma) const
61{
62 // sanity checks
63 if (n < 0) {
64 oocoutE(nullptr, Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n = " << n
65 << std::endl;
66 return false;
67 }
68 if (!(nSigma > 0.0)) {
69 oocoutE(nullptr, Plotting) << "RooHistError::getPoissonInterval: nSigma must be > 0, got " << nSigma << std::endl;
70 return false;
71 }
72
73 // Convert "number of sigmas" to central Gaussian probability beta, and
74 // corresponding two-sided tail probability alpha.
75 const double beta = std::erf(nSigma / std::sqrt(2.0));
76 const double alpha = 1.0 - beta;
77
78 // Special case n = 0 (boundary at mu >= 0).
79 // Use a one-sided interval including the MLE mu=0:
80 // mu1 = 0
81 // P(N <= 0 | mu2) = alpha,
82 // with alpha = 1 - erf(nSigma / sqrt(2)).
83 if (n == 0) {
84 mu1 = 0.0;
85 mu2 = 0.5 * ROOT::Math::chisquared_quantile(1.0 - alpha, 2.0 * (n + 1));
86 return true;
87 }
88
89 // For n>0, use the central (equal-tailed) Garwood interval, which
90 // corresponds to allocating alpha/2 in each tail.
91 const double a2 = 0.5 * alpha;
92 mu1 = 0.5 * ROOT::Math::chisquared_quantile(a2, 2.0 * n);
93 mu2 = 0.5 * ROOT::Math::chisquared_quantile_c(a2, 2.0 * (n + 1));
94 return true;
95}
96
97
98////////////////////////////////////////////////////////////////////////////////
99/// Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
100/// If the return values is false and error occurred.
101
103 double &asym1, double &asym2, double nSigma) const
104{
105 // sanity checks
106 if(n < 0 || m < 0) {
107 oocoutE(nullptr,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << std::endl;
108 return false;
109 }
110
111 // handle the special case of no events in either category
112 if(n == 0 && m == 0) {
113 asym1= -1;
114 asym2= +1;
115 return true;
116 }
117
118 // handle cases when n,m>100 (factorials in BinomialSum will overflow around 170)
119 if ((n>100&&m>100)) {
120 double N = n ;
121 double M = m ;
122 double asym = 1.0*(N-M)/(N+M) ;
123 double approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
124
127 return true ;
128 }
129
130 // swap n and m to ensure that n <= m
131 bool swapped(false);
132 if(n > m) {
133 swapped= true;
134 Int_t tmp(m);
135 m= n;
136 n= tmp;
137 }
138
139 // create the function objects to use
140 bool status(false);
142 if(n > 0) {
144 status= getInterval(&upper,&lower,(double)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
145 }
146 else {
147 status= getInterval(&upper,nullptr,(double)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
148 }
149
150 // undo the swap here
151 if(swapped) {
152 double tmp(asym1);
153 asym1= -asym2;
154 asym2= -tmp;
155 }
156
157 return status;
158}
159
160
161////////////////////////////////////////////////////////////////////////////////
162/// Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
163/// If the return values is false and error occurred.
164
166 double &asym1, double &asym2, double nSigma) const
167{
168 // sanity checks
169 if(n < 0 || m < 0) {
170 oocoutE(nullptr,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << std::endl;
171 return false;
172 }
173
174 // handle the special case of no events in either category
175 if(n == 0 && m == 0) {
176 asym1= -1;
177 asym2= +1;
178 return true;
179 }
180
181 // handle cases when n,m>80 (factorials in BinomialSum will overflow around 170)
182 if ((n>80&&m>80)) {
183 double N = n ;
184 double M = m ;
185 double asym = 1.0*(N)/(N+M) ;
186 double approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
187
188 asym1 = asym-nSigma*0.5*approxErr ;
189 asym2 = asym+nSigma*0.5*approxErr ;
190 return true ;
191 }
192
193 // swap n and m to ensure that n <= m
194 bool swapped(false);
195 if(n > m) {
196 swapped= true;
197 Int_t tmp(m);
198 m= n;
199 n= tmp;
200 }
201
202 // create the function objects to use
203 bool status(false);
205 double eff = (double)(n)/(n+m) ;
206 if(n > 0) {
207 BinomialSumEff lower(n-1,m+1);
208 status= getInterval(&upper,&lower,eff,0.1,asym1,asym2,nSigma*0.5);
209 }
210 else {
211 status= getInterval(&upper,nullptr,eff,0.1,asym1,asym2,nSigma*0.5);
212 }
213
214 // undo the swap here
215 if(swapped) {
216 double tmp(asym1);
217 asym1= 1-asym2;
218 asym2= 1-tmp;
219 }
220
221 return status;
222}
223
224
225
226////////////////////////////////////////////////////////////////////////////////
227/// Calculate a confidence interval using the cumulative functions provided.
228/// The interval will be "central" when both cumulative functions are provided,
229/// unless this would exclude the pointEstimate, in which case a one-sided interval
230/// pinned at the point estimate is returned instead.
231
233 double stepSize, double &lo, double &hi, double nSigma) const
234{
235 // sanity checks
236 assert(nullptr != Qu || nullptr != Ql);
237
238 // convert number of sigma into a confidence level
239 double beta= std::erf(nSigma/sqrt(2.));
240 double alpha= 0.5*(1-beta);
241
242 // Does the central interval contain the point estimate?
243 bool ok(true);
244 double loProb(1);
245 double hiProb(0);
246 if(nullptr != Ql) loProb= (*Ql)(&pointEstimate);
247 if(nullptr != Qu) hiProb= (*Qu)(&pointEstimate);
248
249 if (Qu && (nullptr == Ql || loProb > alpha + beta)) {
250 // Force the low edge to be at the pointEstimate
251 lo= pointEstimate;
252 double target= loProb - beta;
253 hi= seek(*Qu,lo,+stepSize,target);
255 ok= uFinder.findRoot(hi,hi-stepSize,hi,target);
256 }
257 else if(Ql && (nullptr == Qu || hiProb < alpha)) {
258 // Force the high edge to be at pointEstimate
260 double target= hiProb + beta;
261 lo= seek(*Ql,hi,-stepSize,target);
263 ok= lFinder.findRoot(lo,lo,lo+stepSize,target);
264 }
265 else if (Qu && Ql) {
266 // use a central interval
267 lo= seek(*Ql,pointEstimate,-stepSize,alpha+beta);
268 hi= seek(*Qu,pointEstimate,+stepSize,alpha);
271 ok= lFinder.findRoot(lo,lo,lo+stepSize,alpha+beta);
272 ok|= uFinder.findRoot(hi,hi-stepSize,hi,alpha);
273 }
274 if(!ok) oocoutE(nullptr,Plotting) << "RooHistError::getInterval: failed to find root(s)" << std::endl;
275
276 return ok;
277}
278
279
280////////////////////////////////////////////////////////////////////////////////
281/// Scan f(x)-value until it changes sign. Start at the specified point and take constant
282/// steps of the specified size. Give up after 1000 steps.
283
284double RooHistError::seek(const RooAbsFunc &f, double startAt, double step, double value) const
285{
286 Int_t steps(1000);
287 double min(f.getMinLimit(1));
288 double max(f.getMaxLimit(1));
289 double x(startAt);
290 double f0 = f(&startAt) - value;
291 do {
292 x+= step;
293 }
294 while(steps-- && (f0*(f(&x)-value) >= 0) && ((x-min)*(max-x) >= 0));
295 assert(0 != steps);
296 if(x < min) x= min;
297 if(x > max) x= max;
298
299 return x;
300}
301
302
303
304////////////////////////////////////////////////////////////////////////////////
305/// Create and return a PoissonSum function binding
306
311
312
313////////////////////////////////////////////////////////////////////////////////
314/// Create and return a BinomialSum function binding
315
317{
318 if (eff) {
319 return new BinomialSumEff(n,m) ;
320 } else {
321 return new BinomialSumAsym(n,m) ;
322 }
323}
#define f(i)
Definition RSha256.hxx:104
#define oocoutE(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
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 target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
#define hi
Abstract interface for evaluating a real-valued function of one real variable and performing numerica...
Definition RooAbsFunc.h:27
Implement the abstract 1-dimensional root finding interface using the Brent-Decker method.
Singleton class used to calculate the error bars for each bin of a RooHist object.
bool getBinomialIntervalAsym(Int_t n, Int_t m, double &a1, double &a2, double nSigma=1) const
Return 'nSigma' binomial confidence interval for (n,m).
static const RooHistError & instance()
Return a reference to a singleton object that is created the first time this method is called.
bool getBinomialIntervalEff(Int_t n, Int_t m, double &a1, double &a2, double nSigma=1) const
Return 'nSigma' binomial confidence interval for (n,m).
bool getInterval(const RooAbsFunc *Qu, const RooAbsFunc *Ql, double pointEstimate, double stepSize, double &lo, double &hi, double nSigma) const
Calculate a confidence interval using the cumulative functions provided.
double seek(const RooAbsFunc &f, double startAt, double step, double value) const
Scan f(x)-value until it changes sign.
bool getPoissonInterval(Int_t n, double &mu1, double &mu2, double nSigma=1) const
Calculate a confidence interval for the expected number of events given n observed (unweighted) event...
static RooAbsFunc * createPoissonSum(Int_t n)
Create and return a PoissonSum function binding.
static RooAbsFunc * createBinomialSum(Int_t n, Int_t m, bool eff)
Create and return a BinomialSum function binding.
double chisquared_quantile_c(double z, double r)
Inverse ( ) of the cumulative distribution function of the upper tail of the distribution with degr...
double chisquared_quantile(double z, double r)
Inverse ( ) of the cumulative distribution function of the lower tail of the distribution with degr...
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TMarker m
Definition textangle.C:8