Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooGamma.cxx
Go to the documentation of this file.
1  /*****************************************************************************
2  * Project: RooFit *
3  * *
4  * Simple Gamma distribution
5  * authors: Stefan A. Schmitz, Gregory Schott
6  * *
7  *****************************************************************************/
8 
9 /** \class RooGamma
10  \ingroup Roofit
11 
12 Implementation of the Gamma PDF for RooFit/RooStats.
13 \f[
14 f(x) = \frac{(x-\mu)^{\gamma-1} \cdot \exp^{(-(x-mu) / \beta}}{\Gamma(\gamma) \cdot \beta^{\gamma}}
15 \f]
16 defined for \f$ x \geq 0 \f$ if \f$ \mu = 0 \f$
17 
18 Notes from Kyle Cranmer:
19 
20 Wikipedia and several sources refer to the Gamma distribution as
21 
22 \f[
23 G(\mu,\alpha,\beta) = \beta^\alpha \mu^{(\alpha-1)} \frac{e^{(-\beta \mu)}}{\Gamma(\alpha)}
24 \f]
25 
26 Below is the correspondence:
27 
28 | Wikipedia | This Implementation |
29 |-----------------|--------------------------|
30 | \f$ \alpha \f$ | \f$ \gamma \f$ |
31 | \f$ \beta \f$ | \f$ \frac{1}{\beta} \f$ |
32 | \f$ \mu \f$ | x |
33 | 0 | \f$ \mu \f$ |
34 
35 
36 Note, that for a model Pois(N|mu), a uniform prior on mu, and a measurement N
37 the posterior is in the Wikipedia parameterization Gamma(mu, alpha=N+1, beta=1)
38 thus for this implementation it is:
39 
40 `RooGamma(_x=mu,_gamma=N+1,_beta=1,_mu=0)`
41 
42 Also note, that in this case it is equivalent to
43 RooPoison(N,mu) and treating the function as a PDF in mu.
44 **/
45 
46 #include "RooGamma.h"
47 
48 #include "RooAbsReal.h"
49 #include "RooRealVar.h"
50 #include "RooRandom.h"
51 #include "RooMath.h"
52 #include "RooHelpers.h"
53 #include "BatchHelpers.h"
54 #include "RooVDTHeaders.h"
55 
56 #include "TMath.h"
57 #include <Math/SpecFuncMathCore.h>
58 #include <Math/PdfFuncMathCore.h>
59 #include <Math/ProbFuncMathCore.h>
60 
61 #include <iostream>
62 #include <cmath>
63 using namespace std;
64 
65 ClassImp(RooGamma);
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 
69 RooGamma::RooGamma(const char *name, const char *title,
70  RooAbsReal& _x, RooAbsReal& _gamma,
71  RooAbsReal& _beta, RooAbsReal& _mu) :
72  RooAbsPdf(name,title),
73  x("x","Observable",this,_x),
74  gamma("gamma","Mean",this,_gamma),
75  beta("beta","Width",this,_beta),
76  mu("mu","Para",this,_mu)
77 {
78  RooHelpers::checkRangeOfParameters(this, {&_gamma, &_beta}, 0.);
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 
83 RooGamma::RooGamma(const RooGamma& other, const char* name) :
84  RooAbsPdf(other,name), x("x",this,other.x), gamma("mean",this,other.gamma),
85  beta("beta",this,other.beta), mu("mu",this,other.mu)
86 {
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 
91 Double_t RooGamma::evaluate() const
92 {
93  return TMath::GammaDist(x, gamma, mu, beta) ;
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 
98 namespace {
99 //Author: Emmanouil Michalainas, CERN 22 August 2019
100 
101 template<class Tx, class Tgamma, class Tbeta, class Tmu>
102 void compute( size_t batchSize,
103  double * __restrict output,
104  Tx X, Tgamma G, Tbeta B, Tmu M)
105 {
106  constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
107  for (size_t i=0; i<batchSize; i++) {
108  if (X[i]<M[i] || G[i] <= 0.0 || B[i] <= 0.0) {
109  output[i] = NaN;
110  }
111  if (X[i] == M[i]) {
112  output[i] = (G[i]==1.0)/B[i];
113  }
114  else {
115  output[i] = 0.0;
116  }
117  }
118 
119  if (G.isBatch()) {
120  for (size_t i=0; i<batchSize; i++) {
121  if (output[i] == 0.0) {
122  output[i] = -std::lgamma(G[i]);
123  }
124  }
125  }
126  else {
127  double gamma = -std::lgamma(G[2019]);
128  for (size_t i=0; i<batchSize; i++) {
129  if (output[i] == 0.0) {
130  output[i] = gamma;
131  }
132  }
133  }
134 
135  for (size_t i=0; i<batchSize; i++) {
136  if (X[i] != M[i]) {
137  const double invBeta = 1/B[i];
138  double arg = (X[i]-M[i])*invBeta;
139  output[i] -= arg;
140  arg = _rf_fast_log(arg);
141  output[i] += arg*(G[i]-1);
142  output[i] = _rf_fast_exp(output[i]);
143  output[i] *= invBeta;
144  }
145  }
146 }
147 };
148 
149 RooSpan<double> RooGamma::evaluateBatch(std::size_t begin, std::size_t batchSize) const {
150  using namespace BatchHelpers;
151 
152  EvaluateInfo info = getInfo( {&x, &gamma, &beta, &mu}, begin, batchSize );
153  if (info.nBatches == 0) {
154  return {};
155  }
156  auto output = _batchData.makeWritableBatchUnInit(begin, batchSize);
157  auto xData = x.getValBatch(begin, info.size);
158 
159  if (info.nBatches==1 && !xData.empty()) {
160  compute(info.size, output.data(), xData.data(),
161  BracketAdapter<double> (gamma),
162  BracketAdapter<double> (beta),
163  BracketAdapter<double> (mu));
164  }
165  else {
166  compute(info.size, output.data(),
167  BracketAdapterWithMask (x,x.getValBatch(begin,info.size)),
168  BracketAdapterWithMask (gamma,gamma.getValBatch(begin,info.size)),
169  BracketAdapterWithMask (beta,beta.getValBatch(begin,info.size)),
170  BracketAdapterWithMask (mu,mu.getValBatch(begin,info.size)));
171  }
172  return output;
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 
177 Int_t RooGamma::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
178 {
179  if (matchArgs(allVars,analVars,x)) return 1 ;
180  return 0 ;
181 }
182 
183 ////////////////////////////////////////////////////////////////////////////////
184 
185 Double_t RooGamma::analyticalIntegral(Int_t code, const char* rangeName) const
186 {
187  R__ASSERT(code==1) ;
188 
189  //integral of the Gamma distribution via ROOT::Math
190  Double_t integral = ROOT::Math::gamma_cdf(x.max(rangeName), gamma, beta, mu) - ROOT::Math::gamma_cdf(x.min(rangeName), gamma, beta, mu);
191  return integral ;
192 }
193 
194 ////////////////////////////////////////////////////////////////////////////////
195 
196 Int_t RooGamma::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const
197 {
198  if (matchArgs(directVars,generateVars,x)) return 1 ;
199  return 0 ;
200 }
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 /// algorithm adapted from code example in:
204 /// Marsaglia, G. and Tsang, W. W.
205 /// A Simple Method for Generating Gamma Variables
206 /// ACM Transactions on Mathematical Software, Vol. 26, No. 3, September 2000
207 ///
208 /// The speed of this algorithm depends on the speed of generating normal variates.
209 /// The algorithm is limited to \f$ \gamma \geq 0 \f$ !
210 
211 void RooGamma::generateEvent(Int_t code)
212 {
213  R__ASSERT(code==1) ;
214 
215 
216  while(1) {
217 
218  double d = 0;
219  double c = 0;
220  double xgen = 0;
221  double v = 0;
222  double u = 0;
223  d = gamma -1./3.; c = 1./TMath::Sqrt(9.*d);
224 
225  while(v <= 0.){
226  xgen = RooRandom::randomGenerator()->Gaus(); v = 1. + c*xgen;
227  }
228  v = v*v*v; u = RooRandom::randomGenerator()->Uniform();
229  if( u < 1.-.0331*(xgen*xgen)*(xgen*xgen) ) {
230  if ( (((d*v)* beta + mu ) < x.max()) && (((d*v)* beta + mu) > x.min()) ) {
231  x = ((d*v)* beta + mu) ;
232  break;
233  }
234  }
235  if( TMath::Log(u) < 0.5*xgen*xgen + d*(1.-v + TMath::Log(v)) ) {
236  if ( (((d*v)* beta + mu ) < x.max()) && (((d*v)* beta + mu) > x.min()) ) {
237  x = ((d*v)* beta + mu) ;
238  break;
239  }
240  }
241 
242  }
243 
244 
245  return;
246 }
247 
248