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 <cassert>
34#include <cmath>
35#include <ostream>
36
37using std::endl;
38
39
40////////////////////////////////////////////////////////////////////////////////
41/// Return a reference to a singleton object that is created the
42/// first time this method is called. Only one object will be
43/// constructed per ROOT session.
44
50
51
52////////////////////////////////////////////////////////////////////////////////
53/// Calculate a confidence interval for the expected number of events given n
54/// observed (unweighted) events. The interval will contain the same probability
55/// as nSigma of a Gaussian. Uses a central interval unless this does not enclose
56/// the point estimate n (ie, for small n) in which case the interval is adjusted
57/// to start at n.
58
59bool RooHistError::getPoissonInterval(Int_t n, double &mu1, double &mu2, double nSigma) const
60{
61 // sanity checks
62 if (n < 0) {
63 oocoutE(nullptr, Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n = " << n
64 << std::endl;
65 return false;
66 }
67 if (!(nSigma > 0.0)) {
68 oocoutE(nullptr, Plotting) << "RooHistError::getPoissonInterval: nSigma must be > 0, got " << nSigma << std::endl;
69 return false;
70 }
71
72 // Convert "number of sigmas" to central Gaussian probability beta, and
73 // corresponding two-sided tail probability alpha.
74 const double beta = std::erf(nSigma / std::sqrt(2.0));
75 const double alpha = 1.0 - beta;
76
77 // Special case n = 0 (boundary at mu >= 0).
78 // Use a one-sided interval including the MLE mu=0:
79 // mu1 = 0
80 // P(N <= 0 | mu2) = alpha,
81 // with alpha = 1 - erf(nSigma / sqrt(2)).
82 if (n == 0) {
83 mu1 = 0.0;
84 mu2 = 0.5 * ROOT::Math::chisquared_quantile(1.0 - alpha, 2.0 * (n + 1));
85 return true;
86 }
87
88 // For n>0, use the central (equal-tailed) Garwood interval, which
89 // corresponds to allocating alpha/2 in each tail.
90 const double a2 = 0.5 * alpha;
91 mu1 = 0.5 * ROOT::Math::chisquared_quantile(a2, 2.0 * n);
92 mu2 = 0.5 * ROOT::Math::chisquared_quantile_c(a2, 2.0 * (n + 1));
93 return true;
94}
95
96
97////////////////////////////////////////////////////////////////////////////////
98/// Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
99/// If the return values is false and error occurred.
100
102 double &asym1, double &asym2, double nSigma) const
103{
104 // sanity checks
105 if(n < 0 || m < 0) {
106 oocoutE(nullptr,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << std::endl;
107 return false;
108 }
109
110 // handle the special case of no events in either category
111 if(n == 0 && m == 0) {
112 asym1= -1;
113 asym2= +1;
114 return true;
115 }
116
117 // handle cases when n,m>100 (factorials in BinomialSum will overflow around 170)
118 if ((n>100&&m>100)) {
119 double N = n ;
120 double M = m ;
121 double asym = 1.0*(N-M)/(N+M) ;
122 double approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
123
126 return true ;
127 }
128
129 // swap n and m to ensure that n <= m
130 bool swapped(false);
131 if(n > m) {
132 swapped= true;
133 Int_t tmp(m);
134 m= n;
135 n= tmp;
136 }
137
138 // create the function objects to use
139 bool status(false);
141 if(n > 0) {
143 status= getInterval(&upper,&lower,(double)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
144 }
145 else {
146 status= getInterval(&upper,nullptr,(double)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
147 }
148
149 // undo the swap here
150 if(swapped) {
151 double tmp(asym1);
152 asym1= -asym2;
153 asym2= -tmp;
154 }
155
156 return status;
157}
158
159
160////////////////////////////////////////////////////////////////////////////////
161/// Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
162/// If the return values is false and error occurred.
163
165 double &asym1, double &asym2, double nSigma) const
166{
167 // sanity checks
168 if(n < 0 || m < 0) {
169 oocoutE(nullptr,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << std::endl;
170 return false;
171 }
172
173 // handle the special case of no events in either category
174 if(n == 0 && m == 0) {
175 asym1= -1;
176 asym2= +1;
177 return true;
178 }
179
180 // handle cases when n,m>80 (factorials in BinomialSum will overflow around 170)
181 if ((n>80&&m>80)) {
182 double N = n ;
183 double M = m ;
184 double asym = 1.0*(N)/(N+M) ;
185 double approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
186
187 asym1 = asym-nSigma*0.5*approxErr ;
188 asym2 = asym+nSigma*0.5*approxErr ;
189 return true ;
190 }
191
192 // swap n and m to ensure that n <= m
193 bool swapped(false);
194 if(n > m) {
195 swapped= true;
196 Int_t tmp(m);
197 m= n;
198 n= tmp;
199 }
200
201 // create the function objects to use
202 bool status(false);
204 double eff = (double)(n)/(n+m) ;
205 if(n > 0) {
206 BinomialSumEff lower(n-1,m+1);
207 status= getInterval(&upper,&lower,eff,0.1,asym1,asym2,nSigma*0.5);
208 }
209 else {
210 status= getInterval(&upper,nullptr,eff,0.1,asym1,asym2,nSigma*0.5);
211 }
212
213 // undo the swap here
214 if(swapped) {
215 double tmp(asym1);
216 asym1= 1-asym2;
217 asym2= 1-tmp;
218 }
219
220 return status;
221}
222
223
224
225////////////////////////////////////////////////////////////////////////////////
226/// Calculate a confidence interval using the cumulative functions provided.
227/// The interval will be "central" when both cumulative functions are provided,
228/// unless this would exclude the pointEstimate, in which case a one-sided interval
229/// pinned at the point estimate is returned instead.
230
232 double stepSize, double &lo, double &hi, double nSigma) const
233{
234 // sanity checks
235 assert(nullptr != Qu || nullptr != Ql);
236
237 // convert number of sigma into a confidence level
238 double beta= std::erf(nSigma/sqrt(2.));
239 double alpha= 0.5*(1-beta);
240
241 // Does the central interval contain the point estimate?
242 bool ok(true);
243 double loProb(1);
244 double hiProb(0);
245 if(nullptr != Ql) loProb= (*Ql)(&pointEstimate);
246 if(nullptr != Qu) hiProb= (*Qu)(&pointEstimate);
247
248 if (Qu && (nullptr == Ql || loProb > alpha + beta)) {
249 // Force the low edge to be at the pointEstimate
250 lo= pointEstimate;
251 double target= loProb - beta;
252 hi= seek(*Qu,lo,+stepSize,target);
254 ok= uFinder.findRoot(hi,hi-stepSize,hi,target);
255 }
256 else if(Ql && (nullptr == Qu || hiProb < alpha)) {
257 // Force the high edge to be at pointEstimate
259 double target= hiProb + beta;
260 lo= seek(*Ql,hi,-stepSize,target);
262 ok= lFinder.findRoot(lo,lo,lo+stepSize,target);
263 }
264 else if (Qu && Ql) {
265 // use a central interval
266 lo= seek(*Ql,pointEstimate,-stepSize,alpha+beta);
267 hi= seek(*Qu,pointEstimate,+stepSize,alpha);
270 ok= lFinder.findRoot(lo,lo,lo+stepSize,alpha+beta);
271 ok|= uFinder.findRoot(hi,hi-stepSize,hi,alpha);
272 }
273 if(!ok) oocoutE(nullptr,Plotting) << "RooHistError::getInterval: failed to find root(s)" << std::endl;
274
275 return ok;
276}
277
278
279////////////////////////////////////////////////////////////////////////////////
280/// Scan f(x)-value until it changes sign. Start at the specified point and take constant
281/// steps of the specified size. Give up after 1000 steps.
282
283double RooHistError::seek(const RooAbsFunc &f, double startAt, double step, double value) const
284{
285 Int_t steps(1000);
286 double min(f.getMinLimit(1));
287 double max(f.getMaxLimit(1));
288 double x(startAt);
289 double f0 = f(&startAt) - value;
290 do {
291 x+= step;
292 }
293 while(steps-- && (f0*(f(&x)-value) >= 0) && ((x-min)*(max-x) >= 0));
294 assert(0 != steps);
295 if(x < min) x= min;
296 if(x > max) x= max;
297
298 return x;
299}
300
301
302
303////////////////////////////////////////////////////////////////////////////////
304/// Create and return a PoissonSum function binding
305
310
311
312////////////////////////////////////////////////////////////////////////////////
313/// Create and return a BinomialSum function binding
314
316{
317 if (eff) {
318 return new BinomialSumEff(n,m) ;
319 } else {
320 return new BinomialSumAsym(n,m) ;
321 }
322}
#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