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 poisson(double x, double par)
179{
180 if (par < 0)
181 return TMath::QuietNaN();
182
183 if (x < 0) {
184 return 0;
185 } else if (x == 0.0) {
186 return std::exp(-par);
187 } else {
188 double out = x * std::log(par) - TMath::LnGamma(x + 1.) - par;
189 return std::exp(out);
190 }
191}
192
193inline double flexibleInterpSingle(unsigned int code, double low, double high, double boundary, double nominal,
194 double paramVal, double res)
195{
196 if (code == 0) {
197 // piece-wise linear
198 if (paramVal > 0) {
199 return paramVal * (high - nominal);
200 } else {
201 return paramVal * (nominal - low);
202 }
203 } else if (code == 1) {
204 // piece-wise log
205 if (paramVal >= 0) {
206 return res * (std::pow(high / nominal, +paramVal) - 1);
207 } else {
208 return res * (std::pow(low / nominal, -paramVal) - 1);
209 }
210 } else if (code == 2) {
211 // parabolic with linear
212 double a = 0.5 * (high + low) - nominal;
213 double b = 0.5 * (high - low);
214 double c = 0;
215 if (paramVal > 1) {
216 return (2 * a + b) * (paramVal - 1) + high - nominal;
217 } else if (paramVal < -1) {
218 return -1 * (2 * a - b) * (paramVal + 1) + low - nominal;
219 } else {
220 return a * std::pow(paramVal, 2) + b * paramVal + c;
221 }
222 } else if (code == 3) {
223 // parabolic version of log-normal
224 double a = 0.5 * (high + low) - nominal;
225 double b = 0.5 * (high - low);
226 double c = 0;
227 if (paramVal > 1) {
228 return (2 * a + b) * (paramVal - 1) + high - nominal;
229 } else if (paramVal < -1) {
230 return -1 * (2 * a - b) * (paramVal + 1) + low - nominal;
231 } else {
232 return a * std::pow(paramVal, 2) + b * paramVal + c;
233 }
234 } else if (code == 4) {
235 double x = paramVal;
236 if (x >= boundary) {
237 return x * (high - nominal);
238 } else if (x <= -boundary) {
239 return x * (nominal - low);
240 }
241
242 // interpolate 6th degree
243 double t = x / boundary;
244 double eps_plus = high - nominal;
245 double eps_minus = nominal - low;
246 double S = 0.5 * (eps_plus + eps_minus);
247 double A = 0.0625 * (eps_plus - eps_minus);
248
249 return x * (S + t * A * (15 + t * t * (-10 + t * t * 3)));
250 } else if (code == 5) {
251 double x = paramVal;
252 double mod = 1.0;
253 if (x >= boundary) {
254 mod = std::pow(high / nominal, +paramVal);
255 } else if (x <= -boundary) {
256 mod = std::pow(low / nominal, -paramVal);
257 } else {
258 // interpolate 6th degree exp
259 double x0 = boundary;
260
261 // GHL: Swagato's suggestions
262 double powUp = std::pow(high / nominal, x0);
263 double powDown = std::pow(low / nominal, x0);
264 double logHi = std::log(high);
265 double logLo = std::log(low);
266 double powUpLog = high <= 0.0 ? 0.0 : powUp * logHi;
267 double powDownLog = low <= 0.0 ? 0.0 : -powDown * logLo;
268 double powUpLog2 = high <= 0.0 ? 0.0 : powUpLog * logHi;
269 double powDownLog2 = low <= 0.0 ? 0.0 : -powDownLog * logLo;
270
271 double S0 = 0.5 * (powUp + powDown);
272 double A0 = 0.5 * (powUp - powDown);
273 double S1 = 0.5 * (powUpLog + powDownLog);
274 double A1 = 0.5 * (powUpLog - powDownLog);
275 double S2 = 0.5 * (powUpLog2 + powDownLog2);
276 double A2 = 0.5 * (powUpLog2 - powDownLog2);
277
278 // fcns+der+2nd_der are eq at bd
279
280 double a = 1. / (8 * x0) * (15 * A0 - 7 * x0 * S1 + x0 * x0 * A2);
281 double b = 1. / (8 * x0 * x0) * (-24 + 24 * S0 - 9 * x0 * A1 + x0 * x0 * S2);
282 double c = 1. / (4 * std::pow(x0, 3)) * (-5 * A0 + 5 * x0 * S1 - x0 * x0 * A2);
283 double d = 1. / (4 * std::pow(x0, 4)) * (12 - 12 * S0 + 7 * x0 * A1 - x0 * x0 * S2);
284 double e = 1. / (8 * std::pow(x0, 5)) * (+3 * A0 - 3 * x0 * S1 + x0 * x0 * A2);
285 double f = 1. / (8 * std::pow(x0, 6)) * (-8 + 8 * S0 - 5 * x0 * A1 + x0 * x0 * S2);
286
287 // evaluate the 6-th degree polynomial using Horner's method
288 double value = 1. + x * (a + x * (b + x * (c + x * (d + x * (e + x * f)))));
289 mod = value;
290 }
291 return res * (mod - 1.0);
292 }
293
294 return 0.0;
295}
296
297inline double flexibleInterp(unsigned int code, double *params, unsigned int n, double *low, double *high,
298 double boundary, double nominal, int doCutoff)
299{
300 double total = nominal;
301 for (std::size_t i = 0; i < n; ++i) {
302 total += flexibleInterpSingle(code, low[i], high[i], boundary, nominal, params[i], total);
303 }
304
305 return doCutoff && total <= 0 ? TMath::Limits<double>::Min() : total;
306}
307
308inline double landau(double x, double mu, double sigma)
309{
310 if (sigma <= 0.)
311 return 0.;
312 return ROOT::Math::landau_pdf((x - mu) / sigma);
313}
314
315inline double logNormal(double x, double k, double m0)
316{
317 return ROOT::Math::lognormal_pdf(x, std::log(m0), std::abs(std::log(k)));
318}
319
320inline double logNormalStandard(double x, double sigma, double mu)
321{
322 return ROOT::Math::lognormal_pdf(x, mu, std::abs(sigma));
323}
324
325inline double effProd(double eff, double pdf)
326{
327 return eff * pdf;
328}
329
330inline double nll(double pdf, double weight, int binnedL, int doBinOffset)
331{
332 if (binnedL) {
333 // Special handling of this case since std::log(Poisson(0,0)=0 but can't be
334 // calculated with usual log-formula since std::log(mu)=0. No update of result
335 // is required since term=0.
336 if (std::abs(pdf) < 1e-10 && std::abs(weight) < 1e-10) {
337 return 0.0;
338 }
339 if (doBinOffset) {
340 return pdf - weight - weight * (std::log(pdf) - std::log(weight));
341 }
342 return pdf - weight * std::log(pdf) + TMath::LnGamma(weight + 1);
343 } else {
344 return -weight * std::log(pdf);
345 }
346}
347
348inline double recursiveFraction(double *a, unsigned int n)
349{
350 double prod = a[0];
351
352 for (unsigned int i = 1; i < n; ++i) {
353 prod *= 1.0 - a[i];
354 }
355
356 return prod;
357}
358
359inline double cbShape(double m, double m0, double sigma, double alpha, double n)
360{
361 double t = (m - m0) / sigma;
362 if (alpha < 0)
363 t = -t;
364
365 double absAlpha = std::abs((double)alpha);
366
367 if (t >= -absAlpha) {
368 return std::exp(-0.5 * t * t);
369 } else {
370 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
371 double b = n / absAlpha - absAlpha;
372
373 return a / std::pow(b - t, n);
374 }
375}
376
377// For RooCBShape
378inline double approxErf(double arg)
379{
380 if (arg > 5.0)
381 return 1.0;
382 if (arg < -5.0)
383 return -1.0;
384
385 return TMath::Erf(arg);
386}
387
388/// @brief Function to calculate the integral of an un-normalized RooGaussian over x. To calculate the integral over
389/// mean, just interchange the respective values of x and mean.
390/// @param xMin Minimum value of variable to integrate wrt.
391/// @param xMax Maximum value of of variable to integrate wrt.
392/// @param mean Mean.
393/// @param sigma Sigma.
394/// @return The integral of an un-normalized RooGaussian over the value in x.
395inline double gaussianIntegral(double xMin, double xMax, double mean, double sigma)
396{
397 // The normalisation constant 1./sqrt(2*pi*sigma^2) is left out in evaluate().
398 // Therefore, the integral is scaled up by that amount to make RooFit normalise
399 // correctly.
400 double resultScale = 0.5 * std::sqrt(TMath::TwoPi()) * sigma;
401
402 // Here everything is scaled and shifted into a standard normal distribution:
403 double xscale = TMath::Sqrt2() * sigma;
404 double scaledMin = 0.;
405 double scaledMax = 0.;
406 scaledMin = (xMin - mean) / xscale;
407 scaledMax = (xMax - mean) / xscale;
408
409 // Here we go for maximum precision: We compute all integrals in the UPPER
410 // tail of the Gaussian, because erfc has the highest precision there.
411 // Therefore, the different cases for range limits in the negative hemisphere are mapped onto
412 // the equivalent points in the upper hemisphere using erfc(-x) = 2. - erfc(x)
413 double ecmin = TMath::Erfc(std::abs(scaledMin));
414 double ecmax = TMath::Erfc(std::abs(scaledMax));
415
416 double cond = 0.0;
417 // Don't put this "prd" inside the "if" because clad will not be able to differentiate the code correctly (as of
418 // v1.1)!
419 double prd = scaledMin * scaledMax;
420 if (prd < 0.0) {
421 cond = 2.0 - (ecmin + ecmax);
422 } else if (scaledMax <= 0.0) {
423 cond = ecmax - ecmin;
424 } else {
425 cond = ecmin - ecmax;
426 }
427 return resultScale * cond;
428}
429
430inline double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
431{
432 const double xscaleL = TMath::Sqrt2() * sigmaL;
433 const double xscaleR = TMath::Sqrt2() * sigmaR;
434
435 const double resultScale = 0.5 * std::sqrt(TMath::TwoPi());
436
437 if (xMax < mean) {
438 return resultScale * (sigmaL * (TMath::Erf((xMax - mean) / xscaleL) - TMath::Erf((xMin - mean) / xscaleL)));
439 } else if (xMin > mean) {
440 return resultScale * (sigmaR * (TMath::Erf((xMax - mean) / xscaleR) - TMath::Erf((xMin - mean) / xscaleR)));
441 } else {
442 return resultScale *
443 (sigmaR * TMath::Erf((xMax - mean) / xscaleR) - sigmaL * TMath::Erf((xMin - mean) / xscaleL));
444 }
445}
446
447inline double exponentialIntegral(double xMin, double xMax, double constant)
448{
449 if (constant == 0.0) {
450 return xMax - xMin;
451 }
452
453 return (std::exp(constant * xMax) - std::exp(constant * xMin)) / constant;
454}
455
456/// In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
457template <bool pdfMode = false>
458inline double polynomialIntegral(double const *coeffs, int nCoeffs, int lowestOrder, double xMin, double xMax)
459{
460 int denom = lowestOrder + nCoeffs;
461 double min = coeffs[nCoeffs - 1] / double(denom);
462 double max = coeffs[nCoeffs - 1] / double(denom);
463
464 for (int i = nCoeffs - 2; i >= 0; i--) {
465 denom--;
466 min = (coeffs[i] / double(denom)) + xMin * min;
467 max = (coeffs[i] / double(denom)) + xMax * max;
468 }
469
470 max = max * std::pow(xMax, 1 + lowestOrder);
471 min = min * std::pow(xMin, 1 + lowestOrder);
472
473 return max - min + (pdfMode && lowestOrder > 0.0 ? xMax - xMin : 0.0);
474}
475
476/// use fast FMA if available, fall back to normal arithmetic if not
477inline double fast_fma(double x, double y, double z) noexcept
478{
479#if defined(FP_FAST_FMA) // check if std::fma has fast hardware implementation
480 return std::fma(x, y, z);
481#else // defined(FP_FAST_FMA)
482 // std::fma might be slow, so use a more pedestrian implementation
483#if defined(__clang__)
484#pragma STDC FP_CONTRACT ON // hint clang that using an FMA is okay here
485#endif // defined(__clang__)
486 return (x * y) + z;
487#endif // defined(FP_FAST_FMA)
488}
489
490inline double chebychevIntegral(double const *coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull,
491 double xMaxFull)
492{
493 const double halfrange = .5 * (xMax - xMin);
494 const double mid = .5 * (xMax + xMin);
495
496 // the full range of the function is mapped to the normalised [-1, 1] range
497 const double b = (xMaxFull - mid) / halfrange;
498 const double a = (xMinFull - mid) / halfrange;
499
500 // coefficient for integral(T_0(x)) is 1 (implicit), integrate by hand
501 // T_0(x) and T_1(x), and use for n > 1: integral(T_n(x) dx) =
502 // (T_n+1(x) / (n + 1) - T_n-1(x) / (n - 1)) / 2
503 double sum = b - a; // integrate T_0(x) by hand
504
505 const unsigned int iend = nCoeffs;
506 if (iend > 0) {
507 {
508 // integrate T_1(x) by hand...
509 const double c = coeffs[0];
510 sum = fast_fma(0.5 * (b + a) * (b - a), c, sum);
511 }
512 if (1 < iend) {
513 double bcurr = b;
514 double btwox = 2 * b;
515 double blast = 1;
516
517 double acurr = a;
518 double atwox = 2 * a;
519 double alast = 1;
520
521 double newval = atwox * acurr - alast;
522 alast = acurr;
523 acurr = newval;
524
525 newval = btwox * bcurr - blast;
526 blast = bcurr;
527 bcurr = newval;
528 double nminus1 = 1.;
529 for (unsigned int i = 1; iend != i; ++i) {
530 // integrate using recursion relation
531 const double c = coeffs[i];
532 const double term2 = (blast - alast) / nminus1;
533
534 newval = atwox * acurr - alast;
535 alast = acurr;
536 acurr = newval;
537
538 newval = btwox * bcurr - blast;
539 blast = bcurr;
540 bcurr = newval;
541
542 ++nminus1;
543 const double term1 = (bcurr - acurr) / (nminus1 + 1.);
544 const double intTn = 0.5 * (term1 - term2);
545 sum = fast_fma(intTn, c, sum);
546 }
547 }
548 }
549
550 // take care to multiply with the right factor to account for the mapping to
551 // normalised range [-1, 1]
552 return halfrange * sum;
553}
554
555// The last param should be of type bool but it is not as that causes some issues with Cling for some reason...
556inline double
557poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
558{
559 if (protectNegative && mu < 0.0) {
560 return std::exp(-2.0 * mu); // make it fall quickly
561 }
562
563 if (code == 1) {
564 // Implement integral over x as summation. Add special handling in case
565 // range boundaries are not on integer values of x
566 integrandMin = std::max(0., integrandMin);
567
568 if (integrandMax < 0. || integrandMax < integrandMin) {
569 return 0;
570 }
571 const double delta = 100.0 * std::sqrt(mu);
572 // If the limits are more than many standard deviations away from the mean,
573 // we might as well return the integral of the full Poisson distribution to
574 // save computing time.
575 if (integrandMin < std::max(mu - delta, 0.0) && integrandMax > mu + delta) {
576 return 1.;
577 }
578
579 // The range as integers. ixMin is included, ixMax outside.
580 const unsigned int ixMin = integrandMin;
581 const unsigned int ixMax = std::min(integrandMax + 1, (double)std::numeric_limits<unsigned int>::max());
582
583 // Sum from 0 to just before the bin outside of the range.
584 if (ixMin == 0) {
585 return ROOT::Math::gamma_cdf_c(mu, ixMax, 1);
586 } else {
587 // If necessary, subtract from 0 to the beginning of the range
588 if (ixMin <= mu) {
589 return ROOT::Math::gamma_cdf_c(mu, ixMax, 1) - ROOT::Math::gamma_cdf_c(mu, ixMin, 1);
590 } else {
591 // Avoid catastrophic cancellation in the high tails:
592 return ROOT::Math::gamma_cdf(mu, ixMin, 1) - ROOT::Math::gamma_cdf(mu, ixMax, 1);
593 }
594 }
595 }
596
597 // the integral with respect to the mean is the integral of a gamma distribution
598 // negative ix does not need protection (gamma returns 0.0)
599 const double ix = 1 + x;
600
601 return ROOT::Math::gamma_cdf(integrandMax, ix, 1.0) - ROOT::Math::gamma_cdf(integrandMin, ix, 1.0);
602}
603
604inline double logNormalIntegral(double xMin, double xMax, double m0, double k)
605{
606 const double root2 = std::sqrt(2.);
607
608 double ln_k = std::abs(std::log(k));
609 double ret =
610 0.5 * (TMath::Erf(std::log(xMax / m0) / (root2 * ln_k)) - TMath::Erf(std::log(xMin / m0) / (root2 * ln_k)));
611
612 return ret;
613}
614
615inline double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
616{
617 const double root2 = std::sqrt(2.);
618
619 double ln_k = std::abs(sigma);
620 double ret =
621 0.5 * (TMath::Erf((std::log(xMax) - mu) / (root2 * ln_k)) - TMath::Erf((std::log(xMin) - mu) / (root2 * ln_k)));
622
623 return ret;
624}
625
626inline double cbShapeIntegral(double mMin, double mMax, double m0, double sigma, double alpha, double n)
627{
628 const double sqrtPiOver2 = 1.2533141373;
629 const double sqrt2 = 1.4142135624;
630
631 double result = 0.0;
632 bool useLog = false;
633
634 if (std::abs(n - 1.0) < 1.0e-05)
635 useLog = true;
636
637 double sig = std::abs(sigma);
638
639 double tmin = (mMin - m0) / sig;
640 double tmax = (mMax - m0) / sig;
641
642 if (alpha < 0) {
643 double tmp = tmin;
644 tmin = -tmax;
645 tmax = -tmp;
646 }
647
648 double absAlpha = std::abs(alpha);
649
650 if (tmin >= -absAlpha) {
651 result += sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(tmin / sqrt2));
652 } else if (tmax <= -absAlpha) {
653 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
654 double b = n / absAlpha - absAlpha;
655
656 if (useLog) {
657 result += a * sig * (std::log(b - tmin) - std::log(b - tmax));
658 } else {
659 result += a * sig / (1.0 - n) * (1.0 / (std::pow(b - tmin, n - 1.0)) - 1.0 / (std::pow(b - tmax, n - 1.0)));
660 }
661 } else {
662 double a = std::pow(n / absAlpha, n) * std::exp(-0.5 * absAlpha * absAlpha);
663 double b = n / absAlpha - absAlpha;
664
665 double term1 = 0.0;
666 if (useLog) {
667 term1 = a * sig * (std::log(b - tmin) - std::log(n / absAlpha));
668 } else {
669 term1 = a * sig / (1.0 - n) * (1.0 / (std::pow(b - tmin, n - 1.0)) - 1.0 / (std::pow(n / absAlpha, n - 1.0)));
670 }
671
672 double term2 = sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(-absAlpha / sqrt2));
673
674 result += term1 + term2;
675 }
676
677 if (result == 0)
678 return 1.E-300;
679 return result;
680}
681
682inline double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, double *coefs, int nCoefs)
683{
684 double xloScaled = (xlo - xmin) / (xmax - xmin);
685 double xhiScaled = (xhi - xmin) / (xmax - xmin);
686
687 int degree = nCoefs - 1; // n+1 polys of degree n
688 double norm = 0.;
689
690 for (int i = 0; i <= degree; ++i) {
691 // for each of the i Bernstein basis polynomials
692 // represent it in the 'power basis' (the naive polynomial basis)
693 // where the integral is straight forward.
694 double temp = 0.;
695 for (int j = i; j <= degree; ++j) { // power basisŧ
696 double binCoefs = binomial(degree, j) * binomial(j, i);
697 double oneOverJPlusOne = 1. / (j + 1.);
698 double powDiff = std::pow(xhiScaled, j + 1.) - std::pow(xloScaled, j + 1.);
699 temp += std::pow(-1., j - i) * binCoefs * powDiff * oneOverJPlusOne;
700 }
701 temp *= coefs[i]; // include coeff
702 norm += temp; // add this basis's contribution to total
703 }
704
705 return norm * (xmax - xmin);
706}
707
708} // namespace MathFuncs
709
710} // namespace Detail
711
712} // namespace RooFit
713
714#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:604
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:395
double chebychevIntegral(double const *coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull, double xMaxFull)
Definition MathFuncs.h:490
double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
Definition MathFuncs.h:430
double cbShape(double m, double m0, double sigma, double alpha, double n)
Definition MathFuncs.h:359
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:348
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:626
double flexibleInterp(unsigned int code, double *params, unsigned int n, double *low, double *high, double boundary, double nominal, int doCutoff)
Definition MathFuncs.h:297
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:477
double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
Definition MathFuncs.h:615
double landau(double x, double mu, double sigma)
Definition MathFuncs.h:308
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:178
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:193
double logNormalStandard(double x, double sigma, double mu)
Definition MathFuncs.h:320
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:458
double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, double *coefs, int nCoefs)
Definition MathFuncs.h:682
double approxErf(double arg)
Definition MathFuncs.h:378
double effProd(double eff, double pdf)
Definition MathFuncs.h:325
double poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
Definition MathFuncs.h:557
double logNormal(double x, double k, double m0)
Definition MathFuncs.h:315
double nll(double pdf, double weight, int binnedL, int doBinOffset)
Definition MathFuncs.h:330
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 exponentialIntegral(double xMin, double xMax, double constant)
Definition MathFuncs.h:447
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