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