ibeta_inv_ab.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. //
  6. // This is not a complete header file, it is included by beta.hpp
  7. // after it has defined it's definitions. This inverts the incomplete
  8. // beta functions ibeta and ibetac on the first parameters "a"
  9. // and "b" using a generic root finding algorithm (TOMS Algorithm 748).
  10. //
  11. #ifndef BOOST_MATH_SP_DETAIL_BETA_INV_AB
  12. #define BOOST_MATH_SP_DETAIL_BETA_INV_AB
  13. #ifdef _MSC_VER
  14. #pragma once
  15. #endif
  16. #include <cstdint>
  17. #include <utility>
  18. #include <boost/math/tools/toms748_solve.hpp>
  19. namespace boost{ namespace math{ namespace detail{
  20. template <class T, class Policy>
  21. struct beta_inv_ab_t
  22. {
  23. beta_inv_ab_t(T b_, T z_, T p_, bool invert_, bool swap_ab_) : b(b_), z(z_), p(p_), invert(invert_), swap_ab(swap_ab_) {}
  24. T operator()(T a)
  25. {
  26. return invert ?
  27. p - boost::math::ibetac(swap_ab ? b : a, swap_ab ? a : b, z, Policy())
  28. : boost::math::ibeta(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) - p;
  29. }
  30. private:
  31. T b, z, p;
  32. bool invert, swap_ab;
  33. };
  34. template <class T, class Policy>
  35. T inverse_negative_binomial_cornish_fisher(T n, T sf, T sfc, T p, T q, const Policy& pol)
  36. {
  37. BOOST_MATH_STD_USING
  38. // mean:
  39. T m = n * (sfc) / sf;
  40. T t = sqrt(n * (sfc));
  41. // standard deviation:
  42. T sigma = t / sf;
  43. // skewness
  44. T sk = (1 + sfc) / t;
  45. // kurtosis:
  46. T k = (6 - sf * (5+sfc)) / (n * (sfc));
  47. // Get the inverse of a std normal distribution:
  48. T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
  49. // Set the sign:
  50. if(p < 0.5)
  51. x = -x;
  52. T x2 = x * x;
  53. // w is correction term due to skewness
  54. T w = x + sk * (x2 - 1) / 6;
  55. //
  56. // Add on correction due to kurtosis.
  57. //
  58. if(n >= 10)
  59. w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
  60. w = m + sigma * w;
  61. if(w < tools::min_value<T>())
  62. return tools::min_value<T>();
  63. return w;
  64. }
  65. template <class T, class Policy>
  66. T ibeta_inv_ab_imp(const T& b, const T& z, const T& p, const T& q, bool swap_ab, const Policy& pol)
  67. {
  68. BOOST_MATH_STD_USING // for ADL of std lib math functions
  69. //
  70. // Special cases first:
  71. //
  72. BOOST_MATH_INSTRUMENT_CODE("b = " << b << " z = " << z << " p = " << p << " q = " << " swap = " << swap_ab);
  73. if(p == 0)
  74. {
  75. return swap_ab ? tools::min_value<T>() : tools::max_value<T>();
  76. }
  77. if(q == 0)
  78. {
  79. return swap_ab ? tools::max_value<T>() : tools::min_value<T>();
  80. }
  81. //
  82. // Function object, this is the functor whose root
  83. // we have to solve:
  84. //
  85. beta_inv_ab_t<T, Policy> f(b, z, (p < q) ? p : q, (p < q) ? false : true, swap_ab);
  86. //
  87. // Tolerance: full precision.
  88. //
  89. tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
  90. //
  91. // Now figure out a starting guess for what a may be,
  92. // we'll start out with a value that'll put p or q
  93. // right bang in the middle of their range, the functions
  94. // are quite sensitive so we should need too many steps
  95. // to bracket the root from there:
  96. //
  97. T guess = 0;
  98. T factor = 5;
  99. //
  100. // Convert variables to parameters of a negative binomial distribution:
  101. //
  102. T n = b;
  103. T sf = swap_ab ? z : 1-z;
  104. T sfc = swap_ab ? 1-z : z;
  105. T u = swap_ab ? p : q;
  106. T v = swap_ab ? q : p;
  107. if(u <= pow(sf, n))
  108. {
  109. //
  110. // Result is less than 1, negative binomial approximation
  111. // is useless....
  112. //
  113. if((p < q) != swap_ab)
  114. {
  115. guess = (std::min)(T(b * 2), T(1));
  116. }
  117. else
  118. {
  119. guess = (std::min)(T(b / 2), T(1));
  120. }
  121. }
  122. if(n * n * n * u * sf > 0.005)
  123. guess = 1 + inverse_negative_binomial_cornish_fisher(n, sf, sfc, u, v, pol);
  124. if(guess < 10)
  125. {
  126. //
  127. // Negative binomial approximation not accurate in this area:
  128. //
  129. if((p < q) != swap_ab)
  130. {
  131. guess = (std::min)(T(b * 2), T(10));
  132. }
  133. else
  134. {
  135. guess = (std::min)(T(b / 2), T(10));
  136. }
  137. }
  138. else
  139. factor = (v < sqrt(tools::epsilon<T>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
  140. BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
  141. //
  142. // Max iterations permitted:
  143. //
  144. std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  145. std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, swap_ab ? true : false, tol, max_iter, pol);
  146. if(max_iter >= policies::get_max_root_iterations<Policy>())
  147. return policies::raise_evaluation_error<T>("boost::math::ibeta_invab_imp<%1%>(%1%,%1%,%1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
  148. return (r.first + r.second) / 2;
  149. }
  150. } // namespace detail
  151. template <class RT1, class RT2, class RT3, class Policy>
  152. typename tools::promote_args<RT1, RT2, RT3>::type
  153. ibeta_inva(RT1 b, RT2 x, RT3 p, const Policy& pol)
  154. {
  155. typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
  156. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  157. typedef typename policies::normalise<
  158. Policy,
  159. policies::promote_float<false>,
  160. policies::promote_double<false>,
  161. policies::discrete_quantile<>,
  162. policies::assert_undefined<> >::type forwarding_policy;
  163. static const char* function = "boost::math::ibeta_inva<%1%>(%1%,%1%,%1%)";
  164. if(p == 0)
  165. {
  166. return policies::raise_overflow_error<result_type>(function, 0, Policy());
  167. }
  168. if(p == 1)
  169. {
  170. return tools::min_value<result_type>();
  171. }
  172. return policies::checked_narrowing_cast<result_type, forwarding_policy>(
  173. detail::ibeta_inv_ab_imp(
  174. static_cast<value_type>(b),
  175. static_cast<value_type>(x),
  176. static_cast<value_type>(p),
  177. static_cast<value_type>(1 - static_cast<value_type>(p)),
  178. false, pol),
  179. function);
  180. }
  181. template <class RT1, class RT2, class RT3, class Policy>
  182. typename tools::promote_args<RT1, RT2, RT3>::type
  183. ibetac_inva(RT1 b, RT2 x, RT3 q, const Policy& pol)
  184. {
  185. typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
  186. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  187. typedef typename policies::normalise<
  188. Policy,
  189. policies::promote_float<false>,
  190. policies::promote_double<false>,
  191. policies::discrete_quantile<>,
  192. policies::assert_undefined<> >::type forwarding_policy;
  193. static const char* function = "boost::math::ibetac_inva<%1%>(%1%,%1%,%1%)";
  194. if(q == 1)
  195. {
  196. return policies::raise_overflow_error<result_type>(function, 0, Policy());
  197. }
  198. if(q == 0)
  199. {
  200. return tools::min_value<result_type>();
  201. }
  202. return policies::checked_narrowing_cast<result_type, forwarding_policy>(
  203. detail::ibeta_inv_ab_imp(
  204. static_cast<value_type>(b),
  205. static_cast<value_type>(x),
  206. static_cast<value_type>(1 - static_cast<value_type>(q)),
  207. static_cast<value_type>(q),
  208. false, pol),
  209. function);
  210. }
  211. template <class RT1, class RT2, class RT3, class Policy>
  212. typename tools::promote_args<RT1, RT2, RT3>::type
  213. ibeta_invb(RT1 a, RT2 x, RT3 p, const Policy& pol)
  214. {
  215. typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
  216. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  217. typedef typename policies::normalise<
  218. Policy,
  219. policies::promote_float<false>,
  220. policies::promote_double<false>,
  221. policies::discrete_quantile<>,
  222. policies::assert_undefined<> >::type forwarding_policy;
  223. static const char* function = "boost::math::ibeta_invb<%1%>(%1%,%1%,%1%)";
  224. if(p == 0)
  225. {
  226. return tools::min_value<result_type>();
  227. }
  228. if(p == 1)
  229. {
  230. return policies::raise_overflow_error<result_type>(function, 0, Policy());
  231. }
  232. return policies::checked_narrowing_cast<result_type, forwarding_policy>(
  233. detail::ibeta_inv_ab_imp(
  234. static_cast<value_type>(a),
  235. static_cast<value_type>(x),
  236. static_cast<value_type>(p),
  237. static_cast<value_type>(1 - static_cast<value_type>(p)),
  238. true, pol),
  239. function);
  240. }
  241. template <class RT1, class RT2, class RT3, class Policy>
  242. typename tools::promote_args<RT1, RT2, RT3>::type
  243. ibetac_invb(RT1 a, RT2 x, RT3 q, const Policy& pol)
  244. {
  245. static const char* function = "boost::math::ibeta_invb<%1%>(%1%, %1%, %1%)";
  246. typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
  247. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  248. typedef typename policies::normalise<
  249. Policy,
  250. policies::promote_float<false>,
  251. policies::promote_double<false>,
  252. policies::discrete_quantile<>,
  253. policies::assert_undefined<> >::type forwarding_policy;
  254. if(q == 1)
  255. {
  256. return tools::min_value<result_type>();
  257. }
  258. if(q == 0)
  259. {
  260. return policies::raise_overflow_error<result_type>(function, 0, Policy());
  261. }
  262. return policies::checked_narrowing_cast<result_type, forwarding_policy>(
  263. detail::ibeta_inv_ab_imp(
  264. static_cast<value_type>(a),
  265. static_cast<value_type>(x),
  266. static_cast<value_type>(1 - static_cast<value_type>(q)),
  267. static_cast<value_type>(q),
  268. true, pol),
  269. function);
  270. }
  271. template <class RT1, class RT2, class RT3>
  272. inline typename tools::promote_args<RT1, RT2, RT3>::type
  273. ibeta_inva(RT1 b, RT2 x, RT3 p)
  274. {
  275. return boost::math::ibeta_inva(b, x, p, policies::policy<>());
  276. }
  277. template <class RT1, class RT2, class RT3>
  278. inline typename tools::promote_args<RT1, RT2, RT3>::type
  279. ibetac_inva(RT1 b, RT2 x, RT3 q)
  280. {
  281. return boost::math::ibetac_inva(b, x, q, policies::policy<>());
  282. }
  283. template <class RT1, class RT2, class RT3>
  284. inline typename tools::promote_args<RT1, RT2, RT3>::type
  285. ibeta_invb(RT1 a, RT2 x, RT3 p)
  286. {
  287. return boost::math::ibeta_invb(a, x, p, policies::policy<>());
  288. }
  289. template <class RT1, class RT2, class RT3>
  290. inline typename tools::promote_args<RT1, RT2, RT3>::type
  291. ibetac_invb(RT1 a, RT2 x, RT3 q)
  292. {
  293. return boost::math::ibetac_invb(a, x, q, policies::policy<>());
  294. }
  295. } // namespace math
  296. } // namespace boost
  297. #endif // BOOST_MATH_SP_DETAIL_BETA_INV_AB