Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/random/random_test.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: 16.8 KB
Line 
1/* boost random_test.cpp various tests
2 *
3 * Copyright Jens Maurer 2000
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: random_test.cpp,v 1.58 2005/08/25 16:27:27 johnmaddock Exp $
9 */
10
11#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
12#pragma warning( disable : 4786 )
13#endif
14
15#include <iostream>
16#include <sstream>
17#include <string>
18#include <cmath>
19#include <iterator>
20#include <vector>
21#include <boost/random.hpp>
22#include <boost/config.hpp>
23
24#include <boost/test/test_tools.hpp>
25#include <boost/test/included/test_exec_monitor.hpp>
26
27#ifdef BOOST_NO_STDC_NAMESPACE
28  namespace std { using ::abs; using ::fabs; using ::pow; }
29#endif
30
31
32/*
33 * General portability note:
34 * MSVC mis-compiles explicit function template instantiations.
35 * For example, f<A>() and f<B>() are both compiled to call f<A>().
36 * BCC is unable to implicitly convert a "const char *" to a std::string
37 * when using explicit function template instantiations.
38 *
39 * Therefore, avoid explicit function template instantiations.
40 */
41
42/*
43 * Validate correct implementation
44 */
45
46// own run
47bool check(unsigned long x, const boost::mt11213b&) { return x == 3809585648U; }
48
49// validation by experiment from mt19937.c
50bool check(unsigned long x, const boost::mt19937&) { return x == 4123659995U; }
51
52// validation values from the publications
53bool check(int x, const boost::minstd_rand0&) { return x == 1043618065; }
54
55// validation values from the publications
56bool check(int x, const boost::minstd_rand&) { return x == 399268537; }
57
58#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
59// by experiment from lrand48()
60bool check(unsigned long x, const boost::rand48&) { return x == 1993516219; }
61#endif
62
63// ????
64bool check(unsigned long x, const boost::taus88&) { return x == 3535848941U; }
65
66// ????
67bool check(int x, const boost::ecuyer1988&) { return x == 2060321752; }
68
69// validation by experiment from Harry Erwin's generator.h (private e-mail)
70bool check(unsigned int x, const boost::kreutzer1986&) { return x == 139726; }
71
72bool check(double x, const boost::lagged_fibonacci607&) { return std::abs(x-0.401269) < 1e-5; }
73
74// principal operation validated with CLHEP, values by experiment
75bool check(unsigned long x, const boost::ranlux3&) { return x == 5957620; }
76bool check(unsigned long x, const boost::ranlux4&) { return x == 8587295; }
77
78bool check(float x, const boost::ranlux3_01&)
79{ return std::abs(x-5957620/std::pow(2.0f,24)) < 1e-6; }
80bool check(float x, const boost::ranlux4_01&)
81{ return std::abs(x-8587295/std::pow(2.0f,24)) < 1e-6; }
82
83bool check(double x, const boost::ranlux64_3_01&)
84{ return std::abs(x-0.838413) < 1e-6; }
85bool check(double x, const boost::ranlux64_4_01&)
86{ return std::abs(x-0.59839) < 1e-6; }
87
88template<class PRNG>
89void validate(const std::string & name, const PRNG &)
90{
91  std::cout << "validating " << name << ": ";
92  PRNG rng;  // default ctor
93  for(int i = 0; i < 9999; i++)
94    rng();
95  typename PRNG::result_type val = rng();
96  // make sure the validation function is a static member
97  bool result = check(val, rng);
98 
99  // allow for a simple eyeball check for MSVC instantiation brokenness
100  // (if the numbers for all generators are the same, it's obviously broken)
101  std::cout << val << std::endl;
102  BOOST_CHECK(result);
103}
104
105void validate_all()
106{
107  using namespace boost;
108#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
109  validate("rand48", rand48());
110#endif
111  validate("minstd_rand", minstd_rand());
112  validate("minstd_rand0", minstd_rand0());
113  validate("ecuyer combined", ecuyer1988());
114  validate("mt11213b", mt11213b());
115  validate("mt19937", mt19937());
116  validate("kreutzer1986", kreutzer1986());
117  validate("ranlux3", ranlux3());
118  validate("ranlux4", ranlux4());
119  validate("ranlux3_01", ranlux3_01());
120  validate("ranlux4_01", ranlux4_01());
121  validate("ranlux64_3_01", ranlux64_3_01());
122  validate("ranlux64_4_01", ranlux64_4_01());
123  validate("taus88", taus88());
124  validate("lagged_fibonacci607", lagged_fibonacci607());
125}
126
127
128/*
129 * Check function signatures
130 */
131
132#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x570) )
133#pragma warn -par
134#endif
135template<class URNG, class Dist>
136void instantiate_dist(URNG& urng, const char * name, const Dist& dist)
137{
138  // this makes a copy of urng
139  boost::variate_generator<URNG, Dist> gen(urng, dist);
140
141  // this keeps a reference to urng
142  boost::variate_generator<URNG&, Dist> genref(urng, dist);
143
144#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
145  // and here is a pointer to (a copy of) the urng
146  URNG copy = urng;
147  boost::variate_generator<URNG*, Dist> genptr(&copy, dist);
148#endif
149
150  for(int i = 0; i < 1000; ++i) {
151    (void) gen();
152    (void) genref();
153#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
154    (void) genptr();
155#endif
156  }
157  typename Dist::result_type g = gen();
158  BOOST_CHECK(std::abs(g - genref()) < 1e-6);
159#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
160  BOOST_CHECK(std::abs(g - genptr()) < 1e-6);
161#endif
162
163  (void) gen.engine();
164  gen.distribution().reset();
165
166  Dist d = dist;            // copy ctor
167  d = dist;                 // copy assignment
168
169#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
170  {
171    std::ostringstream file;
172    file << urng << std::endl;
173    file << d;
174    std::istringstream input(file.str());
175    // std::cout << file.str() << std::endl;
176    URNG restored_engine;
177    input >> restored_engine;
178    input >> std::ws;
179    Dist restored_dist;
180    input >> restored_dist;
181#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
182    boost::variate_generator<URNG, Dist> old(urng, d);
183    boost::variate_generator<URNG, Dist> restored(restored_engine, restored_dist);
184    // advance some more so that state is exercised
185    for(int i = 0; i < 1000; ++i) {
186      (void) old();
187      (void) restored();
188    }
189    BOOST_CHECK_MESSAGE((std::abs(old()-restored()) < 0.0001),
190                        (std::string(name) + " old == restored_dist"));
191#endif // BOOST_MSVC
192  }
193#endif // BOOST_NO_OPERATORS_IN_NAMESPACE
194}
195
196template<class URNG, class RealType>
197void instantiate_real_dist(URNG& urng, RealType /* ignored */)
198{
199  instantiate_dist(urng, "uniform_real",
200                   boost::uniform_real<RealType>(0, 2.1));
201  instantiate_dist(urng, "triangle_distribution",
202                   boost::triangle_distribution<RealType>(1, 1.5, 7));
203  instantiate_dist(urng, "exponential_distribution",
204                   boost::exponential_distribution<RealType>(5));
205  instantiate_dist(urng, "normal_distribution",
206                   boost::normal_distribution<RealType>());
207  instantiate_dist(urng, "lognormal_distribution",
208                   boost::lognormal_distribution<RealType>(1, 1));
209  instantiate_dist(urng, "cauchy_distribution",
210                   boost::cauchy_distribution<RealType>(1));
211  instantiate_dist(urng, "gamma_distribution",
212                   boost::gamma_distribution<RealType>(1));
213}
214
215template<class URNG, class ResultType>
216void instantiate_urng(const std::string & s, const URNG &, const ResultType &)
217{
218  std::cout << "Basic tests for " << s;
219  URNG urng;
220  urng.seed();                                  // seed() member function
221  int a[URNG::has_fixed_range ? 5 : 10];        // compile-time constant
222  (void) a;   // avoid "unused" warning
223  typename URNG::result_type x1 = urng();
224  ResultType x2 = x1;
225  (void) &x2;           // avoid "unused" warning
226
227  URNG urng2 = urng;             // copy constructor
228#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
229  BOOST_CHECK(urng == urng2);     // operator==
230  BOOST_CHECK(!(urng != urng2));  // operator!=
231  urng();
232  urng2 = urng;                  // copy assignment
233  BOOST_CHECK(urng == urng2);
234#endif // BOOST_MSVC
235
236  const std::vector<int> v(9999u, 0x41);
237  std::vector<int>::const_iterator it = v.begin();
238  std::vector<int>::const_iterator it_end = v.end();
239  URNG urng3(it, it_end);
240  BOOST_CHECK(it != v.begin());
241  std::cout << "; seeding uses " << (it - v.begin()) << " words" << std::endl;
242
243  bool have_exception = false;
244  try {
245    // now check that exceptions are thrown
246    it = v.end();
247    urng3.seed(it, it_end);
248  } catch(std::invalid_argument& x) {
249    have_exception = true;
250  }
251  BOOST_CHECK(have_exception);
252
253  // check for min/max members
254  ResultType min = (urng3.min)();
255  (void) &min;
256  ResultType max = (urng3.max)();
257  (void) &max;
258
259#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
260  // Streamable concept not supported for broken compilers
261
262  // advance a little so that state is relatively arbitrary
263  for(int i = 0; i < 9307; ++i)
264    urng();
265  urng2 = urng;
266
267  {
268    // narrow stream first
269    std::ostringstream file;
270    file << urng;
271    // move forward
272    urng();
273    // restore old state
274    std::istringstream input(file.str());
275    input >> urng;
276    // std::cout << file.str() << std::endl;
277#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
278    // advance some more so that state is exercised
279    for(int i = 0; i < 10000; ++i) {
280      urng();
281      urng2();
282    }
283    BOOST_CHECK(urng == urng2);
284#endif // BOOST_MSVC
285  }
286 
287  urng2 = urng;
288#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING)
289  {
290    // then wide stream
291    std::wostringstream file;
292    file << urng;
293    // move forward
294    urng();
295    std::wistringstream input(file.str());
296    input >> urng;
297#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
298    // advance some more so that state is exercised
299    for(int i = 0; i < 10000; ++i) {
300      urng();
301      urng2();
302    }
303    BOOST_CHECK(urng == urng2);
304#endif // BOOST_MSVC
305  }
306#endif // BOOST_NO_STD_WSTREAMBUF, BOOST_NO_STD_WSTRING
307#endif // BOOST_NO_OPERATORS_IN_NAMESPACE etc.
308
309  // instantiate various distributions with this URNG
310  // instantiate_dist(urng, "uniform_smallint", boost::uniform_smallint(0, 11));
311  instantiate_dist(urng, "uniform_int", boost::uniform_int<>(-200, 20000));
312  instantiate_dist(urng, "bernoulli_distribution",
313                   boost::bernoulli_distribution<>(0.2));
314  instantiate_dist(urng, "binomial_distribution",
315                   boost::binomial_distribution<>(4, 0.2));
316  instantiate_dist(urng, "geometric_distribution",
317                   boost::geometric_distribution<>(0.8));
318  instantiate_dist(urng, "poisson_distribution",
319                   boost::poisson_distribution<>(1));
320
321  instantiate_real_dist(urng, 1.0f);
322  instantiate_real_dist(urng, 1.0);
323  instantiate_real_dist(urng, 1.0l);
324
325#if 0
326  // We cannot compare the outcomes before/after save with std::abs(x-y)
327  instantiate_dist("uniform_on_sphere",
328                   boost::uniform_on_sphere<URNG>(urng, 2));
329#endif
330}
331
332void instantiate_all()
333{
334  using namespace boost;
335
336#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
337  instantiate_urng("rand48", rand48(), 0);
338  rand48 rnd(boost::int32_t(5));
339  rand48 rnd2(boost::uint64_t(0x80000000) * 42);
340  rnd.seed(boost::int32_t(17));
341  rnd2.seed(boost::uint64_t(0x80000000) * 49);
342#endif
343
344  instantiate_urng("minstd_rand0", minstd_rand0(), 0);
345  instantiate_urng("minstd_rand", minstd_rand(), 0);
346  minstd_rand mstd(42);
347  mstd.seed(17);
348
349  instantiate_urng("ecuyer1988", ecuyer1988(), 0);
350  instantiate_urng("kreutzer1986", kreutzer1986(), 0);
351  instantiate_urng("hellekalek1995", hellekalek1995(), 0);
352
353  instantiate_urng("mt11213b", mt11213b(), 0u);
354  instantiate_urng("mt19937", mt19937(), 0u);
355
356  mt19937 mt(boost::uint32_t(17));  // needs to be an exact type match for MSVC
357  int i = 42;
358  mt.seed(boost::uint32_t(i));
359  mt19937 mt2(mstd);
360  mt2.seed(mstd);
361
362
363  random_number_generator<mt19937> std_rng(mt2);
364  (void) std_rng(10);
365
366  instantiate_urng("lagged_fibonacci",
367                   boost::random::lagged_fibonacci<boost::uint32_t, 24, 607, 273>(),
368                   0u);
369  instantiate_urng("lagged_fibonacci607", lagged_fibonacci607(), 0.0);
370
371  instantiate_urng("ranlux3", ranlux3(), 0u);
372  instantiate_urng("ranlux4", ranlux4(), 0u);
373
374  instantiate_urng("ranlux3_01", ranlux3_01(), 0.0f);
375  instantiate_urng("ranlux4_01", ranlux4_01(), 0.0f);
376
377  instantiate_urng("ranlux64_3_01", ranlux64_3_01(), 0.0);
378  instantiate_urng("ranlux64_4_01", ranlux64_4_01(), 0.0);
379
380  instantiate_urng("taus88", taus88(), 0u);
381}
382
383/*
384 * A few equidistribution tests
385 */
386
387// yet to come...
388
389template<class Generator>
390void check_uniform_int(Generator & gen, int iter)
391{
392  std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)() 
393            << ")" << std::endl;
394  int range = (gen.max)()-(gen.min)()+1;
395  std::vector<int> bucket(range);
396  for(int j = 0; j < iter; j++) {
397    int result = gen();
398    if(result < (gen.min)() || result > (gen.max)())
399      std::cerr << "   ... delivers " << result << std::endl;
400    else
401      bucket[result-(gen.min)()]++;
402  }
403  int sum = 0;
404  // use a different variable name "k", because MSVC has broken "for" scoping
405  for(int k = 0; k < range; k++)
406    sum += bucket[k];
407  double avg = static_cast<double>(sum)/range;
408  double threshold = 2*avg/std::sqrt(static_cast<double>(iter));
409  for(int i = 0; i < range; i++) {
410    if(std::fabs(bucket[i] - avg) > threshold) {
411      // 95% confidence interval
412      std::cout << "   ... has bucket[" << i << "] = " << bucket[i] 
413                << "  (distance " << (bucket[i] - avg) << ")" 
414                << std::endl;
415    }
416  }
417}
418
419template<class Generator>
420void test_uniform_int(Generator & gen)
421{
422  typedef boost::uniform_int<int> int_gen;
423
424  // large range => small range (modulo case)
425  typedef boost::variate_generator<Generator&, int_gen> level_one;
426
427  level_one uint12(gen, int_gen(1,2));
428  BOOST_CHECK((uint12.distribution().min)() == 1);
429  BOOST_CHECK((uint12.distribution().max)() == 2);
430  check_uniform_int(uint12, 100000);
431  level_one uint16(gen, int_gen(1,6));
432  check_uniform_int(uint16, 100000);
433
434  // test chaining to get all cases in operator()
435
436  // identity map
437  typedef boost::variate_generator<level_one&, int_gen> level_two;
438  level_two uint01(uint12, int_gen(0, 1));
439  check_uniform_int(uint01, 100000);
440
441  // small range => larger range
442  level_two uint05(uint12, int_gen(-3, 2));
443  check_uniform_int(uint05, 100000);
444
445  // larger => small range, rejection case
446  typedef boost::variate_generator<level_two&, int_gen> level_three;
447  level_three uint1_4(uint05, int_gen(1, 4));
448  check_uniform_int(uint1_4, 100000);
449}
450
451#if defined(BOOST_MSVC) && _MSC_VER < 1300
452
453// These explicit instantiations are necessary, otherwise MSVC does
454// not find the <boost/operators.hpp> inline friends.
455// We ease the typing with a suitable preprocessor macro.
456#define INSTANT(x) \
457template class boost::uniform_smallint<x>; \
458template class boost::uniform_int<x>; \
459template class boost::uniform_real<x>; \
460template class boost::bernoulli_distribution<x>; \
461template class boost::geometric_distribution<x>; \
462template class boost::triangle_distribution<x>; \
463template class boost::exponential_distribution<x>; \
464template class boost::normal_distribution<x>; \
465template class boost::uniform_on_sphere<x>; \
466template class boost::lognormal_distribution<x>;
467
468INSTANT(boost::minstd_rand0)
469INSTANT(boost::minstd_rand)
470INSTANT(boost::ecuyer1988)
471INSTANT(boost::kreutzer1986)
472INSTANT(boost::hellekalek1995)
473INSTANT(boost::mt19937)
474INSTANT(boost::mt11213b)
475
476#undef INSTANT
477#endif
478
479#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
480// testcase by Mario R�tti
481class ruetti_gen
482{
483public:
484  typedef boost::uint64_t result_type;
485  result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
486  result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits<result_type>::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
487  result_type operator()() { return (max)()-1; }
488};
489
490void test_overflow_range()
491{
492  ruetti_gen gen;
493  boost::variate_generator<ruetti_gen, boost::uniform_int<> >
494    rng(gen, boost::uniform_int<>(0, 10));
495  for (int i=0;i<10;i++)
496    (void) rng();
497}
498#else
499void test_overflow_range()
500{ }
501#endif
502
503int test_main(int, char*[])
504{
505
506#if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700
507  instantiate_all();
508  validate_all();
509  boost::mt19937 mt;
510  test_uniform_int(mt);
511
512  // bug report from Ken Mahler:  This used to lead to an endless loop.
513  typedef boost::uniform_int<unsigned int> uint_dist;
514  boost::minstd_rand mr;
515  boost::variate_generator<boost::minstd_rand, uint_dist> r2(mr,
516                                                            uint_dist(0, 0xffffffff));
517  r2();
518  r2();
519
520  // bug report from Fernando Cacciola:  This used to lead to an endless loop.
521  // also from Douglas Gregor
522  boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > x(mr, boost::uniform_int<>(0, 8361));
523  (void) x();
524
525  // bug report from Alan Stokes and others: this throws an assertion
526  boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > y(mr, boost::uniform_int<>(1,1));
527  std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y()
528            << std::endl;
529
530  test_overflow_range();
531
532  return 0;
533#else
534  std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n";
535  return 1;
536#endif
537}
Note: See TracBrowser for help on using the repository browser.