non_central_f.hpp 16 KB

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