non_central_f.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // boost\math\distributions\non_central_f.hpp
  2. // Copyright John Maddock 2008.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP
  8. #define BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP
  9. #include <boost/math/distributions/non_central_beta.hpp>
  10. #include <boost/math/distributions/detail/generic_mode.hpp>
  11. #include <boost/math/special_functions/pow.hpp>
  12. namespace boost
  13. {
  14. namespace math
  15. {
  16. template <class RealType = double, class Policy = policies::policy<> >
  17. class non_central_f_distribution
  18. {
  19. public:
  20. typedef RealType value_type;
  21. typedef Policy policy_type;
  22. non_central_f_distribution(RealType v1_, RealType v2_, RealType lambda) : v1(v1_), v2(v2_), ncp(lambda)
  23. {
  24. const char* function = "boost::math::non_central_f_distribution<%1%>::non_central_f_distribution(%1%,%1%)";
  25. RealType r;
  26. detail::check_df(
  27. function,
  28. v1, &r, Policy());
  29. detail::check_df(
  30. function,
  31. v2, &r, Policy());
  32. detail::check_non_centrality(
  33. function,
  34. lambda,
  35. &r,
  36. Policy());
  37. } // non_central_f_distribution constructor.
  38. RealType degrees_of_freedom1()const
  39. {
  40. return v1;
  41. }
  42. RealType degrees_of_freedom2()const
  43. {
  44. return v2;
  45. }
  46. RealType non_centrality() const
  47. { // Private data getter function.
  48. return ncp;
  49. }
  50. private:
  51. // Data member, initialized by constructor.
  52. RealType v1; // alpha.
  53. RealType v2; // beta.
  54. RealType ncp; // non-centrality parameter
  55. }; // template <class RealType, class Policy> class non_central_f_distribution
  56. typedef non_central_f_distribution<double> non_central_f; // Reserved name of type double.
  57. #ifdef __cpp_deduction_guides
  58. template <class RealType>
  59. non_central_f_distribution(RealType,RealType,RealType)->non_central_f_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  60. #endif
  61. // Non-member functions to give properties of the distribution.
  62. template <class RealType, class Policy>
  63. inline const std::pair<RealType, RealType> range(const non_central_f_distribution<RealType, Policy>& /* dist */)
  64. { // Range of permissible values for random variable k.
  65. using boost::math::tools::max_value;
  66. return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
  67. }
  68. template <class RealType, class Policy>
  69. inline const std::pair<RealType, RealType> support(const non_central_f_distribution<RealType, Policy>& /* dist */)
  70. { // Range of supported values for random variable k.
  71. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  72. using boost::math::tools::max_value;
  73. return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
  74. }
  75. template <class RealType, class Policy>
  76. inline RealType mean(const non_central_f_distribution<RealType, Policy>& dist)
  77. {
  78. const char* function = "mean(non_central_f_distribution<%1%> const&)";
  79. RealType v1 = dist.degrees_of_freedom1();
  80. RealType v2 = dist.degrees_of_freedom2();
  81. RealType l = dist.non_centrality();
  82. RealType r;
  83. if(!detail::check_df(
  84. function,
  85. v1, &r, Policy())
  86. ||
  87. !detail::check_df(
  88. function,
  89. v2, &r, Policy())
  90. ||
  91. !detail::check_non_centrality(
  92. function,
  93. l,
  94. &r,
  95. Policy()))
  96. return r;
  97. if(v2 <= 2)
  98. return policies::raise_domain_error(
  99. function,
  100. "Second degrees of freedom parameter was %1%, but must be > 2 !",
  101. v2, Policy());
  102. return v2 * (v1 + l) / (v1 * (v2 - 2));
  103. } // mean
  104. template <class RealType, class Policy>
  105. inline RealType mode(const non_central_f_distribution<RealType, Policy>& dist)
  106. { // mode.
  107. static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)";
  108. RealType n = dist.degrees_of_freedom1();
  109. RealType m = dist.degrees_of_freedom2();
  110. RealType l = dist.non_centrality();
  111. RealType r;
  112. if(!detail::check_df(
  113. function,
  114. n, &r, Policy())
  115. ||
  116. !detail::check_df(
  117. function,
  118. m, &r, Policy())
  119. ||
  120. !detail::check_non_centrality(
  121. function,
  122. l,
  123. &r,
  124. Policy()))
  125. return r;
  126. RealType guess = m > 2 ? RealType(m * (n + l) / (n * (m - 2))) : RealType(1);
  127. return detail::generic_find_mode(
  128. dist,
  129. guess,
  130. function);
  131. }
  132. template <class RealType, class Policy>
  133. inline RealType variance(const non_central_f_distribution<RealType, Policy>& dist)
  134. { // variance.
  135. const char* function = "variance(non_central_f_distribution<%1%> const&)";
  136. RealType n = dist.degrees_of_freedom1();
  137. RealType m = dist.degrees_of_freedom2();
  138. RealType l = dist.non_centrality();
  139. RealType r;
  140. if(!detail::check_df(
  141. function,
  142. n, &r, Policy())
  143. ||
  144. !detail::check_df(
  145. function,
  146. m, &r, Policy())
  147. ||
  148. !detail::check_non_centrality(
  149. function,
  150. l,
  151. &r,
  152. Policy()))
  153. return r;
  154. if(m <= 4)
  155. return policies::raise_domain_error(
  156. function,
  157. "Second degrees of freedom parameter was %1%, but must be > 4 !",
  158. m, Policy());
  159. RealType result = 2 * m * m * ((n + l) * (n + l)
  160. + (m - 2) * (n + 2 * l));
  161. result /= (m - 4) * (m - 2) * (m - 2) * n * n;
  162. return result;
  163. }
  164. // RealType standard_deviation(const non_central_f_distribution<RealType, Policy>& dist)
  165. // standard_deviation provided by derived accessors.
  166. template <class RealType, class Policy>
  167. inline RealType skewness(const non_central_f_distribution<RealType, Policy>& dist)
  168. { // skewness = sqrt(l).
  169. const char* function = "skewness(non_central_f_distribution<%1%> const&)";
  170. BOOST_MATH_STD_USING
  171. RealType n = dist.degrees_of_freedom1();
  172. RealType m = dist.degrees_of_freedom2();
  173. RealType l = dist.non_centrality();
  174. RealType r;
  175. if(!detail::check_df(
  176. function,
  177. n, &r, Policy())
  178. ||
  179. !detail::check_df(
  180. function,
  181. m, &r, Policy())
  182. ||
  183. !detail::check_non_centrality(
  184. function,
  185. l,
  186. &r,
  187. Policy()))
  188. return r;
  189. if(m <= 6)
  190. return policies::raise_domain_error(
  191. function,
  192. "Second degrees of freedom parameter was %1%, but must be > 6 !",
  193. m, Policy());
  194. RealType result = 2 * constants::root_two<RealType>();
  195. result *= sqrt(m - 4);
  196. result *= (n * (m + n - 2) *(m + 2 * n - 2)
  197. + 3 * (m + n - 2) * (m + 2 * n - 2) * l
  198. + 6 * (m + n - 2) * l * l + 2 * l * l * l);
  199. result /= (m - 6) * pow(n * (m + n - 2) + 2 * (m + n - 2) * l + l * l, RealType(1.5f));
  200. return result;
  201. }
  202. template <class RealType, class Policy>
  203. inline RealType kurtosis_excess(const non_central_f_distribution<RealType, Policy>& dist)
  204. {
  205. const char* function = "kurtosis_excess(non_central_f_distribution<%1%> const&)";
  206. BOOST_MATH_STD_USING
  207. RealType n = dist.degrees_of_freedom1();
  208. RealType m = dist.degrees_of_freedom2();
  209. RealType l = dist.non_centrality();
  210. RealType r;
  211. if(!detail::check_df(
  212. function,
  213. n, &r, Policy())
  214. ||
  215. !detail::check_df(
  216. function,
  217. m, &r, Policy())
  218. ||
  219. !detail::check_non_centrality(
  220. function,
  221. l,
  222. &r,
  223. Policy()))
  224. return r;
  225. if(m <= 8)
  226. return policies::raise_domain_error(
  227. function,
  228. "Second degrees of freedom parameter was %1%, but must be > 8 !",
  229. m, Policy());
  230. RealType l2 = l * l;
  231. RealType l3 = l2 * l;
  232. RealType l4 = l2 * l2;
  233. RealType result = (3 * (m - 4) * (n * (m + n - 2)
  234. * (4 * (m - 2) * (m - 2)
  235. + (m - 2) * (m + 10) * n
  236. + (10 + m) * n * n)
  237. + 4 * (m + n - 2) * (4 * (m - 2) * (m - 2)
  238. + (m - 2) * (10 + m) * n
  239. + (10 + m) * n * n) * l + 2 * (10 + m)
  240. * (m + n - 2) * (2 * m + 3 * n - 4) * l2
  241. + 4 * (10 + m) * (-2 + m + n) * l3
  242. + (10 + m) * l4))
  243. /
  244. ((-8 + m) * (-6 + m) * boost::math::pow<2>(n * (-2 + m + n)
  245. + 2 * (-2 + m + n) * l + l2));
  246. return result;
  247. } // kurtosis_excess
  248. template <class RealType, class Policy>
  249. inline RealType kurtosis(const non_central_f_distribution<RealType, Policy>& dist)
  250. {
  251. return kurtosis_excess(dist) + 3;
  252. }
  253. template <class RealType, class Policy>
  254. inline RealType pdf(const non_central_f_distribution<RealType, Policy>& dist, const RealType& x)
  255. { // Probability Density/Mass Function.
  256. typedef typename policies::evaluation<RealType, Policy>::type value_type;
  257. typedef typename policies::normalise<
  258. Policy,
  259. policies::promote_float<false>,
  260. policies::promote_double<false>,
  261. policies::discrete_quantile<>,
  262. policies::assert_undefined<> >::type forwarding_policy;
  263. value_type alpha = dist.degrees_of_freedom1() / 2;
  264. value_type beta = dist.degrees_of_freedom2() / 2;
  265. value_type y = x * alpha / beta;
  266. value_type r = pdf(boost::math::non_central_beta_distribution<value_type, forwarding_policy>(alpha, beta, dist.non_centrality()), y / (1 + y));
  267. return policies::checked_narrowing_cast<RealType, forwarding_policy>(
  268. r * (dist.degrees_of_freedom1() / dist.degrees_of_freedom2()) / ((1 + y) * (1 + y)),
  269. "pdf(non_central_f_distribution<%1%>, %1%)");
  270. } // pdf
  271. template <class RealType, class Policy>
  272. RealType cdf(const non_central_f_distribution<RealType, Policy>& dist, const RealType& x)
  273. {
  274. const char* function = "cdf(const non_central_f_distribution<%1%>&, %1%)";
  275. RealType r;
  276. if(!detail::check_df(
  277. function,
  278. dist.degrees_of_freedom1(), &r, Policy())
  279. ||
  280. !detail::check_df(
  281. function,
  282. dist.degrees_of_freedom2(), &r, Policy())
  283. ||
  284. !detail::check_non_centrality(
  285. function,
  286. dist.non_centrality(),
  287. &r,
  288. Policy()))
  289. return r;
  290. if((x < 0) || !(boost::math::isfinite)(x))
  291. {
  292. return policies::raise_domain_error<RealType>(
  293. function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy());
  294. }
  295. RealType alpha = dist.degrees_of_freedom1() / 2;
  296. RealType beta = dist.degrees_of_freedom2() / 2;
  297. RealType y = x * alpha / beta;
  298. RealType c = y / (1 + y);
  299. RealType cp = 1 / (1 + y);
  300. //
  301. // To ensure accuracy, we pass both x and 1-x to the
  302. // non-central beta cdf routine, this ensures accuracy
  303. // even when we compute x to be ~ 1:
  304. //
  305. r = detail::non_central_beta_cdf(c, cp, alpha, beta,
  306. dist.non_centrality(), false, Policy());
  307. return r;
  308. } // cdf
  309. template <class RealType, class Policy>
  310. RealType cdf(const complemented2_type<non_central_f_distribution<RealType, Policy>, RealType>& c)
  311. { // Complemented Cumulative Distribution Function
  312. const char* function = "cdf(complement(const non_central_f_distribution<%1%>&, %1%))";
  313. RealType r;
  314. if(!detail::check_df(
  315. function,
  316. c.dist.degrees_of_freedom1(), &r, Policy())
  317. ||
  318. !detail::check_df(
  319. function,
  320. c.dist.degrees_of_freedom2(), &r, Policy())
  321. ||
  322. !detail::check_non_centrality(
  323. function,
  324. c.dist.non_centrality(),
  325. &r,
  326. Policy()))
  327. return r;
  328. if((c.param < 0) || !(boost::math::isfinite)(c.param))
  329. {
  330. return policies::raise_domain_error<RealType>(
  331. function, "Random Variable parameter was %1%, but must be > 0 !", c.param, Policy());
  332. }
  333. RealType alpha = c.dist.degrees_of_freedom1() / 2;
  334. RealType beta = c.dist.degrees_of_freedom2() / 2;
  335. RealType y = c.param * alpha / beta;
  336. RealType x = y / (1 + y);
  337. RealType cx = 1 / (1 + y);
  338. //
  339. // To ensure accuracy, we pass both x and 1-x to the
  340. // non-central beta cdf routine, this ensures accuracy
  341. // even when we compute x to be ~ 1:
  342. //
  343. r = detail::non_central_beta_cdf(x, cx, alpha, beta,
  344. c.dist.non_centrality(), true, Policy());
  345. return r;
  346. } // ccdf
  347. template <class RealType, class Policy>
  348. inline RealType quantile(const non_central_f_distribution<RealType, Policy>& dist, const RealType& p)
  349. { // Quantile (or Percent Point) function.
  350. RealType alpha = dist.degrees_of_freedom1() / 2;
  351. RealType beta = dist.degrees_of_freedom2() / 2;
  352. RealType x = quantile(boost::math::non_central_beta_distribution<RealType, Policy>(alpha, beta, dist.non_centrality()), p);
  353. if(x == 1)
  354. return policies::raise_overflow_error<RealType>(
  355. "quantile(const non_central_f_distribution<%1%>&, %1%)",
  356. "Result of non central F quantile is too large to represent.",
  357. Policy());
  358. return (x / (1 - x)) * (dist.degrees_of_freedom2() / dist.degrees_of_freedom1());
  359. } // quantile
  360. template <class RealType, class Policy>
  361. inline RealType quantile(const complemented2_type<non_central_f_distribution<RealType, Policy>, RealType>& c)
  362. { // Quantile (or Percent Point) function.
  363. RealType alpha = c.dist.degrees_of_freedom1() / 2;
  364. RealType beta = c.dist.degrees_of_freedom2() / 2;
  365. RealType x = quantile(complement(boost::math::non_central_beta_distribution<RealType, Policy>(alpha, beta, c.dist.non_centrality()), c.param));
  366. if(x == 1)
  367. return policies::raise_overflow_error<RealType>(
  368. "quantile(complement(const non_central_f_distribution<%1%>&, %1%))",
  369. "Result of non central F quantile is too large to represent.",
  370. Policy());
  371. return (x / (1 - x)) * (c.dist.degrees_of_freedom2() / c.dist.degrees_of_freedom1());
  372. } // quantile complement.
  373. } // namespace math
  374. } // namespace boost
  375. // This include must be at the end, *after* the accessors
  376. // for this distribution have been defined, in order to
  377. // keep compilers that support two-phase lookup happy.
  378. #include <boost/math/distributions/detail/derived_accessors.hpp>
  379. #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP