File indexing completed on 2025-12-16 09:54:38
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
0009 #define BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
0010
0011 #include <boost/math/tools/config.hpp>
0012 #include <boost/math/tools/cstdint.hpp>
0013 #include <boost/math/tools/minima.hpp> // function minimization for mode
0014 #include <boost/math/policies/error_handling.hpp>
0015 #include <boost/math/distributions/fwd.hpp>
0016 #include <boost/math/policies/policy.hpp>
0017
0018 namespace boost{ namespace math{ namespace detail{
0019
0020 template <class Dist>
0021 struct pdf_minimizer
0022 {
0023 BOOST_MATH_GPU_ENABLED pdf_minimizer(const Dist& d)
0024 : dist(d) {}
0025
0026 BOOST_MATH_GPU_ENABLED typename Dist::value_type operator()(const typename Dist::value_type& x)
0027 {
0028 return -pdf(dist, x);
0029 }
0030 private:
0031 Dist dist;
0032 };
0033
0034 template <class Dist>
0035 BOOST_MATH_GPU_ENABLED typename Dist::value_type generic_find_mode(const Dist& dist, typename Dist::value_type guess, const char* function, typename Dist::value_type step = 0)
0036 {
0037 BOOST_MATH_STD_USING
0038 typedef typename Dist::value_type value_type;
0039 typedef typename Dist::policy_type policy_type;
0040
0041
0042
0043 value_type maxval;
0044 value_type upper_bound = guess;
0045 value_type lower_bound;
0046 value_type v = pdf(dist, guess);
0047 if(v == 0)
0048 {
0049
0050
0051
0052
0053 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());
0054 }
0055 do
0056 {
0057 maxval = v;
0058 if(step != 0)
0059 upper_bound += step;
0060 else
0061 upper_bound *= 2;
0062 v = pdf(dist, upper_bound);
0063 }while(maxval < v);
0064
0065 lower_bound = upper_bound;
0066 do
0067 {
0068 maxval = v;
0069 if(step != 0)
0070 lower_bound -= step;
0071 else
0072 lower_bound /= 2;
0073 v = pdf(dist, lower_bound);
0074 }while(maxval < v);
0075
0076 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
0077
0078 value_type result = tools::brent_find_minima(
0079 pdf_minimizer<Dist>(dist),
0080 lower_bound,
0081 upper_bound,
0082 policies::digits<value_type, policy_type>(),
0083 max_iter).first;
0084 if(max_iter >= policies::get_max_root_iterations<policy_type>())
0085 {
0086 return policies::raise_evaluation_error<value_type>(function,
0087 "Unable to locate solution in a reasonable time: either there is no answer to the mode of the distribution"
0088 " or the answer is infinite. Current best guess is %1%", result, policy_type());
0089 }
0090 return result;
0091 }
0092
0093
0094
0095 template <class Dist>
0096 BOOST_MATH_GPU_ENABLED typename Dist::value_type generic_find_mode_01(const Dist& dist, typename Dist::value_type guess, const char* function)
0097 {
0098 BOOST_MATH_STD_USING
0099 typedef typename Dist::value_type value_type;
0100 typedef typename Dist::policy_type policy_type;
0101
0102
0103
0104 value_type maxval;
0105 value_type upper_bound = guess;
0106 value_type lower_bound;
0107 value_type v = pdf(dist, guess);
0108 do
0109 {
0110 maxval = v;
0111 upper_bound = 1 - (1 - upper_bound) / 2;
0112 if(upper_bound == 1)
0113 return 1;
0114 v = pdf(dist, upper_bound);
0115 }while(maxval < v);
0116
0117 lower_bound = upper_bound;
0118 do
0119 {
0120 maxval = v;
0121 lower_bound /= 2;
0122 if(lower_bound < tools::min_value<value_type>())
0123 return 0;
0124 v = pdf(dist, lower_bound);
0125 }while(maxval < v);
0126
0127 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
0128
0129 value_type result = tools::brent_find_minima(
0130 pdf_minimizer<Dist>(dist),
0131 lower_bound,
0132 upper_bound,
0133 policies::digits<value_type, policy_type>(),
0134 max_iter).first;
0135 if(max_iter >= policies::get_max_root_iterations<policy_type>())
0136 {
0137 return policies::raise_evaluation_error<value_type>(function, "Unable to locate solution in a reasonable time:"
0138 " either there is no answer to the mode of the distribution or the answer is infinite. Current best guess is %1%", result, policy_type());
0139 }
0140 return result;
0141 }
0142
0143 }}}
0144
0145 #endif