beta.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // boost\math\distributions\beta.hpp
  2. // Copyright John Maddock 2006.
  3. // Copyright Paul A. Bristow 2006.
  4. // Use, modification and distribution are subject to the
  5. // Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. // http://en.wikipedia.org/wiki/Beta_distribution
  9. // http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm
  10. // http://mathworld.wolfram.com/BetaDistribution.html
  11. // The Beta Distribution is a continuous probability distribution.
  12. // The beta distribution is used to model events which are constrained to take place
  13. // within an interval defined by maxima and minima,
  14. // so is used extensively in PERT and other project management systems
  15. // to describe the time to completion.
  16. // The cdf of the beta distribution is used as a convenient way
  17. // of obtaining the sum over a set of binomial outcomes.
  18. // The beta distribution is also used in Bayesian statistics.
  19. #ifndef BOOST_MATH_DIST_BETA_HPP
  20. #define BOOST_MATH_DIST_BETA_HPP
  21. #include <boost/math/distributions/fwd.hpp>
  22. #include <boost/math/special_functions/beta.hpp> // for beta.
  23. #include <boost/math/distributions/complement.hpp> // complements.
  24. #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
  25. #include <boost/math/special_functions/fpclassify.hpp> // isnan.
  26. #include <boost/math/tools/roots.hpp> // for root finding.
  27. #if defined (BOOST_MSVC)
  28. # pragma warning(push)
  29. # pragma warning(disable: 4702) // unreachable code
  30. // in domain_error_imp in error_handling
  31. #endif
  32. #include <utility>
  33. namespace boost
  34. {
  35. namespace math
  36. {
  37. namespace beta_detail
  38. {
  39. // Common error checking routines for beta distribution functions:
  40. template <class RealType, class Policy>
  41. inline bool check_alpha(const char* function, const RealType& alpha, RealType* result, const Policy& pol)
  42. {
  43. if(!(boost::math::isfinite)(alpha) || (alpha <= 0))
  44. {
  45. *result = policies::raise_domain_error<RealType>(
  46. function,
  47. "Alpha argument is %1%, but must be > 0 !", alpha, pol);
  48. return false;
  49. }
  50. return true;
  51. } // bool check_alpha
  52. template <class RealType, class Policy>
  53. inline bool check_beta(const char* function, const RealType& beta, RealType* result, const Policy& pol)
  54. {
  55. if(!(boost::math::isfinite)(beta) || (beta <= 0))
  56. {
  57. *result = policies::raise_domain_error<RealType>(
  58. function,
  59. "Beta argument is %1%, but must be > 0 !", beta, pol);
  60. return false;
  61. }
  62. return true;
  63. } // bool check_beta
  64. template <class RealType, class Policy>
  65. inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
  66. {
  67. if((p < 0) || (p > 1) || !(boost::math::isfinite)(p))
  68. {
  69. *result = policies::raise_domain_error<RealType>(
  70. function,
  71. "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
  72. return false;
  73. }
  74. return true;
  75. } // bool check_prob
  76. template <class RealType, class Policy>
  77. inline bool check_x(const char* function, const RealType& x, RealType* result, const Policy& pol)
  78. {
  79. if(!(boost::math::isfinite)(x) || (x < 0) || (x > 1))
  80. {
  81. *result = policies::raise_domain_error<RealType>(
  82. function,
  83. "x argument is %1%, but must be >= 0 and <= 1 !", x, pol);
  84. return false;
  85. }
  86. return true;
  87. } // bool check_x
  88. template <class RealType, class Policy>
  89. inline bool check_dist(const char* function, const RealType& alpha, const RealType& beta, RealType* result, const Policy& pol)
  90. { // Check both alpha and beta.
  91. return check_alpha(function, alpha, result, pol)
  92. && check_beta(function, beta, result, pol);
  93. } // bool check_dist
  94. template <class RealType, class Policy>
  95. inline bool check_dist_and_x(const char* function, const RealType& alpha, const RealType& beta, RealType x, RealType* result, const Policy& pol)
  96. {
  97. return check_dist(function, alpha, beta, result, pol)
  98. && beta_detail::check_x(function, x, result, pol);
  99. } // bool check_dist_and_x
  100. template <class RealType, class Policy>
  101. inline bool check_dist_and_prob(const char* function, const RealType& alpha, const RealType& beta, RealType p, RealType* result, const Policy& pol)
  102. {
  103. return check_dist(function, alpha, beta, result, pol)
  104. && check_prob(function, p, result, pol);
  105. } // bool check_dist_and_prob
  106. template <class RealType, class Policy>
  107. inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
  108. {
  109. if(!(boost::math::isfinite)(mean) || (mean <= 0))
  110. {
  111. *result = policies::raise_domain_error<RealType>(
  112. function,
  113. "mean argument is %1%, but must be > 0 !", mean, pol);
  114. return false;
  115. }
  116. return true;
  117. } // bool check_mean
  118. template <class RealType, class Policy>
  119. inline bool check_variance(const char* function, const RealType& variance, RealType* result, const Policy& pol)
  120. {
  121. if(!(boost::math::isfinite)(variance) || (variance <= 0))
  122. {
  123. *result = policies::raise_domain_error<RealType>(
  124. function,
  125. "variance argument is %1%, but must be > 0 !", variance, pol);
  126. return false;
  127. }
  128. return true;
  129. } // bool check_variance
  130. } // namespace beta_detail
  131. // typedef beta_distribution<double> beta;
  132. // is deliberately NOT included to avoid a name clash with the beta function.
  133. // Use beta_distribution<> mybeta(...) to construct type double.
  134. template <class RealType = double, class Policy = policies::policy<> >
  135. class beta_distribution
  136. {
  137. public:
  138. typedef RealType value_type;
  139. typedef Policy policy_type;
  140. beta_distribution(RealType l_alpha = 1, RealType l_beta = 1) : m_alpha(l_alpha), m_beta(l_beta)
  141. {
  142. RealType result;
  143. beta_detail::check_dist(
  144. "boost::math::beta_distribution<%1%>::beta_distribution",
  145. m_alpha,
  146. m_beta,
  147. &result, Policy());
  148. } // beta_distribution constructor.
  149. // Accessor functions:
  150. RealType alpha() const
  151. {
  152. return m_alpha;
  153. }
  154. RealType beta() const
  155. { // .
  156. return m_beta;
  157. }
  158. // Estimation of the alpha & beta parameters.
  159. // http://en.wikipedia.org/wiki/Beta_distribution
  160. // gives formulae in section on parameter estimation.
  161. // Also NIST EDA page 3 & 4 give the same.
  162. // http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm
  163. // http://www.epi.ucdavis.edu/diagnostictests/betabuster.html
  164. static RealType find_alpha(
  165. RealType mean, // Expected value of mean.
  166. RealType variance) // Expected value of variance.
  167. {
  168. static const char* function = "boost::math::beta_distribution<%1%>::find_alpha";
  169. RealType result = 0; // of error checks.
  170. if(false ==
  171. (
  172. beta_detail::check_mean(function, mean, &result, Policy())
  173. && beta_detail::check_variance(function, variance, &result, Policy())
  174. )
  175. )
  176. {
  177. return result;
  178. }
  179. return mean * (( (mean * (1 - mean)) / variance)- 1);
  180. } // RealType find_alpha
  181. static RealType find_beta(
  182. RealType mean, // Expected value of mean.
  183. RealType variance) // Expected value of variance.
  184. {
  185. static const char* function = "boost::math::beta_distribution<%1%>::find_beta";
  186. RealType result = 0; // of error checks.
  187. if(false ==
  188. (
  189. beta_detail::check_mean(function, mean, &result, Policy())
  190. &&
  191. beta_detail::check_variance(function, variance, &result, Policy())
  192. )
  193. )
  194. {
  195. return result;
  196. }
  197. return (1 - mean) * (((mean * (1 - mean)) /variance)-1);
  198. } // RealType find_beta
  199. // Estimate alpha & beta from either alpha or beta, and x and probability.
  200. // Uses for these parameter estimators are unclear.
  201. static RealType find_alpha(
  202. RealType beta, // from beta.
  203. RealType x, // x.
  204. RealType probability) // cdf
  205. {
  206. static const char* function = "boost::math::beta_distribution<%1%>::find_alpha";
  207. RealType result = 0; // of error checks.
  208. if(false ==
  209. (
  210. beta_detail::check_prob(function, probability, &result, Policy())
  211. &&
  212. beta_detail::check_beta(function, beta, &result, Policy())
  213. &&
  214. beta_detail::check_x(function, x, &result, Policy())
  215. )
  216. )
  217. {
  218. return result;
  219. }
  220. return ibeta_inva(beta, x, probability, Policy());
  221. } // RealType find_alpha(beta, a, probability)
  222. static RealType find_beta(
  223. // ibeta_invb(T b, T x, T p); (alpha, x, cdf,)
  224. RealType alpha, // alpha.
  225. RealType x, // probability x.
  226. RealType probability) // probability cdf.
  227. {
  228. static const char* function = "boost::math::beta_distribution<%1%>::find_beta";
  229. RealType result = 0; // of error checks.
  230. if(false ==
  231. (
  232. beta_detail::check_prob(function, probability, &result, Policy())
  233. &&
  234. beta_detail::check_alpha(function, alpha, &result, Policy())
  235. &&
  236. beta_detail::check_x(function, x, &result, Policy())
  237. )
  238. )
  239. {
  240. return result;
  241. }
  242. return ibeta_invb(alpha, x, probability, Policy());
  243. } // RealType find_beta(alpha, x, probability)
  244. private:
  245. RealType m_alpha; // Two parameters of the beta distribution.
  246. RealType m_beta;
  247. }; // template <class RealType, class Policy> class beta_distribution
  248. template <class RealType, class Policy>
  249. inline const std::pair<RealType, RealType> range(const beta_distribution<RealType, Policy>& /* dist */)
  250. { // Range of permissible values for random variable x.
  251. using boost::math::tools::max_value;
  252. return std::pair<RealType, RealType>(static_cast<RealType>(0), static_cast<RealType>(1));
  253. }
  254. template <class RealType, class Policy>
  255. inline const std::pair<RealType, RealType> support(const beta_distribution<RealType, Policy>& /* dist */)
  256. { // Range of supported values for random variable x.
  257. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  258. return std::pair<RealType, RealType>(static_cast<RealType>(0), static_cast<RealType>(1));
  259. }
  260. template <class RealType, class Policy>
  261. inline RealType mean(const beta_distribution<RealType, Policy>& dist)
  262. { // Mean of beta distribution = np.
  263. return dist.alpha() / (dist.alpha() + dist.beta());
  264. } // mean
  265. template <class RealType, class Policy>
  266. inline RealType variance(const beta_distribution<RealType, Policy>& dist)
  267. { // Variance of beta distribution = np(1-p).
  268. RealType a = dist.alpha();
  269. RealType b = dist.beta();
  270. return (a * b) / ((a + b ) * (a + b) * (a + b + 1));
  271. } // variance
  272. template <class RealType, class Policy>
  273. inline RealType mode(const beta_distribution<RealType, Policy>& dist)
  274. {
  275. static const char* function = "boost::math::mode(beta_distribution<%1%> const&)";
  276. RealType result;
  277. if ((dist.alpha() <= 1))
  278. {
  279. result = policies::raise_domain_error<RealType>(
  280. function,
  281. "mode undefined for alpha = %1%, must be > 1!", dist.alpha(), Policy());
  282. return result;
  283. }
  284. if ((dist.beta() <= 1))
  285. {
  286. result = policies::raise_domain_error<RealType>(
  287. function,
  288. "mode undefined for beta = %1%, must be > 1!", dist.beta(), Policy());
  289. return result;
  290. }
  291. RealType a = dist.alpha();
  292. RealType b = dist.beta();
  293. return (a-1) / (a + b - 2);
  294. } // mode
  295. //template <class RealType, class Policy>
  296. //inline RealType median(const beta_distribution<RealType, Policy>& dist)
  297. //{ // Median of beta distribution is not defined.
  298. // return tools::domain_error<RealType>(function, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
  299. //} // median
  300. //But WILL be provided by the derived accessor as quantile(0.5).
  301. template <class RealType, class Policy>
  302. inline RealType skewness(const beta_distribution<RealType, Policy>& dist)
  303. {
  304. BOOST_MATH_STD_USING // ADL of std functions.
  305. RealType a = dist.alpha();
  306. RealType b = dist.beta();
  307. return (2 * (b-a) * sqrt(a + b + 1)) / ((a + b + 2) * sqrt(a * b));
  308. } // skewness
  309. template <class RealType, class Policy>
  310. inline RealType kurtosis_excess(const beta_distribution<RealType, Policy>& dist)
  311. {
  312. RealType a = dist.alpha();
  313. RealType b = dist.beta();
  314. RealType a_2 = a * a;
  315. RealType n = 6 * (a_2 * a - a_2 * (2 * b - 1) + b * b * (b + 1) - 2 * a * b * (b + 2));
  316. RealType d = a * b * (a + b + 2) * (a + b + 3);
  317. return n / d;
  318. } // kurtosis_excess
  319. template <class RealType, class Policy>
  320. inline RealType kurtosis(const beta_distribution<RealType, Policy>& dist)
  321. {
  322. return 3 + kurtosis_excess(dist);
  323. } // kurtosis
  324. template <class RealType, class Policy>
  325. inline RealType pdf(const beta_distribution<RealType, Policy>& dist, const RealType& x)
  326. { // Probability Density/Mass Function.
  327. BOOST_FPU_EXCEPTION_GUARD
  328. static const char* function = "boost::math::pdf(beta_distribution<%1%> const&, %1%)";
  329. BOOST_MATH_STD_USING // for ADL of std functions
  330. RealType a = dist.alpha();
  331. RealType b = dist.beta();
  332. // Argument checks:
  333. RealType result = 0;
  334. if(false == beta_detail::check_dist_and_x(
  335. function,
  336. a, b, x,
  337. &result, Policy()))
  338. {
  339. return result;
  340. }
  341. using boost::math::beta;
  342. // Corner case: check_x ensures x element of [0, 1], but PDF is 0 for x = 0 and x = 1. PDF EQN:
  343. // https://wikimedia.org/api/rest_v1/media/math/render/svg/125fdaa41844a8703d1a8610ac00fbf3edacc8e7
  344. if(x == 0 || x == 1)
  345. {
  346. return RealType(0);
  347. }
  348. return ibeta_derivative(a, b, x, Policy());
  349. } // pdf
  350. template <class RealType, class Policy>
  351. inline RealType cdf(const beta_distribution<RealType, Policy>& dist, const RealType& x)
  352. { // Cumulative Distribution Function beta.
  353. BOOST_MATH_STD_USING // for ADL of std functions
  354. static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)";
  355. RealType a = dist.alpha();
  356. RealType b = dist.beta();
  357. // Argument checks:
  358. RealType result = 0;
  359. if(false == beta_detail::check_dist_and_x(
  360. function,
  361. a, b, x,
  362. &result, Policy()))
  363. {
  364. return result;
  365. }
  366. // Special cases:
  367. if (x == 0)
  368. {
  369. return 0;
  370. }
  371. else if (x == 1)
  372. {
  373. return 1;
  374. }
  375. return ibeta(a, b, x, Policy());
  376. } // beta cdf
  377. template <class RealType, class Policy>
  378. inline RealType cdf(const complemented2_type<beta_distribution<RealType, Policy>, RealType>& c)
  379. { // Complemented Cumulative Distribution Function beta.
  380. BOOST_MATH_STD_USING // for ADL of std functions
  381. static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)";
  382. RealType const& x = c.param;
  383. beta_distribution<RealType, Policy> const& dist = c.dist;
  384. RealType a = dist.alpha();
  385. RealType b = dist.beta();
  386. // Argument checks:
  387. RealType result = 0;
  388. if(false == beta_detail::check_dist_and_x(
  389. function,
  390. a, b, x,
  391. &result, Policy()))
  392. {
  393. return result;
  394. }
  395. if (x == 0)
  396. {
  397. return 1;
  398. }
  399. else if (x == 1)
  400. {
  401. return 0;
  402. }
  403. // Calculate cdf beta using the incomplete beta function.
  404. // Use of ibeta here prevents cancellation errors in calculating
  405. // 1 - x if x is very small, perhaps smaller than machine epsilon.
  406. return ibetac(a, b, x, Policy());
  407. } // beta cdf
  408. template <class RealType, class Policy>
  409. inline RealType quantile(const beta_distribution<RealType, Policy>& dist, const RealType& p)
  410. { // Quantile or Percent Point beta function or
  411. // Inverse Cumulative probability distribution function CDF.
  412. // Return x (0 <= x <= 1),
  413. // for a given probability p (0 <= p <= 1).
  414. // These functions take a probability as an argument
  415. // and return a value such that the probability that a random variable x
  416. // will be less than or equal to that value
  417. // is whatever probability you supplied as an argument.
  418. static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)";
  419. RealType result = 0; // of argument checks:
  420. RealType a = dist.alpha();
  421. RealType b = dist.beta();
  422. if(false == beta_detail::check_dist_and_prob(
  423. function,
  424. a, b, p,
  425. &result, Policy()))
  426. {
  427. return result;
  428. }
  429. // Special cases:
  430. if (p == 0)
  431. {
  432. return 0;
  433. }
  434. if (p == 1)
  435. {
  436. return 1;
  437. }
  438. return ibeta_inv(a, b, p, static_cast<RealType*>(0), Policy());
  439. } // quantile
  440. template <class RealType, class Policy>
  441. inline RealType quantile(const complemented2_type<beta_distribution<RealType, Policy>, RealType>& c)
  442. { // Complement Quantile or Percent Point beta function .
  443. // Return the number of expected x for a given
  444. // complement of the probability q.
  445. static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)";
  446. //
  447. // Error checks:
  448. RealType q = c.param;
  449. const beta_distribution<RealType, Policy>& dist = c.dist;
  450. RealType result = 0;
  451. RealType a = dist.alpha();
  452. RealType b = dist.beta();
  453. if(false == beta_detail::check_dist_and_prob(
  454. function,
  455. a,
  456. b,
  457. q,
  458. &result, Policy()))
  459. {
  460. return result;
  461. }
  462. // Special cases:
  463. if(q == 1)
  464. {
  465. return 0;
  466. }
  467. if(q == 0)
  468. {
  469. return 1;
  470. }
  471. return ibetac_inv(a, b, q, static_cast<RealType*>(0), Policy());
  472. } // Quantile Complement
  473. } // namespace math
  474. } // namespace boost
  475. // This include must be at the end, *after* the accessors
  476. // for this distribution have been defined, in order to
  477. // keep compilers that support two-phase lookup happy.
  478. #include <boost/math/distributions/detail/derived_accessors.hpp>
  479. #if defined (BOOST_MSVC)
  480. # pragma warning(pop)
  481. #endif
  482. #endif // BOOST_MATH_DIST_BETA_HPP