1 //  Copyright Thijs van den Berg, 2008.
2 //  Copyright John Maddock 2008.
3 //  Copyright Paul A. Bristow 2008, 2014.
4 
5 //  Use, modification and distribution are subject to the
6 //  Boost Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 // This module implements the Laplace distribution.
10 // Weisstein, Eric W. "Laplace Distribution." From MathWorld--A Wolfram Web Resource.
11 // http://mathworld.wolfram.com/LaplaceDistribution.html
12 // http://en.wikipedia.org/wiki/Laplace_distribution
13 //
14 // Abramowitz and Stegun 1972, p 930
15 // http://www.math.sfu.ca/~cbm/aands/page_930.htm
16 
17 #ifndef BOOST_STATS_LAPLACE_HPP
18 #define BOOST_STATS_LAPLACE_HPP
19 
20 #include <boost/math/distributions/detail/common_error_handling.hpp>
21 #include <boost/math/distributions/complement.hpp>
22 #include <boost/math/constants/constants.hpp>
23 #include <limits>
24 
25 namespace boost{ namespace math{
26 
27 #ifdef BOOST_MSVC
28 #  pragma warning(push)
29 #  pragma warning(disable:4127) // conditional expression is constant
30 #endif
31 
32 template <class RealType = double, class Policy = policies::policy<> >
33 class laplace_distribution
34 {
35 public:
36    // ----------------------------------
37    // public Types
38    // ----------------------------------
39    typedef RealType value_type;
40    typedef Policy policy_type;
41 
42    // ----------------------------------
43    // Constructor(s)
44    // ----------------------------------
laplace_distribution(RealType l_location=0,RealType l_scale=1)45    laplace_distribution(RealType l_location = 0, RealType l_scale = 1)
46       : m_location(l_location), m_scale(l_scale)
47    {
48       RealType result;
49       check_parameters("boost::math::laplace_distribution<%1%>::laplace_distribution()", &result);
50    }
51 
52 
53    // ----------------------------------
54    // Public functions
55    // ----------------------------------
56 
location() const57    RealType location() const
58    {
59       return m_location;
60    }
61 
scale() const62    RealType scale() const
63    {
64       return m_scale;
65    }
66 
check_parameters(const char * function,RealType * result) const67    bool check_parameters(const char* function, RealType* result) const
68    {
69          if(false == detail::check_scale(function, m_scale, result, Policy())) return false;
70          if(false == detail::check_location(function, m_location, result, Policy())) return false;
71          return true;
72    }
73 
74 private:
75    RealType m_location;
76    RealType m_scale;
77 }; // class laplace_distribution
78 
79 //
80 // Convenient type synonym for double.
81 typedef laplace_distribution<double> laplace;
82 
83 //
84 // Non-member functions.
85 template <class RealType, class Policy>
range(const laplace_distribution<RealType,Policy> &)86 inline const std::pair<RealType, RealType> range(const laplace_distribution<RealType, Policy>&)
87 {
88    if (std::numeric_limits<RealType>::has_infinity)
89   {  // Can use infinity.
90      return std::pair<RealType, RealType>(-std::numeric_limits<RealType>::infinity(), std::numeric_limits<RealType>::infinity()); // - to + infinity.
91   }
92   else
93   { // Can only use max_value.
94     using boost::math::tools::max_value;
95     return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.
96   }
97 
98 }
99 
100 template <class RealType, class Policy>
support(const laplace_distribution<RealType,Policy> &)101 inline const std::pair<RealType, RealType> support(const laplace_distribution<RealType, Policy>&)
102 {
103   if (std::numeric_limits<RealType>::has_infinity)
104   { // Can Use infinity.
105      return std::pair<RealType, RealType>(-std::numeric_limits<RealType>::infinity(), std::numeric_limits<RealType>::infinity()); // - to + infinity.
106   }
107   else
108   { // Can only use max_value.
109     using boost::math::tools::max_value;
110     return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.
111   }
112 }
113 
114 template <class RealType, class Policy>
pdf(const laplace_distribution<RealType,Policy> & dist,const RealType & x)115 inline RealType pdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)
116 {
117    BOOST_MATH_STD_USING // for ADL of std functions
118 
119    // Checking function argument
120    RealType result = 0;
121    const char* function = "boost::math::pdf(const laplace_distribution<%1%>&, %1%))";
122 
123    // Check scale and location.
124    if (false == dist.check_parameters(function, &result)) return result;
125    // Special pdf values.
126    if((boost::math::isinf)(x))
127    {
128       return 0; // pdf + and - infinity is zero.
129    }
130    if (false == detail::check_x(function, x, &result, Policy())) return result;
131 
132    // General case
133    RealType scale( dist.scale() );
134    RealType location( dist.location() );
135 
136    RealType exponent = x - location;
137    if (exponent>0) exponent = -exponent;
138    exponent /= scale;
139 
140    result = exp(exponent);
141    result /= 2 * scale;
142 
143    return result;
144 } // pdf
145 
146 template <class RealType, class Policy>
cdf(const laplace_distribution<RealType,Policy> & dist,const RealType & x)147 inline RealType cdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)
148 {
149    BOOST_MATH_STD_USING  // For ADL of std functions.
150 
151    RealType result = 0;
152    // Checking function argument.
153    const char* function = "boost::math::cdf(const laplace_distribution<%1%>&, %1%)";
154    // Check scale and location.
155    if (false == dist.check_parameters(function, &result)) return result;
156 
157    // Special cdf values:
158    if((boost::math::isinf)(x))
159    {
160      if(x < 0) return 0; // -infinity.
161      return 1; // + infinity.
162    }
163    if (false == detail::check_x(function, x, &result, Policy())) return result;
164 
165    // General cdf  values
166    RealType scale( dist.scale() );
167    RealType location( dist.location() );
168 
169    if (x < location)
170    {
171       result = exp( (x-location)/scale )/2;
172    }
173    else
174    {
175       result = 1 - exp( (location-x)/scale )/2;
176    }
177    return result;
178 } // cdf
179 
180 
181 template <class RealType, class Policy>
quantile(const laplace_distribution<RealType,Policy> & dist,const RealType & p)182 inline RealType quantile(const laplace_distribution<RealType, Policy>& dist, const RealType& p)
183 {
184    BOOST_MATH_STD_USING // for ADL of std functions.
185 
186    // Checking function argument
187    RealType result = 0;
188    const char* function = "boost::math::quantile(const laplace_distribution<%1%>&, %1%)";
189    if (false == dist.check_parameters(function, &result)) return result;
190    if(false == detail::check_probability(function, p, &result, Policy())) return result;
191 
192    // Extreme values of p:
193    if(p == 0)
194    {
195       result = policies::raise_overflow_error<RealType>(function,
196         "probability parameter is 0, but must be > 0!", Policy());
197       return -result; // -std::numeric_limits<RealType>::infinity();
198    }
199 
200    if(p == 1)
201    {
202       result = policies::raise_overflow_error<RealType>(function,
203         "probability parameter is 1, but must be < 1!", Policy());
204       return result; // std::numeric_limits<RealType>::infinity();
205    }
206    // Calculate Quantile
207    RealType scale( dist.scale() );
208    RealType location( dist.location() );
209 
210    if (p - 0.5 < 0.0)
211       result = location + scale*log( static_cast<RealType>(p*2) );
212    else
213       result = location - scale*log( static_cast<RealType>(-p*2 + 2) );
214 
215    return result;
216 } // quantile
217 
218 
219 template <class RealType, class Policy>
cdf(const complemented2_type<laplace_distribution<RealType,Policy>,RealType> & c)220 inline RealType cdf(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c)
221 {
222    // Calculate complement of cdf.
223    BOOST_MATH_STD_USING // for ADL of std functions
224 
225    RealType scale = c.dist.scale();
226    RealType location = c.dist.location();
227    RealType x = c.param;
228    RealType result = 0;
229 
230    // Checking function argument.
231    const char* function = "boost::math::cdf(const complemented2_type<laplace_distribution<%1%>, %1%>&)";
232 
233    // Check scale and location.
234    //if(false == detail::check_scale(function, scale, result, Policy())) return false;
235    //if(false == detail::check_location(function, location, result, Policy())) return false;
236     if (false == c.dist.check_parameters(function, &result)) return result;
237 
238    // Special cdf values.
239    if((boost::math::isinf)(x))
240    {
241      if(x < 0) return 1; // cdf complement -infinity is unity.
242      return 0; // cdf complement +infinity is zero.
243    }
244    if(false == detail::check_x(function, x, &result, Policy()))return result;
245 
246    // Cdf interval value.
247    if (-x < -location)
248    {
249       result = exp( (-x+location)/scale )/2;
250    }
251    else
252    {
253       result = 1 - exp( (-location+x)/scale )/2;
254    }
255    return result;
256 } // cdf complement
257 
258 
259 template <class RealType, class Policy>
quantile(const complemented2_type<laplace_distribution<RealType,Policy>,RealType> & c)260 inline RealType quantile(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c)
261 {
262    BOOST_MATH_STD_USING // for ADL of std functions.
263 
264    // Calculate quantile.
265    RealType scale = c.dist.scale();
266    RealType location = c.dist.location();
267    RealType q = c.param;
268    RealType result = 0;
269 
270    // Checking function argument.
271    const char* function = "quantile(const complemented2_type<laplace_distribution<%1%>, %1%>&)";
272    if (false == c.dist.check_parameters(function, &result)) return result;
273 
274    // Extreme values.
275    if(q == 0)
276    {
277        return std::numeric_limits<RealType>::infinity();
278    }
279    if(q == 1)
280    {
281        return -std::numeric_limits<RealType>::infinity();
282    }
283    if(false == detail::check_probability(function, q, &result, Policy())) return result;
284 
285    if (0.5 - q < 0.0)
286       result = location + scale*log( static_cast<RealType>(-q*2 + 2) );
287    else
288       result = location - scale*log( static_cast<RealType>(q*2) );
289 
290 
291    return result;
292 } // quantile
293 
294 template <class RealType, class Policy>
mean(const laplace_distribution<RealType,Policy> & dist)295 inline RealType mean(const laplace_distribution<RealType, Policy>& dist)
296 {
297    return dist.location();
298 }
299 
300 template <class RealType, class Policy>
standard_deviation(const laplace_distribution<RealType,Policy> & dist)301 inline RealType standard_deviation(const laplace_distribution<RealType, Policy>& dist)
302 {
303    return constants::root_two<RealType>() * dist.scale();
304 }
305 
306 template <class RealType, class Policy>
mode(const laplace_distribution<RealType,Policy> & dist)307 inline RealType mode(const laplace_distribution<RealType, Policy>& dist)
308 {
309    return dist.location();
310 }
311 
312 template <class RealType, class Policy>
median(const laplace_distribution<RealType,Policy> & dist)313 inline RealType median(const laplace_distribution<RealType, Policy>& dist)
314 {
315    return dist.location();
316 }
317 
318 template <class RealType, class Policy>
skewness(const laplace_distribution<RealType,Policy> &)319 inline RealType skewness(const laplace_distribution<RealType, Policy>& /*dist*/)
320 {
321    return 0;
322 }
323 
324 template <class RealType, class Policy>
kurtosis(const laplace_distribution<RealType,Policy> &)325 inline RealType kurtosis(const laplace_distribution<RealType, Policy>& /*dist*/)
326 {
327    return 6;
328 }
329 
330 template <class RealType, class Policy>
kurtosis_excess(const laplace_distribution<RealType,Policy> &)331 inline RealType kurtosis_excess(const laplace_distribution<RealType, Policy>& /*dist*/)
332 {
333    return 3;
334 }
335 
336 #ifdef BOOST_MSVC
337 #  pragma warning(pop)
338 #endif
339 
340 } // namespace math
341 } // namespace boost
342 
343 // This include must be at the end, *after* the accessors
344 // for this distribution have been defined, in order to
345 // keep compilers that support two-phase lookup happy.
346 #include <boost/math/distributions/detail/derived_accessors.hpp>
347 
348 #endif // BOOST_STATS_LAPLACE_HPP
349 
350 
351