Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/random/statistic_tests.cpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 18.9 KB
Line 
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: statistic_tests.cpp,v 1.11 2004/07/27 03:43:34 dgregor Exp $
9 *
10 * Revision history
11 */
12
13/*
14 * NOTE: This is not part of the official boost submission.  It exists
15 * only as a collection of ideas.
16 */
17
18#include <iostream>
19#include <iomanip>
20#include <string>
21#include <functional>
22#include <math.h>  // lgamma is not in namespace std
23#include <vector>
24#include <algorithm>
25
26#include <boost/cstdint.hpp>
27#include <boost/random.hpp>
28
29#include "statistic_tests.hpp"
30#include "integrate.hpp"
31
32
33namespace boost {
34namespace random {
35
36// Wikramaratna 1989  ACORN
37template<class IntType, int k, IntType m, IntType val>
38class additive_congruential
39{
40public:
41  typedef IntType result_type;
42#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
43  static const bool has_fixed_range = true;
44  static const result_type min_value = 0;
45  static const result_type max_value = m-1;
46#else
47  enum {
48    has_fixed_range = true,
49    min_value = 0,
50    max_value = m-1
51  };
52#endif
53  template<class InputIterator>
54  explicit additive_congruential(InputIterator start) { seed(start); }
55  template<class InputIterator>
56  void seed(InputIterator start)
57  {
58    for(int i = 0; i <= k; ++i, ++start)
59      values[i] = *start;
60  }
61 
62  result_type operator()()
63  {
64    for(int i = 1; i <= k; ++i) {
65      IntType tmp = values[i-1] + values[i];
66      if(tmp >= m)
67        tmp -= m;
68      values[i] = tmp;
69    }
70    return values[k];
71  }
72  result_type validation() const { return val; }
73private:
74  IntType values[k+1];
75};
76
77
78template<class IntType, int r, int s, IntType m, IntType val>
79class lagged_fibonacci_int
80{
81public:
82  typedef IntType result_type;
83#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
84  static const bool has_fixed_range = true;
85  static const result_type min_value = 0;
86  static const result_type max_value = m-1;
87#else
88  enum {
89    has_fixed_range = true,
90    min_value = 0,
91    max_value = m-1
92  };
93#endif
94  explicit lagged_fibonacci_int(IntType start) { seed(start); }
95  template<class Generator>
96  explicit lagged_fibonacci_int(Generator & gen) { seed(gen); }
97  void seed(IntType start)
98  {
99    linear_congruential<uint32_t, 299375077, 0, 0, 0> init;
100    seed(init);
101  }
102  template<class Generator>
103  void seed(Generator & gen)
104  {
105    assert(r > s);
106    for(int i = 0; i < 607; ++i)
107      values[i] = gen();
108    current = 0;
109    lag = r-s;
110  }
111 
112  result_type operator()()
113  {
114    result_type tmp = values[current] + values[lag];
115    if(tmp >= m)
116      tmp -= m;
117    values[current] = tmp;
118    ++current;
119    if(current >= r)
120      current = 0;
121    ++lag;
122    if(lag >= r)
123      lag = 0;
124    return tmp;
125  }
126  result_type validation() const { return val; }
127private:
128  result_type values[r];
129  int current, lag;
130};
131
132} // namespace random
133} // namespace boost
134
135// distributions from Haertel's dissertation
136// (additional parameterizations of the basic templates)
137namespace Haertel {
138  typedef boost::random::linear_congruential<boost::uint64_t, 45965, 453816691,
139    (boost::uint64_t(1)<<31), 0> LCG_Af2;
140  typedef boost::random::linear_congruential<boost::uint64_t, 211936855, 0,
141    (boost::uint64_t(1)<<29)-3, 0> LCG_Die1;
142  typedef boost::random::linear_congruential<boost::uint32_t, 2824527309u, 0,
143    0, 0> LCG_Fis;
144  typedef boost::random::linear_congruential<boost::uint64_t, 950706376u, 0,
145    (boost::uint64_t(1)<<31)-1, 0> LCG_FM;
146  typedef boost::random::linear_congruential<boost::int32_t, 51081, 0,
147    2147483647, 0> LCG_Hae;
148  typedef boost::random::linear_congruential<boost::uint32_t, 69069, 1,
149    0, 0> LCG_VAX;
150  typedef boost::random::inversive_congruential<boost::int64_t, 240318, 197, 
151    1000081, 0> NLG_Inv1;
152  typedef boost::random::inversive_congruential<boost::int64_t, 15707262,
153    13262967, (1<<24)-17, 0> NLG_Inv2;
154  typedef boost::random::inversive_congruential<boost::int32_t, 1, 1,
155    2147483647, 0> NLG_Inv4;
156  typedef boost::random::inversive_congruential<boost::int32_t, 1, 2,
157    1<<30, 0> NLG_Inv5;
158  typedef boost::random::additive_congruential<boost::int32_t, 6,
159    (1<<30)-35, 0> MRG_Acorn7;
160  typedef boost::random::lagged_fibonacci_int<boost::uint32_t, 607, 273,
161    0, 0> MRG_Fib2;
162
163  template<class Gen, class T>
164  inline void check_validation(Gen & gen, T value, const std::string & name)
165  {
166    for(int i = 0; i < 100000-1; ++i)
167      gen();
168    if(value != gen())
169      std::cout << name << ": validation failed" << std::endl;
170  }
171
172  // we have validation after 100000 steps with Haertel's generators
173  template<class Gen, class T>
174  void validate(T value, const std::string & name)
175  {
176    Gen gen(1234567);
177    check_validation(gen, value, name);
178  }
179
180  void validate_all()
181  {
182    validate<LCG_Af2>(183269031u, "LCG_Af2");
183    validate<LCG_Die1>(522319944u, "LCG_Die1");
184    validate<LCG_Fis>(-2065162233u, "LCG_Fis");
185    validate<LCG_FM>(581815473u, "LCG_FM");
186    validate<LCG_Hae>(28931709, "LCG_Hae");
187    validate<LCG_VAX>(1508154087u, "LCG_VAX");
188    validate<NLG_Inv2>(6666884, "NLG_Inv2");
189    validate<NLG_Inv4>(1521640076, "NLG_Inv4");
190    validate<NLG_Inv5>(641840839, "NLG_Inv5");
191    static const int acorn7_init[]
192      = { 1234567, 7654321, 246810, 108642, 13579, 97531, 555555 };
193    MRG_Acorn7 acorn7(acorn7_init);
194    check_validation(acorn7, 874294697, "MRG_Acorn7");
195    validate<MRG_Fib2>(1234567u, "MRG_Fib2");
196  }
197} // namespace Haertel
198
199
200
201
202double normal_density(double x)
203{
204  const double pi = 3.14159265358979323846;
205  return 1/std::sqrt(2*pi) * std::exp(-x*x/2);
206}
207
208namespace std {
209#ifdef _CXXRTCF_H__
210  using _CS_swamp::lgamma;
211#elif defined __SGI_STL_PORT
212  using ::lgamma;
213#endif
214}
215
216
217class chi_square_density : public std::unary_function<double, double>
218{
219public:
220  chi_square_density(int freedom)
221    : _exponent( static_cast<double>(freedom)/2-1 ),
222      _factor(1/(std::pow(2, _exponent+1) * std::exp(lgamma(_exponent+1))))
223  { }
224
225  double operator()(double x)
226  {
227    return _factor*std::pow(x, _exponent)*std::exp(-x/2);
228  }
229private:
230  double _exponent, _factor;
231};
232
233// computes F(x) or F(y) - F(x)
234class chi_square_probability : public distribution_function<double>
235{
236public:
237  chi_square_probability(int freedom) : dens(freedom) {}
238  double operator()(double x) { return operator()(0, x); }
239  double operator()(double x, double y)
240  { return trapezoid(dens, x, y, 1000); }
241private:
242  chi_square_density dens;
243};
244
245class uniform_distribution : public distribution_function<double>
246{
247public:
248  uniform_distribution(double from, double to) : from(from), to(to) 
249  { assert(from < to); }
250  double operator()(double x) 
251  { 
252    if(x < from) 
253      return 0;
254    else if(x > to)
255      return 1;
256    else
257      return (x-from)/(to-from);
258  }
259  double operator()(double x, double delta)
260  { return operator()(x+delta) - operator()(x); }
261private:
262  double from, to;
263};
264
265class test_environment;
266
267class test_base
268{
269protected:
270  explicit test_base(test_environment & env) : environment(env) { }
271  void check(double val) const; 
272private:
273  test_environment & environment;
274};
275
276class equidistribution_test : test_base
277{
278public:
279  equidistribution_test(test_environment & env, unsigned int classes, 
280                        unsigned int high_classes)
281    : test_base(env), classes(classes),
282      test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
283  { }
284
285  template<class RNG>
286  void run(RNG & rng, int n1, int n2)
287  {
288    using namespace boost;
289    std::cout << "equidistribution: " << std::flush;
290    equidistribution_experiment equi(classes);
291    uniform_smallint<RNG> uint_linear(rng, 0, classes-1);
292    check(run_experiment(test_distrib_chi_square,
293                         experiment_generator(equi, uint_linear, n1), n2));
294    check(run_experiment(test_distrib_chi_square, 
295                         experiment_generator(equi, uint_linear, n1), 2*n2));
296
297    std::cout << "  2D: " << std::flush;
298    equidistribution_2d_experiment equi_2d(classes);
299    unsigned int root = static_cast<unsigned int>(std::sqrt(double(classes)));
300    assert(root * root == classes);
301    uniform_smallint<RNG> uint_square(rng, 0, root-1);
302    check(run_experiment(test_distrib_chi_square,
303                         experiment_generator(equi_2d, uint_square, n1), n2));
304    check(run_experiment(test_distrib_chi_square,
305                         experiment_generator(equi_2d, uint_square, n1), 2*n2));
306    std::cout << std::endl;
307  }
308private:
309  unsigned int classes;
310  distribution_experiment test_distrib_chi_square;
311};
312
313class ks_equidistribution_test : test_base
314{
315public:
316  ks_equidistribution_test(test_environment & env, unsigned int classes)
317    : test_base(env),
318      test_distrib_chi_square(kolmogorov_smirnov_probability(5000), 
319                              classes)
320  { }
321
322  template<class RNG>
323  void run(RNG & rng, int n1, int n2)
324  {
325    using namespace boost;
326    std::cout << "KS: " << std::flush;
327    // generator_reference_t<RNG> gen_ref(rng);
328    RNG& gen_ref(rng);
329    kolmogorov_experiment ks(n1);
330    uniform_distribution ud((rng.min)(), (rng.max)());
331    check(run_experiment(test_distrib_chi_square,
332                         ks_experiment_generator(ks, gen_ref, ud), n2));
333    check(run_experiment(test_distrib_chi_square,
334                         ks_experiment_generator(ks, gen_ref, ud), 2*n2));
335  }
336private:
337  distribution_experiment test_distrib_chi_square;
338};
339
340class runs_test : test_base
341{
342public:
343  runs_test(test_environment & env, unsigned int classes,
344            unsigned int high_classes)
345    : test_base(env), classes(classes),
346      test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
347  { }
348
349  template<class RNG>
350  void run(RNG & rng, int n1, int n2)
351  {
352    using namespace boost;
353    std::cout << "runs: up: " << std::flush;
354    runs_experiment<true> r_up(classes);
355    // generator_reference_t<RNG> gen_ref(rng);
356    RNG& gen_ref(rng);
357    check(run_experiment(test_distrib_chi_square,
358                         experiment_generator(r_up, gen_ref, n1), n2));
359    check(run_experiment(test_distrib_chi_square,
360                         experiment_generator(r_up, gen_ref, n1), 2*n2));
361
362    std::cout << "  down: " << std::flush;
363    runs_experiment<false> r_down(classes);
364    check(run_experiment(test_distrib_chi_square,
365                         experiment_generator(r_down, gen_ref, n1), n2));
366    check(run_experiment(test_distrib_chi_square,
367                         experiment_generator(r_down, gen_ref, n1), 2*n2));
368
369    std::cout << std::endl;
370  }
371private:
372  unsigned int classes;
373  distribution_experiment test_distrib_chi_square;
374};
375
376class gap_test : test_base
377{
378public:
379  gap_test(test_environment & env, unsigned int classes,
380            unsigned int high_classes)
381    : test_base(env), classes(classes),
382      test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
383  { }
384
385  template<class RNG>
386  void run(RNG & rng, int n1, int n2)
387  {
388    using namespace boost;
389    std::cout << "gaps: " << std::flush;
390    gap_experiment gap(classes, 0.2, 0.8);
391    // generator_reference_t<RNG> gen_ref(rng);
392    RNG& gen_ref(rng);
393    check(run_experiment(test_distrib_chi_square,
394                         experiment_generator(gap, gen_ref, n1), n2));
395    check(run_experiment(test_distrib_chi_square,
396                         experiment_generator(gap, gen_ref, n1), 2*n2));
397
398    std::cout << std::endl;
399  }
400private:
401  unsigned int classes;
402  distribution_experiment test_distrib_chi_square;
403};
404
405class poker_test : test_base
406{
407public:
408  poker_test(test_environment & env, unsigned int classes,
409             unsigned int high_classes)
410    : test_base(env), classes(classes),
411      test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
412  { }
413
414  template<class RNG>
415  void run(RNG & rng, int n1, int n2)
416  {
417    using namespace boost;
418    std::cout << "poker: " << std::flush;
419    poker_experiment poker(8, classes);
420    uniform_smallint<RNG> usmall(rng, 0, 7);
421    check(run_experiment(test_distrib_chi_square,
422                         experiment_generator(poker, usmall, n1), n2));
423    check(run_experiment(test_distrib_chi_square,
424                         experiment_generator(poker, usmall, n1), 2*n2));
425    std::cout << std::endl;
426  }
427private:
428  unsigned int classes;
429  distribution_experiment test_distrib_chi_square;
430};
431
432class coupon_collector_test : test_base
433{
434public:
435  coupon_collector_test(test_environment & env, unsigned int classes,
436                        unsigned int high_classes)
437    : test_base(env), classes(classes),
438      test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
439  { }
440
441  template<class RNG>
442  void run(RNG & rng, int n1, int n2)
443  {
444    using namespace boost;
445    std::cout << "coupon collector: " << std::flush;
446    coupon_collector_experiment coupon(5, classes);
447
448    uniform_smallint<RNG> usmall(rng, 0, 4);
449    check(run_experiment(test_distrib_chi_square,
450                         experiment_generator(coupon, usmall, n1), n2));
451    check(run_experiment(test_distrib_chi_square,
452                         experiment_generator(coupon, usmall, n1), 2*n2));
453    std::cout << std::endl;
454  }
455private:
456  unsigned int classes;
457  distribution_experiment test_distrib_chi_square;
458};
459
460class permutation_test : test_base
461{
462public:
463  permutation_test(test_environment & env, unsigned int classes,
464                   unsigned int high_classes)
465    : test_base(env), classes(classes),
466      test_distrib_chi_square(chi_square_probability(fac<int>(classes)-1), 
467                              high_classes)
468  { }
469
470  template<class RNG>
471  void run(RNG & rng, int n1, int n2)
472  {
473    using namespace boost;
474    std::cout << "permutation: " << std::flush;
475    permutation_experiment perm(classes);
476   
477    // generator_reference_t<RNG> gen_ref(rng);
478    RNG& gen_ref(rng);
479    check(run_experiment(test_distrib_chi_square,
480                         experiment_generator(perm, gen_ref, n1), n2));
481    check(run_experiment(test_distrib_chi_square,
482                         experiment_generator(perm, gen_ref, n1), 2*n2));
483    std::cout << std::endl;
484  }
485private:
486  unsigned int classes;
487  distribution_experiment test_distrib_chi_square;
488};
489
490class maximum_test : test_base
491{
492public:
493  maximum_test(test_environment & env, unsigned int high_classes)
494    : test_base(env),
495      test_distrib_chi_square(kolmogorov_smirnov_probability(1000),
496                              high_classes)
497  { }
498
499  template<class RNG>
500  void run(RNG & rng, int n1, int n2)
501  {
502    using namespace boost;
503    std::cout << "maximum-of-t: " << std::flush;
504    maximum_experiment<RNG> mx(rng, n1, 5);   
505    check(run_experiment(test_distrib_chi_square, mx, n2));
506    check(run_experiment(test_distrib_chi_square, mx, 2*n2));
507    std::cout << std::endl;
508  }
509private:
510  distribution_experiment test_distrib_chi_square;
511};
512
513class birthday_test : test_base
514{
515public:
516  birthday_test(test_environment & env)
517    : test_base(env)
518  { }
519
520  template<class RNG>
521  void run(RNG & rng, int n1, int n2)
522  {
523    using namespace boost;
524    std::cout << "birthday spacing: " << std::flush;
525    uniform_int<RNG> uni(rng, 0, (1<<25)-1);
526    birthday_spacing_experiment bsp(4, 512, (1<<25));
527    std::cout << run_experiment(bsp, uni, n1);
528#if 0
529    check(run_experiment(test_distrib_chi_square,
530                         experiment_generator(perm, gen_ref, n1), n2));
531    check(run_experiment(test_distrib_chi_square,
532                         experiment_generator(perm, gen_ref, n1), 2*n2));
533#endif
534    std::cout << std::endl;
535  }
536 
537   
538};
539
540class test_environment
541{
542public:
543  static const int classes = 20;
544  explicit test_environment(double confid) 
545    : confidence(confid),
546      confidence_chi_square_quantil(quantil(chi_square_density(classes-1), 0, confidence, 1e-4)),
547      test_distrib_chi_square6(chi_square_probability(7-1), classes),
548      ksequi_test(*this, classes),
549      equi_test(*this, 100, classes),
550      rns_test(*this, 7, classes),
551      gp_test(*this, 7, classes),
552      pk_test(*this, 5, classes),
553      cpn_test(*this, 15, classes),
554      perm_test(*this, 5, classes),
555      max_test(*this, classes),
556      bday_test(*this)
557  {
558    std::cout << "Confidence level: " << confid
559              << "; 1-alpha = " << (1-confid)
560              << "; chi_square(" << (classes-1) 
561              << ", " << confidence_chi_square_quantil
562              << ") = " 
563              << chi_square_probability(classes-1)(0, confidence_chi_square_quantil)
564              << std::endl;
565  }
566 
567  bool check_confidence(double val, double chi_square_conf) const
568  {
569    std::cout << val;
570    bool result = (val <= chi_square_conf);
571    if(!result) {
572      std::cout << "* [";
573      double prob = (val > 10*chi_square_conf ? 1 :
574                     chi_square_probability(classes-1)(0, val));
575      std::cout << (1-prob) << "]";
576    }
577    std::cout << " " << std::flush;
578    return result;
579  }
580
581  bool check(double chi_square_value) const
582  {
583    return check_confidence(chi_square_value, confidence_chi_square_quantil);
584  }
585
586  template<class RNG>
587  void run_test(const std::string & name)
588  {
589    using namespace boost;
590
591    std::cout << "Running tests on " << name << std::endl;
592
593    RNG rng(1234567);
594    typedef boost::uniform_01<RNG> UGen;
595
596#if 1
597    ksequi_test.run(rng, 5000, 250);
598    equi_test.run(rng, 5000, 250);
599    rns_test.run(rng, 100000, 250);
600    gp_test.run(rng, 10000, 250);
601    pk_test.run(rng, 5000, 250);
602    cpn_test.run(rng, 500, 250);
603    perm_test.run(rng, 1200, 250);
604    max_test.run(rng, 1000, 250);
605#endif
606    bday_test.run(rng, 1000, 150);
607
608    std::cout << std::endl;
609  }
610
611private:
612  double confidence;
613  double confidence_chi_square_quantil;
614  distribution_experiment test_distrib_chi_square6;
615  ks_equidistribution_test ksequi_test;
616  equidistribution_test equi_test;
617  runs_test rns_test;
618  gap_test gp_test;
619  poker_test pk_test;
620  coupon_collector_test cpn_test;
621  permutation_test perm_test;
622  maximum_test max_test;
623  birthday_test bday_test;
624};
625
626void test_base::check(double val) const
627{ 
628  environment.check(val);
629}
630
631void print_ks_table()
632{
633  std::cout.setf(std::ios::fixed);
634  std::cout.precision(5);
635  static const double all_p[] = { 0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99 };
636  for(int n = 0; n <= 10000;  (n < 55 ? ++n : n *= 10)) {
637    std::cout << std::setw(4) << n << " ";
638    for(unsigned int i = 0; i < sizeof(all_p)/sizeof(all_p[0]); ++i) {
639      std::cout << std::setw(8) 
640                << (n == 0 ? all_p[i] : 
641                    invert_monotone_inc(kolmogorov_smirnov_probability(n), all_p[i], 0, 10))
642                << " ";
643    }
644    std::cout << std::endl;
645  }
646}
647
648int main()
649{
650  //  Haertel::validate_all();
651  test_environment env(0.99);
652  env.run_test<boost::minstd_rand>("minstd_rand");
653  env.run_test<boost::mt19937>("mt19937");
654  env.run_test<Haertel::LCG_Af2>("LCG_Af2");
655  env.run_test<Haertel::LCG_Die1>("LCG_Die1");
656  env.run_test<Haertel::LCG_Fis>("LCG_Fis");
657  env.run_test<Haertel::LCG_FM>("LCG_FM");
658  env.run_test<Haertel::LCG_Hae>("LCG_Hae");
659  env.run_test<Haertel::LCG_VAX>("LCG_VAX");
660  env.run_test<Haertel::NLG_Inv1>("NLG_Inv1");
661  env.run_test<Haertel::NLG_Inv2>("NLG_Inv2");
662  env.run_test<Haertel::NLG_Inv4>("NLG_Inv4");
663  env.run_test<Haertel::NLG_Inv5>("NLG_Inv5");
664}
Note: See TracBrowser for help on using the repository browser.