Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooPoisson.cxx
Go to the documentation of this file.
1  /*****************************************************************************
2  * Project: RooFit *
3  * *
4  * Simple Poisson PDF
5  * author: Kyle Cranmer <cranmer@cern.ch>
6  * *
7  *****************************************************************************/
8 
9 /** \class RooPoisson
10  \ingroup Roofit
11 
12 Poisson pdf
13 **/
14 
15 #include "RooPoisson.h"
16 
17 #include "RooAbsReal.h"
18 #include "RooAbsCategory.h"
19 
20 #include "RooRandom.h"
21 #include "RooMath.h"
22 #include "TMath.h"
23 #include "Math/ProbFuncMathCore.h"
24 
25 #include "BatchHelpers.h"
26 #include "RooVDTHeaders.h"
27 
28 #include <limits>
29 #include <cmath>
30 
31 using namespace std;
32 
33 ClassImp(RooPoisson);
34 
35 ////////////////////////////////////////////////////////////////////////////////
36 /// Constructor
37 
38 RooPoisson::RooPoisson(const char *name, const char *title,
39  RooAbsReal& _x,
40  RooAbsReal& _mean,
41  Bool_t noRounding) :
42  RooAbsPdf(name,title),
43  x("x","x",this,_x),
44  mean("mean","mean",this,_mean),
45  _noRounding(noRounding),
46  _protectNegative(false)
47 {
48 }
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Copy constructor
52 
53  RooPoisson::RooPoisson(const RooPoisson& other, const char* name) :
54  RooAbsPdf(other,name),
55  x("x",this,other.x),
56  mean("mean",this,other.mean),
57  _noRounding(other._noRounding),
58  _protectNegative(other._protectNegative)
59 {
60 }
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 /// Implementation in terms of the TMath::Poisson() function.
64 
65 Double_t RooPoisson::evaluate() const
66 {
67  Double_t k = _noRounding ? x : floor(x);
68  if(_protectNegative && mean<0)
69  return 1e-3;
70  return TMath::Poisson(k,mean) ;
71 }
72 
73 
74 
75 namespace {
76 
77 template<class Tx, class TMean>
78 void compute(const size_t n, double* __restrict output, Tx x, TMean mean,
79  const bool protectNegative, const bool noRounding) {
80 
81  for (size_t i = 0; i < n; ++i) { //CHECK_VECTORISE
82  const double x_i = noRounding ? x[i] : floor(x[i]);
83  // The std::lgamma yields different values than in the scalar implementation.
84  // Need to check which one is more accurate.
85 // output[i] = std::lgamma(x_i + 1.);
86  output[i] = TMath::LnGamma(x_i + 1.);
87  }
88 
89 
90  for (size_t i = 0; i < n; ++i) { //CHECK_VECTORISE
91  const double x_i = noRounding ? x[i] : floor(x[i]);
92  const double logMean = _rf_fast_log(mean[i]);
93  const double logPoisson = x_i * logMean - mean[i] - output[i];
94  output[i] = _rf_fast_exp(logPoisson);
95 
96  // Cosmetics
97  if (x_i < 0.)
98  output[i] = 0.;
99  else if (x_i == 0.) {
100  output[i] = 1./_rf_fast_exp(mean[i]);
101  }
102  if (protectNegative && mean[i] < 0.)
103  output[i] = 1.E-3;
104  }
105 }
106 
107 }
108 
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Compute Poisson values in batches.
112 RooSpan<double> RooPoisson::evaluateBatch(std::size_t begin, std::size_t batchSize) const {
113  using namespace BatchHelpers;
114  auto xData = x.getValBatch(begin, batchSize);
115  auto meanData = mean.getValBatch(begin, batchSize);
116  const bool batchX = !xData.empty();
117  const bool batchMean = !meanData.empty();
118 
119  if (!batchX && !batchMean) {
120  return {};
121  }
122  batchSize = findSize({ xData, meanData });
123  auto output = _batchData.makeWritableBatchUnInit(begin, batchSize);
124 
125  if (batchX && !batchMean ) {
126  compute(batchSize, output.data(), xData, BracketAdapter<double>(mean), _protectNegative, _noRounding);
127  }
128  else if (!batchX && batchMean ) {
129  compute(batchSize, output.data(), BracketAdapter<double>(x), meanData, _protectNegative, _noRounding);
130  }
131  else if (batchX && batchMean ) {
132  compute(batchSize, output.data(), xData, meanData, _protectNegative, _noRounding);
133  }
134  return output;
135 }
136 
137 
138 ////////////////////////////////////////////////////////////////////////////////
139 
140 Int_t RooPoisson::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
141 {
142  if (matchArgs(allVars,analVars,x)) return 1 ;
143  if (matchArgs(allVars, analVars, mean)) return 2;
144  return 0 ;
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 
149 Double_t RooPoisson::analyticalIntegral(Int_t code, const char* rangeName) const
150 {
151  R__ASSERT(code == 1 || code == 2) ;
152 
153  if(_protectNegative && mean<0)
154  return exp(-2*mean); // make it fall quickly
155 
156  if (code == 1) {
157  // Implement integral over x as summation. Add special handling in case
158  // range boundaries are not on integer values of x
159  const double xmin = std::max(0., x.min(rangeName));
160  const double xmax = x.max(rangeName);
161 
162  if (xmax < 0. || xmax < xmin) {
163  return 0.;
164  }
165  if (!x.hasMax() || RooNumber::isInfinite(xmax)) {
166  //Integrating the full Poisson distribution here
167  return 1.;
168  }
169 
170  // The range as integers. ixmin is included, ixmax outside.
171  const unsigned int ixmin = xmin;
172  const unsigned int ixmax = std::min(xmax + 1.,
173  (double)std::numeric_limits<unsigned int>::max());
174 
175  // Sum from 0 to just before the bin outside of the range.
176  if (ixmin == 0) {
177  return ROOT::Math::poisson_cdf(ixmax - 1, mean);
178  }
179  else {
180  // If necessary, subtract from 0 to the beginning of the range
181  if (ixmin <= mean) {
182  return ROOT::Math::poisson_cdf(ixmax - 1, mean) - ROOT::Math::poisson_cdf(ixmin - 1, mean);
183  }
184  else {
185  //Avoid catastrophic cancellation in the high tails:
186  return ROOT::Math::poisson_cdf_c(ixmin - 1, mean) - ROOT::Math::poisson_cdf_c(ixmax - 1, mean);
187  }
188 
189  }
190 
191  } else if(code == 2) {
192 
193  // the integral with respect to the mean is the integral of a gamma distribution
194  Double_t mean_min = mean.min(rangeName);
195  Double_t mean_max = mean.max(rangeName);
196 
197  Double_t ix;
198  if(_noRounding) ix = x + 1;
199  else ix = Int_t(TMath::Floor(x)) + 1.0; // negative ix does not need protection (gamma returns 0.0)
200 
201  return ROOT::Math::gamma_cdf(mean_max, ix, 1.0) - ROOT::Math::gamma_cdf(mean_min, ix, 1.0);
202  }
203 
204  return 0;
205 
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// Advertise internal generator in x
210 
211 Int_t RooPoisson::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const
212 {
213  if (matchArgs(directVars,generateVars,x)) return 1 ;
214  return 0 ;
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Implement internal generator using TRandom::Poisson
219 
220 void RooPoisson::generateEvent(Int_t code)
221 {
222  R__ASSERT(code==1) ;
223  Double_t xgen ;
224  while(1) {
225  xgen = RooRandom::randomGenerator()->Poisson(mean);
226  if (xgen<=x.max() && xgen>=x.min()) {
227  x = xgen ;
228  break;
229  }
230  }
231  return;
232 }