statistic_tests.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /* statistic_tests.cpp file
  2. *
  3. * Copyright Jens Maurer 2000, 2002
  4. * Distributed under the Boost Software License, Version 1.0. (See
  5. * accompanying file LICENSE_1_0.txt or copy at
  6. * http://www.boost.org/LICENSE_1_0.txt)
  7. *
  8. * $Id$
  9. *
  10. * Revision history
  11. */
  12. #include <iostream>
  13. #include <iomanip>
  14. #include <string>
  15. #include <functional>
  16. #include <vector>
  17. #include <set>
  18. #include <algorithm>
  19. #include <boost/cstdint.hpp>
  20. #include <boost/random.hpp>
  21. #include <boost/math/special_functions/gamma.hpp>
  22. #include <boost/math/distributions/uniform.hpp>
  23. #include <boost/math/distributions/chi_squared.hpp>
  24. #include <boost/math/distributions/normal.hpp>
  25. #include <boost/math/distributions/triangular.hpp>
  26. #include <boost/math/distributions/cauchy.hpp>
  27. #include <boost/math/distributions/gamma.hpp>
  28. #include <boost/math/distributions/exponential.hpp>
  29. #include <boost/math/distributions/lognormal.hpp>
  30. #include "statistic_tests.hpp"
  31. #include "integrate.hpp"
  32. class test_environment;
  33. class test_base
  34. {
  35. protected:
  36. explicit test_base(test_environment & env) : environment(env) { }
  37. void check_(double val) const;
  38. private:
  39. test_environment & environment;
  40. };
  41. class equidistribution_test : test_base
  42. {
  43. public:
  44. equidistribution_test(test_environment & env, unsigned int classes,
  45. unsigned int high_classes)
  46. : test_base(env), classes(classes),
  47. test_distrib_chi_square(boost::math::chi_squared(classes-1), high_classes)
  48. { }
  49. template<class RNG>
  50. void run(RNG & rng, int n1, int n2)
  51. {
  52. using namespace boost;
  53. std::cout << "equidistribution: " << std::flush;
  54. equidistribution_experiment equi(classes);
  55. variate_generator<RNG&, uniform_smallint<> > uint_linear(rng, uniform_smallint<>(0, classes-1));
  56. check_(run_experiment(test_distrib_chi_square,
  57. experiment_generator(equi, uint_linear, n1), n2));
  58. check_(run_experiment(test_distrib_chi_square,
  59. experiment_generator(equi, uint_linear, n1), 2*n2));
  60. std::cout << " 2D: " << std::flush;
  61. equidistribution_2d_experiment equi_2d(classes);
  62. unsigned int root = static_cast<unsigned int>(std::sqrt(double(classes)));
  63. assert(root * root == classes);
  64. variate_generator<RNG&, uniform_smallint<> > uint_square(rng, uniform_smallint<>(0, root-1));
  65. check_(run_experiment(test_distrib_chi_square,
  66. experiment_generator(equi_2d, uint_square, n1), n2));
  67. check_(run_experiment(test_distrib_chi_square,
  68. experiment_generator(equi_2d, uint_square, n1), 2*n2));
  69. std::cout << std::endl;
  70. }
  71. private:
  72. unsigned int classes;
  73. distribution_experiment test_distrib_chi_square;
  74. };
  75. class ks_distribution_test : test_base
  76. {
  77. public:
  78. ks_distribution_test(test_environment & env, unsigned int classes)
  79. : test_base(env),
  80. test_distrib_chi_square(kolmogorov_smirnov_probability(5000),
  81. classes)
  82. { }
  83. template<class RNG>
  84. void run(RNG & rng, int n1, int n2)
  85. {
  86. boost::math::uniform ud(static_cast<double>((rng.min)()), static_cast<double>((rng.max)()));
  87. run(rng, ud, n1, n2);
  88. }
  89. template<class RNG, class Dist>
  90. void run(RNG & rng, const Dist& dist, int n1, int n2)
  91. {
  92. using namespace boost;
  93. std::cout << "KS: " << std::flush;
  94. kolmogorov_experiment ks(n1);
  95. check_(run_experiment(test_distrib_chi_square,
  96. ks_experiment_generator(ks, rng, dist), n2));
  97. check_(run_experiment(test_distrib_chi_square,
  98. ks_experiment_generator(ks, rng, dist), 2*n2));
  99. std::cout << std::endl;
  100. }
  101. private:
  102. distribution_experiment test_distrib_chi_square;
  103. };
  104. class runs_test : test_base
  105. {
  106. public:
  107. runs_test(test_environment & env, unsigned int classes,
  108. unsigned int high_classes)
  109. : test_base(env), classes(classes),
  110. test_distrib_chi_square(boost::math::chi_squared(classes-1), high_classes)
  111. { }
  112. template<class RNG>
  113. void run(RNG & rng, int n1, int n2)
  114. {
  115. using namespace boost;
  116. std::cout << "runs: up: " << std::flush;
  117. runs_experiment<true> r_up(classes);
  118. check_(run_experiment(test_distrib_chi_square,
  119. experiment_generator(r_up, rng, n1), n2));
  120. check_(run_experiment(test_distrib_chi_square,
  121. experiment_generator(r_up, rng, n1), 2*n2));
  122. std::cout << " down: " << std::flush;
  123. runs_experiment<false> r_down(classes);
  124. check_(run_experiment(test_distrib_chi_square,
  125. experiment_generator(r_down, rng, n1), n2));
  126. check_(run_experiment(test_distrib_chi_square,
  127. experiment_generator(r_down, rng, n1), 2*n2));
  128. std::cout << std::endl;
  129. }
  130. private:
  131. unsigned int classes;
  132. distribution_experiment test_distrib_chi_square;
  133. };
  134. class gap_test : test_base
  135. {
  136. public:
  137. gap_test(test_environment & env, unsigned int classes,
  138. unsigned int high_classes)
  139. : test_base(env), classes(classes),
  140. test_distrib_chi_square(boost::math::chi_squared(classes-1), high_classes)
  141. { }
  142. template<class RNG>
  143. void run(RNG & rng, int n1, int n2)
  144. {
  145. boost::math::uniform ud(
  146. static_cast<double>((rng.min)()),
  147. static_cast<double>((rng.max)()) +
  148. (std::numeric_limits<typename RNG::result_type>::is_integer? 0.0 : 1.0));
  149. run(rng, ud, n1, n2);
  150. }
  151. template<class RNG, class Dist>
  152. void run(RNG & rng, const Dist& dist, int n1, int n2)
  153. {
  154. using namespace boost;
  155. std::cout << "gaps: " << std::flush;
  156. gap_experiment gap(classes, dist, 0.2, 0.8);
  157. check_(run_experiment(test_distrib_chi_square,
  158. experiment_generator(gap, rng, n1), n2));
  159. check_(run_experiment(test_distrib_chi_square,
  160. experiment_generator(gap, rng, n1), 2*n2));
  161. std::cout << std::endl;
  162. }
  163. private:
  164. unsigned int classes;
  165. distribution_experiment test_distrib_chi_square;
  166. };
  167. class poker_test : test_base
  168. {
  169. public:
  170. poker_test(test_environment & env, unsigned int classes,
  171. unsigned int high_classes)
  172. : test_base(env), classes(classes),
  173. test_distrib_chi_square(boost::math::chi_squared(classes-1), high_classes)
  174. { }
  175. template<class RNG>
  176. void run(RNG & rng, int n1, int n2)
  177. {
  178. using namespace boost;
  179. std::cout << "poker: " << std::flush;
  180. poker_experiment poker(8, classes);
  181. variate_generator<RNG&, uniform_smallint<> > usmall(rng, uniform_smallint<>(0, 7));
  182. check_(run_experiment(test_distrib_chi_square,
  183. experiment_generator(poker, usmall, n1), n2));
  184. check_(run_experiment(test_distrib_chi_square,
  185. experiment_generator(poker, usmall, n1), 2*n2));
  186. std::cout << std::endl;
  187. }
  188. private:
  189. unsigned int classes;
  190. distribution_experiment test_distrib_chi_square;
  191. };
  192. class coupon_collector_test : test_base
  193. {
  194. public:
  195. coupon_collector_test(test_environment & env, unsigned int classes,
  196. unsigned int high_classes)
  197. : test_base(env), classes(classes),
  198. test_distrib_chi_square(boost::math::chi_squared(classes-1), high_classes)
  199. { }
  200. template<class RNG>
  201. void run(RNG & rng, int n1, int n2)
  202. {
  203. using namespace boost;
  204. std::cout << "coupon collector: " << std::flush;
  205. coupon_collector_experiment coupon(5, classes);
  206. variate_generator<RNG&, uniform_smallint<> > usmall(rng, uniform_smallint<>(0, 4));
  207. check_(run_experiment(test_distrib_chi_square,
  208. experiment_generator(coupon, usmall, n1), n2));
  209. check_(run_experiment(test_distrib_chi_square,
  210. experiment_generator(coupon, usmall, n1), 2*n2));
  211. std::cout << std::endl;
  212. }
  213. private:
  214. unsigned int classes;
  215. distribution_experiment test_distrib_chi_square;
  216. };
  217. class permutation_test : test_base
  218. {
  219. public:
  220. permutation_test(test_environment & env, unsigned int classes,
  221. unsigned int high_classes)
  222. : test_base(env), classes(classes),
  223. test_distrib_chi_square(boost::math::chi_squared(fac<int>(classes)-1),
  224. high_classes)
  225. { }
  226. template<class RNG>
  227. void run(RNG & rng, int n1, int n2)
  228. {
  229. using namespace boost;
  230. std::cout << "permutation: " << std::flush;
  231. permutation_experiment perm(classes);
  232. // generator_reference_t<RNG> gen_ref(rng);
  233. RNG& gen_ref(rng);
  234. check_(run_experiment(test_distrib_chi_square,
  235. experiment_generator(perm, gen_ref, n1), n2));
  236. check_(run_experiment(test_distrib_chi_square,
  237. experiment_generator(perm, gen_ref, n1), 2*n2));
  238. std::cout << std::endl;
  239. }
  240. private:
  241. unsigned int classes;
  242. distribution_experiment test_distrib_chi_square;
  243. };
  244. class maximum_test : test_base
  245. {
  246. public:
  247. maximum_test(test_environment & env, unsigned int high_classes)
  248. : test_base(env),
  249. test_distrib_chi_square(kolmogorov_smirnov_probability(1000),
  250. high_classes)
  251. { }
  252. template<class RNG>
  253. void run(RNG & rng, int n1, int n2)
  254. {
  255. using namespace boost;
  256. std::cout << "maximum-of-t: " << std::flush;
  257. maximum_experiment<RNG> mx(rng, n1, 5);
  258. check_(run_experiment(test_distrib_chi_square, mx, n2));
  259. check_(run_experiment(test_distrib_chi_square, mx, 2*n2));
  260. std::cout << std::endl;
  261. }
  262. private:
  263. distribution_experiment test_distrib_chi_square;
  264. };
  265. class birthday_test : test_base
  266. {
  267. public:
  268. birthday_test(test_environment & env, unsigned int high_classes)
  269. : test_base(env),
  270. test_distrib_chi_square(boost::math::chi_squared(4-1), high_classes)
  271. { }
  272. template<class RNG>
  273. void run(RNG & rng, int n1, int n2)
  274. {
  275. using namespace boost;
  276. std::cout << "birthday spacing: " << std::flush;
  277. boost::variate_generator<RNG&, boost::uniform_int<> > uni(rng, boost::uniform_int<>(0, (1<<25)-1));
  278. birthday_spacing_experiment bsp(4, 512, (1<<25));
  279. check_(run_experiment(test_distrib_chi_square,
  280. experiment_generator(bsp, uni, n1), n2));
  281. check_(run_experiment(test_distrib_chi_square,
  282. experiment_generator(bsp, uni, n1), 2*n2));
  283. std::cout << std::endl;
  284. }
  285. private:
  286. distribution_experiment test_distrib_chi_square;
  287. };
  288. #ifdef BOOST_MSVC
  289. #pragma warning(disable:4355)
  290. #endif
  291. class test_environment
  292. {
  293. public:
  294. static const int classes = 20;
  295. explicit test_environment(double confid)
  296. : confidence(confid),
  297. confidence_chi_square_quantil(quantile(boost::math::chi_squared(classes-1), confidence)),
  298. test_distrib_chi_square6(boost::math::chi_squared(7-1), classes),
  299. ksdist_test(*this, classes),
  300. equi_test(*this, 100, classes),
  301. rns_test(*this, 7, classes),
  302. gp_test(*this, 7, classes),
  303. pk_test(*this, 5, classes),
  304. cpn_test(*this, 15, classes),
  305. perm_test(*this, 5, classes),
  306. max_test(*this, classes),
  307. bday_test(*this, classes)
  308. {
  309. std::cout << "Confidence level: " << confid
  310. << "; 1-alpha = " << (1-confid)
  311. << "; chi_square(" << (classes-1)
  312. << ", " << confidence_chi_square_quantil
  313. << ") = "
  314. << cdf(boost::math::chi_squared(classes-1), confidence_chi_square_quantil)
  315. << std::endl;
  316. }
  317. bool check_confidence(double val, double chi_square_conf) const
  318. {
  319. std::cout << val;
  320. bool result = (val <= chi_square_conf);
  321. if(!result) {
  322. std::cout << "* [";
  323. double prob = (val > 10*chi_square_conf ? 1 :
  324. cdf(boost::math::chi_squared(classes-1), val));
  325. std::cout << (1-prob) << "]";
  326. }
  327. std::cout << " " << std::flush;
  328. return result;
  329. }
  330. bool check_(double chi_square_value) const
  331. {
  332. return check_confidence(chi_square_value, confidence_chi_square_quantil);
  333. }
  334. template<class RNG>
  335. void run_test(const std::string & name)
  336. {
  337. using namespace boost;
  338. std::cout << "Running tests on " << name << std::endl;
  339. RNG rng(1234567);
  340. ksdist_test.run(rng, 5000, 250);
  341. equi_test.run(rng, 5000, 250);
  342. rns_test.run(rng, 100000, 250);
  343. gp_test.run(rng, 10000, 250);
  344. pk_test.run(rng, 5000, 250);
  345. cpn_test.run(rng, 500, 250);
  346. perm_test.run(rng, 1200, 250);
  347. max_test.run(rng, 1000, 250);
  348. bday_test.run(rng, 1000, 150);
  349. std::cout << std::endl;
  350. }
  351. template<class RNG, class Dist, class ExpectedDist>
  352. void run_test(const std::string & name, const Dist & dist, const ExpectedDist & expected_dist)
  353. {
  354. using namespace boost;
  355. std::cout << "Running tests on " << name << std::endl;
  356. RNG rng;
  357. variate_generator<RNG&, Dist> vgen(rng, dist);
  358. ksdist_test.run(vgen, expected_dist, 5000, 250);
  359. rns_test.run(vgen, 100000, 250);
  360. gp_test.run(vgen, expected_dist, 10000, 250);
  361. perm_test.run(vgen, 1200, 250);
  362. std::cout << std::endl;
  363. }
  364. private:
  365. double confidence;
  366. double confidence_chi_square_quantil;
  367. distribution_experiment test_distrib_chi_square6;
  368. ks_distribution_test ksdist_test;
  369. equidistribution_test equi_test;
  370. runs_test rns_test;
  371. gap_test gp_test;
  372. poker_test pk_test;
  373. coupon_collector_test cpn_test;
  374. permutation_test perm_test;
  375. maximum_test max_test;
  376. birthday_test bday_test;
  377. };
  378. void test_base::check_(double val) const
  379. {
  380. environment.check_(val);
  381. }
  382. class program_args
  383. {
  384. public:
  385. program_args(int argc, char** argv)
  386. {
  387. if(argc > 0) {
  388. names.insert(argv + 1, argv + argc);
  389. }
  390. }
  391. bool check_(const std::string & test_name) const
  392. {
  393. return(names.empty() || names.find(test_name) != names.end());
  394. }
  395. private:
  396. std::set<std::string> names;
  397. };
  398. int main(int argc, char* argv[])
  399. {
  400. program_args args(argc, argv);
  401. test_environment env(0.99);
  402. #define TEST(name) \
  403. if(args.check_(#name)) \
  404. env.run_test<boost::name>(#name)
  405. TEST(minstd_rand0);
  406. TEST(minstd_rand);
  407. TEST(rand48);
  408. TEST(ecuyer1988);
  409. TEST(kreutzer1986);
  410. TEST(taus88);
  411. TEST(hellekalek1995);
  412. TEST(mt11213b);
  413. TEST(mt19937);
  414. TEST(lagged_fibonacci607);
  415. TEST(lagged_fibonacci1279);
  416. TEST(lagged_fibonacci2281);
  417. TEST(lagged_fibonacci3217);
  418. TEST(lagged_fibonacci4423);
  419. TEST(lagged_fibonacci9689);
  420. TEST(lagged_fibonacci19937);
  421. TEST(lagged_fibonacci23209);
  422. TEST(lagged_fibonacci44497);
  423. TEST(ranlux3);
  424. TEST(ranlux4);
  425. #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
  426. TEST(ranlux64_3);
  427. TEST(ranlux64_4);
  428. #endif
  429. TEST(ranlux3_01);
  430. TEST(ranlux4_01);
  431. TEST(ranlux64_3_01);
  432. TEST(ranlux64_4_01);
  433. if(args.check_("normal"))
  434. env.run_test<boost::mt19937>("normal", boost::normal_distribution<>(), boost::math::normal());
  435. if(args.check_("triangle"))
  436. env.run_test<boost::mt19937>("triangle", boost::triangle_distribution<>(0, 1, 3), boost::math::triangular(0, 1, 3));
  437. if(args.check_("cauchy"))
  438. env.run_test<boost::mt19937>("cauchy", boost::cauchy_distribution<>(), boost::math::cauchy());
  439. if(args.check_("gamma"))
  440. env.run_test<boost::mt19937>("gamma", boost::gamma_distribution<>(1), boost::math::gamma_distribution<>(1));
  441. if(args.check_("exponential"))
  442. env.run_test<boost::mt19937>("exponential", boost::exponential_distribution<>(), boost::math::exponential());
  443. if(args.check_("lognormal"))
  444. env.run_test<boost::mt19937>("lognormal", boost::lognormal_distribution<>(1, 1),
  445. boost::math::lognormal(std::log(1.0/std::sqrt(2.0)), std::sqrt(std::log(2.0))));
  446. }