1 //  Copyright John Maddock 2007.
2 //  Copyright Paul A. Bristow 2007, 2009
3 //  Use, modification and distribution are subject to the
4 //  Boost Software License, Version 1.0. (See accompanying file
5 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_STATS_PARETO_HPP
8 #define BOOST_STATS_PARETO_HPP
9 
10 // http://en.wikipedia.org/wiki/Pareto_distribution
11 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
12 // Also:
13 // Weisstein, Eric W. "Pareto Distribution."
14 // From MathWorld--A Wolfram Web Resource.
15 // http://mathworld.wolfram.com/ParetoDistribution.html
16 // Handbook of Statistical Distributions with Applications, K Krishnamoorthy, ISBN 1-58488-635-8, Chapter 23, pp 257 - 267.
17 // Caution KK's a and b are the reverse of Mathworld!
18 
19 #include <boost/math/distributions/fwd.hpp>
20 #include <boost/math/distributions/complement.hpp>
21 #include <boost/math/distributions/detail/common_error_handling.hpp>
22 #include <boost/math/special_functions/powm1.hpp>
23 
24 #include <utility> // for BOOST_CURRENT_VALUE?
25 
26 namespace boost
27 {
28   namespace math
29   {
30     namespace detail
31     { // Parameter checking.
32       template <class RealType, class Policy>
check_pareto_scale(const char * function,RealType scale,RealType * result,const Policy & pol)33       inline bool check_pareto_scale(
34         const char* function,
35         RealType scale,
36         RealType* result, const Policy& pol)
37       {
38         if((boost::math::isfinite)(scale))
39         { // any > 0 finite value is OK.
40           if (scale > 0)
41           {
42             return true;
43           }
44           else
45           {
46             *result = policies::raise_domain_error<RealType>(
47               function,
48               "Scale parameter is %1%, but must be > 0!", scale, pol);
49             return false;
50           }
51         }
52         else
53         { // Not finite.
54           *result = policies::raise_domain_error<RealType>(
55             function,
56             "Scale parameter is %1%, but must be finite!", scale, pol);
57           return false;
58         }
59       } // bool check_pareto_scale
60 
61       template <class RealType, class Policy>
check_pareto_shape(const char * function,RealType shape,RealType * result,const Policy & pol)62       inline bool check_pareto_shape(
63         const char* function,
64         RealType shape,
65         RealType* result, const Policy& pol)
66       {
67         if((boost::math::isfinite)(shape))
68         { // Any finite value > 0 is OK.
69           if (shape > 0)
70           {
71             return true;
72           }
73           else
74           {
75             *result = policies::raise_domain_error<RealType>(
76               function,
77               "Shape parameter is %1%, but must be > 0!", shape, pol);
78             return false;
79           }
80         }
81         else
82         { // Not finite.
83           *result = policies::raise_domain_error<RealType>(
84             function,
85             "Shape parameter is %1%, but must be finite!", shape, pol);
86           return false;
87         }
88       } // bool check_pareto_shape(
89 
90       template <class RealType, class Policy>
check_pareto_x(const char * function,RealType const & x,RealType * result,const Policy & pol)91       inline bool check_pareto_x(
92         const char* function,
93         RealType const& x,
94         RealType* result, const Policy& pol)
95       {
96         if((boost::math::isfinite)(x))
97         { //
98           if (x > 0)
99           {
100             return true;
101           }
102           else
103           {
104             *result = policies::raise_domain_error<RealType>(
105               function,
106               "x parameter is %1%, but must be > 0 !", x, pol);
107             return false;
108           }
109         }
110         else
111         { // Not finite..
112           *result = policies::raise_domain_error<RealType>(
113             function,
114             "x parameter is %1%, but must be finite!", x, pol);
115           return false;
116         }
117       } // bool check_pareto_x
118 
119       template <class RealType, class Policy>
check_pareto(const char * function,RealType scale,RealType shape,RealType * result,const Policy & pol)120       inline bool check_pareto( // distribution parameters.
121         const char* function,
122         RealType scale,
123         RealType shape,
124         RealType* result, const Policy& pol)
125       {
126         return check_pareto_scale(function, scale, result, pol)
127            && check_pareto_shape(function, shape, result, pol);
128       } // bool check_pareto(
129 
130     } // namespace detail
131 
132     template <class RealType = double, class Policy = policies::policy<> >
133     class pareto_distribution
134     {
135     public:
136       typedef RealType value_type;
137       typedef Policy policy_type;
138 
pareto_distribution(RealType l_scale=1,RealType l_shape=1)139       pareto_distribution(RealType l_scale = 1, RealType l_shape = 1)
140         : m_scale(l_scale), m_shape(l_shape)
141       { // Constructor.
142         RealType result = 0;
143         detail::check_pareto("boost::math::pareto_distribution<%1%>::pareto_distribution", l_scale, l_shape, &result, Policy());
144       }
145 
scale() const146       RealType scale()const
147       { // AKA Xm and Wolfram b and beta
148         return m_scale;
149       }
150 
shape() const151       RealType shape()const
152       { // AKA k and Wolfram a and alpha
153         return m_shape;
154       }
155     private:
156       // Data members:
157       RealType m_scale;  // distribution scale (xm) or beta
158       RealType m_shape;  // distribution shape (k) or alpha
159     };
160 
161     typedef pareto_distribution<double> pareto; // Convenience to allow pareto(2., 3.);
162 
163     template <class RealType, class Policy>
range(const pareto_distribution<RealType,Policy> &)164     inline const std::pair<RealType, RealType> range(const pareto_distribution<RealType, Policy>& /*dist*/)
165     { // Range of permissible values for random variable x.
166       using boost::math::tools::max_value;
167       return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // scale zero to + infinity.
168     } // range
169 
170     template <class RealType, class Policy>
support(const pareto_distribution<RealType,Policy> & dist)171     inline const std::pair<RealType, RealType> support(const pareto_distribution<RealType, Policy>& dist)
172     { // Range of supported values for random variable x.
173       // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
174       using boost::math::tools::max_value;
175       return std::pair<RealType, RealType>(dist.scale(), max_value<RealType>() ); // scale to + infinity.
176     } // support
177 
178     template <class RealType, class Policy>
pdf(const pareto_distribution<RealType,Policy> & dist,const RealType & x)179     inline RealType pdf(const pareto_distribution<RealType, Policy>& dist, const RealType& x)
180     {
181       BOOST_MATH_STD_USING  // for ADL of std function pow.
182       static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
183       RealType scale = dist.scale();
184       RealType shape = dist.shape();
185       RealType result = 0;
186       if(false == (detail::check_pareto_x(function, x, &result, Policy())
187          && detail::check_pareto(function, scale, shape, &result, Policy())))
188          return result;
189       if (x < scale)
190       { // regardless of shape, pdf is zero (or should be disallow x < scale and throw an exception?).
191         return 0;
192       }
193       result = shape * pow(scale, shape) / pow(x, shape+1);
194       return result;
195     } // pdf
196 
197     template <class RealType, class Policy>
cdf(const pareto_distribution<RealType,Policy> & dist,const RealType & x)198     inline RealType cdf(const pareto_distribution<RealType, Policy>& dist, const RealType& x)
199     {
200       BOOST_MATH_STD_USING  // for ADL of std function pow.
201       static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)";
202       RealType scale = dist.scale();
203       RealType shape = dist.shape();
204       RealType result = 0;
205 
206       if(false == (detail::check_pareto_x(function, x, &result, Policy())
207          && detail::check_pareto(function, scale, shape, &result, Policy())))
208          return result;
209 
210       if (x <= scale)
211       { // regardless of shape, cdf is zero.
212         return 0;
213       }
214 
215       // result = RealType(1) - pow((scale / x), shape);
216       result = -boost::math::powm1(scale/x, shape, Policy()); // should be more accurate.
217       return result;
218     } // cdf
219 
220     template <class RealType, class Policy>
quantile(const pareto_distribution<RealType,Policy> & dist,const RealType & p)221     inline RealType quantile(const pareto_distribution<RealType, Policy>& dist, const RealType& p)
222     {
223       BOOST_MATH_STD_USING  // for ADL of std function pow.
224       static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)";
225       RealType result = 0;
226       RealType scale = dist.scale();
227       RealType shape = dist.shape();
228       if(false == (detail::check_probability(function, p, &result, Policy())
229            && detail::check_pareto(function, scale, shape, &result, Policy())))
230       {
231         return result;
232       }
233       if (p == 0)
234       {
235         return scale; // x must be scale (or less).
236       }
237       if (p == 1)
238       {
239         return policies::raise_overflow_error<RealType>(function, 0, Policy()); // x = + infinity.
240       }
241       result = scale /
242         (pow((1 - p), 1 / shape));
243       // K. Krishnamoorthy,  ISBN 1-58488-635-8 eq 23.1.3
244       return result;
245     } // quantile
246 
247     template <class RealType, class Policy>
cdf(const complemented2_type<pareto_distribution<RealType,Policy>,RealType> & c)248     inline RealType cdf(const complemented2_type<pareto_distribution<RealType, Policy>, RealType>& c)
249     {
250        BOOST_MATH_STD_USING  // for ADL of std function pow.
251        static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)";
252        RealType result = 0;
253        RealType x = c.param;
254        RealType scale = c.dist.scale();
255        RealType shape = c.dist.shape();
256        if(false == (detail::check_pareto_x(function, x, &result, Policy())
257            && detail::check_pareto(function, scale, shape, &result, Policy())))
258          return result;
259 
260        if (x <= scale)
261        { // regardless of shape, cdf is zero, and complement is unity.
262          return 1;
263        }
264        result = pow((scale/x), shape);
265 
266        return result;
267     } // cdf complement
268 
269     template <class RealType, class Policy>
quantile(const complemented2_type<pareto_distribution<RealType,Policy>,RealType> & c)270     inline RealType quantile(const complemented2_type<pareto_distribution<RealType, Policy>, RealType>& c)
271     {
272       BOOST_MATH_STD_USING  // for ADL of std function pow.
273       static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)";
274       RealType result = 0;
275       RealType q = c.param;
276       RealType scale = c.dist.scale();
277       RealType shape = c.dist.shape();
278       if(false == (detail::check_probability(function, q, &result, Policy())
279            && detail::check_pareto(function, scale, shape, &result, Policy())))
280       {
281         return result;
282       }
283       if (q == 1)
284       {
285         return scale; // x must be scale (or less).
286       }
287       if (q == 0)
288       {
289          return policies::raise_overflow_error<RealType>(function, 0, Policy()); // x = + infinity.
290       }
291       result = scale / (pow(q, 1 / shape));
292       // K. Krishnamoorthy,  ISBN 1-58488-635-8 eq 23.1.3
293       return result;
294     } // quantile complement
295 
296     template <class RealType, class Policy>
mean(const pareto_distribution<RealType,Policy> & dist)297     inline RealType mean(const pareto_distribution<RealType, Policy>& dist)
298     {
299       RealType result = 0;
300       static const char* function = "boost::math::mean(const pareto_distribution<%1%>&, %1%)";
301       if(false == detail::check_pareto(function, dist.scale(), dist.shape(), &result, Policy()))
302       {
303         return result;
304       }
305       if (dist.shape() > RealType(1))
306       {
307         return dist.shape() * dist.scale() / (dist.shape() - 1);
308       }
309       else
310       {
311         using boost::math::tools::max_value;
312         return max_value<RealType>(); // +infinity.
313       }
314     } // mean
315 
316     template <class RealType, class Policy>
mode(const pareto_distribution<RealType,Policy> & dist)317     inline RealType mode(const pareto_distribution<RealType, Policy>& dist)
318     {
319       return dist.scale();
320     } // mode
321 
322     template <class RealType, class Policy>
median(const pareto_distribution<RealType,Policy> & dist)323     inline RealType median(const pareto_distribution<RealType, Policy>& dist)
324     {
325       RealType result = 0;
326       static const char* function = "boost::math::median(const pareto_distribution<%1%>&, %1%)";
327       if(false == detail::check_pareto(function, dist.scale(), dist.shape(), &result, Policy()))
328       {
329         return result;
330       }
331       BOOST_MATH_STD_USING
332       return dist.scale() * pow(RealType(2), (1/dist.shape()));
333     } // median
334 
335     template <class RealType, class Policy>
variance(const pareto_distribution<RealType,Policy> & dist)336     inline RealType variance(const pareto_distribution<RealType, Policy>& dist)
337     {
338       RealType result = 0;
339       RealType scale = dist.scale();
340       RealType shape = dist.shape();
341       static const char* function = "boost::math::variance(const pareto_distribution<%1%>&, %1%)";
342       if(false == detail::check_pareto(function, scale, shape, &result, Policy()))
343       {
344         return result;
345       }
346       if (shape > 2)
347       {
348         result = (scale * scale * shape) /
349          ((shape - 1) *  (shape - 1) * (shape - 2));
350       }
351       else
352       {
353         result = policies::raise_domain_error<RealType>(
354           function,
355           "variance is undefined for shape <= 2, but got %1%.", dist.shape(), Policy());
356       }
357       return result;
358     } // variance
359 
360     template <class RealType, class Policy>
skewness(const pareto_distribution<RealType,Policy> & dist)361     inline RealType skewness(const pareto_distribution<RealType, Policy>& dist)
362     {
363       BOOST_MATH_STD_USING
364       RealType result = 0;
365       RealType shape = dist.shape();
366       static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
367       if(false == detail::check_pareto(function, dist.scale(), shape, &result, Policy()))
368       {
369         return result;
370       }
371       if (shape > 3)
372       {
373         result = sqrt((shape - 2) / shape) *
374           2 * (shape + 1) /
375           (shape - 3);
376       }
377       else
378       {
379         result = policies::raise_domain_error<RealType>(
380           function,
381           "skewness is undefined for shape <= 3, but got %1%.", dist.shape(), Policy());
382       }
383       return result;
384     } // skewness
385 
386     template <class RealType, class Policy>
kurtosis(const pareto_distribution<RealType,Policy> & dist)387     inline RealType kurtosis(const pareto_distribution<RealType, Policy>& dist)
388     {
389       RealType result = 0;
390       RealType shape = dist.shape();
391       static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
392       if(false == detail::check_pareto(function, dist.scale(), shape, &result, Policy()))
393       {
394         return result;
395       }
396       if (shape > 4)
397       {
398         result = 3 * ((shape - 2) * (3 * shape * shape + shape + 2)) /
399           (shape * (shape - 3) * (shape - 4));
400       }
401       else
402       {
403         result = policies::raise_domain_error<RealType>(
404           function,
405           "kurtosis_excess is undefined for shape <= 4, but got %1%.", shape, Policy());
406       }
407       return result;
408     } // kurtosis
409 
410     template <class RealType, class Policy>
kurtosis_excess(const pareto_distribution<RealType,Policy> & dist)411     inline RealType kurtosis_excess(const pareto_distribution<RealType, Policy>& dist)
412     {
413       RealType result = 0;
414       RealType shape = dist.shape();
415       static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
416       if(false == detail::check_pareto(function, dist.scale(), shape, &result, Policy()))
417       {
418         return result;
419       }
420       if (shape > 4)
421       {
422         result = 6 * ((shape * shape * shape) + (shape * shape) - 6 * shape - 2) /
423           (shape * (shape - 3) * (shape - 4));
424       }
425       else
426       {
427         result = policies::raise_domain_error<RealType>(
428           function,
429           "kurtosis_excess is undefined for shape <= 4, but got %1%.", dist.shape(), Policy());
430       }
431       return result;
432     } // kurtosis_excess
433 
434     template <class RealType, class Policy>
entropy(const pareto_distribution<RealType,Policy> & dist)435     inline RealType entropy(const pareto_distribution<RealType, Policy>& dist)
436     {
437       using std::log;
438       RealType xm = dist.scale();
439       RealType alpha = dist.shape();
440       return log(xm/alpha) + 1 + 1/alpha;
441     }
442 
443     } // namespace math
444   } // namespace boost
445 
446   // This include must be at the end, *after* the accessors
447   // for this distribution have been defined, in order to
448   // keep compilers that support two-phase lookup happy.
449 #include <boost/math/distributions/detail/derived_accessors.hpp>
450 
451 #endif // BOOST_STATS_PARETO_HPP
452 
453 
454