Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:29:37

0001 // @(#)root/mathcore:$Id$
0002 // Authors: Andras Zsenei & Lorenzo Moneta   06/2005
0003 
0004 /**********************************************************************
0005  *                                                                    *
0006  * Copyright (c) 2005 , LCG ROOT MathLib Team                         *
0007  *                                                                    *
0008  *                                                                    *
0009  **********************************************************************/
0010 
0011 /**
0012 
0013 Probability density functions, cumulative distribution functions
0014 and their inverses (quantiles) for various statistical distributions (continuous and discrete).
0015 Whenever possible the conventions followed are those of the
0016 CRC Concise Encyclopedia of Mathematics, Second Edition
0017 (or <A HREF="http://mathworld.wolfram.com/">Mathworld</A>).
0018 By convention the distributions are centered around 0, so for
0019 example in the case of a Gaussian there is no parameter mu. The
0020 user must calculate the shift themselves if they wish.
0021 
0022 MathCore provides the majority of the probability density functions, of the
0023 cumulative distributions and of the quantiles (inverses of the cumulatives).
0024 Additional distributions are also provided by the \ref MathMore library.
0025 
0026 
0027 @defgroup StatFunc Statistical functions
0028 @ingroup  MathCore
0029 */
0030 
0031 #ifndef ROOT_Math_PdfFuncMathCore
0032 #define ROOT_Math_PdfFuncMathCore
0033 
0034 #include "Math/Math.h"
0035 #include "Math/SpecFuncMathCore.h"
0036 
0037 #include <limits>
0038 
0039 namespace ROOT {
0040 namespace Math {
0041 
0042 
0043 
0044   /** @defgroup PdfFunc Probability Density Functions (PDF)
0045    *   @ingroup StatFunc
0046    *  Probability density functions of various statistical distributions
0047    *  (continuous and discrete).
0048    *  The probability density function returns the probability that
0049    *  the variate has the value x.
0050    *  In statistics the PDF is also called the frequency function.
0051    *
0052    *
0053    */
0054 
0055 /** @name Probability Density Functions from MathCore
0056  *   Additional PDFs are provided in the MathMore library when the GSL is available.
0057  */
0058 
0059 //@{
0060 
0061   /**
0062 
0063   Probability density function of the beta distribution.
0064 
0065   \f[ p(x) = \frac{\Gamma (a + b) } {\Gamma(a)\Gamma(b) } x ^{a-1} (1 - x)^{b-1} \f]
0066 
0067   for \f$0 \leq x \leq 1 \f$. For detailed description see
0068   <A HREF="http://mathworld.wolfram.com/BetaDistribution.html">
0069   Mathworld</A>.
0070 
0071   @ingroup PdfFunc
0072 
0073   */
0074 
0075   inline double beta_pdf(double x, double a, double b) {
0076     // Inlined to enable clad-auto-derivation for this function.
0077 
0078     if (x < 0 || x > 1.0) return 0;
0079     if (x == 0 ) {
0080       // need this work Windows
0081       if (a < 1) return  std::numeric_limits<double>::infinity();
0082       else if (a > 1) return  0;
0083       else if ( a == 1) return b; // to avoid a nan from log(0)*0
0084     }
0085     if (x == 1 ) {
0086       // need this work Windows
0087       if (b < 1) return  std::numeric_limits<double>::infinity();
0088       else if (b > 1) return  0;
0089       else if ( b == 1) return a; // to avoid a nan from log(0)*0
0090     }
0091     return std::exp( ROOT::Math::lgamma(a + b) - ROOT::Math::lgamma(a) - ROOT::Math::lgamma(b) +
0092                      std::log(x) * (a -1.) + ROOT::Math::log1p(-x ) * (b - 1.) );
0093   }
0094 
0095 
0096 
0097   /**
0098 
0099   Probability density function of the binomial distribution.
0100 
0101   \f[ p(k) = \frac{n!}{k! (n-k)!} p^k (1-p)^{n-k} \f]
0102 
0103   for \f$ 0 \leq k \leq n \f$. For detailed description see
0104   <A HREF="http://mathworld.wolfram.com/BinomialDistribution.html">
0105   Mathworld</A>.
0106 
0107   @ingroup PdfFunc
0108 
0109   */
0110 
0111   inline double binomial_pdf(unsigned int k, double p, unsigned int n) {
0112     // Inlined to enable clad-auto-derivation for this function.
0113     if (k > n)
0114       return 0.0;
0115 
0116     double coeff = ROOT::Math::lgamma(n+1) - ROOT::Math::lgamma(k+1) - ROOT::Math::lgamma(n-k+1);
0117     return std::exp(coeff + k * std::log(p) + (n - k) * ROOT::Math::log1p(-p));
0118   }
0119 
0120 
0121 
0122   /**
0123 
0124   Probability density function of the negative binomial distribution.
0125 
0126   \f[ p(k) = \frac{(k+n-1)!}{k! (n-1)!} p^{n} (1-p)^{k} \f]
0127 
0128   For detailed description see
0129   <A HREF="http://mathworld.wolfram.com/NegativeBinomialDistribution.html">
0130   Mathworld</A> (where \f$k \to x\f$ and \f$n \to r\f$).
0131   The distribution in <A HREF="http://en.wikipedia.org/wiki/Negative_binomial_distribution">
0132   Wikipedia</A> is defined with a \f$p\f$ corresponding to \f$1-p\f$ in this case.
0133 
0134 
0135   @ingroup PdfFunc
0136 
0137   */
0138 
0139   inline double negative_binomial_pdf(unsigned int k, double p, double n) {
0140     // Inlined to enable clad-auto-derivation for this function.
0141 
0142     // implement in term of gamma function
0143 
0144     if (n < 0)  return 0.0;
0145     if (p < 0 || p > 1.0) return 0.0;
0146 
0147     double coeff = ROOT::Math::lgamma(k+n) - ROOT::Math::lgamma(k+1.0) - ROOT::Math::lgamma(n);
0148     return std::exp(coeff + n * std::log(p) + double(k) * ROOT::Math::log1p(-p));
0149 
0150   }
0151 
0152 
0153 
0154 
0155   /**
0156 
0157   Probability density function of Breit-Wigner distribution, which is similar, just
0158   a different definition of the parameters, to the Cauchy distribution
0159   (see  #cauchy_pdf )
0160 
0161   \f[ p(x) = \frac{1}{\pi} \frac{\frac{1}{2} \Gamma}{x^2 + (\frac{1}{2} \Gamma)^2} \f]
0162 
0163 
0164   @ingroup PdfFunc
0165 
0166   */
0167 
0168   inline double breitwigner_pdf(double x, double gamma, double x0 = 0) {
0169     // Inlined to enable clad-auto-derivation for this function.
0170     double gammahalf = gamma/2.0;
0171     return gammahalf/(M_PI * ((x-x0)*(x-x0) + gammahalf*gammahalf));
0172   }
0173 
0174 
0175 
0176 
0177   /**
0178 
0179   Probability density function of the Cauchy distribution which is also
0180   called Lorentzian distribution.
0181 
0182 
0183   \f[ p(x) = \frac{1}{\pi} \frac{ b }{ (x-m)^2 + b^2} \f]
0184 
0185   For detailed description see
0186   <A HREF="http://mathworld.wolfram.com/CauchyDistribution.html">
0187   Mathworld</A>. It is also related to the #breitwigner_pdf which
0188   will call the same implementation.
0189 
0190   @ingroup PdfFunc
0191 
0192   */
0193 
0194   inline double cauchy_pdf(double x, double b = 1, double x0 = 0) {
0195 
0196     return b/(M_PI * ((x-x0)*(x-x0) + b*b));
0197 
0198   }
0199 
0200 
0201 
0202 
0203   /**
0204 
0205   Probability density function of the \f$\chi^2\f$ distribution with \f$r\f$
0206   degrees of freedom.
0207 
0208   \f[ p_r(x) = \frac{1}{\Gamma(r/2) 2^{r/2}} x^{r/2-1} e^{-x/2} \f]
0209 
0210   for \f$x \geq 0\f$. For detailed description see
0211   <A HREF="http://mathworld.wolfram.com/Chi-SquaredDistribution.html">
0212   Mathworld</A>.
0213 
0214   @ingroup PdfFunc
0215 
0216   */
0217 
0218   inline double chisquared_pdf(double x, double r, double x0 = 0) {
0219     // Inlined to enable clad-auto-derivation for this function.
0220 
0221     if ((x-x0) <  0) {
0222       return 0.0;
0223     }
0224     double a = r/2 -1.;
0225     // let return inf for case x  = x0 and treat special case of r = 2 otherwise will return nan
0226     if (x == x0 && a == 0) return 0.5;
0227 
0228     return std::exp ((r/2 - 1) * std::log((x-x0)/2) - (x-x0)/2 - ROOT::Math::lgamma(r/2))/2;
0229 
0230   }
0231 
0232 
0233   /**
0234 
0235   Crystal ball function
0236 
0237   See the definition at
0238   <A HREF="http://en.wikipedia.org/wiki/Crystal_Ball_function">
0239   Wikipedia</A>.
0240 
0241   It is not really a pdf since it is not normalized
0242 
0243   @ingroup PdfFunc
0244 
0245   */
0246 
0247   inline double crystalball_function(double x, double alpha, double n, double sigma, double mean = 0) {
0248      // Inlined to enable clad-auto-derivation for this function.
0249 
0250      // evaluate the crystal ball function
0251      if (sigma < 0.)     return 0.;
0252      double z = (x - mean)/sigma;
0253      if (alpha < 0) z = -z;
0254      double abs_alpha = std::abs(alpha);
0255      // double C = n/abs_alpha * 1./(n-1.) * std::exp(-alpha*alpha/2.);
0256      // double D = std::sqrt(M_PI/2.)*(1.+ROOT::Math::erf(abs_alpha/std::sqrt(2.)));
0257      // double N = 1./(sigma*(C+D));
0258      if (z  > - abs_alpha)
0259         return std::exp(- 0.5 * z * z);
0260      //double A = std::pow(n/abs_alpha,n) * std::exp(-0.5*abs_alpha*abs_alpha);
0261      double nDivAlpha = n/abs_alpha;
0262      double AA =  std::exp(-0.5*abs_alpha*abs_alpha);
0263      double B = nDivAlpha -abs_alpha;
0264      double arg = nDivAlpha/(B-z);
0265      return AA * std::pow(arg,n);
0266    }
0267 
0268    /**
0269        pdf definition of the crystal_ball which is defined only for n > 1 otherwise integral is diverging
0270     */
0271   inline double crystalball_pdf(double x, double alpha, double n, double sigma, double mean = 0) {
0272     // Inlined to enable clad-auto-derivation for this function.
0273 
0274     // evaluation of the PDF ( is defined only for n >1)
0275     if (sigma < 0.)     return 0.;
0276     if ( n <= 1) return std::numeric_limits<double>::quiet_NaN();  // pdf is not normalized for n <=1
0277     double abs_alpha = std::abs(alpha);
0278     double C = n/abs_alpha * 1./(n-1.) * std::exp(-alpha*alpha/2.);
0279     double D = std::sqrt(M_PI/2.)*(1.+ROOT::Math::erf(abs_alpha/std::sqrt(2.)));
0280     double N = 1./(sigma*(C+D));
0281     return N * crystalball_function(x,alpha,n,sigma,mean);
0282    }
0283 
0284   /**
0285 
0286   Probability density function of the exponential distribution.
0287 
0288   \f[ p(x) = \lambda e^{-\lambda x} \f]
0289 
0290   for x>0. For detailed description see
0291   <A HREF="http://mathworld.wolfram.com/ExponentialDistribution.html">
0292   Mathworld</A>.
0293 
0294 
0295   @ingroup PdfFunc
0296 
0297   */
0298 
0299   inline double exponential_pdf(double x, double lambda, double x0 = 0) {
0300     // Inlined to enable clad-auto-derivation for this function.
0301 
0302     if ((x-x0) < 0)
0303       return 0.0;
0304     return lambda * std::exp (-lambda * (x-x0));
0305   }
0306 
0307 
0308 
0309 
0310   /**
0311 
0312   Probability density function of the F-distribution.
0313 
0314   \f[ p_{n,m}(x) = \frac{\Gamma(\frac{n+m}{2})}{\Gamma(\frac{n}{2}) \Gamma(\frac{m}{2})} n^{n/2} m^{m/2} x^{n/2 -1} (m+nx)^{-(n+m)/2} \f]
0315 
0316   for x>=0. For detailed description see
0317   <A HREF="http://mathworld.wolfram.com/F-Distribution.html">
0318   Mathworld</A>.
0319 
0320   @ingroup PdfFunc
0321 
0322   */
0323 
0324 
0325   inline double fdistribution_pdf(double x, double n, double m, double x0 = 0) {
0326     // Inlined to enable clad-auto-derivation for this function.
0327 
0328     // function is defined only for both n and m > 0
0329     if (n < 0 || m < 0)
0330       return std::numeric_limits<double>::quiet_NaN();
0331     if ((x-x0) < 0)
0332       return 0.0;
0333 
0334     return std::exp((n/2) * std::log(n) + (m/2) * std::log(m) + ROOT::Math::lgamma((n+m)/2) - ROOT::Math::lgamma(n/2) - ROOT::Math::lgamma(m/2)
0335                     + (n/2 -1) * std::log(x-x0) - ((n+m)/2) * std::log(m +  n*(x-x0)) );
0336 
0337   }
0338 
0339 
0340 
0341 
0342   /**
0343 
0344   Probability density function of the gamma distribution.
0345 
0346   \f[ p(x) = {1 \over \Gamma(\alpha) \theta^{\alpha}} x^{\alpha-1} e^{-x/\theta} \f]
0347 
0348   for x>0. For detailed description see
0349   <A HREF="http://mathworld.wolfram.com/GammaDistribution.html">
0350   Mathworld</A>.
0351 
0352   @ingroup PdfFunc
0353 
0354   */
0355 
0356   inline double gamma_pdf(double x, double alpha, double theta, double x0 = 0) {
0357     // Inlined to enable clad-auto-derivation for this function.
0358 
0359     if ((x-x0) < 0) {
0360       return 0.0;
0361     } else if ((x-x0) == 0) {
0362 
0363       if (alpha == 1) {
0364         return 1.0/theta;
0365       } else {
0366         return 0.0;
0367       }
0368 
0369     } else if (alpha == 1) {
0370       return std::exp(-(x-x0)/theta)/theta;
0371     } else {
0372       return std::exp((alpha - 1) * std::log((x-x0)/theta) - (x-x0)/theta - ROOT::Math::lgamma(alpha))/theta;
0373     }
0374 
0375   }
0376 
0377 
0378 
0379 
0380   /**
0381 
0382   Probability density function of the normal (Gaussian) distribution with mean x0 and standard deviation sigma.
0383 
0384   \f[ p(x) = {1 \over \sqrt{2 \pi \sigma^2}} e^{-(x-x_0)^2 / 2\sigma^2} \f]
0385 
0386   For detailed description see
0387   <A HREF="http://mathworld.wolfram.com/NormalDistribution.html">
0388   Mathworld</A>. It can also be evaluated using #normal_pdf which will
0389   call the same implementation.
0390 
0391   @ingroup PdfFunc
0392 
0393   */
0394 
0395   inline double gaussian_pdf(double x, double sigma = 1, double x0 = 0) {
0396 
0397     double tmp = (x-x0)/sigma;
0398     return (1.0/(std::sqrt(2 * M_PI) * std::abs(sigma))) * std::exp(-tmp*tmp/2);
0399   }
0400 
0401    /**
0402 
0403   Probability density function of the bi-dimensional (Gaussian) distribution.
0404 
0405   \f[ p(x,y) = {1 \over 2 \pi \sigma_x \sigma_y \sqrt{1-\rho^2}} \exp (-((x-x0)^2/\sigma_x^2 + (y-y0)^2/\sigma_y^2 - 2 \rho x y/(\sigma_x\sigma_y))/2(1-\rho^2)) \f]
0406 
0407   For detailed description see
0408   <A HREF="http://mathworld.wolfram.com/BivariateNormalDistribution.html">
0409   Mathworld</A>. It can also be evaluated using #normal_pdf which will
0410   call the same implementation.
0411 
0412   @param x x variable
0413   @param y y variable
0414   @param sigmax the stdev in x
0415   @param sigmay the stdev in y
0416   @param rho correlation, must be between -1,1
0417   @param x0 the offset in x
0418   @param y0 the offset in y
0419 
0420   @ingroup PdfFunc
0421 
0422   */
0423 
0424   inline double bigaussian_pdf(double x, double y, double sigmax = 1, double sigmay = 1, double rho = 0, double x0 = 0, double y0 = 0) {
0425     double u = (x-x0)/sigmax;
0426     double v = (y-y0)/sigmay;
0427     double c = 1. - rho*rho;
0428     double z = u*u - 2.*rho*u*v + v*v;
0429     return  1./(2 * M_PI * sigmax * sigmay * std::sqrt(c) ) * std::exp(- z / (2. * c) );
0430   }
0431 
0432    /**
0433 
0434    Probability density function of the Landau distribution:
0435   \f[ p(x) = \frac{1}{\xi} \phi (\lambda) \f]
0436    with
0437    \f[  \phi(\lambda) = \frac{1}{2 \pi i}\int_{c-i\infty}^{c+i\infty} e^{\lambda s + s \log{s}} ds\f]
0438    where \f$\lambda = (x-x_0)/\xi\f$. For a detailed description see
0439    K.S. K&ouml;lbig and B. Schorr, A program package for the Landau distribution,
0440    <A HREF="http://dx.doi.org/10.1016/0010-4655(84)90085-7">Computer Phys. Comm. 31 (1984) 97-111</A>
0441    <A HREF="http://dx.doi.org/10.1016/j.cpc.2008.03.002">[Erratum-ibid. 178 (2008) 972]</A>.
0442    The same algorithms as in
0443    <A HREF="https://cern-tex.web.cern.ch/cern-tex/shortwrupsdir/g110/top.html">
0444    CERNLIB</A> (DENLAN)  is used
0445 
0446    @param x The argument \f$x\f$
0447    @param xi The width parameter \f$\xi\f$
0448    @param x0 The location parameter \f$x_0\f$
0449 
0450    @ingroup PdfFunc
0451 
0452    */
0453 
0454    double landau_pdf(double x, double xi = 1, double x0 = 0);
0455 
0456 
0457 
0458   /**
0459 
0460   Probability density function of the lognormal distribution.
0461 
0462   \f[ p(x) = {1 \over x \sqrt{2 \pi s^2} } e^{-(\ln{x} - m)^2/2 s^2} \f]
0463 
0464   for x>0. For detailed description see
0465   <A HREF="http://mathworld.wolfram.com/LogNormalDistribution.html">
0466   Mathworld</A>.
0467   @param x x variable
0468   @param m M = 0 for lognormal
0469   @param s scale parameter (not the sigma of the distribution which is not even defined)
0470   @param x0  location parameter, corresponds approximately to the most probable value. For x0 = 0, sigma = 1, the x_mpv = -0.22278
0471 
0472   @ingroup PdfFunc
0473 
0474   */
0475 
0476   inline double lognormal_pdf(double x, double m, double s, double x0 = 0) {
0477     // Inlined to enable clad-auto-derivation for this function.
0478     if ((x-x0) <= 0)
0479       return 0.0;
0480     double tmp = (std::log((x-x0)) - m)/s;
0481     return 1.0 / ((x-x0) * std::abs(s) * std::sqrt(2 * M_PI)) * std::exp(-(tmp * tmp) /2);
0482   }
0483 
0484 
0485 
0486 
0487   /**
0488 
0489   Probability density function of the normal (Gaussian) distribution with mean x0 and standard deviation sigma.
0490 
0491   \f[ p(x) = {1 \over \sqrt{2 \pi \sigma^2}} e^{-(x-x_0)^2 / 2\sigma^2} \f]
0492 
0493   For detailed description see
0494   <A HREF="http://mathworld.wolfram.com/NormalDistribution.html">
0495   Mathworld</A>. It can also be evaluated using #gaussian_pdf which will call the same
0496   implementation.
0497 
0498   @ingroup PdfFunc
0499 
0500   */
0501 
0502   inline double normal_pdf(double x, double sigma =1, double x0 = 0) {
0503     // Inlined to enable clad-auto-derivation for this function.
0504 
0505     double tmp = (x-x0)/sigma;
0506     return (1.0/(std::sqrt(2 * M_PI) * std::abs(sigma))) * std::exp(-tmp*tmp/2);
0507 
0508   }
0509 
0510 
0511   /**
0512 
0513   Probability density function of the Poisson distribution.
0514 
0515   \f[ p(n) = \frac{\mu^n}{n!} e^{- \mu} \f]
0516 
0517   For detailed description see
0518   <A HREF="http://mathworld.wolfram.com/PoissonDistribution.html">
0519   Mathworld</A>.
0520 
0521   @ingroup PdfFunc
0522 
0523   */
0524 
0525   inline double poisson_pdf(unsigned int n, double mu) {
0526     // Inlined to enable clad-auto-derivation for this function.
0527 
0528     if (n > 0 && mu >= 0)
0529       return std::exp (n*std::log(mu) - ROOT::Math::lgamma(n+1) - mu);
0530 
0531     //  when  n = 0 and mu = 0,  1 is returned
0532     if (mu >= 0)
0533       return std::exp(-mu);
0534 
0535     // return a nan for mu < 0 since it does not make sense
0536     return std::numeric_limits<double>::quiet_NaN();
0537   }
0538 
0539 
0540 
0541 
0542   /**
0543 
0544   Probability density function of Student's t-distribution.
0545 
0546   \f[ p_{r}(x) = \frac{\Gamma(\frac{r+1}{2})}{\sqrt{r \pi}\Gamma(\frac{r}{2})} \left( 1+\frac{x^2}{r}\right)^{-(r+1)/2}  \f]
0547 
0548   for \f$r \geq 0\f$. For detailed description see
0549   <A HREF="http://mathworld.wolfram.com/Studentst-Distribution.html">
0550   Mathworld</A>.
0551 
0552   @ingroup PdfFunc
0553 
0554   */
0555 
0556   inline double tdistribution_pdf(double x, double r, double x0 = 0) {
0557     // Inlined to enable clad-auto-derivation for this function.
0558 
0559     return (std::exp (ROOT::Math::lgamma((r + 1.0)/2.0) - ROOT::Math::lgamma(r/2.0)) / std::sqrt (M_PI * r))
0560     * std::pow ((1.0 + (x-x0)*(x-x0)/r), -(r + 1.0)/2.0);
0561 
0562   }
0563 
0564 
0565 
0566 
0567   /**
0568 
0569   Probability density function of the uniform (flat) distribution.
0570 
0571   \f[ p(x) = {1 \over (b-a)} \f]
0572 
0573   if \f$a \leq x<b\f$ and 0 otherwise. For detailed description see
0574   <A HREF="http://mathworld.wolfram.com/UniformDistribution.html">
0575   Mathworld</A>.
0576 
0577   @ingroup PdfFunc
0578 
0579   */
0580 
0581   inline double uniform_pdf(double x, double a, double b, double x0 = 0) {
0582     // Inlined to enable clad-auto-derivation for this function.
0583 
0584     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! when a=b
0585 
0586     if ((x-x0) < b && (x-x0) >= a)
0587       return 1.0/(b - a);
0588     return 0.0;
0589 
0590   }
0591 
0592 
0593 
0594 } // namespace Math
0595 } // namespace ROOT
0596 
0597 
0598 
0599 #endif // ROOT_Math_PdfFunc