495 lines · plain
1// Copyright Thijs van den Berg, 2008.2// Copyright John Maddock 2008.3// Copyright Paul A. Bristow 2008, 2014.4// Copyright Matt Borland 2024.5 6// Use, modification and distribution are subject to the7// Boost Software License, Version 1.0. (See accompanying file8// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)9 10// This module implements the Laplace distribution.11// Weisstein, Eric W. "Laplace Distribution." From MathWorld--A Wolfram Web Resource.12// http://mathworld.wolfram.com/LaplaceDistribution.html13// http://en.wikipedia.org/wiki/Laplace_distribution14//15// Abramowitz and Stegun 1972, p 93016// http://www.math.sfu.ca/~cbm/aands/page_930.htm17 18#ifndef BOOST_STATS_LAPLACE_HPP19#define BOOST_STATS_LAPLACE_HPP20 21#include <boost/math/tools/config.hpp>22#include <boost/math/tools/numeric_limits.hpp>23#include <boost/math/tools/tuple.hpp>24#include <boost/math/special_functions/log1p.hpp>25#include <boost/math/distributions/detail/common_error_handling.hpp>26#include <boost/math/distributions/complement.hpp>27#include <boost/math/constants/constants.hpp>28#include <boost/math/policies/policy.hpp>29#include <boost/math/policies/error_handling.hpp>30 31namespace boost{ namespace math{32 33#ifdef _MSC_VER34# pragma warning(push)35# pragma warning(disable:4127) // conditional expression is constant36#endif37 38template <class RealType = double, class Policy = policies::policy<> >39class laplace_distribution40{41public:42 // ----------------------------------43 // public Types44 // ----------------------------------45 using value_type = RealType;46 using policy_type = Policy;47 48 // ----------------------------------49 // Constructor(s)50 // ----------------------------------51 BOOST_MATH_GPU_ENABLED explicit laplace_distribution(RealType l_location = 0, RealType l_scale = 1)52 : m_location(l_location), m_scale(l_scale)53 {54 RealType result;55 check_parameters("boost::math::laplace_distribution<%1%>::laplace_distribution()", &result);56 }57 58 59 // ----------------------------------60 // Public functions61 // ----------------------------------62 63 BOOST_MATH_GPU_ENABLED RealType location() const64 {65 return m_location;66 }67 68 BOOST_MATH_GPU_ENABLED RealType scale() const69 {70 return m_scale;71 }72 73 BOOST_MATH_GPU_ENABLED bool check_parameters(const char* function, RealType* result) const74 {75 if(false == detail::check_scale(function, m_scale, result, Policy())) return false;76 if(false == detail::check_location(function, m_location, result, Policy())) return false;77 return true;78 }79 80private:81 RealType m_location;82 RealType m_scale;83}; // class laplace_distribution84 85//86// Convenient type synonym for double.87using laplace = laplace_distribution<double>;88 89#ifdef __cpp_deduction_guides90template <class RealType>91laplace_distribution(RealType)->laplace_distribution<typename boost::math::tools::promote_args<RealType>::type>;92template <class RealType>93laplace_distribution(RealType,RealType)->laplace_distribution<typename boost::math::tools::promote_args<RealType>::type>;94#endif95 96//97// Non-member functions.98template <class RealType, class Policy>99BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> range(const laplace_distribution<RealType, Policy>&)100{101 BOOST_MATH_IF_CONSTEXPR (boost::math::numeric_limits<RealType>::has_infinity)102 { // Can use infinity.103 return boost::math::pair<RealType, RealType>(-boost::math::numeric_limits<RealType>::infinity(), boost::math::numeric_limits<RealType>::infinity()); // - to + infinity.104 }105 else106 { // Can only use max_value.107 using boost::math::tools::max_value;108 return boost::math::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.109 }110 111}112 113template <class RealType, class Policy>114BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> support(const laplace_distribution<RealType, Policy>&)115{116 BOOST_MATH_IF_CONSTEXPR (boost::math::numeric_limits<RealType>::has_infinity)117 { // Can Use infinity.118 return boost::math::pair<RealType, RealType>(-boost::math::numeric_limits<RealType>::infinity(), boost::math::numeric_limits<RealType>::infinity()); // - to + infinity.119 }120 else121 { // Can only use max_value.122 using boost::math::tools::max_value;123 return boost::math::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.124 }125}126 127template <class RealType, class Policy>128BOOST_MATH_GPU_ENABLED inline RealType pdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)129{130 BOOST_MATH_STD_USING // for ADL of std functions131 132 // Checking function argument133 RealType result = 0;134 constexpr auto function = "boost::math::pdf(const laplace_distribution<%1%>&, %1%))";135 136 // Check scale and location.137 if (false == dist.check_parameters(function, &result)) return result;138 // Special pdf values.139 if((boost::math::isinf)(x))140 {141 return 0; // pdf + and - infinity is zero.142 }143 if (false == detail::check_x(function, x, &result, Policy())) return result;144 145 // General case146 RealType scale( dist.scale() );147 RealType location( dist.location() );148 149 RealType exponent = x - location;150 if (exponent>0) exponent = -exponent;151 exponent /= scale;152 153 result = exp(exponent);154 result /= 2 * scale;155 156 return result;157} // pdf158 159template <class RealType, class Policy>160BOOST_MATH_GPU_ENABLED inline RealType logpdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)161{162 BOOST_MATH_STD_USING // for ADL of std functions163 164 // Checking function argument165 RealType result = -boost::math::numeric_limits<RealType>::infinity();166 constexpr auto function = "boost::math::logpdf(const laplace_distribution<%1%>&, %1%))";167 168 // Check scale and location.169 if (false == dist.check_parameters(function, &result))170 {171 return result;172 }173 // Special pdf values.174 if((boost::math::isinf)(x))175 {176 return result; // pdf + and - infinity is zero so logpdf is -INF177 }178 if (false == detail::check_x(function, x, &result, Policy()))179 {180 return result;181 }182 183 const RealType mu = dist.scale();184 const RealType b = dist.location();185 186 // if b is 0 avoid divide by 0 error187 if(abs(b) < boost::math::numeric_limits<RealType>::epsilon())188 {189 result = log(pdf(dist, x));190 }191 else192 {193 // General case194 const RealType log2 = boost::math::constants::ln_two<RealType>();195 result = -abs(x-mu)/b - log(b) - log2;196 }197 198 return result;199} // logpdf200 201template <class RealType, class Policy>202BOOST_MATH_GPU_ENABLED inline RealType cdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)203{204 BOOST_MATH_STD_USING // For ADL of std functions.205 206 RealType result = 0;207 // Checking function argument.208 constexpr auto function = "boost::math::cdf(const laplace_distribution<%1%>&, %1%)";209 // Check scale and location.210 if (false == dist.check_parameters(function, &result)) return result;211 212 // Special cdf values:213 if((boost::math::isinf)(x))214 {215 if(x < 0) return 0; // -infinity.216 return 1; // + infinity.217 }218 if (false == detail::check_x(function, x, &result, Policy())) return result;219 220 // General cdf values221 RealType scale( dist.scale() );222 RealType location( dist.location() );223 224 if (x < location)225 {226 result = exp( (x-location)/scale )/2;227 }228 else229 {230 result = 1 - exp( (location-x)/scale )/2;231 }232 return result;233} // cdf234 235template <class RealType, class Policy>236BOOST_MATH_GPU_ENABLED inline RealType logcdf(const laplace_distribution<RealType, Policy>& dist, const RealType& x)237{238 BOOST_MATH_STD_USING // For ADL of std functions.239 240 RealType result = 0;241 // Checking function argument.242 constexpr auto function = "boost::math::logcdf(const laplace_distribution<%1%>&, %1%)";243 // Check scale and location.244 if (false == dist.check_parameters(function, &result)) 245 {246 return result;247 }248 249 // Special cdf values:250 if((boost::math::isinf)(x))251 {252 if(x < 0) 253 {254 return 0; // -infinity.255 }256 return 1; // + infinity.257 }258 259 if (false == detail::check_x(function, x, &result, Policy())) 260 {261 return result;262 }263 264 // General cdf values265 RealType scale( dist.scale() );266 RealType location( dist.location() );267 268 if (x < location)269 {270 result = ((x - location) / scale) - boost::math::constants::ln_two<RealType>();271 }272 else273 {274 result = log1p(-exp((location - x) / scale) / 2);275 }276 277 return result;278} // logcdf279 280template <class RealType, class Policy>281BOOST_MATH_GPU_ENABLED inline RealType quantile(const laplace_distribution<RealType, Policy>& dist, const RealType& p)282{283 BOOST_MATH_STD_USING // for ADL of std functions.284 285 // Checking function argument286 RealType result = 0;287 constexpr auto function = "boost::math::quantile(const laplace_distribution<%1%>&, %1%)";288 if (false == dist.check_parameters(function, &result)) return result;289 if(false == detail::check_probability(function, p, &result, Policy())) return result;290 291 // Extreme values of p:292 if(p == 0)293 {294 result = policies::raise_overflow_error<RealType>(function,295 "probability parameter is 0, but must be > 0!", Policy());296 return -result; // -inf297 }298 299 if(p == 1)300 {301 result = policies::raise_overflow_error<RealType>(function,302 "probability parameter is 1, but must be < 1!", Policy());303 return result; // inf304 }305 // Calculate Quantile306 RealType scale( dist.scale() );307 RealType location( dist.location() );308 309 if (p - 0.5 < 0.0)310 result = location + scale*log( static_cast<RealType>(p*2) );311 else312 result = location - scale*log( static_cast<RealType>(-p*2 + 2) );313 314 return result;315} // quantile316 317 318template <class RealType, class Policy>319BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c)320{321 // Calculate complement of cdf.322 BOOST_MATH_STD_USING // for ADL of std functions323 324 RealType scale = c.dist.scale();325 RealType location = c.dist.location();326 RealType x = c.param;327 RealType result = 0;328 329 // Checking function argument.330 constexpr auto function = "boost::math::cdf(const complemented2_type<laplace_distribution<%1%>, %1%>&)";331 332 // Check scale and location.333 if (false == c.dist.check_parameters(function, &result)) return result;334 335 // Special cdf values.336 if((boost::math::isinf)(x))337 {338 if(x < 0) return 1; // cdf complement -infinity is unity.339 return 0; // cdf complement +infinity is zero.340 }341 if(false == detail::check_x(function, x, &result, Policy()))return result;342 343 // Cdf interval value.344 if (-x < -location)345 {346 result = exp( (-x+location)/scale )/2;347 }348 else349 {350 result = 1 - exp( (-location+x)/scale )/2;351 }352 return result;353} // cdf complement354 355template <class RealType, class Policy>356BOOST_MATH_GPU_ENABLED inline RealType logcdf(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c)357{358 // Calculate complement of logcdf.359 BOOST_MATH_STD_USING // for ADL of std functions360 361 RealType scale = c.dist.scale();362 RealType location = c.dist.location();363 RealType x = c.param;364 RealType result = 0;365 366 // Checking function argument.367 constexpr auto function = "boost::math::logcdf(const complemented2_type<laplace_distribution<%1%>, %1%>&)";368 369 // Check scale and location.370 if (false == c.dist.check_parameters(function, &result)) return result;371 372 // Special cdf values.373 if((boost::math::isinf)(x))374 {375 if(x < 0) 376 { 377 return 1; // cdf complement -infinity is unity.378 }379 380 return 0; // cdf complement +infinity is zero.381 }382 if(false == detail::check_x(function, x, &result, Policy()))return result;383 384 // Cdf interval value.385 if (-x < -location)386 {387 result = (-x+location)/scale - boost::math::constants::ln_two<RealType>();388 }389 else390 {391 result = log1p(-exp( (-location+x)/scale )/2, Policy());392 }393 return result;394} // cdf complement395 396template <class RealType, class Policy>397BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<laplace_distribution<RealType, Policy>, RealType>& c)398{399 BOOST_MATH_STD_USING // for ADL of std functions.400 401 // Calculate quantile.402 RealType scale = c.dist.scale();403 RealType location = c.dist.location();404 RealType q = c.param;405 RealType result = 0;406 407 // Checking function argument.408 constexpr auto function = "quantile(const complemented2_type<laplace_distribution<%1%>, %1%>&)";409 if (false == c.dist.check_parameters(function, &result)) return result;410 411 // Extreme values.412 if(q == 0)413 {414 return boost::math::numeric_limits<RealType>::infinity();415 }416 if(q == 1)417 {418 return -boost::math::numeric_limits<RealType>::infinity();419 }420 if(false == detail::check_probability(function, q, &result, Policy())) return result;421 422 if (0.5 - q < 0.0)423 result = location + scale*log( static_cast<RealType>(-q*2 + 2) );424 else425 result = location - scale*log( static_cast<RealType>(q*2) );426 427 428 return result;429} // quantile430 431template <class RealType, class Policy>432BOOST_MATH_GPU_ENABLED inline RealType mean(const laplace_distribution<RealType, Policy>& dist)433{434 return dist.location();435}436 437template <class RealType, class Policy>438BOOST_MATH_GPU_ENABLED inline RealType standard_deviation(const laplace_distribution<RealType, Policy>& dist)439{440 return constants::root_two<RealType>() * dist.scale();441}442 443template <class RealType, class Policy>444BOOST_MATH_GPU_ENABLED inline RealType mode(const laplace_distribution<RealType, Policy>& dist)445{446 return dist.location();447}448 449template <class RealType, class Policy>450BOOST_MATH_GPU_ENABLED inline RealType median(const laplace_distribution<RealType, Policy>& dist)451{452 return dist.location();453}454 455template <class RealType, class Policy>456BOOST_MATH_GPU_ENABLED inline RealType skewness(const laplace_distribution<RealType, Policy>& /*dist*/)457{458 return 0;459}460 461template <class RealType, class Policy>462BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const laplace_distribution<RealType, Policy>& /*dist*/)463{464 return 6;465}466 467template <class RealType, class Policy>468BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const laplace_distribution<RealType, Policy>& /*dist*/)469{470 return 3;471}472 473template <class RealType, class Policy>474BOOST_MATH_GPU_ENABLED inline RealType entropy(const laplace_distribution<RealType, Policy> & dist)475{476 using std::log;477 return log(2*dist.scale()*constants::e<RealType>());478}479 480#ifdef _MSC_VER481# pragma warning(pop)482#endif483 484} // namespace math485} // namespace boost486 487// This include must be at the end, *after* the accessors488// for this distribution have been defined, in order to489// keep compilers that support two-phase lookup happy.490#include <boost/math/distributions/detail/derived_accessors.hpp>491 492#endif // BOOST_STATS_LAPLACE_HPP493 494 495