Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
MathFuncs.h
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Jonas Rembser, CERN 2024
5 * Garima Singh, CERN 2023
6 *
7 * Copyright (c) 2024, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
14#ifndef RooFit_Detail_MathFuncs_h
15#define RooFit_Detail_MathFuncs_h
16
17#include <TMath.h>
20
21#include <cmath>
22
23namespace RooFit {
24
25namespace Detail {
26
27namespace MathFuncs {
28
29/// Calculates the binomial coefficient n over k.
30/// Equivalent to TMath::Binomial, but inlined.
31inline double binomial(int n, int k)
32{
33 if (n < 0 || k < 0 || n < k)
34 return TMath::SignalingNaN();
35 if (k == 0 || n == k)
36 return 1;
37
38 int k1 = std::min(k, n - k);
39 int k2 = n - k1;
40 double fact = k2 + 1;
41 for (double i = k1; i > 1.; --i) {
42 fact *= (k2 + i) / i;
43 }
44 return fact;
45}
46
47/// The caller needs to make sure that there is at least one coefficient.
48inline double bernstein(double x, double xmin, double xmax, double *coefs, int nCoefs)
49{
50 double xScaled = (x - xmin) / (xmax - xmin); // rescale to [0,1]
51 int degree = nCoefs - 1; // n+1 polys of degree n
52
53 // in case list of arguments passed is empty
54 if (degree < 0) {
55 return TMath::SignalingNaN();
56 } else if (degree == 0) {
57 return coefs[0];
58 } else if (degree == 1) {
59
60 double a0 = coefs[0]; // c0
61 double a1 = coefs[1] - a0; // c1 - c0
62 return a1 * xScaled + a0;
63
64 } else if (degree == 2) {
65
66 double a0 = coefs[0]; // c0
67 double a1 = 2 * (coefs[1] - a0); // 2 * (c1 - c0)
68 double a2 = coefs[2] - a1 - a0; // c0 - 2 * c1 + c2
69 return (a2 * xScaled + a1) * xScaled + a0;
70 }
71
72 double t = xScaled;
73 double s = 1. - xScaled;
74
75 double result = coefs[0] * s;
76 for (int i = 1; i < degree; i++) {
77 result = (result + t * binomial(degree, i) * coefs[i]) * s;
78 t *= xScaled;
79 }
80 result += t * coefs[degree];
81
82 return result;
83}
84
85/// @brief Function to evaluate an un-normalized RooGaussian.
86inline double gaussian(double x, double mean, double sigma)
87{
88 const double arg = x - mean;
89 const double sig = sigma;
90 return std::exp(-0.5 * arg * arg / (sig * sig));
91}
92
93inline double product(double const *factors, std::size_t nFactors)
94{
95 double out = 1.0;
96 for (std::size_t i = 0; i < nFactors; ++i) {
97 out *= factors[i];
98 }
99 return out;
100}
101
102// RooRatio evaluate function.
103inline double ratio(double numerator, double denominator)
104{
105 return numerator / denominator;
106}
107
108inline double bifurGauss(double x, double mean, double sigmaL, double sigmaR)
109{
110 // Note: this simplification does not work with Clad as of v1.1!
111 // return gaussian(x, mean, x < mean ? sigmaL : sigmaR);
112 if (x < mean)
113 return gaussian(x, mean, sigmaL);
114 return gaussian(x, mean, sigmaR);
115}
116
117inline double efficiency(double effFuncVal, int catIndex, int sigCatIndex)
118{
119 // Truncate efficiency function in range 0.0-1.0
120 effFuncVal = std::clamp(effFuncVal, 0.0, 1.0);
121
122 if (catIndex == sigCatIndex)
123 return effFuncVal; // Accept case
124 else
125 return 1 - effFuncVal; // Reject case
126}
127
128/// In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
129template <bool pdfMode = false>
130inline double polynomial(double const *coeffs, int nCoeffs, int lowestOrder, double x)
131{
132 double retVal = coeffs[nCoeffs - 1];
133 for (int i = nCoeffs - 2; i >= 0; i--)
134 retVal = coeffs[i] + x * retVal;
135 retVal = retVal * std::pow(x, lowestOrder);
136 return retVal + (pdfMode && lowestOrder > 0 ? 1.0 : 0.0);
137}
138
139inline double chebychev(double *coeffs, unsigned int nCoeffs, double x_in, double xMin, double xMax)
140{
141 // transform to range [-1, +1]
142 const double xPrime = (x_in - 0.5 * (xMax + xMin)) / (0.5 * (xMax - xMin));
143
144 // extract current values of coefficients
145 double sum = 1.;
146 if (nCoeffs > 0) {
147 double curr = xPrime;
148 double twox = 2 * xPrime;
149 double last = 1;
150 double newval = twox * curr - last;
151 last = curr;
152 curr = newval;
153 for (unsigned int i = 0; nCoeffs != i; ++i) {
154 sum += last * coeffs[i];
155 newval = twox * curr - last;
156 last = curr;
157 curr = newval;
158 }
159 }
160 return sum;
161}
162
163inline double constraintSum(double const *comp, unsigned int compSize)
164{
165 double sum = 0;
166 for (unsigned int i = 0; i < compSize; i++) {
167 sum -= std::log(comp[i]);
168 }
169 return sum;
170}
171
172inline unsigned int getUniformBinning(double low, double high, double val, unsigned int numBins)
173{
174 double binWidth = (high - low) / numBins;
175 return val >= high ? numBins - 1 : std::abs((val - low) / binWidth);
176}
177
178inline double interpolate1d(double low, double high, double val, unsigned int numBins, double const* vals)
179{
180 double binWidth = (high - low) / numBins;
181 int idx = val >= high ? numBins - 1 : std::abs((val - low) / binWidth);
182
183 // interpolation
184 double central = low + (idx + 0.5) * binWidth;
185 if (val > low + 0.5 * binWidth && val < high - 0.5 * binWidth) {
186 double slope;
187 if (val < central) {
188 slope = vals[idx] - vals[idx - 1];
189 } else {
190 slope = vals[idx + 1] - vals[idx];
191 }
192 return vals[idx] + slope * (val - central) / binWidth;
193 }
194
195 return vals[idx];
196}
197
198inline double poisson(double x, double par)
199{
200 if (par < 0)
201 return TMath::QuietNaN();
202
203 if (x < 0) {
204 return 0;
205 } else if (x == 0.0) {
206 return std::exp(-par);
207 } else {
208 double out = x * std::log(par) - TMath::LnGamma(x + 1.) - par;
209 return std::exp(out);
210 }
211}
212
213inline double flexibleInterpSingle(unsigned int code, double low, double high, double boundary, double nominal,
214 double paramVal, double res)
215{
216 if (code == 0) {
217 // piece-wise linear
218 if (paramVal > 0) {
219 return paramVal * (high - nominal);
220 } else {
221 return paramVal * (nominal - low);
222 }
223 } else if (code == 1) {
224 // piece-wise log
225 if (paramVal >= 0) {
226 return res * (std::pow(high / nominal, +paramVal) - 1);
227 } else {
228 return res * (std::pow(low / nominal, -paramVal) - 1);
229 }
230 } else if (code == 2) {
231 // parabolic with linear
232 double a = 0.5 * (high + low) - nominal;
233 double b = 0.5 * (high - low);
234 double c = 0;
235 if (paramVal > 1) {
236 return (2 * a + b) * (paramVal - 1) + high - nominal;
237 } else if (paramVal < -1) {
238 return -1 * (2 * a - b) * (paramVal + 1) + low - nominal;
239 } else {
240 return a * std::pow(paramVal, 2) + b * paramVal + c;
241 }
242 } else if (code == 3) {
243 // parabolic version of log-normal
244 double a = 0.5 * (high + low) - nominal;
245 double b = 0.5 * (high - low);
246 double c = 0;
247 if (paramVal > 1) {
248 return (2 * a + b) * (paramVal - 1) + high - nominal;
249 } else if (paramVal < -1) {
250 return -1 * (2 * a - b) * (paramVal + 1) + low - nominal;
251 } else {
252 return a * std::pow(paramVal, 2) + b * paramVal + c;
253 }
254 } else if (code == 4) {
255 double x = paramVal;
256 if (x >= boundary) {
257 return x * (high - nominal);
258 } else if (x <= -boundary) {
259 return x * (nominal - low);
260 }
261
262 // interpolate 6th degree
263 double t = x / boundary;
264 double eps_plus = high - nominal;
265 double eps_minus = nominal - low;
266 double S = 0.5 * (eps_plus + eps_minus);
267 double A = 0.0625 * (eps_plus - eps_minus);
268
269 return x * (S + t * A * (15 + t * t * (-10 + t * t * 3)));
270 } else if (code == 5) {
271 double x = paramVal;
272 double mod = 1.0;
273 if (x >= boundary) {
274 mod = std::pow(high / nominal, +paramVal);
275 } else if (x <= -boundary) {
276 mod = std::pow(low / nominal, -paramVal);
277 } else {
278 // interpolate 6th degree exp
279 double x0 = boundary;
280
281 high /= nominal;
282 low /= nominal;
283
284 // GHL: Swagato's suggestions
285 double powUp = std::pow(high, x0);
286 double powDown = std::pow(low, x0);
287 double logHi = std::log(high);
288 double logLo = std::log(low);
289 double powUpLog = high <= 0.0 ? 0.0 : powUp * logHi;
290 double powDownLog = low <= 0.0 ? 0.0 : -powDown * logLo;
291 double powUpLog2 = high <= 0.0 ? 0.0 : powUpLog * logHi;
292 double powDownLog2 = low <= 0.0 ? 0.0 : -powDownLog * logLo;
293
294 double S0 = 0.5 * (powUp + powDown);
295 double A0 = 0.5 * (powUp - powDown);
296 double S1 = 0.5 * (powUpLog + powDownLog);
297 double A1 = 0.5 * (powUpLog - powDownLog);
298 double S2 = 0.5 * (powUpLog2 + powDownLog2);
299 double A2 = 0.5 * (powUpLog2 - powDownLog2);
300
301 // fcns+der+2nd_der are eq at bd
302
303 double a = 1. / (8 * x0) * (15 * A0 - 7 * x0 * S1 + x0 * x0 * A2);
304 double b = 1. / (8 * x0 * x0) * (-24 + 24 * S0 - 9 * x0 * A1 + x0 * x0 * S2);
305 double c = 1. / (4 * std::pow(x0, 3)) * (-5 * A0 + 5 * x0 * S1 - x0 * x0 * A2);
306 double d = 1. / (4 * std::pow(x0, 4)) * (12 - 12 * S0 + 7 * x0 * A1 - x0 * x0 * S2);
307 double e = 1. / (8 * std::pow(x0, 5)) * (+3 * A0 - 3 * x0 * S1 + x0 * x0 * A2);
308 double f = 1. / (8 * std::pow(x0, 6)) * (-8 + 8 * S0 - 5 * x0 * A1 + x0 * x0 * S2);
309
310 // evaluate the 6-th degree polynomial using Horner's method
311 double value = 1. + x * (a + x * (b + x * (c + x * (d + x * (e + x * f)))));
312 mod = value;
313 }
314 return res * (mod - 1.0);
315 }
316
317 return 0.0;
318}
319
320inline double flexibleInterp(unsigned int code, double const *params, unsigned int n, double const *low,
321 double const *high, double boundary, double nominal, int doCutoff)
322{
323 double total = nominal;
324 for (std::size_t i = 0; i < n; ++i) {
325 total += flexibleInterpSingle(code, low[i], high[i], boundary, nominal, params[i], total);
326 }
327
328 return doCutoff && total <= 0 ? TMath::Limits<double>::Min() : total;
329}
330
331inline double landau(double x, double mu, double sigma)
332{
333 if (sigma <= 0.)
334 return 0.;
335 return ROOT::Math::landau_pdf((x - mu) / sigma);
336}
337
338inline double logNormal(double x, double k, double m0)
339{
340 return ROOT::Math::lognormal_pdf(x, std::log(m0), std::abs(std::log(k)));
341}
342
343inline double logNormalStandard(double x, double sigma, double mu)
344{
345 return ROOT::Math::lognormal_pdf(x, mu, std::abs(sigma));
346}
347
348inline double effProd(double eff, double pdf)
349{
350 return eff * pdf;
351}
352
353inline double nll(double pdf, double weight, int binnedL, int doBinOffset)
354{
355 if (binnedL) {
356 // Special handling of this case since std::log(Poisson(0,0)=0 but can't be
357 // calculated with usual log-formula since std::log(mu)=0. No update of result
358 // is required since term=0.
359 if (std::abs(pdf) < 1e-10 && std::abs(weight) < 1e-10) {
360 return 0.0;
361 }
362 if (doBinOffset) {
363 return pdf - weight - weight * (std::log(pdf) - std::log(weight));
364 }
365 return pdf - weight * std::log(pdf) + TMath::LnGamma(weight + 1);
366 } else {
367 return -weight * std::log(pdf);
368 }
369}
370
371inline double recursiveFraction(double *a, unsigned int n)
372{
373 double prod = a[0];
374
375 for (unsigned int i = 1; i < n; ++i) {
376 prod *= 1.0 - a[i];
377 }
378
379 return prod;
380}
381
382inline double cbShape(double m, double m0, double sigma, double alpha, double n)
383{
384 double t = (m - m0) / sigma;
385 if (alpha < 0)
386 t = -t;
387
388 double absAlpha = std::abs((double)alpha);
389
390 if (t >= -absAlpha) {
391 return std::exp(-0.5 * t * t);
392 } else {
393 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
394 double b = n / absAlpha - absAlpha;
395
396 return a / std::pow(b - t, n);
397 }
398}
399
400// For RooCBShape
401inline double approxErf(double arg)
402{
403 if (arg > 5.0)
404 return 1.0;
405 if (arg < -5.0)
406 return -1.0;
407
408 return TMath::Erf(arg);
409}
410
411/// @brief Function to calculate the integral of an un-normalized RooGaussian over x. To calculate the integral over
412/// mean, just interchange the respective values of x and mean.
413/// @param xMin Minimum value of variable to integrate wrt.
414/// @param xMax Maximum value of of variable to integrate wrt.
415/// @param mean Mean.
416/// @param sigma Sigma.
417/// @return The integral of an un-normalized RooGaussian over the value in x.
418inline double gaussianIntegral(double xMin, double xMax, double mean, double sigma)
419{
420 // The normalisation constant 1./sqrt(2*pi*sigma^2) is left out in evaluate().
421 // Therefore, the integral is scaled up by that amount to make RooFit normalise
422 // correctly.
423 double resultScale = 0.5 * std::sqrt(TMath::TwoPi()) * sigma;
424
425 // Here everything is scaled and shifted into a standard normal distribution:
426 double xscale = TMath::Sqrt2() * sigma;
427 double scaledMin = 0.;
428 double scaledMax = 0.;
429 scaledMin = (xMin - mean) / xscale;
430 scaledMax = (xMax - mean) / xscale;
431
432 // Here we go for maximum precision: We compute all integrals in the UPPER
433 // tail of the Gaussian, because erfc has the highest precision there.
434 // Therefore, the different cases for range limits in the negative hemisphere are mapped onto
435 // the equivalent points in the upper hemisphere using erfc(-x) = 2. - erfc(x)
436 double ecmin = TMath::Erfc(std::abs(scaledMin));
437 double ecmax = TMath::Erfc(std::abs(scaledMax));
438
439 double cond = 0.0;
440 // Don't put this "prd" inside the "if" because clad will not be able to differentiate the code correctly (as of
441 // v1.1)!
442 double prd = scaledMin * scaledMax;
443 if (prd < 0.0) {
444 cond = 2.0 - (ecmin + ecmax);
445 } else if (scaledMax <= 0.0) {
446 cond = ecmax - ecmin;
447 } else {
448 cond = ecmin - ecmax;
449 }
450 return resultScale * cond;
451}
452
453inline double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
454{
455 const double xscaleL = TMath::Sqrt2() * sigmaL;
456 const double xscaleR = TMath::Sqrt2() * sigmaR;
457
458 const double resultScale = 0.5 * std::sqrt(TMath::TwoPi());
459
460 if (xMax < mean) {
461 return resultScale * (sigmaL * (TMath::Erf((xMax - mean) / xscaleL) - TMath::Erf((xMin - mean) / xscaleL)));
462 } else if (xMin > mean) {
463 return resultScale * (sigmaR * (TMath::Erf((xMax - mean) / xscaleR) - TMath::Erf((xMin - mean) / xscaleR)));
464 } else {
465 return resultScale *
466 (sigmaR * TMath::Erf((xMax - mean) / xscaleR) - sigmaL * TMath::Erf((xMin - mean) / xscaleL));
467 }
468}
469
470inline double exponentialIntegral(double xMin, double xMax, double constant)
471{
472 if (constant == 0.0) {
473 return xMax - xMin;
474 }
475
476 return (std::exp(constant * xMax) - std::exp(constant * xMin)) / constant;
477}
478
479/// In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
480template <bool pdfMode = false>
481inline double polynomialIntegral(double const *coeffs, int nCoeffs, int lowestOrder, double xMin, double xMax)
482{
483 int denom = lowestOrder + nCoeffs;
484 double min = coeffs[nCoeffs - 1] / double(denom);
485 double max = coeffs[nCoeffs - 1] / double(denom);
486
487 for (int i = nCoeffs - 2; i >= 0; i--) {
488 denom--;
489 min = (coeffs[i] / double(denom)) + xMin * min;
490 max = (coeffs[i] / double(denom)) + xMax * max;
491 }
492
493 max = max * std::pow(xMax, 1 + lowestOrder);
494 min = min * std::pow(xMin, 1 + lowestOrder);
495
496 return max - min + (pdfMode && lowestOrder > 0.0 ? xMax - xMin : 0.0);
497}
498
499/// use fast FMA if available, fall back to normal arithmetic if not
500inline double fast_fma(double x, double y, double z) noexcept
501{
502#if defined(FP_FAST_FMA) // check if std::fma has fast hardware implementation
503 return std::fma(x, y, z);
504#else // defined(FP_FAST_FMA)
505 // std::fma might be slow, so use a more pedestrian implementation
506#if defined(__clang__)
507#pragma STDC FP_CONTRACT ON // hint clang that using an FMA is okay here
508#endif // defined(__clang__)
509 return (x * y) + z;
510#endif // defined(FP_FAST_FMA)
511}
512
513inline double chebychevIntegral(double const *coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull,
514 double xMaxFull)
515{
516 const double halfrange = .5 * (xMax - xMin);
517 const double mid = .5 * (xMax + xMin);
518
519 // the full range of the function is mapped to the normalised [-1, 1] range
520 const double b = (xMaxFull - mid) / halfrange;
521 const double a = (xMinFull - mid) / halfrange;
522
523 // coefficient for integral(T_0(x)) is 1 (implicit), integrate by hand
524 // T_0(x) and T_1(x), and use for n > 1: integral(T_n(x) dx) =
525 // (T_n+1(x) / (n + 1) - T_n-1(x) / (n - 1)) / 2
526 double sum = b - a; // integrate T_0(x) by hand
527
528 const unsigned int iend = nCoeffs;
529 if (iend > 0) {
530 {
531 // integrate T_1(x) by hand...
532 const double c = coeffs[0];
533 sum = fast_fma(0.5 * (b + a) * (b - a), c, sum);
534 }
535 if (1 < iend) {
536 double bcurr = b;
537 double btwox = 2 * b;
538 double blast = 1;
539
540 double acurr = a;
541 double atwox = 2 * a;
542 double alast = 1;
543
544 double newval = atwox * acurr - alast;
545 alast = acurr;
546 acurr = newval;
547
548 newval = btwox * bcurr - blast;
549 blast = bcurr;
550 bcurr = newval;
551 double nminus1 = 1.;
552 for (unsigned int i = 1; iend != i; ++i) {
553 // integrate using recursion relation
554 const double c = coeffs[i];
555 const double term2 = (blast - alast) / nminus1;
556
557 newval = atwox * acurr - alast;
558 alast = acurr;
559 acurr = newval;
560
561 newval = btwox * bcurr - blast;
562 blast = bcurr;
563 bcurr = newval;
564
565 ++nminus1;
566 const double term1 = (bcurr - acurr) / (nminus1 + 1.);
567 const double intTn = 0.5 * (term1 - term2);
568 sum = fast_fma(intTn, c, sum);
569 }
570 }
571 }
572
573 // take care to multiply with the right factor to account for the mapping to
574 // normalised range [-1, 1]
575 return halfrange * sum;
576}
577
578// The last param should be of type bool but it is not as that causes some issues with Cling for some reason...
579inline double
580poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
581{
582 if (protectNegative && mu < 0.0) {
583 return std::exp(-2.0 * mu); // make it fall quickly
584 }
585
586 if (code == 1) {
587 // Implement integral over x as summation. Add special handling in case
588 // range boundaries are not on integer values of x
589 integrandMin = std::max(0., integrandMin);
590
591 if (integrandMax < 0. || integrandMax < integrandMin) {
592 return 0;
593 }
594 const double delta = 100.0 * std::sqrt(mu);
595 // If the limits are more than many standard deviations away from the mean,
596 // we might as well return the integral of the full Poisson distribution to
597 // save computing time.
598 if (integrandMin < std::max(mu - delta, 0.0) && integrandMax > mu + delta) {
599 return 1.;
600 }
601
602 // The range as integers. ixMin is included, ixMax outside.
603 const unsigned int ixMin = integrandMin;
604 const unsigned int ixMax = std::min(integrandMax + 1, (double)std::numeric_limits<unsigned int>::max());
605
606 // Sum from 0 to just before the bin outside of the range.
607 if (ixMin == 0) {
608 return ROOT::Math::gamma_cdf_c(mu, ixMax, 1);
609 } else {
610 // If necessary, subtract from 0 to the beginning of the range
611 if (ixMin <= mu) {
612 return ROOT::Math::gamma_cdf_c(mu, ixMax, 1) - ROOT::Math::gamma_cdf_c(mu, ixMin, 1);
613 } else {
614 // Avoid catastrophic cancellation in the high tails:
615 return ROOT::Math::gamma_cdf(mu, ixMin, 1) - ROOT::Math::gamma_cdf(mu, ixMax, 1);
616 }
617 }
618 }
619
620 // the integral with respect to the mean is the integral of a gamma distribution
621 // negative ix does not need protection (gamma returns 0.0)
622 const double ix = 1 + x;
623
624 return ROOT::Math::gamma_cdf(integrandMax, ix, 1.0) - ROOT::Math::gamma_cdf(integrandMin, ix, 1.0);
625}
626
627inline double logNormalIntegral(double xMin, double xMax, double m0, double k)
628{
629 const double root2 = std::sqrt(2.);
630
631 double ln_k = std::abs(std::log(k));
632 double ret =
633 0.5 * (TMath::Erf(std::log(xMax / m0) / (root2 * ln_k)) - TMath::Erf(std::log(xMin / m0) / (root2 * ln_k)));
634
635 return ret;
636}
637
638inline double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
639{
640 const double root2 = std::sqrt(2.);
641
642 double ln_k = std::abs(sigma);
643 double ret =
644 0.5 * (TMath::Erf((std::log(xMax) - mu) / (root2 * ln_k)) - TMath::Erf((std::log(xMin) - mu) / (root2 * ln_k)));
645
646 return ret;
647}
648
649inline double cbShapeIntegral(double mMin, double mMax, double m0, double sigma, double alpha, double n)
650{
651 const double sqrtPiOver2 = 1.2533141373;
652 const double sqrt2 = 1.4142135624;
653
654 double result = 0.0;
655 bool useLog = false;
656
657 if (std::abs(n - 1.0) < 1.0e-05)
658 useLog = true;
659
660 double sig = std::abs(sigma);
661
662 double tmin = (mMin - m0) / sig;
663 double tmax = (mMax - m0) / sig;
664
665 if (alpha < 0) {
666 double tmp = tmin;
667 tmin = -tmax;
668 tmax = -tmp;
669 }
670
671 double absAlpha = std::abs(alpha);
672
673 if (tmin >= -absAlpha) {
674 result += sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(tmin / sqrt2));
675 } else if (tmax <= -absAlpha) {
676 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
677 double b = n / absAlpha - absAlpha;
678
679 if (useLog) {
680 result += a * sig * (std::log(b - tmin) - std::log(b - tmax));
681 } else {
682 result += a * sig / (1.0 - n) * (1.0 / (std::pow(b - tmin, n - 1.0)) - 1.0 / (std::pow(b - tmax, n - 1.0)));
683 }
684 } else {
685 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
686 double b = n / absAlpha - absAlpha;
687
688 double term1 = 0.0;
689 if (useLog) {
690 term1 = a * sig * (std::log(b - tmin) - std::log(n / absAlpha));
691 } else {
692 term1 = a * sig / (1.0 - n) * (1.0 / (std::pow(b - tmin, n - 1.0)) - 1.0 / (std::pow(n / absAlpha, n - 1.0)));
693 }
694
695 double term2 = sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(-absAlpha / sqrt2));
696
697 result += term1 + term2;
698 }
699
700 if (result == 0)
701 return 1.E-300;
702 return result;
703}
704
705inline double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, double *coefs, int nCoefs)
706{
707 double xloScaled = (xlo - xmin) / (xmax - xmin);
708 double xhiScaled = (xhi - xmin) / (xmax - xmin);
709
710 int degree = nCoefs - 1; // n+1 polys of degree n
711 double norm = 0.;
712
713 for (int i = 0; i <= degree; ++i) {
714 // for each of the i Bernstein basis polynomials
715 // represent it in the 'power basis' (the naive polynomial basis)
716 // where the integral is straight forward.
717 double temp = 0.;
718 for (int j = i; j <= degree; ++j) { // power basisŧ
719 double binCoefs = binomial(degree, j) * binomial(j, i);
720 double oneOverJPlusOne = 1. / (j + 1.);
721 double powDiff = std::pow(xhiScaled, j + 1.) - std::pow(xloScaled, j + 1.);
722 temp += std::pow(-1., j - i) * binCoefs * powDiff * oneOverJPlusOne;
723 }
724 temp *= coefs[i]; // include coeff
725 norm += temp; // add this basis's contribution to total
726 }
727
728 return norm * (xmax - xmin);
729}
730
731} // namespace MathFuncs
732
733} // namespace Detail
734
735} // namespace RooFit
736
737#endif
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define S0(x)
Definition RSha256.hxx:88
#define S1(x)
Definition RSha256.hxx:89
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
static unsigned int total
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 result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
float xmin
float xmax
double lognormal_pdf(double x, double m, double s, double x0=0)
Probability density function of the lognormal distribution.
double landau_pdf(double x, double xi=1, double x0=0)
Probability density function of the Landau distribution:
double gamma_cdf_c(double x, double alpha, double theta, double x0=0)
Complement of the cumulative distribution function of the gamma distribution (upper tail).
double gamma_cdf(double x, double alpha, double theta, double x0=0)
Cumulative distribution function of the gamma distribution (lower tail).
const Double_t sigma
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
double logNormalIntegral(double xMin, double xMax, double m0, double k)
Definition MathFuncs.h:627
double gaussianIntegral(double xMin, double xMax, double mean, double sigma)
Function to calculate the integral of an un-normalized RooGaussian over x.
Definition MathFuncs.h:418
double chebychevIntegral(double const *coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull, double xMaxFull)
Definition MathFuncs.h:513
double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
Definition MathFuncs.h:453
double cbShape(double m, double m0, double sigma, double alpha, double n)
Definition MathFuncs.h:382
double polynomial(double const *coeffs, int nCoeffs, int lowestOrder, double x)
In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
Definition MathFuncs.h:130
double recursiveFraction(double *a, unsigned int n)
Definition MathFuncs.h:371
double constraintSum(double const *comp, unsigned int compSize)
Definition MathFuncs.h:163
double cbShapeIntegral(double mMin, double mMax, double m0, double sigma, double alpha, double n)
Definition MathFuncs.h:649
double fast_fma(double x, double y, double z) noexcept
use fast FMA if available, fall back to normal arithmetic if not
Definition MathFuncs.h:500
double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
Definition MathFuncs.h:638
double landau(double x, double mu, double sigma)
Definition MathFuncs.h:331
double gaussian(double x, double mean, double sigma)
Function to evaluate an un-normalized RooGaussian.
Definition MathFuncs.h:86
double product(double const *factors, std::size_t nFactors)
Definition MathFuncs.h:93
double chebychev(double *coeffs, unsigned int nCoeffs, double x_in, double xMin, double xMax)
Definition MathFuncs.h:139
double poisson(double x, double par)
Definition MathFuncs.h:198
double binomial(int n, int k)
Calculates the binomial coefficient n over k.
Definition MathFuncs.h:31
unsigned int getUniformBinning(double low, double high, double val, unsigned int numBins)
Definition MathFuncs.h:172
double flexibleInterpSingle(unsigned int code, double low, double high, double boundary, double nominal, double paramVal, double res)
Definition MathFuncs.h:213
double interpolate1d(double low, double high, double val, unsigned int numBins, double const *vals)
Definition MathFuncs.h:178
double logNormalStandard(double x, double sigma, double mu)
Definition MathFuncs.h:343
double bifurGauss(double x, double mean, double sigmaL, double sigmaR)
Definition MathFuncs.h:108
double ratio(double numerator, double denominator)
Definition MathFuncs.h:103
double polynomialIntegral(double const *coeffs, int nCoeffs, int lowestOrder, double xMin, double xMax)
In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
Definition MathFuncs.h:481
double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, double *coefs, int nCoefs)
Definition MathFuncs.h:705
double approxErf(double arg)
Definition MathFuncs.h:401
double effProd(double eff, double pdf)
Definition MathFuncs.h:348
double poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
Definition MathFuncs.h:580
double logNormal(double x, double k, double m0)
Definition MathFuncs.h:338
double nll(double pdf, double weight, int binnedL, int doBinOffset)
Definition MathFuncs.h:353
double bernstein(double x, double xmin, double xmax, double *coefs, int nCoefs)
The caller needs to make sure that there is at least one coefficient.
Definition MathFuncs.h:48
double efficiency(double effFuncVal, int catIndex, int sigCatIndex)
Definition MathFuncs.h:117
double flexibleInterp(unsigned int code, double const *params, unsigned int n, double const *low, double const *high, double boundary, double nominal, int doCutoff)
Definition MathFuncs.h:320
double exponentialIntegral(double xMin, double xMax, double constant)
Definition MathFuncs.h:470
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition JSONIO.h:26
Double_t Erf(Double_t x)
Computation of the error function erf(x).
Definition TMath.cxx:190
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754.
Definition TMath.h:902
constexpr Double_t Sqrt2()
Definition TMath.h:86
Double_t Erfc(Double_t x)
Computes the complementary error function erfc(x).
Definition TMath.cxx:199
Double_t LnGamma(Double_t z)
Computation of ln[gamma(z)] for all z.
Definition TMath.cxx:509
Double_t SignalingNaN()
Returns a signaling NaN as defined by IEEE 754](http://en.wikipedia.org/wiki/NaN#Signaling_NaN).
Definition TMath.h:910
constexpr Double_t TwoPi()
Definition TMath.h:44
TMarker m
Definition textangle.C:8
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345