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