ibeta_data.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // (C) Copyright John Maddock 2006.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include <boost/math/special_functions/gamma.hpp>
  6. #include <boost/math/special_functions/beta.hpp>
  7. #include <boost/math/constants/constants.hpp>
  8. #include <boost/lexical_cast.hpp>
  9. #include <fstream>
  10. #include <map>
  11. #include <boost/math/tools/test_data.hpp>
  12. #include <boost/random.hpp>
  13. #include "mp_t.hpp"
  14. using namespace boost::math::tools;
  15. using namespace boost::math;
  16. using namespace std;
  17. template <class T>
  18. struct ibeta_fraction1_t
  19. {
  20. typedef std::pair<T, T> result_type;
  21. ibeta_fraction1_t(T a_, T b_, T x_) : a(a_), b(b_), x(x_), k(1) {}
  22. result_type operator()()
  23. {
  24. T aN;
  25. if(k & 1)
  26. {
  27. int m = (k - 1) / 2;
  28. aN = -(a + m) * (a + b + m) * x;
  29. aN /= a + 2*m;
  30. aN /= a + 2*m + 1;
  31. }
  32. else
  33. {
  34. int m = k / 2;
  35. aN = m * (b - m) *x;
  36. aN /= a + 2*m - 1;
  37. aN /= a + 2*m;
  38. }
  39. ++k;
  40. return std::make_pair(aN, T(1));
  41. }
  42. private:
  43. T a, b, x;
  44. int k;
  45. };
  46. //
  47. // This function caches previous calls to beta
  48. // just so we can speed things up a bit:
  49. //
  50. template <class T>
  51. T get_beta(T a, T b)
  52. {
  53. static std::map<std::pair<T, T>, T> m;
  54. if(a < b)
  55. std::swap(a, b);
  56. std::pair<T, T> p(a, b);
  57. typename std::map<std::pair<T, T>, T>::const_iterator i = m.find(p);
  58. if(i != m.end())
  59. return i->second;
  60. T r = beta(a, b);
  61. p.first = a;
  62. p.second = b;
  63. m[p] = r;
  64. return r;
  65. }
  66. //
  67. // compute the continued fraction:
  68. //
  69. template <class T>
  70. T get_ibeta_fraction1(T a, T b, T x)
  71. {
  72. ibeta_fraction1_t<T> f(a, b, x);
  73. T fract = boost::math::tools::continued_fraction_a(f, boost::math::policies::digits<T, boost::math::policies::policy<> >());
  74. T denom = (a * (fract + 1));
  75. T num = pow(x, a) * pow(1 - x, b);
  76. if(num == 0)
  77. return 0;
  78. else if(denom == 0)
  79. return -1;
  80. return num / denom;
  81. }
  82. //
  83. // calculate the incomplete beta from the fraction:
  84. //
  85. template <class T>
  86. std::pair<T,T> ibeta_fraction1(T a, T b, T x)
  87. {
  88. T bet = get_beta(a, b);
  89. if(x > ((a+1)/(a+b+2)))
  90. {
  91. T fract = get_ibeta_fraction1(b, a, 1-x);
  92. if(fract/bet > 0.75)
  93. {
  94. fract = get_ibeta_fraction1(a, b, x);
  95. return std::make_pair(fract, bet - fract);
  96. }
  97. return std::make_pair(bet - fract, fract);
  98. }
  99. T fract = get_ibeta_fraction1(a, b, x);
  100. if(fract/bet > 0.75)
  101. {
  102. fract = get_ibeta_fraction1(b, a, 1-x);
  103. return std::make_pair(bet - fract, fract);
  104. }
  105. return std::make_pair(fract, bet - fract);
  106. }
  107. //
  108. // calculate the regularised incomplete beta from the fraction:
  109. //
  110. template <class T>
  111. std::pair<T,T> ibeta_fraction1_regular(T a, T b, T x)
  112. {
  113. T bet = get_beta(a, b);
  114. if(x > ((a+1)/(a+b+2)))
  115. {
  116. T fract = get_ibeta_fraction1(b, a, 1-x);
  117. if(fract == 0)
  118. bet = 1; // normalise so we don't get 0/0
  119. else if(bet == 0)
  120. return std::make_pair(T(-1), T(-1)); // Yikes!!
  121. if(fract / bet > 0.75)
  122. {
  123. fract = get_ibeta_fraction1(a, b, x);
  124. return std::make_pair(fract / bet, 1 - (fract / bet));
  125. }
  126. return std::make_pair(1 - (fract / bet), fract / bet);
  127. }
  128. T fract = get_ibeta_fraction1(a, b, x);
  129. if(fract / bet > 0.75)
  130. {
  131. fract = get_ibeta_fraction1(b, a, 1-x);
  132. return std::make_pair(1 - (fract / bet), fract / bet);
  133. }
  134. return std::make_pair(fract / bet, 1 - (fract / bet));
  135. }
  136. //
  137. // we absolutely must trunctate the input values to float
  138. // precision: we have to be certain that the input values
  139. // can be represented exactly in whatever width floating
  140. // point type we are testing, otherwise the output will
  141. // necessarily be off.
  142. //
  143. float external_f;
  144. float force_truncate(const float* f)
  145. {
  146. external_f = *f;
  147. return external_f;
  148. }
  149. float truncate_to_float(mp_t r)
  150. {
  151. float f = boost::math::tools::real_cast<float>(r);
  152. return force_truncate(&f);
  153. }
  154. boost::mt19937 rnd;
  155. boost::uniform_real<float> ur_a(1.0F, 5.0F);
  156. boost::variate_generator<boost::mt19937, boost::uniform_real<float> > gen(rnd, ur_a);
  157. boost::uniform_real<float> ur_a2(0.0F, 100.0F);
  158. boost::variate_generator<boost::mt19937, boost::uniform_real<float> > gen2(rnd, ur_a2);
  159. struct beta_data_generator
  160. {
  161. boost::math::tuple<mp_t, mp_t, mp_t, mp_t, mp_t, mp_t, mp_t> operator()(mp_t ap, mp_t bp, mp_t x_)
  162. {
  163. float a = truncate_to_float(real_cast<float>(gen() * pow(mp_t(10), ap)));
  164. float b = truncate_to_float(real_cast<float>(gen() * pow(mp_t(10), bp)));
  165. float x = truncate_to_float(real_cast<float>(x_));
  166. std::cout << a << " " << b << " " << x << std::endl;
  167. std::pair<mp_t, mp_t> ib_full = ibeta_fraction1(mp_t(a), mp_t(b), mp_t(x));
  168. std::pair<mp_t, mp_t> ib_reg = ibeta_fraction1_regular(mp_t(a), mp_t(b), mp_t(x));
  169. return boost::math::make_tuple(a, b, x, ib_full.first, ib_full.second, ib_reg.first, ib_reg.second);
  170. }
  171. };
  172. // medium sized values:
  173. struct beta_data_generator_medium
  174. {
  175. boost::math::tuple<mp_t, mp_t, mp_t, mp_t, mp_t, mp_t, mp_t> operator()(mp_t x_)
  176. {
  177. mp_t a = gen2();
  178. mp_t b = gen2();
  179. mp_t x = x_;
  180. a = ConvPrec(a, 22);
  181. b = ConvPrec(b, 22);
  182. x = ConvPrec(x, 22);
  183. std::cout << a << " " << b << " " << x << std::endl;
  184. //mp_t exp_beta = boost::math::beta(a, b, x);
  185. std::pair<mp_t, mp_t> ib_full = ibeta_fraction1(mp_t(a), mp_t(b), mp_t(x));
  186. /*exp_beta = boost::math::tools::relative_error(ib_full.first, exp_beta);
  187. if(exp_beta > 1e-40)
  188. {
  189. std::cout << exp_beta << std::endl;
  190. }*/
  191. std::pair<mp_t, mp_t> ib_reg = ibeta_fraction1_regular(mp_t(a), mp_t(b), mp_t(x));
  192. return boost::math::make_tuple(a, b, x, ib_full.first, ib_full.second, ib_reg.first, ib_reg.second);
  193. }
  194. };
  195. struct beta_data_generator_small
  196. {
  197. boost::math::tuple<mp_t, mp_t, mp_t, mp_t, mp_t, mp_t, mp_t> operator()(mp_t x_)
  198. {
  199. float a = truncate_to_float(gen2()/10);
  200. float b = truncate_to_float(gen2()/10);
  201. float x = truncate_to_float(real_cast<float>(x_));
  202. std::cout << a << " " << b << " " << x << std::endl;
  203. std::pair<mp_t, mp_t> ib_full = ibeta_fraction1(mp_t(a), mp_t(b), mp_t(x));
  204. std::pair<mp_t, mp_t> ib_reg = ibeta_fraction1_regular(mp_t(a), mp_t(b), mp_t(x));
  205. return boost::math::make_tuple(a, b, x, ib_full.first, ib_full.second, ib_reg.first, ib_reg.second);
  206. }
  207. };
  208. struct beta_data_generator_int
  209. {
  210. boost::math::tuple<mp_t, mp_t, mp_t, mp_t, mp_t, mp_t, mp_t> operator()(mp_t a, mp_t b, mp_t x_)
  211. {
  212. float x = truncate_to_float(real_cast<float>(x_));
  213. std::cout << a << " " << b << " " << x << std::endl;
  214. std::pair<mp_t, mp_t> ib_full = ibeta_fraction1(a, b, mp_t(x));
  215. std::pair<mp_t, mp_t> ib_reg = ibeta_fraction1_regular(a, b, mp_t(x));
  216. return boost::math::make_tuple(a, b, x, ib_full.first, ib_full.second, ib_reg.first, ib_reg.second);
  217. }
  218. };
  219. int main(int, char* [])
  220. {
  221. parameter_info<mp_t> arg1, arg2, arg3, arg4, arg5;
  222. test_data<mp_t> data;
  223. std::cout << "Welcome.\n"
  224. "This program will generate spot tests for the incomplete beta functions:\n"
  225. " beta(a, b, x) and ibeta(a, b, x)\n\n"
  226. "This is not an interactive program be prepared for a long wait!!!\n\n";
  227. arg1 = make_periodic_param(mp_t(-5), mp_t(6), 11);
  228. arg2 = make_periodic_param(mp_t(-5), mp_t(6), 11);
  229. arg3 = make_random_param(mp_t(0.0001), mp_t(1), 10);
  230. arg4 = make_random_param(mp_t(0.0001), mp_t(1), 100 /*500*/);
  231. arg5 = make_periodic_param(mp_t(1), mp_t(41), 10);
  232. arg1.type |= dummy_param;
  233. arg2.type |= dummy_param;
  234. arg3.type |= dummy_param;
  235. arg4.type |= dummy_param;
  236. arg5.type |= dummy_param;
  237. // comment out all but one of the following when running
  238. // or this program will take forever to complete!
  239. //data.insert(beta_data_generator(), arg1, arg2, arg3);
  240. //data.insert(beta_data_generator_medium(), arg4);
  241. //data.insert(beta_data_generator_small(), arg4);
  242. data.insert(beta_data_generator_int(), arg5, arg5, arg3);
  243. test_data<mp_t>::const_iterator i, j;
  244. i = data.begin();
  245. j = data.end();
  246. while(i != j)
  247. {
  248. mp_t v1 = beta((*i)[0], (*i)[1], (*i)[2]);
  249. mp_t v2 = relative_error(v1, (*i)[3]);
  250. std::string s = boost::lexical_cast<std::string>((*i)[3]);
  251. mp_t v3 = boost::lexical_cast<mp_t>(s);
  252. mp_t v4 = relative_error(v3, (*i)[3]);
  253. if(v2 > 1e-40)
  254. {
  255. std::cout << v2 << std::endl;
  256. }
  257. if(v4 > 1e-60)
  258. {
  259. std::cout << v4 << std::endl;
  260. }
  261. ++ i;
  262. }
  263. std::cout << "Enter name of test data file [default=ibeta_data.ipp]";
  264. std::string line;
  265. std::getline(std::cin, line);
  266. boost::algorithm::trim(line);
  267. if(line == "")
  268. line = "ibeta_data.ipp";
  269. std::ofstream ofs(line.c_str());
  270. ofs << std::scientific << std::setprecision(40);
  271. write_code(ofs, data, "ibeta_data");
  272. return 0;
  273. }