123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- // Copyright John Maddock 2008.
- // Use, modification and distribution are subject to the
- // Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt
- // or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
- #define BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
- #include <boost/math/tools/minima.hpp> // function minimization for mode
- #include <boost/math/policies/error_handling.hpp>
- #include <boost/math/distributions/fwd.hpp>
- namespace boost{ namespace math{ namespace detail{
- template <class Dist>
- struct pdf_minimizer
- {
- pdf_minimizer(const Dist& d)
- : dist(d) {}
- typename Dist::value_type operator()(const typename Dist::value_type& x)
- {
- return -pdf(dist, x);
- }
- private:
- Dist dist;
- };
- template <class Dist>
- typename Dist::value_type generic_find_mode(const Dist& dist, typename Dist::value_type guess, const char* function, typename Dist::value_type step = 0)
- {
- BOOST_MATH_STD_USING
- typedef typename Dist::value_type value_type;
- typedef typename Dist::policy_type policy_type;
- //
- // Need to begin by bracketing the maxima of the PDF:
- //
- value_type maxval;
- value_type upper_bound = guess;
- value_type lower_bound;
- value_type v = pdf(dist, guess);
- if(v == 0)
- {
- //
- // Oops we don't know how to handle this, or even in which
- // direction we should move in, treat as an evaluation error:
- //
- 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
- }
- do
- {
- maxval = v;
- if(step != 0)
- upper_bound += step;
- else
- upper_bound *= 2;
- v = pdf(dist, upper_bound);
- }while(maxval < v);
- lower_bound = upper_bound;
- do
- {
- maxval = v;
- if(step != 0)
- lower_bound -= step;
- else
- lower_bound /= 2;
- v = pdf(dist, lower_bound);
- }while(maxval < v);
- std::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
- value_type result = tools::brent_find_minima(
- pdf_minimizer<Dist>(dist),
- lower_bound,
- upper_bound,
- policies::digits<value_type, policy_type>(),
- max_iter).first;
- if(max_iter >= policies::get_max_root_iterations<policy_type>())
- {
- return policies::raise_evaluation_error<value_type>(function, // LCOV_EXCL_LINE
- "Unable to locate solution in a reasonable time: either there is no answer to the mode of the distribution" // LCOV_EXCL_LINE
- " or the answer is infinite. Current best guess is %1%", result, policy_type()); // LCOV_EXCL_LINE
- }
- return result;
- }
- //
- // As above,but confined to the interval [0,1]:
- //
- template <class Dist>
- typename Dist::value_type generic_find_mode_01(const Dist& dist, typename Dist::value_type guess, const char* function)
- {
- BOOST_MATH_STD_USING
- typedef typename Dist::value_type value_type;
- typedef typename Dist::policy_type policy_type;
- //
- // Need to begin by bracketing the maxima of the PDF:
- //
- value_type maxval;
- value_type upper_bound = guess;
- value_type lower_bound;
- value_type v = pdf(dist, guess);
- do
- {
- maxval = v;
- upper_bound = 1 - (1 - upper_bound) / 2;
- if(upper_bound == 1)
- return 1;
- v = pdf(dist, upper_bound);
- }while(maxval < v);
- lower_bound = upper_bound;
- do
- {
- maxval = v;
- lower_bound /= 2;
- if(lower_bound < tools::min_value<value_type>())
- return 0;
- v = pdf(dist, lower_bound);
- }while(maxval < v);
- std::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
- value_type result = tools::brent_find_minima(
- pdf_minimizer<Dist>(dist),
- lower_bound,
- upper_bound,
- policies::digits<value_type, policy_type>(),
- max_iter).first;
- if(max_iter >= policies::get_max_root_iterations<policy_type>())
- {
- return policies::raise_evaluation_error<value_type>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
- " 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
- }
- return result;
- }
- }}} // namespaces
- #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
|