univariate_statistics_test.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /*
  2. * (C) Copyright Nick Thompson 2018.
  3. * Use, modification and distribution are subject to the
  4. * Boost Software License, Version 1.0. (See accompanying file
  5. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #include <vector>
  8. #include <array>
  9. #include <forward_list>
  10. #include <algorithm>
  11. #include <random>
  12. #include <boost/core/lightweight_test.hpp>
  13. #include <boost/numeric/ublas/vector.hpp>
  14. #include <boost/math/constants/constants.hpp>
  15. #include <boost/math/statistics/univariate_statistics.hpp>
  16. #include <boost/multiprecision/cpp_bin_float.hpp>
  17. #include <boost/multiprecision/cpp_complex.hpp>
  18. using boost::multiprecision::cpp_bin_float_50;
  19. using boost::multiprecision::cpp_complex_50;
  20. /*
  21. * Test checklist:
  22. * 1) Does it work with multiprecision?
  23. * 2) Does it work with .cbegin()/.cend() if the data is not altered?
  24. * 3) Does it work with ublas and std::array? (Checking Eigen and Armadillo will make the CI system really unhappy.)
  25. * 4) Does it work with std::forward_list if a forward iterator is all that is required?
  26. * 5) Does it work with complex data if complex data is sensible?
  27. */
  28. // To stress test, set global_seed = 0, global_size = huge.
  29. static const constexpr size_t global_seed = 0;
  30. static const constexpr size_t global_size = 128;
  31. template<class T>
  32. std::vector<T> generate_random_vector(size_t size, size_t seed)
  33. {
  34. if (seed == 0)
  35. {
  36. std::random_device rd;
  37. seed = rd();
  38. }
  39. std::vector<T> v(size);
  40. std::mt19937 gen(seed);
  41. if constexpr (std::is_floating_point<T>::value)
  42. {
  43. std::normal_distribution<T> dis(0, 1);
  44. for (size_t i = 0; i < v.size(); ++i)
  45. {
  46. v[i] = dis(gen);
  47. }
  48. return v;
  49. }
  50. else if constexpr (std::is_integral<T>::value)
  51. {
  52. // Rescaling by larger than 2 is UB!
  53. std::uniform_int_distribution<T> dis(std::numeric_limits<T>::lowest()/2, (std::numeric_limits<T>::max)()/2);
  54. for (size_t i = 0; i < v.size(); ++i)
  55. {
  56. v[i] = dis(gen);
  57. }
  58. return v;
  59. }
  60. else if constexpr (boost::is_complex<T>::value)
  61. {
  62. std::normal_distribution<typename T::value_type> dis(0, 1);
  63. for (size_t i = 0; i < v.size(); ++i)
  64. {
  65. v[i] = {dis(gen), dis(gen)};
  66. }
  67. return v;
  68. }
  69. else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_complex)
  70. {
  71. std::normal_distribution<long double> dis(0, 1);
  72. for (size_t i = 0; i < v.size(); ++i)
  73. {
  74. v[i] = {dis(gen), dis(gen)};
  75. }
  76. return v;
  77. }
  78. else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_floating_point)
  79. {
  80. std::normal_distribution<long double> dis(0, 1);
  81. for (size_t i = 0; i < v.size(); ++i)
  82. {
  83. v[i] = dis(gen);
  84. }
  85. return v;
  86. }
  87. else
  88. {
  89. BOOST_ASSERT_MSG(false, "Could not identify type for random vector generation.");
  90. return v;
  91. }
  92. }
  93. template<class Z>
  94. void test_integer_mean()
  95. {
  96. double tol = 100*std::numeric_limits<double>::epsilon();
  97. std::vector<Z> v{1,2,3,4,5};
  98. double mu = boost::math::statistics::mean(v);
  99. BOOST_TEST(abs(mu - 3) < tol);
  100. // Work with std::array?
  101. std::array<Z, 5> w{1,2,3,4,5};
  102. mu = boost::math::statistics::mean(w);
  103. BOOST_TEST(abs(mu - 3) < tol);
  104. v = generate_random_vector<Z>(global_size, global_seed);
  105. Z scale = 2;
  106. double m1 = scale*boost::math::statistics::mean(v);
  107. for (auto & x : v)
  108. {
  109. x *= scale;
  110. }
  111. double m2 = boost::math::statistics::mean(v);
  112. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  113. }
  114. template<class RandomAccessContainer>
  115. auto naive_mean(RandomAccessContainer const & v)
  116. {
  117. typename RandomAccessContainer::value_type sum = 0;
  118. for (auto & x : v)
  119. {
  120. sum += x;
  121. }
  122. return sum/v.size();
  123. }
  124. template<class Real>
  125. void test_mean()
  126. {
  127. Real tol = std::numeric_limits<Real>::epsilon();
  128. std::vector<Real> v{1,2,3,4,5};
  129. Real mu = boost::math::statistics::mean(v.begin(), v.end());
  130. BOOST_TEST(abs(mu - 3) < tol);
  131. // Does range call work?
  132. mu = boost::math::statistics::mean(v);
  133. BOOST_TEST(abs(mu - 3) < tol);
  134. // Can we successfully average only part of the vector?
  135. mu = boost::math::statistics::mean(v.begin(), v.begin() + 3);
  136. BOOST_TEST(abs(mu - 2) < tol);
  137. // Does it work when we const qualify?
  138. mu = boost::math::statistics::mean(v.cbegin(), v.cend());
  139. BOOST_TEST(abs(mu - 3) < tol);
  140. // Does it work for std::array?
  141. std::array<Real, 7> u{1,2,3,4,5,6,7};
  142. mu = boost::math::statistics::mean(u.begin(), u.end());
  143. BOOST_TEST(abs(mu - 4) < tol);
  144. // Does it work for a forward iterator?
  145. std::forward_list<Real> l{1,2,3,4,5,6,7};
  146. mu = boost::math::statistics::mean(l.begin(), l.end());
  147. BOOST_TEST(abs(mu - 4) < tol);
  148. // Does it work with ublas vectors?
  149. boost::numeric::ublas::vector<Real> w(7);
  150. for (size_t i = 0; i < w.size(); ++i)
  151. {
  152. w[i] = i+1;
  153. }
  154. mu = boost::math::statistics::mean(w.cbegin(), w.cend());
  155. BOOST_TEST(abs(mu - 4) < tol);
  156. v = generate_random_vector<Real>(global_size, global_seed);
  157. Real scale = 2;
  158. Real m1 = scale*boost::math::statistics::mean(v);
  159. for (auto & x : v)
  160. {
  161. x *= scale;
  162. }
  163. Real m2 = boost::math::statistics::mean(v);
  164. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  165. // Stress test:
  166. for (size_t i = 1; i < 30; ++i)
  167. {
  168. v = generate_random_vector<Real>(i, 12803);
  169. auto naive_ = naive_mean(v);
  170. auto higham_ = boost::math::statistics::mean(v);
  171. if (abs(higham_ - naive_) >= 100*tol*abs(naive_))
  172. {
  173. std::cout << std::hexfloat;
  174. std::cout << "Terms = " << v.size() << "\n";
  175. std::cout << "higham = " << higham_ << "\n";
  176. std::cout << "naive_ = " << naive_ << "\n";
  177. }
  178. BOOST_TEST(abs(higham_ - naive_) < 100*tol*abs(naive_));
  179. }
  180. }
  181. template<class Complex>
  182. void test_complex_mean()
  183. {
  184. typedef typename Complex::value_type Real;
  185. Real tol = std::numeric_limits<Real>::epsilon();
  186. std::vector<Complex> v{{0,1},{0,2},{0,3},{0,4},{0,5}};
  187. auto mu = boost::math::statistics::mean(v.begin(), v.end());
  188. BOOST_TEST(abs(mu.imag() - 3) < tol);
  189. BOOST_TEST(abs(mu.real()) < tol);
  190. // Does range work?
  191. mu = boost::math::statistics::mean(v);
  192. BOOST_TEST(abs(mu.imag() - 3) < tol);
  193. BOOST_TEST(abs(mu.real()) < tol);
  194. }
  195. template<class Real>
  196. void test_variance()
  197. {
  198. Real tol = std::numeric_limits<Real>::epsilon();
  199. std::vector<Real> v{1,1,1,1,1,1};
  200. Real sigma_sq = boost::math::statistics::variance(v.begin(), v.end());
  201. BOOST_TEST(abs(sigma_sq) < tol);
  202. sigma_sq = boost::math::statistics::variance(v);
  203. BOOST_TEST(abs(sigma_sq) < tol);
  204. Real s_sq = boost::math::statistics::sample_variance(v);
  205. BOOST_TEST(abs(s_sq) < tol);
  206. std::vector<Real> u{1};
  207. sigma_sq = boost::math::statistics::variance(u.cbegin(), u.cend());
  208. BOOST_TEST(abs(sigma_sq) < tol);
  209. std::array<Real, 8> w{0,1,0,1,0,1,0,1};
  210. sigma_sq = boost::math::statistics::variance(w.begin(), w.end());
  211. BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
  212. sigma_sq = boost::math::statistics::variance(w);
  213. BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
  214. std::forward_list<Real> l{0,1,0,1,0,1,0,1};
  215. sigma_sq = boost::math::statistics::variance(l.begin(), l.end());
  216. BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
  217. v = generate_random_vector<Real>(global_size, global_seed);
  218. Real scale = 2;
  219. Real m1 = scale*scale*boost::math::statistics::variance(v);
  220. for (auto & x : v)
  221. {
  222. x *= scale;
  223. }
  224. Real m2 = boost::math::statistics::variance(v);
  225. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  226. // Wikipedia example for a variance of N sided die:
  227. // https://en.wikipedia.org/wiki/Variance
  228. for (size_t j = 16; j < 2048; j *= 2)
  229. {
  230. v.resize(1024);
  231. Real n = v.size();
  232. for (size_t i = 0; i < v.size(); ++i)
  233. {
  234. v[i] = i + 1;
  235. }
  236. sigma_sq = boost::math::statistics::variance(v);
  237. BOOST_TEST(abs(sigma_sq - (n*n-1)/Real(12)) <= tol*sigma_sq);
  238. }
  239. }
  240. template<class Z>
  241. void test_integer_variance()
  242. {
  243. double tol = std::numeric_limits<double>::epsilon();
  244. std::vector<Z> v{1,1,1,1,1,1};
  245. double sigma_sq = boost::math::statistics::variance(v);
  246. BOOST_TEST(abs(sigma_sq) < tol);
  247. std::forward_list<Z> l{0,1,0,1,0,1,0,1};
  248. sigma_sq = boost::math::statistics::variance(l.begin(), l.end());
  249. BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
  250. v = generate_random_vector<Z>(global_size, global_seed);
  251. Z scale = 2;
  252. double m1 = scale*scale*boost::math::statistics::variance(v);
  253. for (auto & x : v)
  254. {
  255. x *= scale;
  256. }
  257. double m2 = boost::math::statistics::variance(v);
  258. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  259. }
  260. template<class Z>
  261. void test_integer_skewness()
  262. {
  263. double tol = std::numeric_limits<double>::epsilon();
  264. std::vector<Z> v{1,1,1};
  265. double skew = boost::math::statistics::skewness(v);
  266. BOOST_TEST(abs(skew) < tol);
  267. // Dataset is symmetric about the mean:
  268. v = {1,2,3,4,5};
  269. skew = boost::math::statistics::skewness(v);
  270. BOOST_TEST(abs(skew) < tol);
  271. v = {0,0,0,0,5};
  272. // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2
  273. skew = boost::math::statistics::skewness(v);
  274. BOOST_TEST(abs(skew - 3.0/2.0) < tol);
  275. std::forward_list<Z> v2{0,0,0,0,5};
  276. skew = boost::math::statistics::skewness(v);
  277. BOOST_TEST(abs(skew - 3.0/2.0) < tol);
  278. v = generate_random_vector<Z>(global_size, global_seed);
  279. Z scale = 2;
  280. double m1 = boost::math::statistics::skewness(v);
  281. for (auto & x : v)
  282. {
  283. x *= scale;
  284. }
  285. double m2 = boost::math::statistics::skewness(v);
  286. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  287. }
  288. template<class Real>
  289. void test_skewness()
  290. {
  291. Real tol = std::numeric_limits<Real>::epsilon();
  292. std::vector<Real> v{1,1,1};
  293. Real skew = boost::math::statistics::skewness(v);
  294. BOOST_TEST(abs(skew) < tol);
  295. // Dataset is symmetric about the mean:
  296. v = {1,2,3,4,5};
  297. skew = boost::math::statistics::skewness(v);
  298. BOOST_TEST(abs(skew) < tol);
  299. v = {0,0,0,0,5};
  300. // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2
  301. skew = boost::math::statistics::skewness(v);
  302. BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
  303. std::array<Real, 5> w1{0,0,0,0,5};
  304. skew = boost::math::statistics::skewness(w1);
  305. BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
  306. std::forward_list<Real> w2{0,0,0,0,5};
  307. skew = boost::math::statistics::skewness(w2);
  308. BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
  309. v = generate_random_vector<Real>(global_size, global_seed);
  310. Real scale = 2;
  311. Real m1 = boost::math::statistics::skewness(v);
  312. for (auto & x : v)
  313. {
  314. x *= scale;
  315. }
  316. Real m2 = boost::math::statistics::skewness(v);
  317. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  318. }
  319. template<class Real>
  320. void test_kurtosis()
  321. {
  322. Real tol = std::numeric_limits<Real>::epsilon();
  323. std::vector<Real> v{1,1,1};
  324. Real kurt = boost::math::statistics::kurtosis(v);
  325. BOOST_TEST(abs(kurt) < tol);
  326. v = {1,2,3,4,5};
  327. // mu =1, sigma^2 = 2, kurtosis = 17/10
  328. kurt = boost::math::statistics::kurtosis(v);
  329. BOOST_TEST(abs(kurt - Real(17)/Real(10)) < tol);
  330. v = {0,0,0,0,5};
  331. // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2, kurtosis = 13/4
  332. kurt = boost::math::statistics::kurtosis(v);
  333. BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
  334. std::array<Real, 5> v1{0,0,0,0,5};
  335. kurt = boost::math::statistics::kurtosis(v1);
  336. BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
  337. std::forward_list<Real> v2{0,0,0,0,5};
  338. kurt = boost::math::statistics::kurtosis(v2);
  339. BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
  340. std::vector<Real> v3(10000);
  341. std::mt19937 gen(42);
  342. std::normal_distribution<long double> dis(0, 1);
  343. for (size_t i = 0; i < v3.size(); ++i) {
  344. v3[i] = dis(gen);
  345. }
  346. kurt = boost::math::statistics::kurtosis(v3);
  347. BOOST_TEST(abs(kurt - 3) < 0.1);
  348. std::uniform_real_distribution<long double> udis(-1, 3);
  349. for (size_t i = 0; i < v3.size(); ++i) {
  350. v3[i] = udis(gen);
  351. }
  352. auto excess_kurtosis = boost::math::statistics::excess_kurtosis(v3);
  353. BOOST_TEST(abs(excess_kurtosis + 6.0/5.0) < 0.2);
  354. v = generate_random_vector<Real>(global_size, global_seed);
  355. Real scale = 2;
  356. Real m1 = boost::math::statistics::kurtosis(v);
  357. for (auto & x : v)
  358. {
  359. x *= scale;
  360. }
  361. Real m2 = boost::math::statistics::kurtosis(v);
  362. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  363. // This test only passes when there are a large number of samples.
  364. // Otherwise, the distribution doesn't generate enough outliers to give,
  365. // or generates too many, giving pretty wildly different values of kurtosis on different runs.
  366. // However, by kicking up the samples to 1,000,000, I got very close to 6 for the excess kurtosis on every run.
  367. // The CI system, however, would die on a million long doubles.
  368. //v3.resize(1000000);
  369. //std::exponential_distribution<long double> edis(0.1);
  370. //for (size_t i = 0; i < v3.size(); ++i) {
  371. // v3[i] = edis(gen);
  372. //}
  373. //excess_kurtosis = boost::math::statistics::kurtosis(v3) - 3;
  374. //BOOST_TEST(abs(excess_kurtosis - 6.0) < 0.2);
  375. }
  376. template<class Z>
  377. void test_integer_kurtosis()
  378. {
  379. double tol = std::numeric_limits<double>::epsilon();
  380. std::vector<Z> v{1,1,1};
  381. double kurt = boost::math::statistics::kurtosis(v);
  382. BOOST_TEST(abs(kurt) < tol);
  383. v = {1,2,3,4,5};
  384. // mu =1, sigma^2 = 2, kurtosis = 17/10
  385. kurt = boost::math::statistics::kurtosis(v);
  386. BOOST_TEST(abs(kurt - 17.0/10.0) < tol);
  387. v = {0,0,0,0,5};
  388. // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2, kurtosis = 13/4
  389. kurt = boost::math::statistics::kurtosis(v);
  390. BOOST_TEST(abs(kurt - 13.0/4.0) < tol);
  391. v = generate_random_vector<Z>(global_size, global_seed);
  392. Z scale = 2;
  393. double m1 = boost::math::statistics::kurtosis(v);
  394. for (auto & x : v)
  395. {
  396. x *= scale;
  397. }
  398. double m2 = boost::math::statistics::kurtosis(v);
  399. BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
  400. }
  401. template<class Real>
  402. void test_first_four_moments()
  403. {
  404. Real tol = 10*std::numeric_limits<Real>::epsilon();
  405. std::vector<Real> v{1,1,1};
  406. auto [M1_1, M2_1, M3_1, M4_1] = boost::math::statistics::first_four_moments(v);
  407. BOOST_TEST(abs(M1_1 - 1) < tol);
  408. BOOST_TEST(abs(M2_1) < tol);
  409. BOOST_TEST(abs(M3_1) < tol);
  410. BOOST_TEST(abs(M4_1) < tol);
  411. v = {1, 2, 3, 4, 5};
  412. auto [M1_2, M2_2, M3_2, M4_2] = boost::math::statistics::first_four_moments(v);
  413. BOOST_TEST(abs(M1_2 - 3) < tol);
  414. BOOST_TEST(abs(M2_2 - 2) < tol);
  415. BOOST_TEST(abs(M3_2) < tol);
  416. BOOST_TEST(abs(M4_2 - Real(34)/Real(5)) < tol);
  417. }
  418. template<class Real>
  419. void test_median()
  420. {
  421. std::mt19937 g(12);
  422. std::vector<Real> v{1,2,3,4,5,6,7};
  423. Real m = boost::math::statistics::median(v.begin(), v.end());
  424. BOOST_TEST_EQ(m, 4);
  425. std::shuffle(v.begin(), v.end(), g);
  426. // Does range call work?
  427. m = boost::math::statistics::median(v);
  428. BOOST_TEST_EQ(m, 4);
  429. v = {1,2,3,3,4,5};
  430. m = boost::math::statistics::median(v.begin(), v.end());
  431. BOOST_TEST_EQ(m, 3);
  432. std::shuffle(v.begin(), v.end(), g);
  433. m = boost::math::statistics::median(v.begin(), v.end());
  434. BOOST_TEST_EQ(m, 3);
  435. v = {1};
  436. m = boost::math::statistics::median(v.begin(), v.end());
  437. BOOST_TEST_EQ(m, 1);
  438. v = {1,1};
  439. m = boost::math::statistics::median(v.begin(), v.end());
  440. BOOST_TEST_EQ(m, 1);
  441. v = {2,4};
  442. m = boost::math::statistics::median(v.begin(), v.end());
  443. BOOST_TEST_EQ(m, 3);
  444. v = {1,1,1};
  445. m = boost::math::statistics::median(v.begin(), v.end());
  446. BOOST_TEST_EQ(m, 1);
  447. v = {1,2,3};
  448. m = boost::math::statistics::median(v.begin(), v.end());
  449. BOOST_TEST_EQ(m, 2);
  450. std::shuffle(v.begin(), v.end(), g);
  451. m = boost::math::statistics::median(v.begin(), v.end());
  452. BOOST_TEST_EQ(m, 2);
  453. // Does it work with std::array?
  454. std::array<Real, 3> w{1,2,3};
  455. m = boost::math::statistics::median(w);
  456. BOOST_TEST_EQ(m, 2);
  457. // Does it work with ublas?
  458. boost::numeric::ublas::vector<Real> w1(3);
  459. w1[0] = 1;
  460. w1[1] = 2;
  461. w1[2] = 3;
  462. m = boost::math::statistics::median(w);
  463. BOOST_TEST_EQ(m, 2);
  464. }
  465. template<class Real>
  466. void test_median_absolute_deviation()
  467. {
  468. std::vector<Real> v{-1, 2, -3, 4, -5, 6, -7};
  469. Real m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  470. BOOST_TEST_EQ(m, 4);
  471. std::mt19937 g(12);
  472. std::shuffle(v.begin(), v.end(), g);
  473. m = boost::math::statistics::median_absolute_deviation(v, 0);
  474. BOOST_TEST_EQ(m, 4);
  475. v = {1, -2, -3, 3, -4, -5};
  476. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  477. BOOST_TEST_EQ(m, 3);
  478. std::shuffle(v.begin(), v.end(), g);
  479. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  480. BOOST_TEST_EQ(m, 3);
  481. v = {-1};
  482. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  483. BOOST_TEST_EQ(m, 1);
  484. v = {-1, 1};
  485. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  486. BOOST_TEST_EQ(m, 1);
  487. // The median is zero, so coincides with the default:
  488. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
  489. BOOST_TEST_EQ(m, 1);
  490. m = boost::math::statistics::median_absolute_deviation(v);
  491. BOOST_TEST_EQ(m, 1);
  492. v = {2, -4};
  493. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  494. BOOST_TEST_EQ(m, 3);
  495. v = {1, -1, 1};
  496. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  497. BOOST_TEST_EQ(m, 1);
  498. v = {1, 2, -3};
  499. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  500. BOOST_TEST_EQ(m, 2);
  501. std::shuffle(v.begin(), v.end(), g);
  502. m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
  503. BOOST_TEST_EQ(m, 2);
  504. std::array<Real, 3> w{1, 2, -3};
  505. m = boost::math::statistics::median_absolute_deviation(w, 0);
  506. BOOST_TEST_EQ(m, 2);
  507. // boost.ublas vector?
  508. boost::numeric::ublas::vector<Real> u(6);
  509. u[0] = 1;
  510. u[1] = 2;
  511. u[2] = -3;
  512. u[3] = 1;
  513. u[4] = 2;
  514. u[5] = -3;
  515. m = boost::math::statistics::median_absolute_deviation(u, 0);
  516. BOOST_TEST_EQ(m, 2);
  517. }
  518. template<class Real>
  519. void test_sample_gini_coefficient()
  520. {
  521. Real tol = std::numeric_limits<Real>::epsilon();
  522. std::vector<Real> v{1,0,0};
  523. Real gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
  524. BOOST_TEST(abs(gini - 1) < tol);
  525. gini = boost::math::statistics::sample_gini_coefficient(v);
  526. BOOST_TEST(abs(gini - 1) < tol);
  527. v[0] = 1;
  528. v[1] = 1;
  529. v[2] = 1;
  530. gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
  531. BOOST_TEST(abs(gini) < tol);
  532. v[0] = 0;
  533. v[1] = 0;
  534. v[2] = 0;
  535. gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
  536. BOOST_TEST(abs(gini) < tol);
  537. std::array<Real, 3> w{0,0,0};
  538. gini = boost::math::statistics::sample_gini_coefficient(w);
  539. BOOST_TEST(abs(gini) < tol);
  540. }
  541. template<class Real>
  542. void test_gini_coefficient()
  543. {
  544. Real tol = std::numeric_limits<Real>::epsilon();
  545. std::vector<Real> v{1,0,0};
  546. Real gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  547. Real expected = Real(2)/Real(3);
  548. BOOST_TEST(abs(gini - expected) < tol);
  549. gini = boost::math::statistics::gini_coefficient(v);
  550. BOOST_TEST(abs(gini - expected) < tol);
  551. v[0] = 1;
  552. v[1] = 1;
  553. v[2] = 1;
  554. gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  555. BOOST_TEST(abs(gini) < tol);
  556. v[0] = 0;
  557. v[1] = 0;
  558. v[2] = 0;
  559. gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  560. BOOST_TEST(abs(gini) < tol);
  561. std::array<Real, 3> w{0,0,0};
  562. gini = boost::math::statistics::gini_coefficient(w);
  563. BOOST_TEST(abs(gini) < tol);
  564. boost::numeric::ublas::vector<Real> w1(3);
  565. w1[0] = 1;
  566. w1[1] = 1;
  567. w1[2] = 1;
  568. gini = boost::math::statistics::gini_coefficient(w1);
  569. BOOST_TEST(abs(gini) < tol);
  570. std::mt19937 gen(18);
  571. // Gini coefficient for a uniform distribution is (b-a)/(3*(b+a));
  572. std::uniform_real_distribution<long double> dis(0, 3);
  573. expected = (dis.b() - dis.a())/(3*(dis.b()+ dis.a()));
  574. v.resize(1024);
  575. for(size_t i = 0; i < v.size(); ++i)
  576. {
  577. v[i] = dis(gen);
  578. }
  579. gini = boost::math::statistics::gini_coefficient(v);
  580. BOOST_TEST(abs(gini - expected) < 0.01);
  581. }
  582. template<class Z>
  583. void test_integer_gini_coefficient()
  584. {
  585. double tol = std::numeric_limits<double>::epsilon();
  586. std::vector<Z> v{1,0,0};
  587. double gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  588. double expected = 2.0/3.0;
  589. BOOST_TEST(abs(gini - expected) < tol);
  590. gini = boost::math::statistics::gini_coefficient(v);
  591. BOOST_TEST(abs(gini - expected) < tol);
  592. v[0] = 1;
  593. v[1] = 1;
  594. v[2] = 1;
  595. gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  596. BOOST_TEST(abs(gini) < tol);
  597. v[0] = 0;
  598. v[1] = 0;
  599. v[2] = 0;
  600. gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
  601. BOOST_TEST(abs(gini) < tol);
  602. std::array<Z, 3> w{0,0,0};
  603. gini = boost::math::statistics::gini_coefficient(w);
  604. BOOST_TEST(abs(gini) < tol);
  605. boost::numeric::ublas::vector<Z> w1(3);
  606. w1[0] = 1;
  607. w1[1] = 1;
  608. w1[2] = 1;
  609. gini = boost::math::statistics::gini_coefficient(w1);
  610. BOOST_TEST(abs(gini) < tol);
  611. }
  612. int main()
  613. {
  614. test_mean<float>();
  615. test_mean<double>();
  616. test_mean<long double>();
  617. test_mean<cpp_bin_float_50>();
  618. test_integer_mean<unsigned>();
  619. test_integer_mean<int>();
  620. test_complex_mean<std::complex<float>>();
  621. test_complex_mean<cpp_complex_50>();
  622. test_variance<float>();
  623. test_variance<double>();
  624. test_variance<long double>();
  625. test_variance<cpp_bin_float_50>();
  626. test_integer_variance<int>();
  627. test_integer_variance<unsigned>();
  628. test_skewness<float>();
  629. test_skewness<double>();
  630. test_skewness<long double>();
  631. test_skewness<cpp_bin_float_50>();
  632. test_integer_skewness<int>();
  633. test_integer_skewness<unsigned>();
  634. test_first_four_moments<float>();
  635. test_first_four_moments<double>();
  636. test_first_four_moments<long double>();
  637. test_first_four_moments<cpp_bin_float_50>();
  638. test_kurtosis<float>();
  639. test_kurtosis<double>();
  640. test_kurtosis<long double>();
  641. // Kinda expensive:
  642. //test_kurtosis<cpp_bin_float_50>();
  643. test_integer_kurtosis<int>();
  644. test_integer_kurtosis<unsigned>();
  645. test_median<float>();
  646. test_median<double>();
  647. test_median<long double>();
  648. test_median<cpp_bin_float_50>();
  649. test_median<int>();
  650. test_median_absolute_deviation<float>();
  651. test_median_absolute_deviation<double>();
  652. test_median_absolute_deviation<long double>();
  653. test_median_absolute_deviation<cpp_bin_float_50>();
  654. test_gini_coefficient<float>();
  655. test_gini_coefficient<double>();
  656. test_gini_coefficient<long double>();
  657. test_gini_coefficient<cpp_bin_float_50>();
  658. test_integer_gini_coefficient<unsigned>();
  659. test_integer_gini_coefficient<int>();
  660. test_sample_gini_coefficient<float>();
  661. test_sample_gini_coefficient<double>();
  662. test_sample_gini_coefficient<long double>();
  663. test_sample_gini_coefficient<cpp_bin_float_50>();
  664. return boost::report_errors();
  665. }