File indexing completed on 2025-09-18 09:31:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef RooFit_Detail_MathFuncs_h
0015 #define RooFit_Detail_MathFuncs_h
0016
0017 #include <TMath.h>
0018 #include <Math/PdfFuncMathCore.h>
0019 #include <Math/ProbFuncMathCore.h>
0020
0021 #include <algorithm>
0022 #include <cmath>
0023
0024 namespace RooFit {
0025 namespace Detail {
0026 namespace MathFuncs {
0027
0028
0029
0030 inline double binomial(int n, int k)
0031 {
0032 if (n < 0 || k < 0 || n < k)
0033 return TMath::SignalingNaN();
0034 if (k == 0 || n == k)
0035 return 1;
0036
0037 int k1 = std::min(k, n - k);
0038 int k2 = n - k1;
0039 double fact = k2 + 1;
0040 for (double i = k1; i > 1.; --i) {
0041 fact *= (k2 + i) / i;
0042 }
0043 return fact;
0044 }
0045
0046
0047 inline double bernstein(double x, double xmin, double xmax, double *coefs, int nCoefs)
0048 {
0049 double xScaled = (x - xmin) / (xmax - xmin);
0050 int degree = nCoefs - 1;
0051
0052
0053 if (degree < 0) {
0054 return TMath::SignalingNaN();
0055 } else if (degree == 0) {
0056 return coefs[0];
0057 } else if (degree == 1) {
0058
0059 double a0 = coefs[0];
0060 double a1 = coefs[1] - a0;
0061 return a1 * xScaled + a0;
0062
0063 } else if (degree == 2) {
0064
0065 double a0 = coefs[0];
0066 double a1 = 2 * (coefs[1] - a0);
0067 double a2 = coefs[2] - a1 - a0;
0068 return (a2 * xScaled + a1) * xScaled + a0;
0069 }
0070
0071 double t = xScaled;
0072 double s = 1. - xScaled;
0073
0074 double result = coefs[0] * s;
0075 for (int i = 1; i < degree; i++) {
0076 result = (result + t * binomial(degree, i) * coefs[i]) * s;
0077 t *= xScaled;
0078 }
0079 result += t * coefs[degree];
0080
0081 return result;
0082 }
0083
0084
0085 inline double gaussian(double x, double mean, double sigma)
0086 {
0087 const double arg = x - mean;
0088 const double sig = sigma;
0089 return std::exp(-0.5 * arg * arg / (sig * sig));
0090 }
0091
0092 inline double product(double const *factors, std::size_t nFactors)
0093 {
0094 double out = 1.0;
0095 for (std::size_t i = 0; i < nFactors; ++i) {
0096 out *= factors[i];
0097 }
0098 return out;
0099 }
0100
0101
0102 inline double ratio(double numerator, double denominator)
0103 {
0104 return numerator / denominator;
0105 }
0106
0107 inline double bifurGauss(double x, double mean, double sigmaL, double sigmaR)
0108 {
0109
0110
0111 if (x < mean)
0112 return gaussian(x, mean, sigmaL);
0113 return gaussian(x, mean, sigmaR);
0114 }
0115
0116 inline double efficiency(double effFuncVal, int catIndex, int sigCatIndex)
0117 {
0118
0119 effFuncVal = std::clamp(effFuncVal, 0.0, 1.0);
0120
0121 if (catIndex == sigCatIndex)
0122 return effFuncVal;
0123 else
0124 return 1 - effFuncVal;
0125 }
0126
0127
0128 template <bool pdfMode = false>
0129 inline double polynomial(double const *coeffs, int nCoeffs, int lowestOrder, double x)
0130 {
0131 double retVal = coeffs[nCoeffs - 1];
0132 for (int i = nCoeffs - 2; i >= 0; i--) {
0133 retVal = coeffs[i] + x * retVal;
0134 }
0135 retVal = retVal * std::pow(x, lowestOrder);
0136 return retVal + (pdfMode && lowestOrder > 0 ? 1.0 : 0.0);
0137 }
0138
0139 inline double chebychev(double *coeffs, unsigned int nCoeffs, double x_in, double xMin, double xMax)
0140 {
0141
0142 const double xPrime = (x_in - 0.5 * (xMax + xMin)) / (0.5 * (xMax - xMin));
0143
0144
0145 double sum = 1.;
0146 if (nCoeffs > 0) {
0147 double curr = xPrime;
0148 double twox = 2 * xPrime;
0149 double last = 1;
0150 double newval = twox * curr - last;
0151 last = curr;
0152 curr = newval;
0153 for (unsigned int i = 0; nCoeffs != i; ++i) {
0154 sum += last * coeffs[i];
0155 newval = twox * curr - last;
0156 last = curr;
0157 curr = newval;
0158 }
0159 }
0160 return sum;
0161 }
0162
0163 inline double constraintSum(double const *comp, unsigned int compSize)
0164 {
0165 double sum = 0;
0166 for (unsigned int i = 0; i < compSize; i++) {
0167 sum -= std::log(comp[i]);
0168 }
0169 return sum;
0170 }
0171
0172 inline unsigned int uniformBinNumber(double low, double high, double val, unsigned int numBins, double coef)
0173 {
0174 double binWidth = (high - low) / numBins;
0175 return coef * (val >= high ? numBins - 1 : std::abs((val - low) / binWidth));
0176 }
0177
0178 inline unsigned int rawBinNumber(double x, double const *boundaries, std::size_t nBoundaries)
0179 {
0180 double const *end = boundaries + nBoundaries;
0181 double const *it = std::lower_bound(boundaries, end, x);
0182
0183 while (boundaries != it && (end == it || end == it + 1 || x < *it)) {
0184 --it;
0185 }
0186 return it - boundaries;
0187 }
0188
0189 inline unsigned int
0190 binNumber(double x, double coef, double const *boundaries, unsigned int nBoundaries, int nbins, int blo)
0191 {
0192 const int rawBin = rawBinNumber(x, boundaries, nBoundaries);
0193 int tmp = std::min(nbins, rawBin - blo);
0194 return coef * std::max(0, tmp);
0195 }
0196
0197 inline double interpolate1d(double low, double high, double val, unsigned int numBins, double const *vals)
0198 {
0199 double binWidth = (high - low) / numBins;
0200 int idx = val >= high ? numBins - 1 : std::abs((val - low) / binWidth);
0201
0202
0203 double central = low + (idx + 0.5) * binWidth;
0204 if (val > low + 0.5 * binWidth && val < high - 0.5 * binWidth) {
0205 double slope;
0206 if (val < central) {
0207 slope = vals[idx] - vals[idx - 1];
0208 } else {
0209 slope = vals[idx + 1] - vals[idx];
0210 }
0211 return vals[idx] + slope * (val - central) / binWidth;
0212 }
0213
0214 return vals[idx];
0215 }
0216
0217 inline double poisson(double x, double par)
0218 {
0219 if (par < 0)
0220 return TMath::QuietNaN();
0221
0222 if (x < 0) {
0223 return 0;
0224 } else if (x == 0.0) {
0225 return std::exp(-par);
0226 } else {
0227 double out = x * std::log(par) - TMath::LnGamma(x + 1.) - par;
0228 return std::exp(out);
0229 }
0230 }
0231
0232 inline double flexibleInterpSingle(unsigned int code, double low, double high, double boundary, double nominal,
0233 double paramVal, double res)
0234 {
0235 if (code == 0) {
0236
0237 if (paramVal > 0) {
0238 return paramVal * (high - nominal);
0239 } else {
0240 return paramVal * (nominal - low);
0241 }
0242 } else if (code == 1) {
0243
0244 if (paramVal >= 0) {
0245 return res * (std::pow(high / nominal, +paramVal) - 1);
0246 } else {
0247 return res * (std::pow(low / nominal, -paramVal) - 1);
0248 }
0249 } else if (code == 2) {
0250
0251 double a = 0.5 * (high + low) - nominal;
0252 double b = 0.5 * (high - low);
0253 double c = 0;
0254 if (paramVal > 1) {
0255 return (2 * a + b) * (paramVal - 1) + high - nominal;
0256 } else if (paramVal < -1) {
0257 return -1 * (2 * a - b) * (paramVal + 1) + low - nominal;
0258 } else {
0259 return a * paramVal * paramVal + b * paramVal + c;
0260 }
0261
0262
0263
0264
0265 } else if (code == 4 || code == 6) {
0266 double x = paramVal;
0267 double mod = 1.0;
0268 if (code == 6) {
0269 high /= nominal;
0270 low /= nominal;
0271 nominal = 1;
0272 }
0273 if (x >= boundary) {
0274 mod = x * (high - nominal);
0275 } else if (x <= -boundary) {
0276 mod = x * (nominal - low);
0277 } else {
0278
0279 double t = x / boundary;
0280 double eps_plus = high - nominal;
0281 double eps_minus = nominal - low;
0282 double S = 0.5 * (eps_plus + eps_minus);
0283 double A = 0.0625 * (eps_plus - eps_minus);
0284
0285 mod = x * (S + t * A * (15 + t * t * (-10 + t * t * 3)));
0286 }
0287
0288
0289 if (code == 6) {
0290 mod *= res;
0291 }
0292 return mod;
0293
0294 } else if (code == 5) {
0295 double x = paramVal;
0296 double mod = 1.0;
0297 if (x >= boundary) {
0298 mod = std::pow(high / nominal, +paramVal);
0299 } else if (x <= -boundary) {
0300 mod = std::pow(low / nominal, -paramVal);
0301 } else {
0302
0303 double x0 = boundary;
0304
0305 high /= nominal;
0306 low /= nominal;
0307
0308
0309 double logHi = std::log(high);
0310 double logLo = std::log(low);
0311 double powUp = std::exp(x0 * logHi);
0312 double powDown = std::exp(x0 * logLo);
0313 double powUpLog = high <= 0.0 ? 0.0 : powUp * logHi;
0314 double powDownLog = low <= 0.0 ? 0.0 : -powDown * logLo;
0315 double powUpLog2 = high <= 0.0 ? 0.0 : powUpLog * logHi;
0316 double powDownLog2 = low <= 0.0 ? 0.0 : -powDownLog * logLo;
0317
0318 double S0 = 0.5 * (powUp + powDown);
0319 double A0 = 0.5 * (powUp - powDown);
0320 double S1 = 0.5 * (powUpLog + powDownLog);
0321 double A1 = 0.5 * (powUpLog - powDownLog);
0322 double S2 = 0.5 * (powUpLog2 + powDownLog2);
0323 double A2 = 0.5 * (powUpLog2 - powDownLog2);
0324
0325
0326
0327 double x0Sq = x0 * x0;
0328
0329 double a = 1. / (8 * x0) * (15 * A0 - 7 * x0 * S1 + x0 * x0 * A2);
0330 double b = 1. / (8 * x0Sq) * (-24 + 24 * S0 - 9 * x0 * A1 + x0 * x0 * S2);
0331 double c = 1. / (4 * x0Sq * x0) * (-5 * A0 + 5 * x0 * S1 - x0 * x0 * A2);
0332 double d = 1. / (4 * x0Sq * x0Sq) * (12 - 12 * S0 + 7 * x0 * A1 - x0 * x0 * S2);
0333 double e = 1. / (8 * x0Sq * x0Sq * x0) * (+3 * A0 - 3 * x0 * S1 + x0 * x0 * A2);
0334 double f = 1. / (8 * x0Sq * x0Sq * x0Sq) * (-8 + 8 * S0 - 5 * x0 * A1 + x0 * x0 * S2);
0335
0336
0337 double value = 1. + x * (a + x * (b + x * (c + x * (d + x * (e + x * f)))));
0338 mod = value;
0339 }
0340 return res * (mod - 1.0);
0341 }
0342
0343 return 0.0;
0344 }
0345
0346 inline double flexibleInterp(unsigned int code, double const *params, unsigned int n, double const *low,
0347 double const *high, double boundary, double nominal, int doCutoff)
0348 {
0349 double total = nominal;
0350 for (std::size_t i = 0; i < n; ++i) {
0351 total += flexibleInterpSingle(code, low[i], high[i], boundary, nominal, params[i], total);
0352 }
0353
0354 return doCutoff && total <= 0 ? TMath::Limits<double>::Min() : total;
0355 }
0356
0357 inline double landau(double x, double mu, double sigma)
0358 {
0359 if (sigma <= 0.)
0360 return 0.;
0361 return ROOT::Math::landau_pdf((x - mu) / sigma);
0362 }
0363
0364 inline double logNormal(double x, double k, double m0)
0365 {
0366 return ROOT::Math::lognormal_pdf(x, std::log(m0), std::abs(std::log(k)));
0367 }
0368
0369 inline double logNormalStandard(double x, double sigma, double mu)
0370 {
0371 return ROOT::Math::lognormal_pdf(x, mu, std::abs(sigma));
0372 }
0373
0374 inline double effProd(double eff, double pdf)
0375 {
0376 return eff * pdf;
0377 }
0378
0379 inline double nll(double pdf, double weight, int binnedL, int doBinOffset)
0380 {
0381 if (binnedL) {
0382
0383
0384
0385 if (std::abs(pdf) < 1e-10 && std::abs(weight) < 1e-10) {
0386 return 0.0;
0387 }
0388 if (doBinOffset) {
0389 return pdf - weight - weight * (std::log(pdf) - std::log(weight));
0390 }
0391 return pdf - weight * std::log(pdf) + TMath::LnGamma(weight + 1);
0392 } else {
0393 return -weight * std::log(pdf);
0394 }
0395 }
0396
0397 inline double recursiveFraction(double *a, unsigned int n)
0398 {
0399 double prod = a[0];
0400
0401 for (unsigned int i = 1; i < n; ++i) {
0402 prod *= 1.0 - a[i];
0403 }
0404
0405 return prod;
0406 }
0407
0408 inline double cbShape(double m, double m0, double sigma, double alpha, double n)
0409 {
0410 double t = (m - m0) / sigma;
0411 if (alpha < 0)
0412 t = -t;
0413
0414 double absAlpha = std::abs(alpha);
0415
0416 if (t >= -absAlpha) {
0417 return std::exp(-0.5 * t * t);
0418 } else {
0419 double r = n / absAlpha;
0420 double a = std::exp(-0.5 * absAlpha * absAlpha);
0421 double b = r - absAlpha;
0422
0423 return a * std::pow(r / (b - t), n);
0424 }
0425 }
0426
0427
0428 inline double approxErf(double arg)
0429 {
0430 if (arg > 5.0)
0431 return 1.0;
0432 if (arg < -5.0)
0433 return -1.0;
0434
0435 return TMath::Erf(arg);
0436 }
0437
0438
0439
0440
0441
0442
0443
0444
0445 inline double gaussianIntegral(double xMin, double xMax, double mean, double sigma)
0446 {
0447
0448
0449
0450 double resultScale = 0.5 * std::sqrt(TMath::TwoPi()) * sigma;
0451
0452
0453 double xscale = TMath::Sqrt2() * sigma;
0454 double scaledMin = 0.;
0455 double scaledMax = 0.;
0456 scaledMin = (xMin - mean) / xscale;
0457 scaledMax = (xMax - mean) / xscale;
0458
0459
0460
0461
0462
0463 double ecmin = TMath::Erfc(std::abs(scaledMin));
0464 double ecmax = TMath::Erfc(std::abs(scaledMax));
0465
0466 double cond = 0.0;
0467
0468
0469 double prd = scaledMin * scaledMax;
0470 if (prd < 0.0) {
0471 cond = 2.0 - (ecmin + ecmax);
0472 } else if (scaledMax <= 0.0) {
0473 cond = ecmax - ecmin;
0474 } else {
0475 cond = ecmin - ecmax;
0476 }
0477 return resultScale * cond;
0478 }
0479
0480 inline double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
0481 {
0482 const double xscaleL = TMath::Sqrt2() * sigmaL;
0483 const double xscaleR = TMath::Sqrt2() * sigmaR;
0484
0485 const double resultScale = 0.5 * std::sqrt(TMath::TwoPi());
0486
0487 if (xMax < mean) {
0488 return resultScale * (sigmaL * (TMath::Erf((xMax - mean) / xscaleL) - TMath::Erf((xMin - mean) / xscaleL)));
0489 } else if (xMin > mean) {
0490 return resultScale * (sigmaR * (TMath::Erf((xMax - mean) / xscaleR) - TMath::Erf((xMin - mean) / xscaleR)));
0491 } else {
0492 return resultScale *
0493 (sigmaR * TMath::Erf((xMax - mean) / xscaleR) - sigmaL * TMath::Erf((xMin - mean) / xscaleL));
0494 }
0495 }
0496
0497 inline double exponentialIntegral(double xMin, double xMax, double constant)
0498 {
0499 if (constant == 0.0) {
0500 return xMax - xMin;
0501 }
0502
0503 return (std::exp(constant * xMax) - std::exp(constant * xMin)) / constant;
0504 }
0505
0506
0507 template <bool pdfMode = false>
0508 inline double polynomialIntegral(double const *coeffs, int nCoeffs, int lowestOrder, double xMin, double xMax)
0509 {
0510 int denom = lowestOrder + nCoeffs;
0511 double min = coeffs[nCoeffs - 1] / double(denom);
0512 double max = coeffs[nCoeffs - 1] / double(denom);
0513
0514 for (int i = nCoeffs - 2; i >= 0; i--) {
0515 denom--;
0516 min = (coeffs[i] / double(denom)) + xMin * min;
0517 max = (coeffs[i] / double(denom)) + xMax * max;
0518 }
0519
0520 max = max * std::pow(xMax, 1 + lowestOrder);
0521 min = min * std::pow(xMin, 1 + lowestOrder);
0522
0523 return max - min + (pdfMode && lowestOrder > 0.0 ? xMax - xMin : 0.0);
0524 }
0525
0526
0527 inline double fast_fma(double x, double y, double z) noexcept
0528 {
0529 #if defined(FP_FAST_FMA)
0530 return std::fma(x, y, z);
0531 #else
0532
0533 #if defined(__clang__)
0534 #pragma STDC FP_CONTRACT ON
0535 #endif
0536 return (x * y) + z;
0537 #endif
0538 }
0539
0540 inline double chebychevIntegral(double const *coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull,
0541 double xMaxFull)
0542 {
0543 const double halfrange = .5 * (xMax - xMin);
0544 const double mid = .5 * (xMax + xMin);
0545
0546
0547 const double b = (xMaxFull - mid) / halfrange;
0548 const double a = (xMinFull - mid) / halfrange;
0549
0550
0551
0552
0553 double sum = b - a;
0554
0555 const unsigned int iend = nCoeffs;
0556 if (iend > 0) {
0557 {
0558
0559 const double c = coeffs[0];
0560 sum = fast_fma(0.5 * (b + a) * (b - a), c, sum);
0561 }
0562 if (1 < iend) {
0563 double bcurr = b;
0564 double btwox = 2 * b;
0565 double blast = 1;
0566
0567 double acurr = a;
0568 double atwox = 2 * a;
0569 double alast = 1;
0570
0571 double newval = atwox * acurr - alast;
0572 alast = acurr;
0573 acurr = newval;
0574
0575 newval = btwox * bcurr - blast;
0576 blast = bcurr;
0577 bcurr = newval;
0578 double nminus1 = 1.;
0579 for (unsigned int i = 1; iend != i; ++i) {
0580
0581 const double c = coeffs[i];
0582 const double term2 = (blast - alast) / nminus1;
0583
0584 newval = atwox * acurr - alast;
0585 alast = acurr;
0586 acurr = newval;
0587
0588 newval = btwox * bcurr - blast;
0589 blast = bcurr;
0590 bcurr = newval;
0591
0592 ++nminus1;
0593 const double term1 = (bcurr - acurr) / (nminus1 + 1.);
0594 const double intTn = 0.5 * (term1 - term2);
0595 sum = fast_fma(intTn, c, sum);
0596 }
0597 }
0598 }
0599
0600
0601
0602 return halfrange * sum;
0603 }
0604
0605
0606 inline double
0607 poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
0608 {
0609 if (protectNegative && mu < 0.0) {
0610 return std::exp(-2.0 * mu);
0611 }
0612
0613 if (code == 1) {
0614
0615
0616 integrandMin = std::max(0., integrandMin);
0617
0618 if (integrandMax < 0. || integrandMax < integrandMin) {
0619 return 0;
0620 }
0621 const double delta = 100.0 * std::sqrt(mu);
0622
0623
0624
0625 if (integrandMin < std::max(mu - delta, 0.0) && integrandMax > mu + delta) {
0626 return 1.;
0627 }
0628
0629
0630 const unsigned int ixMin = integrandMin;
0631 const unsigned int ixMax = std::min(integrandMax + 1, (double)std::numeric_limits<unsigned int>::max());
0632
0633
0634 if (ixMin == 0) {
0635 return ROOT::Math::inc_gamma_c(ixMax, mu);
0636 } else {
0637
0638 if (ixMin <= mu) {
0639 return ROOT::Math::inc_gamma_c(ixMax, mu) - ROOT::Math::inc_gamma_c(ixMin, mu);
0640 } else {
0641
0642 return ROOT::Math::inc_gamma(ixMin, mu) - ROOT::Math::inc_gamma(ixMax, mu);
0643 }
0644 }
0645 }
0646
0647
0648
0649 const double ix = 1 + x;
0650
0651 return ROOT::Math::inc_gamma(ix, integrandMax) - ROOT::Math::inc_gamma(ix, integrandMin);
0652 }
0653
0654 inline double logNormalIntegral(double xMin, double xMax, double m0, double k)
0655 {
0656 const double root2 = std::sqrt(2.);
0657
0658 double ln_k = std::abs(std::log(k));
0659 double ret =
0660 0.5 * (TMath::Erf(std::log(xMax / m0) / (root2 * ln_k)) - TMath::Erf(std::log(xMin / m0) / (root2 * ln_k)));
0661
0662 return ret;
0663 }
0664
0665 inline double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
0666 {
0667 const double root2 = std::sqrt(2.);
0668
0669 double ln_k = std::abs(sigma);
0670 double ret =
0671 0.5 * (TMath::Erf((std::log(xMax) - mu) / (root2 * ln_k)) - TMath::Erf((std::log(xMin) - mu) / (root2 * ln_k)));
0672
0673 return ret;
0674 }
0675
0676 inline double cbShapeIntegral(double mMin, double mMax, double m0, double sigma, double alpha, double n)
0677 {
0678 const double sqrtPiOver2 = 1.2533141373;
0679 const double sqrt2 = 1.4142135624;
0680
0681 double result = 0.0;
0682 bool useLog = false;
0683
0684 if (std::abs(n - 1.0) < 1.0e-05)
0685 useLog = true;
0686
0687 double sig = std::abs(sigma);
0688
0689 double tmin = (mMin - m0) / sig;
0690 double tmax = (mMax - m0) / sig;
0691
0692 if (alpha < 0) {
0693 double tmp = tmin;
0694 tmin = -tmax;
0695 tmax = -tmp;
0696 }
0697
0698 double absAlpha = std::abs(alpha);
0699
0700 if (tmin >= -absAlpha) {
0701 result += sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(tmin / sqrt2));
0702 } else if (tmax <= -absAlpha) {
0703 double r = n / absAlpha;
0704 double a = r * std::exp(-0.5 * absAlpha * absAlpha);
0705 double b = r - absAlpha;
0706
0707 if (useLog) {
0708 result += a * std::pow(r, n-1) * sig * (std::log(b - tmin) - std::log(b - tmax));
0709 } else {
0710 result += a * sig / (1.0 - n) * (std::pow(r / (b - tmin), n - 1.0) - std::pow(r / (b - tmax), n - 1.0));
0711 }
0712 } else {
0713 double r = n / absAlpha;
0714 double a = r * std::exp(-0.5 * absAlpha * absAlpha);
0715 double b = r - absAlpha;
0716
0717 double term1 = 0.0;
0718 if (useLog) {
0719 term1 = a * std::pow(r, n-1) * sig * (std::log(b - tmin) - std::log(r));
0720 } else {
0721 term1 = a * sig / (1.0 - n) * (std::pow(r / (b - tmin), n - 1.0) - 1.0);
0722 }
0723
0724 double term2 = sig * sqrtPiOver2 * (approxErf(tmax / sqrt2) - approxErf(-absAlpha / sqrt2));
0725
0726 result += term1 + term2;
0727 }
0728
0729 if (result == 0)
0730 return 1.E-300;
0731 return result;
0732 }
0733
0734 inline double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, double *coefs, int nCoefs)
0735 {
0736 double xloScaled = (xlo - xmin) / (xmax - xmin);
0737 double xhiScaled = (xhi - xmin) / (xmax - xmin);
0738
0739 int degree = nCoefs - 1;
0740 double norm = 0.;
0741
0742 for (int i = 0; i <= degree; ++i) {
0743
0744
0745
0746 double temp = 0.;
0747 for (int j = i; j <= degree; ++j) {
0748 double binCoefs = binomial(degree, j) * binomial(j, i);
0749 double oneOverJPlusOne = 1. / (j + 1.);
0750 double powDiff = std::pow(xhiScaled, j + 1.) - std::pow(xloScaled, j + 1.);
0751 temp += std::pow(-1., j - i) * binCoefs * powDiff * oneOverJPlusOne;
0752 }
0753 temp *= coefs[i];
0754 norm += temp;
0755 }
0756
0757 return norm * (xmax - xmin);
0758 }
0759
0760 inline double multiVarGaussian(int n, const double *x, const double *mu, const double *covI)
0761 {
0762 double result = 0.0;
0763
0764
0765 for (int i = 0; i < n; ++i) {
0766 for (int j = 0; j < n; ++j) {
0767 result += (x[i] - mu[i]) * covI[i * n + j] * (x[j] - mu[j]);
0768 }
0769 }
0770 return std::exp(-0.5 * result);
0771 }
0772
0773
0774
0775
0776 inline double stepFunctionIntegral(double xmin, double xmax, std::size_t nBins, double const *boundaries, double const *coefs)
0777 {
0778 double out = 0.0;
0779 for (std::size_t i = 0; i < nBins; ++i) {
0780 double a = boundaries[i];
0781 double b = boundaries[i + 1];
0782 out += coefs[i] * std::max(0.0, std::min(b, xmax) - std::max(a, xmin));
0783 }
0784 return out;
0785 }
0786
0787 }
0788 }
0789 }
0790
0791 namespace clad {
0792 namespace custom_derivatives {
0793 namespace RooFit {
0794 namespace Detail {
0795 namespace MathFuncs {
0796
0797
0798
0799
0800
0801
0802 template <class... Types>
0803 void binNumber_pullback(Types...)
0804 {
0805 }
0806
0807 }
0808 }
0809 }
0810 }
0811 }
0812
0813 #endif