laplace.hpp 15 KB

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