generic_mode.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright John Maddock 2008.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
  7. #define BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
  8. #include <boost/math/tools/minima.hpp> // function minimization for mode
  9. #include <boost/math/policies/error_handling.hpp>
  10. #include <boost/math/distributions/fwd.hpp>
  11. namespace boost{ namespace math{ namespace detail{
  12. template <class Dist>
  13. struct pdf_minimizer
  14. {
  15. pdf_minimizer(const Dist& d)
  16. : dist(d) {}
  17. typename Dist::value_type operator()(const typename Dist::value_type& x)
  18. {
  19. return -pdf(dist, x);
  20. }
  21. private:
  22. Dist dist;
  23. };
  24. template <class Dist>
  25. typename Dist::value_type generic_find_mode(const Dist& dist, typename Dist::value_type guess, const char* function, typename Dist::value_type step = 0)
  26. {
  27. BOOST_MATH_STD_USING
  28. typedef typename Dist::value_type value_type;
  29. typedef typename Dist::policy_type policy_type;
  30. //
  31. // Need to begin by bracketing the maxima of the PDF:
  32. //
  33. value_type maxval;
  34. value_type upper_bound = guess;
  35. value_type lower_bound;
  36. value_type v = pdf(dist, guess);
  37. if(v == 0)
  38. {
  39. //
  40. // Oops we don't know how to handle this, or even in which
  41. // direction we should move in, treat as an evaluation error:
  42. //
  43. return policies::raise_evaluation_error(function, "Could not locate a starting location for the search for the mode, original guess was %1%", guess, policy_type()); // LCOV_EXCL_LINE
  44. }
  45. do
  46. {
  47. maxval = v;
  48. if(step != 0)
  49. upper_bound += step;
  50. else
  51. upper_bound *= 2;
  52. v = pdf(dist, upper_bound);
  53. }while(maxval < v);
  54. lower_bound = upper_bound;
  55. do
  56. {
  57. maxval = v;
  58. if(step != 0)
  59. lower_bound -= step;
  60. else
  61. lower_bound /= 2;
  62. v = pdf(dist, lower_bound);
  63. }while(maxval < v);
  64. std::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
  65. value_type result = tools::brent_find_minima(
  66. pdf_minimizer<Dist>(dist),
  67. lower_bound,
  68. upper_bound,
  69. policies::digits<value_type, policy_type>(),
  70. max_iter).first;
  71. if(max_iter >= policies::get_max_root_iterations<policy_type>())
  72. {
  73. return policies::raise_evaluation_error<value_type>(function, // LCOV_EXCL_LINE
  74. "Unable to locate solution in a reasonable time: either there is no answer to the mode of the distribution" // LCOV_EXCL_LINE
  75. " or the answer is infinite. Current best guess is %1%", result, policy_type()); // LCOV_EXCL_LINE
  76. }
  77. return result;
  78. }
  79. //
  80. // As above,but confined to the interval [0,1]:
  81. //
  82. template <class Dist>
  83. typename Dist::value_type generic_find_mode_01(const Dist& dist, typename Dist::value_type guess, const char* function)
  84. {
  85. BOOST_MATH_STD_USING
  86. typedef typename Dist::value_type value_type;
  87. typedef typename Dist::policy_type policy_type;
  88. //
  89. // Need to begin by bracketing the maxima of the PDF:
  90. //
  91. value_type maxval;
  92. value_type upper_bound = guess;
  93. value_type lower_bound;
  94. value_type v = pdf(dist, guess);
  95. do
  96. {
  97. maxval = v;
  98. upper_bound = 1 - (1 - upper_bound) / 2;
  99. if(upper_bound == 1)
  100. return 1;
  101. v = pdf(dist, upper_bound);
  102. }while(maxval < v);
  103. lower_bound = upper_bound;
  104. do
  105. {
  106. maxval = v;
  107. lower_bound /= 2;
  108. if(lower_bound < tools::min_value<value_type>())
  109. return 0;
  110. v = pdf(dist, lower_bound);
  111. }while(maxval < v);
  112. std::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
  113. value_type result = tools::brent_find_minima(
  114. pdf_minimizer<Dist>(dist),
  115. lower_bound,
  116. upper_bound,
  117. policies::digits<value_type, policy_type>(),
  118. max_iter).first;
  119. if(max_iter >= policies::get_max_root_iterations<policy_type>())
  120. {
  121. return policies::raise_evaluation_error<value_type>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
  122. " either there is no answer to the mode of the distribution or the answer is infinite. Current best guess is %1%", result, policy_type()); // LCOV_EXCL_LINE
  123. }
  124. return result;
  125. }
  126. }}} // namespaces
  127. #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP