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