1 //  Copyright John Maddock 2007.
2 //  Copyright Paul A. Bristow 2007.
3 
4 //  Use, modification and distribution are subject to the
5 //  Boost Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_STATS_FIND_LOCATION_HPP
9 #define BOOST_STATS_FIND_LOCATION_HPP
10 
11 #include <boost/math/distributions/fwd.hpp> // for all distribution signatures.
12 #include <boost/math/distributions/complement.hpp>
13 #include <boost/math/policies/policy.hpp>
14 #include <boost/math/tools/traits.hpp>
15 #include <boost/static_assert.hpp>
16 #include <boost/math/special_functions/fpclassify.hpp>
17 #include <boost/math/policies/error_handling.hpp>
18 // using boost::math::policies::policy;
19 // using boost::math::complement; // will be needed by users who want complement,
20 // but NOT placed here to avoid putting it in global scope.
21 
22 namespace boost
23 {
24   namespace math
25   {
26   // Function to find location of random variable z
27   // to give probability p (given scale)
28   // Applies to normal, lognormal, extreme value, Cauchy, (and symmetrical triangular),
29   // enforced by BOOST_STATIC_ASSERT below.
30 
31     template <class Dist, class Policy>
32     inline
find_location(typename Dist::value_type z,typename Dist::value_type p,typename Dist::value_type scale,const Policy & pol)33       typename Dist::value_type find_location( // For example, normal mean.
34       typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
35       // For example, a nominal minimum acceptable z, so that p * 100 % are > z
36       typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
37       typename Dist::value_type scale, // scale parameter, for example, normal standard deviation.
38       const Policy& pol
39       )
40     {
41 #if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
42       // Will fail to compile here if try to use with a distribution without scale & location,
43       // for example pareto, and many others.  These tests are disabled by the pp-logic
44       // above if the compiler doesn't support the SFINAE tricks used in the traits class.
45       BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<Dist>::value);
46       BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<Dist>::value);
47 #endif
48       static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
49 
50       if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
51       {
52        return policies::raise_domain_error<typename Dist::value_type>(
53            function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, pol);
54       }
55       if(!(boost::math::isfinite)(z))
56       {
57        return policies::raise_domain_error<typename Dist::value_type>(
58            function, "z parameter was %1%, but must be finite!", z, pol);
59       }
60       if(!(boost::math::isfinite)(scale))
61       {
62        return policies::raise_domain_error<typename Dist::value_type>(
63            function, "scale parameter was %1%, but must be finite!", scale, pol);
64       }
65 
66       //cout << "z " << z << ", p " << p << ",  quantile(Dist(), p) "
67       //  << quantile(Dist(), p) << ", quan * scale " << quantile(Dist(), p) * scale << endl;
68       return z - (quantile(Dist(), p) * scale);
69     } // find_location
70 
71     template <class Dist>
72     inline // with default policy.
find_location(typename Dist::value_type z,typename Dist::value_type p,typename Dist::value_type scale)73       typename Dist::value_type find_location( // For example, normal mean.
74       typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
75       // For example, a nominal minimum acceptable z, so that p * 100 % are > z
76       typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
77       typename Dist::value_type scale) // scale parameter, for example, normal standard deviation.
78     { // Forward to find_location with default policy.
79        return (find_location<Dist>(z, p, scale, policies::policy<>()));
80     } // find_location
81 
82     // So the user can start from the complement q = (1 - p) of the probability p,
83     // for example, l = find_location<normal>(complement(z, q, sd));
84 
85     template <class Dist, class Real1, class Real2, class Real3>
find_location(complemented3_type<Real1,Real2,Real3> const & c)86     inline typename Dist::value_type find_location( // Default policy.
87       complemented3_type<Real1, Real2, Real3> const& c)
88     {
89       static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
90 
91       typename Dist::value_type p = c.param1;
92       if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
93       {
94        return policies::raise_domain_error<typename Dist::value_type>(
95            function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, policies::policy<>());
96       }
97       typename Dist::value_type z = c.dist;
98       if(!(boost::math::isfinite)(z))
99       {
100        return policies::raise_domain_error<typename Dist::value_type>(
101            function, "z parameter was %1%, but must be finite!", z, policies::policy<>());
102       }
103       typename Dist::value_type scale = c.param2;
104       if(!(boost::math::isfinite)(scale))
105       {
106        return policies::raise_domain_error<typename Dist::value_type>(
107            function, "scale parameter was %1%, but must be finite!", scale, policies::policy<>());
108       }
109        // cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
110        return z - quantile(Dist(), p) * scale;
111     } // find_location complement
112 
113 
114     template <class Dist, class Real1, class Real2, class Real3, class Real4>
find_location(complemented4_type<Real1,Real2,Real3,Real4> const & c)115     inline typename Dist::value_type find_location( // Explicit policy.
116       complemented4_type<Real1, Real2, Real3, Real4> const& c)
117     {
118       static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
119 
120       typename Dist::value_type p = c.param1;
121       if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
122       {
123        return policies::raise_domain_error<typename Dist::value_type>(
124            function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, c.param3);
125       }
126       typename Dist::value_type z = c.dist;
127       if(!(boost::math::isfinite)(z))
128       {
129        return policies::raise_domain_error<typename Dist::value_type>(
130            function, "z parameter was %1%, but must be finite!", z, c.param3);
131       }
132       typename Dist::value_type scale = c.param2;
133       if(!(boost::math::isfinite)(scale))
134       {
135        return policies::raise_domain_error<typename Dist::value_type>(
136            function, "scale parameter was %1%, but must be finite!", scale, c.param3);
137       }
138        // cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
139        return z - quantile(Dist(), p) * scale;
140     } // find_location complement
141 
142   } // namespace boost
143 } // namespace math
144 
145 #endif // BOOST_STATS_FIND_LOCATION_HPP
146 
147