150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // 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()); | ||
|  |    } | ||
|  |    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); | ||
|  | 
 | ||
|  |    boost::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:" | ||
|  |          " either there is no answer to the mode of the distribution" | ||
|  |          " or the answer is infinite.  Current best guess is %1%", result, policy_type()); | ||
|  |    } | ||
|  |    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); | ||
|  | 
 | ||
|  |    boost::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:" | ||
|  |          " either there is no answer to the mode of the distribution" | ||
|  |          " or the answer is infinite.  Current best guess is %1%", result, policy_type()); | ||
|  |    } | ||
|  |    return result; | ||
|  | } | ||
|  | 
 | ||
|  | }}} // namespaces | ||
|  | 
 | ||
|  | #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP |