1 /*!
2  * Copyright 2019-2020 by Contributors
3  * \file probability_distribution.h
4  * \brief Implementation of a few useful probability distributions
5  * \author Avinash Barnwal and Hyunsu Cho
6  */
7 
8 #ifndef XGBOOST_COMMON_PROBABILITY_DISTRIBUTION_H_
9 #define XGBOOST_COMMON_PROBABILITY_DISTRIBUTION_H_
10 
11 #include <cmath>
12 
13 namespace xgboost {
14 namespace common {
15 
16 #ifndef __CUDACC__
17 
18 using std::exp;
19 using std::sqrt;
20 using std::isinf;
21 using std::isnan;
22 
23 #endif  // __CUDACC__
24 
25 /*! \brief Constant PI */
26 constexpr double kPI = 3.14159265358979323846;
27 /*! \brief The Euler-Mascheroni_constant */
28 constexpr double kEulerMascheroni = 0.57721566490153286060651209008240243104215933593992;
29 
30 /*! \brief Enum encoding possible choices of probability distribution */
31 enum class ProbabilityDistributionType : int {
32   kNormal = 0, kLogistic = 1, kExtreme = 2
33 };
34 
35 struct NormalDistribution {
PDFNormalDistribution36   XGBOOST_DEVICE static double PDF(double z) {
37     return exp(-z * z / 2.0) / sqrt(2.0 * kPI);
38   }
39 
CDFNormalDistribution40   XGBOOST_DEVICE static double CDF(double z) {
41     return 0.5 * (1 + erf(z / sqrt(2.0)));
42   }
43 
GradPDFNormalDistribution44   XGBOOST_DEVICE static double GradPDF(double z) {
45     return -z * PDF(z);
46   }
47 
HessPDFNormalDistribution48   XGBOOST_DEVICE static double HessPDF(double z) {
49     return (z * z - 1.0) * PDF(z);
50   }
51 
TypeNormalDistribution52   XGBOOST_DEVICE static ProbabilityDistributionType Type() {
53     return ProbabilityDistributionType::kNormal;
54   }
55 };
56 
57 struct LogisticDistribution {
PDFLogisticDistribution58   XGBOOST_DEVICE static double PDF(double z) {
59     const double w = exp(z);
60     const double sqrt_denominator = 1 + w;
61     if (isinf(w) || isinf(w * w)) {
62       return 0.0;
63     } else {
64       return w / (sqrt_denominator * sqrt_denominator);
65     }
66   }
67 
CDFLogisticDistribution68   XGBOOST_DEVICE static double CDF(double z) {
69     const double w = exp(z);
70     return isinf(w) ? 1.0 : (w / (1 + w));
71   }
72 
GradPDFLogisticDistribution73   XGBOOST_DEVICE static double GradPDF(double z) {
74     const double w = exp(z);
75     return isinf(w) ? 0.0 : (PDF(z) * (1 - w) / (1 + w));
76   }
77 
HessPDFLogisticDistribution78   XGBOOST_DEVICE static double HessPDF(double z) {
79     const double w = exp(z);
80     if (isinf(w) || isinf(w * w)) {
81       return 0.0;
82     } else {
83       return PDF(z) * (w * w - 4 * w + 1) / ((1 + w) * (1 + w));
84     }
85   }
86 
TypeLogisticDistribution87   XGBOOST_DEVICE static ProbabilityDistributionType Type() {
88     return ProbabilityDistributionType::kLogistic;
89   }
90 };
91 
92 struct ExtremeDistribution {
PDFExtremeDistribution93   XGBOOST_DEVICE static double PDF(double z) {
94     const double w = exp(z);
95     return isinf(w) ? 0.0 : (w * exp(-w));
96   }
97 
CDFExtremeDistribution98   XGBOOST_DEVICE static double CDF(double z) {
99     const double w = exp(z);
100     return 1 - exp(-w);
101   }
102 
GradPDFExtremeDistribution103   XGBOOST_DEVICE static double GradPDF(double z) {
104     const double w = exp(z);
105     return isinf(w) ? 0.0 : ((1 - w) * PDF(z));
106   }
107 
HessPDFExtremeDistribution108   XGBOOST_DEVICE static double HessPDF(double z) {
109     const double w = exp(z);
110     if (isinf(w) || isinf(w * w)) {
111       return 0.0;
112     } else {
113       return (w * w - 3 * w + 1) * PDF(z);
114     }
115   }
116 
TypeExtremeDistribution117   XGBOOST_DEVICE static ProbabilityDistributionType Type() {
118     return ProbabilityDistributionType::kExtreme;
119   }
120 };
121 
122 }  // namespace common
123 }  // namespace xgboost
124 
125 #endif  // XGBOOST_COMMON_PROBABILITY_DISTRIBUTION_H_
126