MCKL
Monte Carlo Kernel Library
beta.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/math/beta.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_MATH_BETA_HPP
33 #define MCKL_MATH_BETA_HPP
34 
35 #include <mckl/internal/config.h>
36 #include <mckl/math/constants.hpp>
37 #include <mckl/math/gamma.hpp>
38 
39 #include <algorithm>
40 #include <limits>
41 
42 namespace mckl {
43 
44 namespace internal {
45 
46 inline double betai_acf(double a, double b, double x)
47 {
48  constexpr double eps = std::numeric_limits<double>::epsilon();
49  constexpr double fpmin = std::numeric_limits<double>::min() / eps;
50 
51  double qab = a + b;
52  double qap = a + 1;
53  double qam = a - 1;
54  double c = 1;
55  double d = 1 - qab * x / qap;
56  if (std::abs(d) < fpmin) {
57  d = fpmin;
58  }
59  d = 1 / d;
60  double h = d;
61  double m = 0;
62  for (int i = 0; i != 10000; ++i) {
63  m += 1;
64  double m2 = 2 * m;
65  double aa = m * (b - m) * x / ((qam + m2) * (a + m2));
66  d = 1 + aa * d;
67  if (std::abs(d) < fpmin) {
68  d = fpmin;
69  }
70  c = 1 + aa / c;
71  if (std::abs(c) < fpmin) {
72  c = fpmin;
73  }
74  d = 1 / d;
75  h *= d * c;
76  aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
77  d = 1 + aa * d;
78  if (std::abs(d) < fpmin) {
79  d = fpmin;
80  }
81  c = 1 + aa / c;
82  if (std::abs(c) < fpmin) {
83  c = fpmin;
84  }
85  d = 1 / d;
86  double del = d * c;
87  h *= del;
88  if (std::abs(del - 1) <= eps) {
89  break;
90  }
91  }
92 
93  return h;
94 }
95 
96 inline double betai_approx(double a, double b, double x)
97 {
98  double a1 = a - 1;
99  double b1 = b - 1;
100  double mu = a / (a + b);
101  double lnmu = std::log(mu);
102  double lnmuc = std::log(1 - mu);
103  double t = std::sqrt(a * b / ((a + b) * (a + b) * (a + b + 1)));
104  double xu = 0;
105  if (x > a / (a + b)) {
106  if (x >= 1) {
107  return 1;
108  }
109  xu = std::min(1.0, std::max(mu + 10 * t, x + 5 * t));
110  } else {
111  if (x <= 0) {
112  return 0;
113  }
114  xu = std::max(0.0, std::min(mu - 10 * t, x - 5 * t));
115  }
116  double sum = 0;
117  for (std::size_t i = 0; i != gammap_approx_n; ++i) {
118  t = x + (xu - x) * gammap_approx_y[i];
119  sum += gammap_approx_w[i] *
120  std::exp(
121  a1 * (std::log(t) - lnmu) + b1 * (std::log(1 - t) - lnmuc));
122  }
123  double ans = sum * (xu - x) *
124  std::exp(a1 * lnmu - std::lgamma(a) + b1 * lnmuc - std::lgamma(b) +
125  std::lgamma(a + b));
126 
127  return ans > 0 ? 1 - ans : -ans;
128 }
129 
130 } // namespace internal
131 
134 inline double betai(double a, double b, double x)
135 {
136  if (a <= 0.0 || b <= 0.0) {
137  return mckl::const_nan<double>();
138  }
139  if (x < 0.0 || x > 1.0) {
140  return mckl::const_nan<double>();
141  }
142  if (!(x > 0 || x < 0)) {
143  return x;
144  }
145  if (!(x > 1 || x < 1)) {
146  return x;
147  }
148  if (a > 3000 && b > 3000) {
149  return internal::betai_approx(a, b, x);
150  }
151 
152  double bt = std::exp(std::lgamma(a + b) - std::lgamma(a) - std::lgamma(b) +
153  a * std::log(x) + b * std::log(1 - x));
154 
155  return x < (a + 1) / (a + b + 2) ?
156  (bt * internal::betai_acf(a, b, x) / a) :
157  (1 - bt * internal::betai_acf(b, a, 1 - x) / b);
158 }
159 
162 inline double betaiinv(double a, double b, double y)
163 {
164  if (y <= 0) {
165  return 0;
166  }
167  if (y >= 1) {
168  return 1;
169  }
170 
171  double eps = 1e-8;
172  double a1 = a - 1;
173  double b1 = b - 1;
174  double x = 0;
175  if (a >= 1 && b >= 1) {
176  double z = (y < 0.5) ? y : 1 - y;
177  double t = std::sqrt(-2 * std::log(z));
178  x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
179  if (y < 0.5) {
180  x = -x;
181  }
182  double al = (x * x - 3) / 6;
183  double h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1));
184  double w = (x * std::sqrt(al + h) / h) -
185  (1 / (2 * b - 1) - 1 / (2 * a - 1)) * (al + 5 / 6 - 2 / (3 * h));
186  x = a / (a + b * std::exp(2 * w));
187  } else {
188  double lna = std::log(a / (a + b));
189  double lnb = std::log(b / (a + b));
190  double t = std::exp(a * lna) / a;
191  double u = std::exp(b * lnb) / b;
192  double w = t + u;
193  x = y < t / w ? std::pow(a * w * y, 1 / a) :
194  1 - std::pow(b * w * (1 - y), 1 / b);
195  }
196  double afac = -std::lgamma(a) - std::lgamma(b) + std::lgamma(a + b);
197  for (int i = 0; i != 10; ++i) {
198  if (!(x > 0 || x < 0)) {
199  return x;
200  }
201  if (!(x > 1 || x < 1)) {
202  return x;
203  }
204  double err = betai(a, b, x) - y;
205  double t = std::exp(a1 * std::log(x) + b1 * std::log(1 - x) + afac);
206  double u = err / t;
207  x -= (t = u / (1 - 0.5 * std::min(1.0, u * (a1 / x - b1 / (1 - x)))));
208  if (x <= 0) {
209  x = 0.5 * (x + t);
210  }
211  if (x >= 1) {
212  x = 0.5 * (x + t + 1);
213  }
214  if (std::abs(t) < eps * x && i > 0) {
215  break;
216  }
217  }
218 
219  return x;
220 }
221 
222 } // namespace mckl
223 
224 #endif // MCKL_MATH_BETA_HPP
void pow(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:184
static constexpr double gammap_approx_w[]
Definition: gamma.hpp:55
double betai(double a, double b, double x)
Regularized incomplete Beta function.
Definition: beta.hpp:134
static constexpr std::size_t gammap_approx_n
Definition: gamma.hpp:45
double betai_acf(double a, double b, double x)
Definition: beta.hpp:46
static constexpr double gammap_approx_y[]
Definition: gamma.hpp:47
void lgamma(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:303
void log(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:226
void abs(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:128
double betai_approx(double a, double b, double x)
Definition: beta.hpp:96
void sqrt(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:177
Definition: mcmc.hpp:40
void exp(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:221
double betaiinv(double a, double b, double y)
Inverse regularized incomplete Beta function.
Definition: beta.hpp:162