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