// Copyright Thijs van den Berg, 2008. // Copyright John Maddock 2008. // Copyright Paul A. Bristow 2008, 2014. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // This module implements the Laplace distribution. // Weisstein, Eric W. "Laplace Distribution." From MathWorld--A Wolfram Web Resource. // http://mathworld.wolfram.com/LaplaceDistribution.html // http://en.wikipedia.org/wiki/Laplace_distribution // // Abramowitz and Stegun 1972, p 930 // http://www.math.sfu.ca/~cbm/aands/page_930.htm #ifndef BOOST_STATS_LAPLACE_HPP #define BOOST_STATS_LAPLACE_HPP #include <boost/math/distributions/detail/common_error_handling.hpp> #include <boost/math/distributions/complement.hpp> #include <boost/math/constants/constants.hpp> #include <limits> namespace boost{ namespace math{ #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable:4127) // conditional expression is constant #endif template <class RealType = double, class Policy = policies::policy<> > class laplace_distribution { public: // ---------------------------------- // public Types // ---------------------------------- typedef RealType value_type; typedef Policy policy_type; // ---------------------------------- // Constructor(s) // ---------------------------------- laplace_distribution(RealType l_location = 0, RealType l_scale = 1) : m_location(l_location), m_scale(l_scale) { RealType result; check_parameters("boost::math::laplace_distribution<%1%>::laplace_distribution()", &result); } // ---------------------------------- // Public functions // ---------------------------------- RealType location() const { return m_location; } RealType scale() const { return m_scale; } bool check_parameters(const char* function, RealType* result) const { if(false == detail::check_scale(function, m_scale, result, Policy())) return false; if(false == detail::check_location(function, m_location, result, Policy())) return false; return true; } private: RealType m_location; RealType m_scale; }; // class laplace_distribution // // Convenient type synonym for double. typedef laplace_distribution<double> laplace; // // Non-member functions. template <class RealType, class Policy> inline const std::pair<RealType, RealType> range(const laplace_distribution<RealType, Policy>&) { if (std::numeric_limits<RealType>::has_infinity) { // Can use infinity. return std::pair<RealType, RealType>(-std::numeric_limits<RealType>::infinity(), std::numeric_limits<RealType>::infinity()); // - to + infinity. } else { // Can only use max_value. using boost::math::tools::max_value; return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value. } } template <class RealType, class Policy> inline const std::pair<RealType, RealType> support(const laplace_distribution<RealType, Policy>&) { if (std::numeric_limits<RealType>::has_infinity) { // Can Use infinity. return std::pair<RealType, RealType>(-std::numeric_limits<RealType>::infinity(), std::numeric_limits<RealType>::infinity()); // - to + infinity. } else { // Can only use max_value. using boost::math::tools::max_value; return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value. } } template <class RealType, class Policy> inline RealType pdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x) { BOOST_MATH_STD_USING // for ADL of std functions // Checking function argument RealType result = 0; const char* function = "boost::math::pdf(const laplace_distribution<%1%>&, %1%))"; // Check scale and location. if (false == dist.check_parameters(function, &result)) return result; // Special pdf values. if((boost::math::isinf)(x)) { return 0; // pdf + and - infinity is zero. } if (false == detail::check_x(function, x, &result, Policy())) return result; // General case RealType scale( dist.scale() ); RealType location( dist.location() ); RealType exponent = x - location; if (exponent>0) exponent = -exponent; exponent /= scale; result = exp(exponent); result /= 2 * scale; return result; } // pdf template <class RealType, class Policy> inline RealType cdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x) { BOOST_MATH_STD_USING // For ADL of std functions. RealType result = 0; // Checking function argument. const char* function = "boost::math::cdf(const laplace_distribution<%1%>&, %1%)"; // Check scale and location. if (false == dist.check_parameters(function, &result)) return result; // Special cdf values: if((boost::math::isinf)(x)) { if(x < 0) return 0; // -infinity. return 1; // + infinity. } if (false == detail::check_x(function, x, &result, Policy())) return result; // General cdf values RealType scale( dist.scale() ); RealType location( dist.location() ); if (x < location) { result = exp( (x-location)/scale )/2; } else { result = 1 - exp( (location-x)/scale )/2; } return result; } // cdf template <class RealType, class Policy> inline RealType quantile(const laplace_distribution<RealType, Policy>& dist, const RealType& p) { BOOST_MATH_STD_USING // for ADL of std functions. // Checking function argument RealType result = 0; const char* function = "boost::math::quantile(const laplace_distribution<%1%>&, %1%)"; if (false == dist.check_parameters(function, &result)) return result; if(false == detail::check_probability(function, p, &result, Policy())) return result; // Extreme values of p: if(p == 0) { result = policies::raise_overflow_error<RealType>(function, "probability parameter is 0, but must be > 0!", Policy()); return -result; // -std::numeric_limits<RealType>::infinity(); } if(p == 1) { result = policies::raise_overflow_error<RealType>(function, "probability parameter is 1, but must be < 1!", Policy()); return result; // std::numeric_limits<RealType>::infinity(); } // Calculate Quantile RealType scale( dist.scale() ); RealType location( dist.location() ); if (p - 0.5 < 0.0) result = location + scale*log( static_cast<RealType>(p*2) ); else result = location - scale*log( static_cast<RealType>(-p*2 + 2) ); return result; } // quantile template <class RealType, class Policy> inline RealType cdf(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c) { // Calculate complement of cdf. BOOST_MATH_STD_USING // for ADL of std functions RealType scale = c.dist.scale(); RealType location = c.dist.location(); RealType x = c.param; RealType result = 0; // Checking function argument. const char* function = "boost::math::cdf(const complemented2_type<laplace_distribution<%1%>, %1%>&)"; // Check scale and location. //if(false == detail::check_scale(function, scale, result, Policy())) return false; //if(false == detail::check_location(function, location, result, Policy())) return false; if (false == c.dist.check_parameters(function, &result)) return result; // Special cdf values. if((boost::math::isinf)(x)) { if(x < 0) return 1; // cdf complement -infinity is unity. return 0; // cdf complement +infinity is zero. } if(false == detail::check_x(function, x, &result, Policy()))return result; // Cdf interval value. if (-x < -location) { result = exp( (-x+location)/scale )/2; } else { result = 1 - exp( (-location+x)/scale )/2; } return result; } // cdf complement template <class RealType, class Policy> inline RealType quantile(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c) { BOOST_MATH_STD_USING // for ADL of std functions. // Calculate quantile. RealType scale = c.dist.scale(); RealType location = c.dist.location(); RealType q = c.param; RealType result = 0; // Checking function argument. const char* function = "quantile(const complemented2_type<laplace_distribution<%1%>, %1%>&)"; if (false == c.dist.check_parameters(function, &result)) return result; // Extreme values. if(q == 0) { return std::numeric_limits<RealType>::infinity(); } if(q == 1) { return -std::numeric_limits<RealType>::infinity(); } if(false == detail::check_probability(function, q, &result, Policy())) return result; if (0.5 - q < 0.0) result = location + scale*log( static_cast<RealType>(-q*2 + 2) ); else result = location - scale*log( static_cast<RealType>(q*2) ); return result; } // quantile template <class RealType, class Policy> inline RealType mean(const laplace_distribution<RealType, Policy>& dist) { return dist.location(); } template <class RealType, class Policy> inline RealType standard_deviation(const laplace_distribution<RealType, Policy>& dist) { return constants::root_two<RealType>() * dist.scale(); } template <class RealType, class Policy> inline RealType mode(const laplace_distribution<RealType, Policy>& dist) { return dist.location(); } template <class RealType, class Policy> inline RealType median(const laplace_distribution<RealType, Policy>& dist) { return dist.location(); } template <class RealType, class Policy> inline RealType skewness(const laplace_distribution<RealType, Policy>& /*dist*/) { return 0; } template <class RealType, class Policy> inline RealType kurtosis(const laplace_distribution<RealType, Policy>& /*dist*/) { return 6; } template <class RealType, class Policy> inline RealType kurtosis_excess(const laplace_distribution<RealType, Policy>& /*dist*/) { return 3; } #ifdef BOOST_MSVC # pragma warning(pop) #endif } // namespace math } // namespace boost // This include must be at the end, *after* the accessors // for this distribution have been defined, in order to // keep compilers that support two-phase lookup happy. #include <boost/math/distributions/detail/derived_accessors.hpp> #endif // BOOST_STATS_LAPLACE_HPP