libatomprobe
Library for Atom Probe Tomography (APT) computation
confidence.cpp
Go to the documentation of this file.
1 /* confidence.cpp : confidence interval estimation routines
2  * Copyright (C) 2020 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <algorithm>
18 #include <limits>
19 #include <cmath>
20 #include <vector>
21 #include <numeric>
22 
23 #include "atomprobe/atomprobe.h"
24 
26 //Brute-force testing
27 #include <gsl/gsl_cdf.h>
28 #include <gsl/gsl_randist.h>
29 #include <gsl/gsl_histogram.h>
30 
31 
32 //Root finding
33 #include <gsl/gsl_errno.h>
34 #include <gsl/gsl_math.h>
35 #include <gsl/gsl_roots.h>
36 
37 using std::vector;
38 
39 //FIXME: we perform quantile estimations by interpolation of the CDF.
40 // GSL provides more quantile estimators, such as gsl_stats_quantile_from_sorted_data
41 // we should probably use these rather than our own
42 
43 //FIXME: The numerical esitmation routines share a lot of code, and only the core
44 // random variable computation changes. We should merge these, possibly using lambda functions
45 namespace AtomProbe{
46 //Kahan Summation
47 //https://codereview.stackexchange.com/questions/56532/kahan-summation
48 template <class T, class T2>
49 typename std::iterator_traits<T>::value_type kahansum(T begin, T end, T2 other) {
50  typedef typename std::iterator_traits<T>::value_type real;
51  real sum = real();
52  real running_error = real();
53 
54  for ( ; begin != end; ++begin) {
55  real difference = *begin - running_error;
56  real temp = sum + difference;
57  running_error = (temp - sum) - difference;
58  sum = temp;
59  *other=sum;
60  ++other;
61  }
62  return sum;
63 }
64 
65 
66 //Brute-force poisson ratio confidence estimator
67 // Biased, as it enforces 1, in the denominator of L1/L2 (ie L2=0 has p=0)
68 bool numericalEstimatePoissRatioConf(float lambda1,float lambda2, float alpha,
69  unsigned int nTrials, gsl_rng *r,float &lBound, float &uBound )
70 {
71  vector<float> values;
72  values.resize(nTrials);
73 
74  //will always be zero for l1
75  if(lambda1 == 0)
76  return false;
77 
78  //Compute Z=X/Y
79  float vMin,vMax;
80  vMin=std::numeric_limits<float>::max();
81  vMax=-vMin;
82  for(auto &v : values)
83  {
84  v=gsl_ran_poisson(r,lambda1)/(float)std::max(gsl_ran_poisson(r,lambda2),1u);
85  vMin=std::min(v,vMin);
86  vMax=std::max(v,vMax);
87  }
88 
89  if(vMin >=vMax)
90  return false;
91 
92  //Create histogram
93  const unsigned int nBins=sqrt(values.size())/2.0f;
94  gsl_histogram *h=gsl_histogram_alloc(nBins);
95  gsl_histogram_set_ranges_uniform(h,vMin,vMax);
96  for(auto &v:values)
97  gsl_histogram_increment(h,v);
98 
99  //Distribution function. First we compute PDF, then integrate
100  vector<float> df;
101  df.resize(nBins);
102  for(auto ui=0u;ui<nBins;ui++)
103  df[ui]=gsl_histogram_get(h,ui);
104 
105  gsl_histogram_free(h);
106 
107  //Normalise to create PDF
108  double dSum=0;;
109  for(auto v : df)
110  dSum +=v;
111  for(auto &v : df)
112  v/=dSum;
113 
114  //OK, so now this gives us the PDF, we have to compute the CDF
115  double accum=0;
116  for(auto &v :df)
117  {
118  accum+=v;
119  v=accum;
120  }
121 
122  //Find upper confidence limit
123  //===
124  auto alphaIt = std::lower_bound(df.begin(),df.end(),alpha);
125 
126  if(alphaIt == df.end())
127  return false;
128 
129  unsigned int offset = std::distance(df.begin(),alphaIt);
130 
131  if(offset > 1)
132  {
133  float dy= df[offset] - df[offset-1];
134  float dx= (vMax-vMin)/(float)df.size();
135 
136  uBound = (alpha-df[offset-1])*dx/dy + (offset-1)*dx + vMin;
137  }
138  else
139  return false;
140  //===
141 
142  //Find lower confidence limit
143  //===
144  alphaIt = std::upper_bound(df.begin(),df.end(),1.0-alpha);
145  if(alphaIt==df.begin())
146  lBound=0;
147  else
148  {
149 
150  offset = std::distance(df.begin(),alphaIt);
151 
152  if(offset < df.size()-1)
153  {
154  float dy= df[offset] - df[offset-1];
155  float dx= (vMax-vMin)/(float)df.size();
156 
157  lBound = ((1.0-alpha)-df[offset])*dx/dy + offset*dx +vMin;
158  }
159  else
160  return false;
161  }
162  //===
163 
164 
165  ASSERT(lBound<=lambda1/lambda2);
166  ASSERT(uBound>=lambda1/lambda2);
167  ASSERT(lBound<=uBound);
168 
169  return true;
170 }
171 
172 //Brute-force Skellam confidence estimator
173 bool numericalEstimateSkellamConf(float lambda1,float lambda2, float alpha,
174  unsigned int nTrials, gsl_rng *r,float &lBound, float &uBound )
175 {
176  vector<float> values;
177  values.resize(nTrials);
178 
179  //Compute Z=X-Y
180  float vMin,vMax;
181  vMin=std::numeric_limits<float>::max();
182  vMax=-vMin;
183  for(auto &v : values)
184  {
185  float v1,v2;
186  v1=gsl_ran_poisson(r,lambda1);
187  v2=gsl_ran_poisson(r,lambda2);
188 
189  v=v1-v2;
190  vMin=std::min(v,vMin);
191  vMax=std::max(v,vMax);
192  }
193 
194  //Create histogram
195  const unsigned int nBins=sqrt(values.size())/2.0f;
196  gsl_histogram *h=gsl_histogram_alloc(nBins);
197  gsl_histogram_set_ranges_uniform(h,vMin,vMax);
198  for(auto &v:values)
199  gsl_histogram_increment(h,v);
200 
201 
202 
203  //Distribution function. First we compute PDF, then integrate
204  vector<float> df;
205  df.resize(nBins);
206  for(auto ui=0u;ui<nBins;ui++)
207  df[ui]=gsl_histogram_get(h,ui);
208 
209  gsl_histogram_free(h);
210 
211  //Normalise to create PDF
212  double dSum=0;;
213  for(auto v : df)
214  dSum +=v;
215  for(auto &v : df)
216  v/=dSum;
217 
218  //OK, so now this gives us the PDF, we have to compute the CDF
219  double accum=0;
220  for(auto &v :df)
221  {
222  accum+=v;
223  v=accum;
224  }
225 
226  //Find upper confidence limit
227  //===
228  auto alphaIt = std::lower_bound(df.begin(),df.end(),alpha);
229 
230  if(alphaIt == df.end())
231  return false;
232 
233  unsigned int offset = std::distance(df.begin(),alphaIt);
234 
235  if(offset > 1)
236  {
237  float dy= df[offset] - df[offset-1];
238  float dx= (vMax-vMin)/(float)df.size();
239 
240  uBound = (alpha-df[offset-1])*dx/dy + (offset-1)*dx + vMin;
241  }
242  else
243  return false;
244  //===
245 
246  //Find lower confidence limit
247  //===
248  alphaIt = std::upper_bound(df.begin(),df.end(),1.0-alpha);
249  if(alphaIt==df.begin())
250  lBound=0;
251  else
252  {
253 
254  offset = std::distance(df.begin(),alphaIt);
255 
256  if(offset < df.size()-1)
257  {
258  float dy= df[offset] - df[offset-1];
259  float dx= (vMax-vMin)/(float)df.size();
260 
261  lBound = ((1.0-alpha)-df[offset])*dx/dy + offset*dx +vMin;
262  }
263  else
264  return false;
265  }
266  //===
267 
268 
269  ASSERT(lBound<=uBound);
270 
271  return true;
272 }
273 //Brute-force gaussian ratio confidence estimator
274 // Biased, as it enforces >1, in the denominator of L1/L2 (ie L2=0 has p=0)
275 bool numericalEstimateGaussRatioConf(float mu1,float mu2,float var1, float var2, float alpha,
276  unsigned int nTrials, gsl_rng *r,float &lBound, float &uBound )
277 {
278  vector<float> values;
279  values.resize(nTrials);
280 
281  //Compute Z=X/Y
282  float vMin,vMax;
283  vMin=std::numeric_limits<float>::max();
284  vMax=-vMin;
285  for(auto &v : values)
286  {
287  v=(gsl_ran_gaussian(r,sqrt(var1))+mu1)/
288  std::max(gsl_ran_gaussian(r,sqrt(var2))+mu2,1.0);
289  vMin=std::min(v,vMin);
290  vMax=std::max(v,vMax);
291  }
292 
293  if(vMin >=vMax)
294  return false;
295 
296  //Create histogram
297  const unsigned int nBins=sqrt(values.size())/2.0f;
298  gsl_histogram *h=gsl_histogram_alloc(nBins);
299  gsl_histogram_set_ranges_uniform(h,vMin,vMax);
300  for(auto &v:values)
301  gsl_histogram_increment(h,v);
302 
303  //Distribution function. First we compute PDF, then integrate
304  vector<float> df;
305  df.resize(nBins);
306  for(auto ui=0u;ui<nBins;ui++)
307  df[ui]=gsl_histogram_get(h,ui);
308 
309  gsl_histogram_free(h);
310 
311  //Normalise to create PDF
312  double dSum=0;;
313  for(auto v : df)
314  dSum +=v;
315  for(auto &v : df)
316  v/=dSum;
317 
318  //OK, so now this gives us the PDF, we have to compute the CDF
319  double accum=0;
320  for(auto &v :df)
321  {
322  accum+=v;
323  v=accum;
324  }
325 
326  //Find upper confidence limit
327  //===
328  auto alphaIt = std::lower_bound(df.begin(),df.end(),alpha);
329 
330  if(alphaIt == df.end())
331  return false;
332 
333  unsigned int offset = std::distance(df.begin(),alphaIt);
334 
335  if(offset > 1)
336  {
337  float dy= df[offset] - df[offset-1];
338  float dx= (vMax-vMin)/(float)df.size();
339 
340  uBound = (alpha-df[offset-1])*dx/dy + (offset-1)*dx + vMin;
341  }
342  else
343  return false;
344  //===
345 
346  //Find lower confidence limit
347  //===
348  alphaIt = std::upper_bound(df.begin(),df.end(),1.0-alpha);
349  if(alphaIt==df.begin())
350  lBound=0;
351  else
352  {
353 
354  offset = std::distance(df.begin(),alphaIt);
355 
356  if(offset < df.size()-1)
357  {
358  float dy= df[offset] - df[offset-1];
359  float dx= (vMax-vMin)/(float)df.size();
360 
361  lBound = ((1.0-alpha)-df[offset])*dx/dy + offset*dx +vMin;
362  }
363  else
364  return false;
365  }
366  //===
367 
368 
369  ASSERT(lBound<=mu1/mu2);
370  ASSERT(uBound>=mu1/mu2);
371  ASSERT(lBound<=uBound);
372 
373  return true;
374 }
375 
376 
377 struct ZECH_ROOT
378 {
379  float alpha;
380  float lambdaBack;
381  float observation;
382 };
383 
384 //Find the root of zech CDF with a specified alpha, at observed signal+back = "observation"
385 // and background intensity of "lambdaBack"
386 double zechRoot(double sigGuess,void *params)
387 {
388  ZECH_ROOT *zr = (ZECH_ROOT*)params;
389 
390  //Initial guess for signal
391  double denom=1.0/gsl_cdf_poisson_P(zr->observation,zr->lambdaBack);
392  double epsilon=0;
393 
394  for(auto i=0u; i<=zr->observation;i++)
395  epsilon+= gsl_ran_poisson_pdf(i,sigGuess+zr->lambdaBack);
396 
397  epsilon*=denom;
398  //Convert to confidence
399  epsilon=1-epsilon;
400 
401  //subtract to get confidence we want as root
402  return epsilon-zr->alpha;
403 }
404 
405 //Obtain the confidence limits at a specified alpha for zech, using a bisection approach
406 bool zechConfidenceLimits(float lambdaBack, unsigned int observation, float alpha,
407  float &estimate)
408 {
409  ASSERT(lambdaBack > 0);
410 
411  //We are working with Equation 3, and the combined distribution W
412  // in Zech.
413 
414  ZECH_ROOT zr;
415  zr.alpha=alpha;
418 
419  gsl_function F;
420  F.function = zechRoot;
421  F.params=&zr;
422 
423  float xLow=0;
424  float xHi=std::max((float)observation,lambdaBack)*5.0f;
425 
426  //Use Brent's method
427  gsl_root_fsolver *s = gsl_root_fsolver_alloc (gsl_root_fsolver_brent);
428  gsl_root_fsolver_set (s, &F, xLow,xHi);
429 
430 
431  const unsigned int MAXITS=1000;
432 
433  auto it=0,status=0;
434  do
435  {
436 
437  gsl_root_fsolver_iterate (s);
438  xLow = gsl_root_fsolver_x_lower (s);
439  xHi = gsl_root_fsolver_x_upper (s);
440  status = gsl_root_test_interval (xLow, xHi,
441  0, 0.01);
442 
443  if (status == GSL_SUCCESS)
444  break;
445  } while(status ==GSL_CONTINUE && it < MAXITS);
446 
447 
448  estimate = gsl_root_fsolver_root (s);
449  gsl_root_fsolver_free(s);
450 
451  //Check for sanity
452  if(estimate<0 || isnan(estimate) || it >=MAXITS)
453  return false;
454 
455 
456  return true;
457 }
458 
459 
460 template<class T>
461 void cumTrapezoid(const vector<T> &x, const vector<T> &vals, vector<T> &res)
462 {
463  ASSERT(vals.size() ==x.size());
464 
465  vector<T> sumVals;
466  sumVals.resize(vals.size()+1);
467  sumVals[0]=0;
468 
469  //Perform stable summation
470  kahansum(vals.begin(),vals.begin()+vals.size(),sumVals.begin()+1);
471 
472  res.resize(x.size());
473  res[0]=0;
474  for(auto ui=1u;ui<vals.size();ui++)
475  res[ui] = 0.5*(sumVals[ui-1] + sumVals[ui])*(x[ui]-x[ui-1]);
476 
477 
478 }
479 
480 // https://en.wikipedia.org/wiki/Ratio_distribution#Gaussian_ratio_distribution (4 Apr, 2019)
481 // Checked with simple M-C simulation. The MC simulation seems to converge for trialed values
482 // as the MC support increases (as we artificially chopped the upper and lower simulation bounds at times)
483 double gauss_ratio_pdf(double x, double muX,double muY, double varX,double varY)
484 {
485  //Original equation is Eqn 1 & 2,
486  // From Hinkley, Biometrika, 1969. 56, 3, pp635
487  // DOI : 10.1093/biomet/56.3.635
488  // We assume rho (cross-correlation coefficient) = 0
489  double a = sqrt(x*x/varX + 1.0/varY);
490  double b =muX/varX*x + muY/varY;
491  double c = muX*muX/varX + muY*muY/varY;
492  double lnD = (b*b - c*a*a)/(2.0*a*a);
493 
494  double d = exp(lnD);
495 
496  double bDivA = b/a;
497 
498  double theta1 = 0.5*(1.0+erf(bDivA/sqrt(2.0)));
499  double theta2 = 0.5*(1.0+erf(-bDivA/sqrt(2.0)));
500 
501  double p1 = b*d/(a*a*a)*1/(sqrt(2*M_PI*varX*varY))*(theta1-theta2);
502 
503  double p2 = 1.0/(a*a*M_PI*sqrt(varX*varY))*exp(-c/2.0);
504 
505  return p1+p2;
506 }
507 
508 void poissonConfidenceObservation(float counts, float alpha, float &lBound, float &uBound)
509 {
510  ASSERT(counts >=0);
511  ASSERT(alpha>0 && alpha < 1);
512 
513  float a = gsl_cdf_chisq_Pinv(alpha,1);
514 
515 
516  lBound = counts + a/2.0 - sqrtf(a*(counts+a/4.0));
517  uBound = counts + a/2.0 + sqrtf(a*(counts+a/4.0));
518 /*
519  float alphaOne=(1.0f-alpha)/2.0;
520  float alphaTwo = 1.0-alphaOne;
521 
522  if(!counts)
523  lBound=0;
524  else
525  lBound=gsl_cdf_chisq_Pinv(alphaOne,2.0*observedCounts)/2.0f;
526 
527  uBound=gsl_cdf_chisq_Pinv(alphaTwo,2.0*(observedCounts+1))/2.0f;
528  */
529 }
530 
531 
532 
533 /* Problems with numerical stability, owing to very sharp PDF
534  - Either we need to estimate the support bounds better, or we
535  need to integrate the bivariate normal distribution numerically
536  to obtain the CDF semi-analytically
537 //Note: Future improvement:
538 // Hinkley (DOI 10.1093/biomet/56.3.635) provides what looks like an analytic CDF
539 // which has integrals in it. In this version, we analytically obtain the PDF, then numerically
540 // convert this to a CDF on a fixed support. An analytical expression could enable
541 // providing an explicit support and bin width unnecessary
542 bool estimateGaussianRatioConf(float muX, float muY,float varX, float varY,float alpha,
543  float &lBound, float &uBound, unsigned int nBins,float supportBound)
544 {
545  ASSERT(varX >0);
546  ASSERT(varY >0);
547  ASSERT(alpha >0.5 && alpha <1.0f);
548 
549  uBound=std::numeric_limits<float>::max();
550  lBound=-uBound;
551 
552  //Compute PDF
553  vector<double> support;
554  support.resize(nBins);
555  for(auto ui=0u;ui<support.size();ui++)
556  support[ui] = (ui - support.size()/2.0)*supportBound/nBins;
557 
558  vector<double> pdf;
559  pdf.resize(support.size());
560  for(auto ui=0u;ui<pdf.size();ui++)
561  pdf[ui] = gauss_ratio_pdf(support[ui],muX,muY,varX,varY);
562 
563  //Integrate PDF. Numerical drift can cause this to exceed 1
564  vector<double> cdf;
565  cumTrapezoid(support,pdf,cdf);
566 
567  //Normalise CDF
568  double cdfMax = *std::max_element(cdf.begin(),cdf.end());
569  for(auto &v : cdf )
570  v/=cdfMax;
571 
572  unsigned int alphaLowIdx=-1;
573  unsigned int alphaHighIdx=-1;
574  float oneAlpha = 1.0-alpha;
575 
576  auto alphaIt = std::lower_bound(cdf.begin(),cdf.end(),alpha);
577  if(alphaIt == cdf.end())
578  return false;
579  alphaHighIdx=std::distance(cdf.begin(),alphaIt);
580 
581  alphaIt = std::upper_bound(cdf.begin(),cdf.end(),oneAlpha);
582  if(alphaIt == cdf.end())
583  return false;
584  alphaLowIdx=std::distance(cdf.begin(),alphaIt);
585 
586  if(alphaHighIdx == (unsigned int)-1 || alphaLowIdx == (unsigned int) -1 ||
587  alphaHighIdx == 0 || alphaLowIdx == (cdf.size()-1))
588  return false;
589  else
590  {
591  //Linear interpolate
592  double dx,dy;
593  dx = support[alphaHighIdx] - support[alphaHighIdx-1];
594  dy = cdf[alphaHighIdx] - cdf[alphaHighIdx-1];
595  uBound = (alpha-cdf[alphaHighIdx])*dx/dy + support[alphaHighIdx];
596 
597  dx = support[alphaLowIdx+1] - support[alphaLowIdx];
598  dy = cdf[alphaLowIdx+1] - cdf[alphaLowIdx];
599  lBound = (oneAlpha-cdf[alphaLowIdx])*dx/dy + support[alphaLowIdx];
600 
601  }
602 
603  ASSERT(lBound <=muX/muY);
604  ASSERT(uBound >=muX/muY);
605 
606  ASSERT(lBound<=uBound);
607 
608  return true;
609 }
610 */
611 
612 #ifdef DEBUG
613 
614 bool runConfidenceTests()
615 {
616  using std::make_pair;
617  using std::map;
618  using std::pair;
619 
620  gsl_rng *rng =AtomProbe::randGen.getRng();
621  float lBound,uBound;
622 
623  //Map (lambda1,lambda2) -> skellam uBound
624  map<pair<float,float>, float> skelMap;
625 
626  //Values at alpha=0.99
627  //FIXME: These values were derived using a "hard cut" of the CDF
628  // (finding alpha > 0.99, over a limited support).
629  // Thus these are an over-estimation
630  skelMap[make_pair(100,100)]=141;
631  skelMap[make_pair(1,10)]=15;
632 
633  using std::endl;
634  using std::cerr;
635 
636  for(auto v : skelMap)
637  {
638  bool returnCode;
639  float l1,l2,res;
640  l1=v.first.first;
641  l2=v.first.second;
642  res=v.second;
643  returnCode=numericalEstimateSkellamConf(l1+l2,l2,0.99,10000,rng,lBound,uBound);
644 
645  ASSERT(returnCode);
646  ASSERT(fabs(uBound - res)/uBound < 0.5); // This is wide due to earlier overestimation
647  }
648 
649  //Test Zech's confidence bounds
650  {
651  //Map background,observation -> lower,upper confidence pair
652  //This is for alpha=(0.01,0.99)
653  map<pair<float,float>, pair<float,float> > confMap;
654  confMap[make_pair(1,10)]= make_pair(3.659,19.17);
655 
656  const float ALPHA=0.99;
657  for(auto &v : confMap)
658  {
659  float low,high;
660  TEST(zechConfidenceLimits(v.first.first,
661  v.first.second,ALPHA,high),"Zech UB");
662  TEST(zechConfidenceLimits(v.first.first,
663  v.first.second,1.0-ALPHA,low),"Zech LB");
664 
665  auto confPair = v.second;
666  TEST(low < confPair.first+0.5f,"Low confidence bound");
667  TEST(high > confPair.second-0.5f,"High confidence bound");
668  }
669  }
670 
671 
672 
673  //Poisson confidence values at fixed interval
674  //===
675  map<unsigned int,pair<float,float> > poissConfVals;
676 // Pearson values
677  poissConfVals[1] = make_pair(0.1765,5.6649);
678  poissConfVals[3] = make_pair(1.0203,8.8212);
679  poissConfVals[5] = make_pair(2.1357,11.7058);
680 /* "Exact" values
681  poissConfVals[1] = make_pair(0.0253,5.5716);
682  poissConfVals[3] = make_pair(0.6187,8.7673);
683  poissConfVals[5] = make_pair(1.6235,11.6683);
684 */
685 
686  for( auto v : poissConfVals)
687  {
688  float lPBound,uPBound;
689  poissonConfidenceObservation(v.first,0.95,lPBound,uPBound);
690  ASSERT(fabs(v.second.first -lPBound) < 0.01);
691  ASSERT(fabs(v.second.second - uPBound) < 0.01);
692  }
693  //===
694 
695 
696  //FIXME: Better unit tests. This simply exercises the
697  // code for crashes, and then runs it repeatedly.
698  // No numerical results are checked.
699  // also, we do not examine all functions
700  const unsigned int NREPEATS=250;
701  for(auto ui=0;ui<NREPEATS;ui++)
702  {
703  float v1,v2;
704  v1=gsl_ran_poisson(rng,360);
705  v2=gsl_ran_poisson(rng,125);
706 
707  numericalEstimateSkellamConf(v1,v2,0.99,1000,rng,lBound,uBound);
708 
709  if(!v2)
710  continue;
711 
712  numericalEstimatePoissRatioConf(v1,v2,0.95,1000,rng,lBound,uBound);
713  numericalEstimateGaussRatioConf(v1,v2,sqrt(v1),sqrt(v2),
714  0.95,1000,rng,lBound,uBound);
715 
716  }
717 
718  return true;
719 }
720 #endif
721 }
bool numericalEstimateSkellamConf(float lambda1, float lambda2, float alpha, unsigned int nTrials, gsl_rng *r, float &lBound, float &uBound)
Brute-force the confidence bounds of a skellam distribution.
Definition: confidence.cpp:173
double gauss_ratio_pdf(double x, double muX, double muY, double varX, double varY)
Definition: confidence.cpp:483
bool zechConfidenceLimits(float lambdaBack, unsigned int observation, float alpha, float &estimate)
Provides a best estimate for true signal when true signal, background.
Definition: confidence.cpp:406
#define TEST(f, g)
Definition: aptAssert.h:49
void cumTrapezoid(const vector< T > &x, const vector< T > &vals, vector< T > &res)
Definition: confidence.cpp:461
double zechRoot(double sigGuess, void *params)
Definition: confidence.cpp:386
std::iterator_traits< T >::value_type kahansum(T begin, T end, T2 other)
Definition: confidence.cpp:49
void poissonConfidenceObservation(float counts, float alpha, float &lBound, float &uBound)
Obtain poisson confidence limits for the mean of a poisson distribution.
Definition: confidence.cpp:508
#define M_PI
Definition: kd-example.cpp:34
bool numericalEstimatePoissRatioConf(float lambda1, float lambda2, float alpha, unsigned int nTrials, gsl_rng *r, float &lBound, float &uBound)
Brute-force poisson ratio confidence estimator. Returns the confidence interval in the estimate of th...
Definition: confidence.cpp:68
bool numericalEstimateGaussRatioConf(float mu1, float mu2, float var1, float var2, float alpha, unsigned int nTrials, gsl_rng *r, float &lBound, float &uBound)
Brute-force guassian ratio confidence estimator.
Definition: confidence.cpp:275
#define ASSERT(f)
gsl_rng * getRng() const
Obtain a GSL random number generator.
Definition: atomprobe.h:115
RandNumGen randGen
Definition: atomprobe.cpp:29