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