openGPMP
Open Source Mathematics Package
quantiles.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  *
3  * Project
4  * _____ _____ __ __ _____
5  * / ____| __ \| \/ | __ \
6  * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) |
7  * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/
8  *| (_) | |_) | __/ | | | |__| | | | | | | |
9  * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_|
10  * | |
11  * |_|
12  *
13  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
14  *
15  * This software is licensed as described in the file LICENSE, which
16  * you should have received as part of this distribution. The terms
17  * among other details are referenced in the official documentation
18  * seen here : https://akielaries.github.io/openGPMP/ along with
19  * important files seen in this project.
20  *
21  * You may opt to use, copy, modify, merge, publish, distribute
22  * and/or sell copies of the Software, and permit persons to whom
23  * the Software is furnished to do so, under the terms of the
24  * LICENSE file. As this is an Open Source effort, all implementations
25  * must be of the same methodology.
26  *
27  *
28  *
29  * This software is distributed on an AS IS basis, WITHOUT
30  * WARRANTY OF ANY KIND, either express or implied.
31  *
32  ************************************************************************/
33 #include <algorithm>
34 #include <cmath>
35 #include <limits>
36 #include <numeric>
37 // #include <openGPMP/stats/quantiles.hpp>
38 #include <random>
39 #include <stdexcept>
40 #include <vector>
41 
42 class Quantile {
43  public:
44  // Bernoulli distribution quantile function
45  static double bernoulli(double p, double q) {
46  return (q < p) ? 0.0 : 1.0;
47  }
48 
49  // Beta distribution quantile function
50  static double beta(double alpha, double beta, double q) {
51  if (q <= 0.0)
52  return 0.0;
53  if (q >= 1.0)
54  return 1.0;
55 
56  double result = 0.0;
57  if (q > 0.5)
58  result = 1.0 - incompleteBeta(beta, alpha, 1.0 - q);
59  else
60  result = incompleteBeta(alpha, beta, q);
61 
62  return result;
63  }
64 
65  // Binomial distribution quantile function
66  static int binomial(int n, double p, double q) {
67  int x = 0;
68  double cdf = 0.0;
69  while (x <= n) {
70  cdf += binomialCoefficient(n, x) * pow(p, x) * pow(1.0 - p, n - x);
71  if (cdf >= q)
72  return x;
73  x++;
74  }
75  return n;
76  }
77 
78  // Cauchy distribution quantile function
79  static double cauchy(double median, double scale, double q) {
80  return median + scale * tan(M_PI * (q - 0.5));
81  }
82 
83  // Chi-squared distribution quantile function
84  static double chiSquared(int df, double q) {
85  if (q < 0.0 || q > 1.0 || df < 1)
86  return NAN;
87  return df * inverseGamma(0.5 * df, q);
88  }
89 
90  // Exponential distribution quantile function
91  static double exponential(double lambda, double q) {
92  if (q < 0.0 || q > 1.0 || lambda <= 0.0)
93  return NAN;
94  return -log(1.0 - q) / lambda;
95  }
96 
97  // F distribution quantile function
98  static double f(int df1, int df2, double q) {
99  if (q <= 0.0 || q >= 1.0 || df1 <= 0 || df2 <= 0)
100  return NAN;
101  return (inverseBeta(0.5 * df2, 0.5 * df1, q) * df2) /
102  (inverseBeta(0.5 * df2, 0.5 * df1, 1.0 - q) * df1);
103  }
104 
105  // Gamma distribution quantile function
106  static double gamma(double shape, double scale, double q) {
107  if (q < 0.0 || q > 1.0 || shape <= 0.0 || scale <= 0.0)
108  return NAN;
109  return shape * scale * inverseGamma(shape, q);
110  }
111 
112  // Inverse-Gamma distribution quantile function
113  static double inverseGamma(double shape, double q) {
114  if (q < 0.0 || q > 1.0 || shape <= 0.0)
115  return NAN;
116  return 1.0 / gamma(shape, 1.0 / shape, 1.0 - q);
117  }
118 
119  private:
120  static double incompleteBeta(double a, double b, double x) {
121  const int maxIterations = 200;
122  const double epsilon = 1.0e-15;
123 
124  double bt = (x == 0.0 || x == 1.0)
125  ? 0.0
126  : exp(gammaLn(a + b) - gammaLn(a) - gammaLn(b) +
127  a * log(x) + b * log(1.0 - x));
128 
129  if (x < (a + 1.0) / (a + b + 2.0))
130  return bt * betaContinuedFraction(a, b, x) / a;
131  else
132  return 1.0 - bt * betaContinuedFraction(b, a, 1.0 - x) / b;
133  }
134 
135  static double gammaLn(double xx) {
136  double x, y, tmp, ser;
137  static const double cof[6] = {76.18009172947146,
138  -86.50532032941677,
139  24.01409824083091,
140  -1.231739572450155,
141  0.1208650973866179e-2,
142  -0.5395239384953e-5};
143  int j;
144 
145  y = x = xx;
146  tmp = x + 5.5;
147  tmp -= (x + 0.5) * log(tmp);
148  ser = 1.000000000190015;
149  for (j = 0; j < 6; j++)
150  ser += cof[j] / ++y;
151  return -tmp + log(2.5066282746310005 * ser / x);
152  }
153 
154  static double betaContinuedFraction(double a, double b, double x) {
155  const int maxIterations = 200;
156  const double epsilon = 1.0e-15;
157 
158  double am = 1.0;
159  double bm = 1.0;
160  double az = 1.0;
161  double qab = a + b;
162  double qap = a + 1.0;
163  double qam = a - 1.0;
164  double bz = 1.0 - qab * x / qap;
165  double aold = 0.0;
166  double em, tem, d, ap, bp, app, bpp;
167  int m;
168 
169  for (m = 1; m <= maxIterations; m++) {
170  em = m;
171  tem = em + em;
172  d = em * (b - m) * x / ((qam + tem) * (a + tem));
173  ap = az + d * am;
174  bp = bz + d * bm;
175  d = -(a + em) * (qab + em) * x / ((a + tem) * (qap + tem));
176  app = ap + d * az;
177  bpp = bp + d * bz;
178  aold = az;
179  am = ap / bpp;
180  bm = bp / bpp;
181  az = app / bpp;
182  bz = 1.0;
183 
184  if (fabs(az - aold) < (epsilon * fabs(az)))
185  return az;
186  }
187  return az;
188  }
189 
190  static double inverseBeta(double a, double b, double q) {
191  return 1.0 - incompleteBeta(b, a, q);
192  }
193 
194  static int binomialCoefficient(int n, int k) {
195  if (k < 0 || k > n)
196  return 0;
197  if (k == 0 || k == n)
198  return 1;
199 
200  int result = 1;
201  if (k > n - k)
202  k = n - k;
203 
204  for (int i = 0; i < k; ++i) {
205  result *= (n - i);
206  result /= (i + 1);
207  }
208 
209  return result;
210  }
211 };
static int binomial(int n, double p, double q)
Definition: quantiles.cpp:66
static int binomialCoefficient(int n, int k)
Definition: quantiles.cpp:194
static double beta(double alpha, double beta, double q)
Definition: quantiles.cpp:50
static double chiSquared(int df, double q)
Definition: quantiles.cpp:84
static double inverseGamma(double shape, double q)
Definition: quantiles.cpp:113
static double bernoulli(double p, double q)
Definition: quantiles.cpp:45
static double f(int df1, int df2, double q)
Definition: quantiles.cpp:98
static double gamma(double shape, double scale, double q)
Definition: quantiles.cpp:106
static double gammaLn(double xx)
Definition: quantiles.cpp:135
static double betaContinuedFraction(double a, double b, double x)
Definition: quantiles.cpp:154
static double exponential(double lambda, double q)
Definition: quantiles.cpp:91
static double cauchy(double median, double scale, double q)
Definition: quantiles.cpp:79
static double inverseBeta(double a, double b, double q)
Definition: quantiles.cpp:190
static double incompleteBeta(double a, double b, double x)
Definition: quantiles.cpp:120