inv_discrete_quantile.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // Copyright John Maddock 2007.
  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. #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
  6. #define BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
  7. #include <algorithm>
  8. namespace boost{ namespace math{ namespace detail{
  9. //
  10. // Functor for root finding algorithm:
  11. //
  12. template <class Dist>
  13. struct distribution_quantile_finder
  14. {
  15. typedef typename Dist::value_type value_type;
  16. typedef typename Dist::policy_type policy_type;
  17. distribution_quantile_finder(const Dist d, value_type p, bool c)
  18. : dist(d), target(p), comp(c) {}
  19. value_type operator()(value_type const& x)
  20. {
  21. return comp ? value_type(target - cdf(complement(dist, x))) : value_type(cdf(dist, x) - target);
  22. }
  23. private:
  24. Dist dist;
  25. value_type target;
  26. bool comp;
  27. };
  28. //
  29. // The purpose of adjust_bounds, is to toggle the last bit of the
  30. // range so that both ends round to the same integer, if possible.
  31. // If they do both round the same then we terminate the search
  32. // for the root *very* quickly when finding an integer result.
  33. // At the point that this function is called we know that "a" is
  34. // below the root and "b" above it, so this change can not result
  35. // in the root no longer being bracketed.
  36. //
  37. template <class Real, class Tol>
  38. void adjust_bounds(Real& /* a */, Real& /* b */, Tol const& /* tol */){}
  39. template <class Real>
  40. void adjust_bounds(Real& /* a */, Real& b, tools::equal_floor const& /* tol */)
  41. {
  42. BOOST_MATH_STD_USING
  43. b -= tools::epsilon<Real>() * b;
  44. }
  45. template <class Real>
  46. void adjust_bounds(Real& a, Real& /* b */, tools::equal_ceil const& /* tol */)
  47. {
  48. BOOST_MATH_STD_USING
  49. a += tools::epsilon<Real>() * a;
  50. }
  51. template <class Real>
  52. void adjust_bounds(Real& a, Real& b, tools::equal_nearest_integer const& /* tol */)
  53. {
  54. BOOST_MATH_STD_USING
  55. a += tools::epsilon<Real>() * a;
  56. b -= tools::epsilon<Real>() * b;
  57. }
  58. //
  59. // This is where all the work is done:
  60. //
  61. template <class Dist, class Tolerance>
  62. typename Dist::value_type
  63. do_inverse_discrete_quantile(
  64. const Dist& dist,
  65. const typename Dist::value_type& p,
  66. bool comp,
  67. typename Dist::value_type guess,
  68. const typename Dist::value_type& multiplier,
  69. typename Dist::value_type adder,
  70. const Tolerance& tol,
  71. boost::uintmax_t& max_iter)
  72. {
  73. typedef typename Dist::value_type value_type;
  74. typedef typename Dist::policy_type policy_type;
  75. static const char* function = "boost::math::do_inverse_discrete_quantile<%1%>";
  76. BOOST_MATH_STD_USING
  77. distribution_quantile_finder<Dist> f(dist, p, comp);
  78. //
  79. // Max bounds of the distribution:
  80. //
  81. value_type min_bound, max_bound;
  82. boost::math::tie(min_bound, max_bound) = support(dist);
  83. if(guess > max_bound)
  84. guess = max_bound;
  85. if(guess < min_bound)
  86. guess = min_bound;
  87. value_type fa = f(guess);
  88. boost::uintmax_t count = max_iter - 1;
  89. value_type fb(fa), a(guess), b =0; // Compiler warning C4701: potentially uninitialized local variable 'b' used
  90. if(fa == 0)
  91. return guess;
  92. //
  93. // For small expected results, just use a linear search:
  94. //
  95. if(guess < 10)
  96. {
  97. b = a;
  98. while((a < 10) && (fa * fb >= 0))
  99. {
  100. if(fb <= 0)
  101. {
  102. a = b;
  103. b = a + 1;
  104. if(b > max_bound)
  105. b = max_bound;
  106. fb = f(b);
  107. --count;
  108. if(fb == 0)
  109. return b;
  110. if(a == b)
  111. return b; // can't go any higher!
  112. }
  113. else
  114. {
  115. b = a;
  116. a = (std::max)(value_type(b - 1), value_type(0));
  117. if(a < min_bound)
  118. a = min_bound;
  119. fa = f(a);
  120. --count;
  121. if(fa == 0)
  122. return a;
  123. if(a == b)
  124. return a; // We can't go any lower than this!
  125. }
  126. }
  127. }
  128. //
  129. // Try and bracket using a couple of additions first,
  130. // we're assuming that "guess" is likely to be accurate
  131. // to the nearest int or so:
  132. //
  133. else if(adder != 0)
  134. {
  135. //
  136. // If we're looking for a large result, then bump "adder" up
  137. // by a bit to increase our chances of bracketing the root:
  138. //
  139. //adder = (std::max)(adder, 0.001f * guess);
  140. if(fa < 0)
  141. {
  142. b = a + adder;
  143. if(b > max_bound)
  144. b = max_bound;
  145. }
  146. else
  147. {
  148. b = (std::max)(value_type(a - adder), value_type(0));
  149. if(b < min_bound)
  150. b = min_bound;
  151. }
  152. fb = f(b);
  153. --count;
  154. if(fb == 0)
  155. return b;
  156. if(count && (fa * fb >= 0))
  157. {
  158. //
  159. // We didn't bracket the root, try
  160. // once more:
  161. //
  162. a = b;
  163. fa = fb;
  164. if(fa < 0)
  165. {
  166. b = a + adder;
  167. if(b > max_bound)
  168. b = max_bound;
  169. }
  170. else
  171. {
  172. b = (std::max)(value_type(a - adder), value_type(0));
  173. if(b < min_bound)
  174. b = min_bound;
  175. }
  176. fb = f(b);
  177. --count;
  178. }
  179. if(a > b)
  180. {
  181. using std::swap;
  182. swap(a, b);
  183. swap(fa, fb);
  184. }
  185. }
  186. //
  187. // If the root hasn't been bracketed yet, try again
  188. // using the multiplier this time:
  189. //
  190. if((boost::math::sign)(fb) == (boost::math::sign)(fa))
  191. {
  192. if(fa < 0)
  193. {
  194. //
  195. // Zero is to the right of x2, so walk upwards
  196. // until we find it:
  197. //
  198. while(((boost::math::sign)(fb) == (boost::math::sign)(fa)) && (a != b))
  199. {
  200. if(count == 0)
  201. return policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, policy_type());
  202. a = b;
  203. fa = fb;
  204. b *= multiplier;
  205. if(b > max_bound)
  206. b = max_bound;
  207. fb = f(b);
  208. --count;
  209. BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
  210. }
  211. }
  212. else
  213. {
  214. //
  215. // Zero is to the left of a, so walk downwards
  216. // until we find it:
  217. //
  218. while(((boost::math::sign)(fb) == (boost::math::sign)(fa)) && (a != b))
  219. {
  220. if(fabs(a) < tools::min_value<value_type>())
  221. {
  222. // Escape route just in case the answer is zero!
  223. max_iter -= count;
  224. max_iter += 1;
  225. return 0;
  226. }
  227. if(count == 0)
  228. return policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, policy_type());
  229. b = a;
  230. fb = fa;
  231. a /= multiplier;
  232. if(a < min_bound)
  233. a = min_bound;
  234. fa = f(a);
  235. --count;
  236. BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
  237. }
  238. }
  239. }
  240. max_iter -= count;
  241. if(fa == 0)
  242. return a;
  243. if(fb == 0)
  244. return b;
  245. if(a == b)
  246. return b; // Ran out of bounds trying to bracket - there is no answer!
  247. //
  248. // Adjust bounds so that if we're looking for an integer
  249. // result, then both ends round the same way:
  250. //
  251. adjust_bounds(a, b, tol);
  252. //
  253. // We don't want zero or denorm lower bounds:
  254. //
  255. if(a < tools::min_value<value_type>())
  256. a = tools::min_value<value_type>();
  257. //
  258. // Go ahead and find the root:
  259. //
  260. std::pair<value_type, value_type> r = toms748_solve(f, a, b, fa, fb, tol, count, policy_type());
  261. max_iter += count;
  262. BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
  263. return (r.first + r.second) / 2;
  264. }
  265. //
  266. // Some special routine for rounding up and down:
  267. // We want to check and see if we are very close to an integer, and if so test to see if
  268. // that integer is an exact root of the cdf. We do this because our root finder only
  269. // guarantees to find *a root*, and there can sometimes be many consecutive floating
  270. // point values which are all roots. This is especially true if the target probability
  271. // is very close 1.
  272. //
  273. template <class Dist>
  274. inline typename Dist::value_type round_to_floor(const Dist& d, typename Dist::value_type result, typename Dist::value_type p, bool c)
  275. {
  276. BOOST_MATH_STD_USING
  277. typename Dist::value_type cc = ceil(result);
  278. typename Dist::value_type pp = cc <= support(d).second ? c ? cdf(complement(d, cc)) : cdf(d, cc) : 1;
  279. if(pp == p)
  280. result = cc;
  281. else
  282. result = floor(result);
  283. //
  284. // Now find the smallest integer <= result for which we get an exact root:
  285. //
  286. while(result != 0)
  287. {
  288. cc = result - 1;
  289. if(cc < support(d).first)
  290. break;
  291. pp = c ? cdf(complement(d, cc)) : cdf(d, cc);
  292. if(pp == p)
  293. result = cc;
  294. else if(c ? pp > p : pp < p)
  295. break;
  296. result -= 1;
  297. }
  298. return result;
  299. }
  300. #ifdef BOOST_MSVC
  301. #pragma warning(push)
  302. #pragma warning(disable:4127)
  303. #endif
  304. template <class Dist>
  305. inline typename Dist::value_type round_to_ceil(const Dist& d, typename Dist::value_type result, typename Dist::value_type p, bool c)
  306. {
  307. BOOST_MATH_STD_USING
  308. typename Dist::value_type cc = floor(result);
  309. typename Dist::value_type pp = cc >= support(d).first ? c ? cdf(complement(d, cc)) : cdf(d, cc) : 0;
  310. if(pp == p)
  311. result = cc;
  312. else
  313. result = ceil(result);
  314. //
  315. // Now find the largest integer >= result for which we get an exact root:
  316. //
  317. while(true)
  318. {
  319. cc = result + 1;
  320. if(cc > support(d).second)
  321. break;
  322. pp = c ? cdf(complement(d, cc)) : cdf(d, cc);
  323. if(pp == p)
  324. result = cc;
  325. else if(c ? pp < p : pp > p)
  326. break;
  327. result += 1;
  328. }
  329. return result;
  330. }
  331. #ifdef BOOST_MSVC
  332. #pragma warning(pop)
  333. #endif
  334. //
  335. // Now finally are the public API functions.
  336. // There is one overload for each policy,
  337. // each one is responsible for selecting the correct
  338. // termination condition, and rounding the result
  339. // to an int where required.
  340. //
  341. template <class Dist>
  342. inline typename Dist::value_type
  343. inverse_discrete_quantile(
  344. const Dist& dist,
  345. typename Dist::value_type p,
  346. bool c,
  347. const typename Dist::value_type& guess,
  348. const typename Dist::value_type& multiplier,
  349. const typename Dist::value_type& adder,
  350. const policies::discrete_quantile<policies::real>&,
  351. boost::uintmax_t& max_iter)
  352. {
  353. if(p > 0.5)
  354. {
  355. p = 1 - p;
  356. c = !c;
  357. }
  358. typename Dist::value_type pp = c ? 1 - p : p;
  359. if(pp <= pdf(dist, 0))
  360. return 0;
  361. return do_inverse_discrete_quantile(
  362. dist,
  363. p,
  364. c,
  365. guess,
  366. multiplier,
  367. adder,
  368. tools::eps_tolerance<typename Dist::value_type>(policies::digits<typename Dist::value_type, typename Dist::policy_type>()),
  369. max_iter);
  370. }
  371. template <class Dist>
  372. inline typename Dist::value_type
  373. inverse_discrete_quantile(
  374. const Dist& dist,
  375. const typename Dist::value_type& p,
  376. bool c,
  377. const typename Dist::value_type& guess,
  378. const typename Dist::value_type& multiplier,
  379. const typename Dist::value_type& adder,
  380. const policies::discrete_quantile<policies::integer_round_outwards>&,
  381. boost::uintmax_t& max_iter)
  382. {
  383. typedef typename Dist::value_type value_type;
  384. BOOST_MATH_STD_USING
  385. typename Dist::value_type pp = c ? 1 - p : p;
  386. if(pp <= pdf(dist, 0))
  387. return 0;
  388. //
  389. // What happens next depends on whether we're looking for an
  390. // upper or lower quantile:
  391. //
  392. if(pp < 0.5f)
  393. return round_to_floor(dist, do_inverse_discrete_quantile(
  394. dist,
  395. p,
  396. c,
  397. (guess < 1 ? value_type(1) : (value_type)floor(guess)),
  398. multiplier,
  399. adder,
  400. tools::equal_floor(),
  401. max_iter), p, c);
  402. // else:
  403. return round_to_ceil(dist, do_inverse_discrete_quantile(
  404. dist,
  405. p,
  406. c,
  407. (value_type)ceil(guess),
  408. multiplier,
  409. adder,
  410. tools::equal_ceil(),
  411. max_iter), p, c);
  412. }
  413. template <class Dist>
  414. inline typename Dist::value_type
  415. inverse_discrete_quantile(
  416. const Dist& dist,
  417. const typename Dist::value_type& p,
  418. bool c,
  419. const typename Dist::value_type& guess,
  420. const typename Dist::value_type& multiplier,
  421. const typename Dist::value_type& adder,
  422. const policies::discrete_quantile<policies::integer_round_inwards>&,
  423. boost::uintmax_t& max_iter)
  424. {
  425. typedef typename Dist::value_type value_type;
  426. BOOST_MATH_STD_USING
  427. typename Dist::value_type pp = c ? 1 - p : p;
  428. if(pp <= pdf(dist, 0))
  429. return 0;
  430. //
  431. // What happens next depends on whether we're looking for an
  432. // upper or lower quantile:
  433. //
  434. if(pp < 0.5f)
  435. return round_to_ceil(dist, do_inverse_discrete_quantile(
  436. dist,
  437. p,
  438. c,
  439. ceil(guess),
  440. multiplier,
  441. adder,
  442. tools::equal_ceil(),
  443. max_iter), p, c);
  444. // else:
  445. return round_to_floor(dist, do_inverse_discrete_quantile(
  446. dist,
  447. p,
  448. c,
  449. (guess < 1 ? value_type(1) : floor(guess)),
  450. multiplier,
  451. adder,
  452. tools::equal_floor(),
  453. max_iter), p, c);
  454. }
  455. template <class Dist>
  456. inline typename Dist::value_type
  457. inverse_discrete_quantile(
  458. const Dist& dist,
  459. const typename Dist::value_type& p,
  460. bool c,
  461. const typename Dist::value_type& guess,
  462. const typename Dist::value_type& multiplier,
  463. const typename Dist::value_type& adder,
  464. const policies::discrete_quantile<policies::integer_round_down>&,
  465. boost::uintmax_t& max_iter)
  466. {
  467. typedef typename Dist::value_type value_type;
  468. BOOST_MATH_STD_USING
  469. typename Dist::value_type pp = c ? 1 - p : p;
  470. if(pp <= pdf(dist, 0))
  471. return 0;
  472. return round_to_floor(dist, do_inverse_discrete_quantile(
  473. dist,
  474. p,
  475. c,
  476. (guess < 1 ? value_type(1) : floor(guess)),
  477. multiplier,
  478. adder,
  479. tools::equal_floor(),
  480. max_iter), p, c);
  481. }
  482. template <class Dist>
  483. inline typename Dist::value_type
  484. inverse_discrete_quantile(
  485. const Dist& dist,
  486. const typename Dist::value_type& p,
  487. bool c,
  488. const typename Dist::value_type& guess,
  489. const typename Dist::value_type& multiplier,
  490. const typename Dist::value_type& adder,
  491. const policies::discrete_quantile<policies::integer_round_up>&,
  492. boost::uintmax_t& max_iter)
  493. {
  494. BOOST_MATH_STD_USING
  495. typename Dist::value_type pp = c ? 1 - p : p;
  496. if(pp <= pdf(dist, 0))
  497. return 0;
  498. return round_to_ceil(dist, do_inverse_discrete_quantile(
  499. dist,
  500. p,
  501. c,
  502. ceil(guess),
  503. multiplier,
  504. adder,
  505. tools::equal_ceil(),
  506. max_iter), p, c);
  507. }
  508. template <class Dist>
  509. inline typename Dist::value_type
  510. inverse_discrete_quantile(
  511. const Dist& dist,
  512. const typename Dist::value_type& p,
  513. bool c,
  514. const typename Dist::value_type& guess,
  515. const typename Dist::value_type& multiplier,
  516. const typename Dist::value_type& adder,
  517. const policies::discrete_quantile<policies::integer_round_nearest>&,
  518. boost::uintmax_t& max_iter)
  519. {
  520. typedef typename Dist::value_type value_type;
  521. BOOST_MATH_STD_USING
  522. typename Dist::value_type pp = c ? 1 - p : p;
  523. if(pp <= pdf(dist, 0))
  524. return 0;
  525. //
  526. // Note that we adjust the guess to the nearest half-integer:
  527. // this increase the chances that we will bracket the root
  528. // with two results that both round to the same integer quickly.
  529. //
  530. return round_to_floor(dist, do_inverse_discrete_quantile(
  531. dist,
  532. p,
  533. c,
  534. (guess < 0.5f ? value_type(1.5f) : floor(guess + 0.5f) + 0.5f),
  535. multiplier,
  536. adder,
  537. tools::equal_nearest_integer(),
  538. max_iter) + 0.5f, p, c);
  539. }
  540. }}} // namespaces
  541. #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE