14#ifndef RooFit_Detail_MathFuncs_h
15#define RooFit_Detail_MathFuncs_h
34 if (
n < 0 || k < 0 ||
n < k)
39 int k1 = std::min(k,
n - k);
42 for (
double i = k1; i > 1.; --i) {
49template <
typename DoubleArray>
53 int degree = nCoefs - 1;
58 }
else if (degree == 0) {
60 }
else if (degree == 1) {
63 double a1 = coefs[1] - a0;
64 return a1 * xScaled + a0;
66 }
else if (degree == 2) {
69 double a1 = 2 * (coefs[1] - a0);
70 double a2 = coefs[2] - a1 - a0;
71 return (a2 * xScaled + a1) * xScaled + a0;
75 double s = 1. - xScaled;
77 double result = coefs[0] * s;
78 for (
int i = 1; i < degree; i++) {
82 result += t * coefs[degree];
90 const double arg =
x - mean;
91 const double sig =
sigma;
92 return std::exp(-0.5 * arg * arg / (sig * sig));
95template <
typename DoubleArray>
96double product(DoubleArray factors, std::size_t nFactors)
99 for (std::size_t i = 0; i < nFactors; ++i) {
106inline double ratio(
double numerator,
double denominator)
108 return numerator / denominator;
111inline double bifurGauss(
double x,
double mean,
double sigmaL,
double sigmaR)
120inline double efficiency(
double effFuncVal,
int catIndex,
int sigCatIndex)
123 effFuncVal = std::clamp(effFuncVal, 0.0, 1.0);
125 if (catIndex == sigCatIndex)
128 return 1 - effFuncVal;
132template <
bool pdfMode = false,
typename DoubleArray>
133double polynomial(DoubleArray coeffs,
int nCoeffs,
int lowestOrder,
double x)
135 double retVal = coeffs[nCoeffs - 1];
136 for (
int i = nCoeffs - 2; i >= 0; i--) {
137 retVal = coeffs[i] +
x * retVal;
139 retVal = retVal * std::pow(
x, lowestOrder);
140 return retVal + (pdfMode && lowestOrder > 0 ? 1.0 : 0.0);
143template <
typename DoubleArray>
144double chebychev(DoubleArray coeffs,
unsigned int nCoeffs,
double x_in,
double xMin,
double xMax)
147 const double xPrime = (x_in - 0.5 * (xMax + xMin)) / (0.5 * (xMax - xMin));
152 double curr = xPrime;
153 double twox = 2 * xPrime;
155 double newval = twox * curr - last;
158 for (
unsigned int i = 0; nCoeffs != i; ++i) {
159 sum += last * coeffs[i];
160 newval = twox * curr - last;
168template <
typename DoubleArray>
179template <
typename DoubleArray>
183#if defined(__CLING__) && defined(R__HAS_CLAD)
184#pragma clad checkpoint loop
186 for (
unsigned int i = 0; i < compSize; i++) {
187 sum -= std::log(comp[i]);
192inline unsigned int uniformBinNumber(
double low,
double high,
double val,
unsigned int numBins,
double coef)
194 double binWidth = (high - low) / numBins;
195 return coef * (val >= high ? numBins - 1 : std::abs((val - low) / binWidth));
198template <
typename DoubleArray>
199unsigned int rawBinNumber(
double x, DoubleArray boundaries, std::size_t nBoundaries)
201 DoubleArray end = boundaries + nBoundaries;
202 DoubleArray it = std::lower_bound(boundaries, end,
x);
204 while (boundaries != it && (end == it || end == it + 1 ||
x < *it)) {
207 return it - boundaries;
210template <
typename DoubleArray>
211unsigned int binNumber(
double x,
double coef, DoubleArray boundaries,
unsigned int nBoundaries,
int nbins,
int blo)
214 int tmp = std::min(nbins, rawBin - blo);
215 return coef * std::max(0, tmp);
218template <
typename DoubleArray>
219double interpolate1d(
double low,
double high,
double val,
unsigned int numBins, DoubleArray vals)
221 double binWidth = (high - low) / numBins;
222 int idx = val >= high ? numBins - 1 : std::abs((val - low) / binWidth);
225 double central = low + (idx + 0.5) * binWidth;
226 if (val > low + 0.5 * binWidth && val < high - 0.5 * binWidth) {
229 slope = vals[idx] - vals[idx - 1];
231 slope = vals[idx + 1] - vals[idx];
233 return vals[idx] + slope * (val - central) / binWidth;
246 }
else if (
x == 0.0) {
247 return std::exp(-par);
250 return std::exp(out);
255 double paramVal,
double res)
260 return paramVal * (high - nominal);
262 return paramVal * (nominal - low);
264 }
else if (code == 1) {
267 return res * (std::pow(high / nominal, +paramVal) - 1);
269 return res * (std::pow(low / nominal, -paramVal) - 1);
271 }
else if (code == 2) {
273 double a = 0.5 * (high + low) - nominal;
274 double b = 0.5 * (high - low);
277 return (2 *
a +
b) * (paramVal - 1) + high - nominal;
278 }
else if (paramVal < -1) {
279 return -1 * (2 *
a -
b) * (paramVal + 1) + low - nominal;
281 return a * paramVal * paramVal +
b * paramVal +
c;
287 }
else if (code == 4 || code == 6) {
296 mod =
x * (high - nominal);
297 }
else if (
x <= -boundary) {
298 mod =
x * (nominal - low);
301 double t =
x / boundary;
302 double eps_plus = high - nominal;
303 double eps_minus = nominal - low;
304 double S = 0.5 * (eps_plus + eps_minus);
305 double A = 0.0625 * (eps_plus - eps_minus);
307 mod =
x * (S + t * A * (15 + t * t * (-10 + t * t * 3)));
316 }
else if (code == 5) {
320 mod = std::pow(high / nominal, +paramVal);
321 }
else if (
x <= -boundary) {
322 mod = std::pow(low / nominal, -paramVal);
325 double x0 = boundary;
331 double logHi = std::log(high);
332 double logLo = std::log(low);
333 double powUp = std::exp(x0 * logHi);
334 double powDown = std::exp(x0 * logLo);
335 double powUpLog = high <= 0.0 ? 0.0 : powUp * logHi;
336 double powDownLog = low <= 0.0 ? 0.0 : -powDown * logLo;
337 double powUpLog2 = high <= 0.0 ? 0.0 : powUpLog * logHi;
338 double powDownLog2 = low <= 0.0 ? 0.0 : -powDownLog * logLo;
340 double S0 = 0.5 * (powUp + powDown);
341 double A0 = 0.5 * (powUp - powDown);
342 double S1 = 0.5 * (powUpLog + powDownLog);
343 double A1 = 0.5 * (powUpLog - powDownLog);
344 double S2 = 0.5 * (powUpLog2 + powDownLog2);
345 double A2 = 0.5 * (powUpLog2 - powDownLog2);
349 double x0Sq = x0 * x0;
351 double a = 1. / (8 * x0) * (15 * A0 - 7 * x0 *
S1 + x0 * x0 * A2);
352 double b = 1. / (8 * x0Sq) * (-24 + 24 *
S0 - 9 * x0 * A1 + x0 * x0 * S2);
353 double c = 1. / (4 * x0Sq * x0) * (-5 * A0 + 5 * x0 *
S1 - x0 * x0 * A2);
354 double d = 1. / (4 * x0Sq * x0Sq) * (12 - 12 *
S0 + 7 * x0 * A1 - x0 * x0 * S2);
355 double e = 1. / (8 * x0Sq * x0Sq * x0) * (+3 * A0 - 3 * x0 *
S1 + x0 * x0 * A2);
356 double f = 1. / (8 * x0Sq * x0Sq * x0Sq) * (-8 + 8 *
S0 - 5 * x0 * A1 + x0 * x0 * S2);
362 return res * (mod - 1.0);
368template <
typename ParamsArray,
typename DoubleArray>
369double flexibleInterp(
unsigned int code, ParamsArray params,
unsigned int n, DoubleArray low, DoubleArray high,
370 double boundary,
double nominal,
int doCutoff)
372 double total = nominal;
373 for (std::size_t i = 0; i <
n; ++i) {
377 return doCutoff && total <= 0 ? TMath::Limits<double>::Min() :
total;
408 if (mu == 0.0 && weight == 0.0) {
412 return std::numeric_limits<double>::quiet_NaN();
414 const double diff = mu - weight;
415 return diff * diff / mu;
422 if (sigma2 == 0.0 && mu == 0.0 && weight == 0.0) {
426 return std::numeric_limits<double>::quiet_NaN();
428 const double diff = mu - weight;
429 return diff * diff / sigma2;
435inline double chi2Asymmetric(
double mu,
double weight,
double errLo,
double errHi)
437 const double diff = mu - weight;
438 const double err = diff > 0.0 ? errHi : errLo;
439 const double sigma2 = err * err;
440 if (sigma2 == 0.0 && mu == 0.0 && weight == 0.0) {
444 return std::numeric_limits<double>::quiet_NaN();
446 return diff * diff / sigma2;
449inline double nll(
double pdf,
double weight,
int binnedL,
int doBinOffset)
455 if (std::abs(pdf) < 1
e-10 && std::abs(weight) < 1
e-10) {
459 return pdf - weight - weight * (std::log(pdf) - std::log(weight));
463 return -weight * std::log(pdf);
467template <
typename DoubleArray>
472 for (
unsigned int i = 1; i <
n; ++i) {
481 double t = (
m - m0) /
sigma;
485 double absAlpha = std::abs(alpha);
487 if (t >= -absAlpha) {
488 return std::exp(-0.5 * t * t);
490 double r =
n / absAlpha;
491 double a = std::exp(-0.5 * absAlpha * absAlpha);
492 double b =
r - absAlpha;
494 return a * std::pow(
r / (
b - t),
n);
506 return std::erf(arg);
525 double scaledMin = 0.;
526 double scaledMax = 0.;
527 scaledMin = (xMin - mean) / xscale;
528 scaledMax = (xMax - mean) / xscale;
534 double ecmin = std::erfc(std::abs(scaledMin));
535 double ecmax = std::erfc(std::abs(scaledMax));
540 double prd = scaledMin * scaledMax;
542 cond = 2.0 - (ecmin + ecmax);
543 }
else if (scaledMax <= 0.0) {
544 cond = ecmax - ecmin;
546 cond = ecmin - ecmax;
548 return resultScale * cond;
556 const double resultScale = 0.5 * std::sqrt(
TMath::TwoPi());
559 return resultScale * (sigmaL * (std::erf((xMax - mean) / xscaleL) - std::erf((xMin - mean) / xscaleL)));
560 }
else if (xMin > mean) {
561 return resultScale * (sigmaR * (std::erf((xMax - mean) / xscaleR) - std::erf((xMin - mean) / xscaleR)));
563 return resultScale * (sigmaR * std::erf((xMax - mean) / xscaleR) - sigmaL * std::erf((xMin - mean) / xscaleL));
572 return x == 0.0 ? 1.0 : std::expm1(
x) /
x;
580 if (std::abs(
x) < 0.25) {
583 return 1. / 2 +
x * (1. / 3 +
x * (1. / 8 +
x * (1. / 30 +
x * (1. / 144 +
x * (1. / 840
584 +
x * (1. / 5760 +
x * (1. / 45360 +
x * (1. / 403200 +
x * (1. / 3991680 +
x * (1. / 43545600))))))))));
599 if (constant == 0.0) {
603 const double z = constant * (xMax - xMin);
605 return -std::exp(constant * xMax) * std::expm1(-z) / constant;
607 return std::exp(constant * xMin) * std::expm1(z) / constant;
617 const bool fromMin = constant * (xMax - xMin) <= 0.0;
618 const double a = fromMin ? xMin : xMax;
619 const double d = fromMin ? xMax - xMin : xMin - xMax;
620 const double w = constant *
d;
626template <
bool pdfMode = false,
typename DoubleArray>
629 int denom = lowestOrder + nCoeffs;
630 double min = coeffs[nCoeffs - 1] /
double(denom);
631 double max = coeffs[nCoeffs - 1] /
double(denom);
633 for (
int i = nCoeffs - 2; i >= 0; i--) {
635 min = (coeffs[i] /
double(denom)) + xMin * min;
636 max = (coeffs[i] /
double(denom)) + xMax * max;
639 max = max * std::pow(xMax, 1 + lowestOrder);
640 min = min * std::pow(xMin, 1 + lowestOrder);
642 return max - min + (pdfMode && lowestOrder > 0.0 ? xMax - xMin : 0.0);
648#if defined(FP_FAST_FMA)
649 return std::fma(
x,
y, z);
652#if defined(__clang__)
653#pragma STDC FP_CONTRACT ON
659template <
typename DoubleArray>
661chebychevIntegral(DoubleArray coeffs,
unsigned int nCoeffs,
double xMin,
double xMax,
double xMinFull,
double xMaxFull)
663 const double halfrange = .5 * (xMax - xMin);
664 const double mid = .5 * (xMax + xMin);
667 const double b = (xMaxFull - mid) / halfrange;
668 const double a = (xMinFull - mid) / halfrange;
675 const unsigned int iend = nCoeffs;
679 const double c = coeffs[0];
684 double btwox = 2 *
b;
688 double atwox = 2 *
a;
691 double newval = atwox * acurr - alast;
695 newval = btwox * bcurr - blast;
699 for (
unsigned int i = 1; iend != i; ++i) {
701 const double c = coeffs[i];
702 const double term2 = (blast - alast) / nminus1;
704 newval = atwox * acurr - alast;
708 newval = btwox * bcurr - blast;
713 const double term1 = (bcurr - acurr) / (nminus1 + 1.);
714 const double intTn = 0.5 * (term1 - term2);
722 return halfrange *
sum;
727poissonIntegral(
int code,
double mu,
double x,
double integrandMin,
double integrandMax,
unsigned int protectNegative)
729 if (protectNegative && mu < 0.0) {
730 return std::exp(-2.0 * mu);
736 integrandMin = std::max(0., integrandMin);
738 if (integrandMax < 0. || integrandMax < integrandMin) {
741 const double delta = 100.0 * std::sqrt(mu);
745 if (integrandMin < std::max(mu - delta, 0.0) && integrandMax > mu + delta) {
750 const unsigned int ixMin = integrandMin;
751 const unsigned int ixMax = std::min(integrandMax + 1, (
double)std::numeric_limits<unsigned int>::max());
769 const double ix = 1 +
x;
776 const double root2 = std::sqrt(2.);
778 double ln_k = std::abs(std::log(k));
779 double ret = 0.5 * (std::erf(std::log(xMax / m0) / (root2 * ln_k)) - std::erf(std::log(xMin / m0) / (root2 * ln_k)));
786 const double root2 = std::sqrt(2.);
788 double ln_k = std::abs(
sigma);
790 0.5 * (std::erf((std::log(xMax) - mu) / (root2 * ln_k)) - std::erf((std::log(xMin) - mu) / (root2 * ln_k)));
797 const double sqrtPiOver2 = 1.2533141373;
798 const double sqrt2 = 1.4142135624;
803 if (std::abs(
n - 1.0) < 1.0e-05)
806 double sig = std::abs(
sigma);
808 double tmin = (mMin - m0) / sig;
809 double tmax = (mMax - m0) / sig;
817 double absAlpha = std::abs(alpha);
819 if (tmin >= -absAlpha) {
821 }
else if (tmax <= -absAlpha) {
822 double r =
n / absAlpha;
823 double a =
r * std::exp(-0.5 * absAlpha * absAlpha);
824 double b =
r - absAlpha;
827 double log_b_tmin = std::log(
b - tmin);
828 double log_b_tmax = std::log(
b - tmax);
830 (log_b_tmin - log_b_tmax + 0.5 * (1.0 -
n) * (log_b_tmin * log_b_tmin - log_b_tmax * log_b_tmax));
832 result +=
a * sig / (1.0 -
n) * (std::pow(
r / (
b - tmin),
n - 1.0) - std::pow(
r / (
b - tmax),
n - 1.0));
835 double r =
n / absAlpha;
836 double a =
r * std::exp(-0.5 * absAlpha * absAlpha);
837 double b =
r - absAlpha;
841 double log_b_tmin = std::log(
b - tmin);
842 double log_r = std::log(
r);
843 term1 =
a * std::pow(
r,
n - 1) * sig *
844 (log_b_tmin - log_r + 0.5 * (1.0 -
n) * (log_b_tmin * log_b_tmin - log_r * log_r));
846 term1 =
a * sig / (1.0 -
n) * (std::pow(
r / (
b - tmin),
n - 1.0) - 1.0);
849 double term2 = sig * sqrtPiOver2 * (
approxErf(tmax / sqrt2) -
approxErf(-absAlpha / sqrt2));
859template <
typename DoubleArray>
865 int degree = nCoefs - 1;
868 for (
int i = 0; i <= degree; ++i) {
873 for (
int j = i; j <= degree; ++j) {
875 double oneOverJPlusOne = 1. / (j + 1.);
876 double powDiff = std::pow(xhiScaled, j + 1.) - std::pow(xloScaled, j + 1.);
877 temp += std::pow(-1., j - i) * binCoefs * powDiff * oneOverJPlusOne;
886template <
typename XArray,
typename MuArray,
typename CovArray>
892 for (
int i = 0; i <
n; ++i) {
893 for (
int j = 0; j <
n; ++j) {
894 result += (
x[i] - mu[i]) * covI[i *
n + j] * (
x[j] - mu[j]);
897 return std::exp(-0.5 *
result);
903template <
typename DoubleArray>
907 for (std::size_t i = 0; i < nBins; ++i) {
908 double a = boundaries[i];
909 double b = boundaries[i + 1];
910 out += coefs[i] * std::max(0.0, std::min(
b,
xmax) - std::max(
a,
xmin));
920template <
typename T,
typename U>
936template <
class... Types>
947template <
typename T,
typename>
952template <
typename DoubleArray,
class... Types>
976template <
typename T =
double>
983 double *d_xMax,
double *d_constant)
985 *d_xMin -= d_out * std::exp(constant * xMin);
986 *d_xMax += d_out * std::exp(constant * xMax);
990template <
typename T =
double>
996 -std::exp(constant * xMin) * d_xMin + std::exp(constant * xMax) * d_xMax +
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 r
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
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)
double exponentialIntegralDConstant(double xMin, double xMax, double constant)
Derivative of exponentialIntegral() with respect to the constant, i.e.
double polynomialIntegral(DoubleArray 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.
double logNormalIntegral(double xMin, double xMax, double m0, double k)
double gaussianIntegral(double xMin, double xMax, double mean, double sigma)
Function to calculate the integral of an un-normalized RooGaussian over x.
double flexibleInterp(unsigned int code, ParamsArray params, unsigned int n, DoubleArray low, DoubleArray high, double boundary, double nominal, int doCutoff)
double bifurGaussIntegral(double xMin, double xMax, double mean, double sigmaL, double sigmaR)
double bernstein(double x, double xmin, double xmax, DoubleArray coefs, int nCoefs)
The caller needs to make sure that there is at least one coefficient.
double constraintSum(DoubleArray comp, unsigned int compSize)
double cbShape(double m, double m0, double sigma, double alpha, double n)
double multipdf(int idx, DoubleArray pdfs)
double chebychevIntegral(DoubleArray coeffs, unsigned int nCoeffs, double xMin, double xMax, double xMinFull, double xMaxFull)
double recursiveFraction(DoubleArray a, unsigned int n)
double cbShapeIntegral(double mMin, double mMax, double m0, double sigma, double alpha, double n)
double polynomial(DoubleArray coeffs, int nCoeffs, int lowestOrder, double x)
In pdfMode, a coefficient for the constant term of 1.0 is implied if lowestOrder > 0.
double fast_fma(double x, double y, double z) noexcept
use fast FMA if available, fall back to normal arithmetic if not
double logNormalIntegralStandard(double xMin, double xMax, double mu, double sigma)
double interpolate1d(double low, double high, double val, unsigned int numBins, DoubleArray vals)
double landau(double x, double mu, double sigma)
double gaussian(double x, double mean, double sigma)
Function to evaluate an un-normalized RooGaussian.
double poisson(double x, double par)
double binomial(int n, int k)
Calculates the binomial coefficient n over k.
unsigned int uniformBinNumber(double low, double high, double val, unsigned int numBins, double coef)
double multiVarGaussian(int n, XArray x, MuArray mu, CovArray covI)
double flexibleInterpSingle(unsigned int code, double low, double high, double boundary, double nominal, double paramVal, double res)
double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax, DoubleArray coefs, int nCoefs)
double chi2Asymmetric(double mu, double weight, double errLo, double errHi)
Chi-squared contribution of one bin with asymmetric (Poisson-style) data errors.
double chebychev(DoubleArray coeffs, unsigned int nCoeffs, double x_in, double xMin, double xMax)
double chi2Expected(double mu, double weight)
Chi-squared contribution of one bin with "expected" errors: .
double product(DoubleArray factors, std::size_t nFactors)
unsigned int rawBinNumber(double x, DoubleArray boundaries, std::size_t nBoundaries)
unsigned int binNumber(double x, double coef, DoubleArray boundaries, unsigned int nBoundaries, int nbins, int blo)
double chi2Symmetric(double mu, double weight, double sigma2)
Chi-squared contribution of one bin with a user-supplied symmetric error squared (e....
double logNormalStandard(double x, double sigma, double mu)
double bifurGauss(double x, double mean, double sigmaL, double sigmaR)
double ratio(double numerator, double denominator)
double expm1OverX(double x)
(exp(x) - 1) / x with the removable singularity at x = 0 filled in.
double approxErf(double arg)
double expm1OverXDerivative(double x)
Derivative of expm1OverX().
double effProd(double eff, double pdf)
double poissonIntegral(int code, double mu, double x, double integrandMin, double integrandMax, unsigned int protectNegative)
double logNormal(double x, double k, double m0)
double stepFunctionIntegral(double xmin, double xmax, std::size_t nBins, DoubleArray boundaries, DoubleArray coefs)
double nll(double pdf, double weight, int binnedL, int doBinOffset)
double efficiency(double effFuncVal, int catIndex, int sigCatIndex)
double exponentialIntegral(double xMin, double xMax, double constant)
Integral of exp(constant * x) from xMin to xMax.
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754.
constexpr Double_t Sqrt2()
Double_t LnGamma(Double_t z)
Computation of ln[gamma(z)] for all z.
Double_t SignalingNaN()
Returns a signaling NaN as defined by IEEE 754.
constexpr Double_t TwoPi()
ValueAndPushforwardOf< unsignedint, DoubleArray >::type binNumber_pushforward(double x, double coef, DoubleArray boundaries, unsigned int nBoundaries, int nbins, int blo, Types...)
void exponentialIntegral_pullback(double xMin, double xMax, double constant, double d_out, double *d_xMin, double *d_xMax, double *d_constant)
ValueAndPushforwardOf< double, T >::type expm1OverX_pushforward(double x, double d_x)
ValueAndPushforwardOf< double, T >::type exponentialIntegral_pushforward(double xMin, double xMax, double constant, double d_xMin, double d_xMax, double d_constant)
void binNumber_pullback(Types...)
void expm1OverX_pullback(double x, double d_out, double *d_x)
::clad::ValueAndPushforward< T, T > type
static uint64_t sum(uint64_t i)