comparison DEPENDENCIES/generic/include/boost/random/mersenne_twister.hpp @ 101:c530137014c0

Update Boost headers (1.58.0)
author Chris Cannam
date Mon, 07 Sep 2015 11:12:49 +0100
parents 2665513ce2d3
children
comparison
equal deleted inserted replaced
100:793467b5e61c 101:c530137014c0
6 * accompanying file LICENSE_1_0.txt or copy at 6 * accompanying file LICENSE_1_0.txt or copy at
7 * http://www.boost.org/LICENSE_1_0.txt) 7 * http://www.boost.org/LICENSE_1_0.txt)
8 * 8 *
9 * See http://www.boost.org for most recent version including documentation. 9 * See http://www.boost.org for most recent version including documentation.
10 * 10 *
11 * $Id: mersenne_twister.hpp 74867 2011-10-09 23:13:31Z steven_watanabe $ 11 * $Id$
12 * 12 *
13 * Revision history 13 * Revision history
14 * 2013-10-14 fixed some warnings with Wshadow (mgaunard)
14 * 2001-02-18 moved to individual header files 15 * 2001-02-18 moved to individual header files
15 */ 16 */
16 17
17 #ifndef BOOST_RANDOM_MERSENNE_TWISTER_HPP 18 #ifndef BOOST_RANDOM_MERSENNE_TWISTER_HPP
18 #define BOOST_RANDOM_MERSENNE_TWISTER_HPP 19 #define BOOST_RANDOM_MERSENNE_TWISTER_HPP
26 #include <boost/random/detail/config.hpp> 27 #include <boost/random/detail/config.hpp>
27 #include <boost/random/detail/ptr_helper.hpp> 28 #include <boost/random/detail/ptr_helper.hpp>
28 #include <boost/random/detail/seed.hpp> 29 #include <boost/random/detail/seed.hpp>
29 #include <boost/random/detail/seed_impl.hpp> 30 #include <boost/random/detail/seed_impl.hpp>
30 #include <boost/random/detail/generator_seed_seq.hpp> 31 #include <boost/random/detail/generator_seed_seq.hpp>
32 #include <boost/random/detail/polynomial.hpp>
33
34 #include <boost/random/detail/disable_warnings.hpp>
31 35
32 namespace boost { 36 namespace boost {
33 namespace random { 37 namespace random {
34 38
35 /** 39 /**
38 * 42 *
39 * @blockquote 43 * @blockquote
40 * "Mersenne Twister: A 623-dimensionally equidistributed uniform 44 * "Mersenne Twister: A 623-dimensionally equidistributed uniform
41 * pseudo-random number generator", Makoto Matsumoto and Takuji Nishimura, 45 * pseudo-random number generator", Makoto Matsumoto and Takuji Nishimura,
42 * ACM Transactions on Modeling and Computer Simulation: Special Issue on 46 * ACM Transactions on Modeling and Computer Simulation: Special Issue on
43 * Uniform Random Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 47 * Uniform Random Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
44 * @endblockquote 48 * @endblockquote
45 * 49 *
46 * @xmlnote 50 * @xmlnote
47 * The boost variant has been implemented from scratch and does not 51 * The boost variant has been implemented from scratch and does not
48 * derive from or use mt19937.c provided on the above WWW site. However, it 52 * derive from or use mt19937.c provided on the above WWW site. However, it
49 * was verified that both produce identical output. 53 * was verified that both produce identical output.
50 * @endxmlnote 54 * @endxmlnote
51 * 55 *
52 * The seeding from an integer was changed in April 2005 to address a 56 * The seeding from an integer was changed in April 2005 to address a
53 * <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html">weakness</a>. 57 * <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html">weakness</a>.
54 * 58 *
55 * The quality of the generator crucially depends on the choice of the 59 * The quality of the generator crucially depends on the choice of the
56 * parameters. User code should employ one of the sensibly parameterized 60 * parameters. User code should employ one of the sensibly parameterized
57 * generators such as \mt19937 instead. 61 * generators such as \mt19937 instead.
58 * 62 *
59 * The generator requires considerable amounts of memory for the storage of 63 * The generator requires considerable amounts of memory for the storage of
81 BOOST_STATIC_CONSTANT(std::size_t, tempering_t = t); 85 BOOST_STATIC_CONSTANT(std::size_t, tempering_t = t);
82 BOOST_STATIC_CONSTANT(UIntType, tempering_c = c); 86 BOOST_STATIC_CONSTANT(UIntType, tempering_c = c);
83 BOOST_STATIC_CONSTANT(std::size_t, tempering_l = l); 87 BOOST_STATIC_CONSTANT(std::size_t, tempering_l = l);
84 BOOST_STATIC_CONSTANT(UIntType, initialization_multiplier = f); 88 BOOST_STATIC_CONSTANT(UIntType, initialization_multiplier = f);
85 BOOST_STATIC_CONSTANT(UIntType, default_seed = 5489u); 89 BOOST_STATIC_CONSTANT(UIntType, default_seed = 5489u);
86 90
87 // backwards compatibility 91 // backwards compatibility
88 BOOST_STATIC_CONSTANT(UIntType, parameter_a = a); 92 BOOST_STATIC_CONSTANT(UIntType, parameter_a = a);
89 BOOST_STATIC_CONSTANT(std::size_t, output_u = u); 93 BOOST_STATIC_CONSTANT(std::size_t, output_u = u);
90 BOOST_STATIC_CONSTANT(std::size_t, output_s = s); 94 BOOST_STATIC_CONSTANT(std::size_t, output_s = s);
91 BOOST_STATIC_CONSTANT(UIntType, output_b = b); 95 BOOST_STATIC_CONSTANT(UIntType, output_b = b);
92 BOOST_STATIC_CONSTANT(std::size_t, output_t = t); 96 BOOST_STATIC_CONSTANT(std::size_t, output_t = t);
93 BOOST_STATIC_CONSTANT(UIntType, output_c = c); 97 BOOST_STATIC_CONSTANT(UIntType, output_c = c);
94 BOOST_STATIC_CONSTANT(std::size_t, output_l = l); 98 BOOST_STATIC_CONSTANT(std::size_t, output_l = l);
95 99
96 // old Boost.Random concept requirements 100 // old Boost.Random concept requirements
97 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); 101 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
98 102
99 103
100 /** 104 /**
134 * (i + f * (x(i-1) xor (x(i-1) rshift w-2))) mod 2<sup>w</sup> 138 * (i + f * (x(i-1) xor (x(i-1) rshift w-2))) mod 2<sup>w</sup>
135 * for i = 1 .. n-1. x(n) is the first value to be returned by operator(). 139 * for i = 1 .. n-1. x(n) is the first value to be returned by operator().
136 */ 140 */
137 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister_engine, UIntType, value) 141 BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister_engine, UIntType, value)
138 { 142 {
139 // New seeding algorithm from 143 // New seeding algorithm from
140 // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html 144 // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
141 // In the previous versions, MSBs of the seed affected only MSBs of the 145 // In the previous versions, MSBs of the seed affected only MSBs of the
142 // state x[]. 146 // state x[].
143 const UIntType mask = (max)(); 147 const UIntType mask = (max)();
144 x[0] = value & mask; 148 x[0] = value & mask;
145 for (i = 1; i < n; i++) { 149 for (i = 1; i < n; i++) {
146 // See Knuth "The Art of Computer Programming" 150 // See Knuth "The Art of Computer Programming"
147 // Vol. 2, 3rd ed., page 106 151 // Vol. 2, 3rd ed., page 106
148 x[i] = (f * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask; 152 x[i] = (f * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask;
149 } 153 }
150 } 154
151 155 normalize_state();
156 }
157
152 /** 158 /**
153 * Seeds a mersenne_twister_engine using values produced by seq.generate(). 159 * Seeds a mersenne_twister_engine using values produced by seq.generate().
154 */ 160 */
155 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(mersenne_twister_engine, SeeqSeq, seq) 161 BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(mersenne_twister_engine, SeeqSeq, seq)
156 { 162 {
157 detail::seed_array_int<w>(seq, x); 163 detail::seed_array_int<w>(seq, x);
158 i = n; 164 i = n;
159 165
160 // fix up the state if it's all zeroes. 166 normalize_state();
161 if((x[0] & (~static_cast<UIntType>(0) << r)) == 0) {
162 for(std::size_t j = 1; j < n; ++j) {
163 if(x[j] != 0) return;
164 }
165 x[0] = static_cast<UIntType>(1) << (w-1);
166 }
167 } 167 }
168 168
169 /** Sets the state of the generator using values from an iterator range. */ 169 /** Sets the state of the generator using values from an iterator range. */
170 template<class It> 170 template<class It>
171 void seed(It& first, It last) 171 void seed(It& first, It last)
172 { 172 {
173 detail::fill_array_int<w>(first, last, x); 173 detail::fill_array_int<w>(first, last, x);
174 i = n; 174 i = n;
175 175
176 // fix up the state if it's all zeroes. 176 normalize_state();
177 if((x[0] & (~static_cast<UIntType>(0) << r)) == 0) { 177 }
178 for(std::size_t j = 1; j < n; ++j) { 178
179 if(x[j] != 0) return;
180 }
181 x[0] = static_cast<UIntType>(1) << (w-1);
182 }
183 }
184
185 /** Returns the smallest value that the generator can produce. */ 179 /** Returns the smallest value that the generator can produce. */
186 static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () 180 static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
187 { return 0; } 181 { return 0; }
188 /** Returns the largest value that the generator can produce. */ 182 /** Returns the largest value that the generator can produce. */
189 static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () 183 static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
190 { return boost::low_bits_mask_t<w>::sig_bits; } 184 { return boost::low_bits_mask_t<w>::sig_bits; }
191 185
192 /** Produces the next value of the generator. */ 186 /** Produces the next value of the generator. */
193 result_type operator()(); 187 result_type operator()();
194 188
195 /** Fills a range with random values */ 189 /** Fills a range with random values */
196 template<class Iter> 190 template<class Iter>
206 * } 200 * }
207 * @endcode 201 * @endcode
208 */ 202 */
209 void discard(boost::uintmax_t z) 203 void discard(boost::uintmax_t z)
210 { 204 {
211 for(boost::uintmax_t j = 0; j < z; ++j) { 205 #ifndef BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD
212 (*this)(); 206 #define BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD 10000000
207 #endif
208 if(z > BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD) {
209 discard_many(z);
210 } else {
211 for(boost::uintmax_t j = 0; j < z; ++j) {
212 (*this)();
213 }
213 } 214 }
214 } 215 }
215 216
216 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS 217 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
217 /** Writes a mersenne_twister_engine to a @c std::ostream */ 218 /** Writes a mersenne_twister_engine to a @c std::ostream */
221 const mersenne_twister_engine& mt) 222 const mersenne_twister_engine& mt)
222 { 223 {
223 mt.print(os); 224 mt.print(os);
224 return os; 225 return os;
225 } 226 }
226 227
227 /** Reads a mersenne_twister_engine from a @c std::istream */ 228 /** Reads a mersenne_twister_engine from a @c std::istream */
228 template<class CharT, class Traits> 229 template<class CharT, class Traits>
229 friend std::basic_istream<CharT,Traits>& 230 friend std::basic_istream<CharT,Traits>&
230 operator>>(std::basic_istream<CharT,Traits>& is, 231 operator>>(std::basic_istream<CharT,Traits>& is,
231 mersenne_twister_engine& mt) 232 mersenne_twister_engine& mt)
242 243
243 /** 244 /**
244 * Returns true if the two generators are in the same state, 245 * Returns true if the two generators are in the same state,
245 * and will thus produce identical sequences. 246 * and will thus produce identical sequences.
246 */ 247 */
247 friend bool operator==(const mersenne_twister_engine& x, 248 friend bool operator==(const mersenne_twister_engine& x_,
248 const mersenne_twister_engine& y) 249 const mersenne_twister_engine& y_)
249 { 250 {
250 if(x.i < y.i) return x.equal_imp(y); 251 if(x_.i < y_.i) return x_.equal_imp(y_);
251 else return y.equal_imp(x); 252 else return y_.equal_imp(x_);
252 } 253 }
253 254
254 /** 255 /**
255 * Returns true if the two generators are in different states. 256 * Returns true if the two generators are in different states.
256 */ 257 */
257 friend bool operator!=(const mersenne_twister_engine& x, 258 friend bool operator!=(const mersenne_twister_engine& x_,
258 const mersenne_twister_engine& y) 259 const mersenne_twister_engine& y_)
259 { return !(x == y); } 260 { return !(x_ == y_); }
260 261
261 private: 262 private:
262 /// \cond show_private 263 /// \cond show_private
263 264
264 void twist(); 265 void twist();
331 y0 = y1; 332 y0 = y1;
332 } 333 }
333 } 334 }
334 335
335 /** 336 /**
337 * Converts an arbitrary array into a valid generator state.
338 * First we normalize x[0], so that it contains the same
339 * value we would get by running the generator forwards
340 * and then in reverse. (The low order r bits are redundant).
341 * Then, if the state consists of all zeros, we set the
342 * high order bit of x[0] to 1. This function only needs to
343 * be called by seed, since the state transform preserves
344 * this relationship.
345 */
346 void normalize_state()
347 {
348 const UIntType upper_mask = (~static_cast<UIntType>(0)) << r;
349 const UIntType lower_mask = ~upper_mask;
350 UIntType y0 = x[m-1] ^ x[n-1];
351 if(y0 & (static_cast<UIntType>(1) << (w-1))) {
352 y0 = ((y0 ^ a) << 1) | 1;
353 } else {
354 y0 = y0 << 1;
355 }
356 x[0] = (x[0] & upper_mask) | (y0 & lower_mask);
357
358 // fix up the state if it's all zeroes.
359 for(std::size_t j = 0; j < n; ++j) {
360 if(x[j] != 0) return;
361 }
362 x[0] = static_cast<UIntType>(1) << (w-1);
363 }
364
365 /**
336 * Given a pointer to the last element of the rewind array, 366 * Given a pointer to the last element of the rewind array,
337 * and the current size of the rewind array, finds an element 367 * and the current size of the rewind array, finds an element
338 * relative to the next available slot in the rewind array. 368 * relative to the next available slot in the rewind array.
339 */ 369 */
340 UIntType 370 UIntType
346 } else { 376 } else {
347 return *(last - (n - 1 - index)); 377 return *(last - (n - 1 - index));
348 } 378 }
349 } 379 }
350 380
381 /**
382 * Optimized algorithm for large jumps.
383 *
384 * Hiroshi Haramoto, Makoto Matsumoto, and Pierre L'Ecuyer. 2008.
385 * A Fast Jump Ahead Algorithm for Linear Recurrences in a Polynomial
386 * Space. In Proceedings of the 5th international conference on
387 * Sequences and Their Applications (SETA '08).
388 * DOI=10.1007/978-3-540-85912-3_26
389 */
390 void discard_many(boost::uintmax_t z)
391 {
392 // Compute the minimal polynomial, phi(t)
393 // This depends only on the transition function,
394 // which is constant. The characteristic
395 // polynomial is the same as the minimal
396 // polynomial for a maximum period generator
397 // (which should be all specializations of
398 // mersenne_twister.) Even if it weren't,
399 // the characteristic polynomial is guaranteed
400 // to be a multiple of the minimal polynomial,
401 // which is good enough.
402 detail::polynomial phi = get_characteristic_polynomial();
403
404 // calculate g(t) = t^z % phi(t)
405 detail::polynomial g = mod_pow_x(z, phi);
406
407 // h(s_0, t) = \sum_{i=0}^{2k-1}o(s_i)t^{2k-i-1}
408 detail::polynomial h;
409 const std::size_t num_bits = w*n - r;
410 for(std::size_t j = 0; j < num_bits * 2; ++j) {
411 // Yes, we're advancing the generator state
412 // here, but it doesn't matter because
413 // we're going to overwrite it completely
414 // in reconstruct_state.
415 if(i >= n) twist();
416 h[2*num_bits - j - 1] = x[i++] & UIntType(1);
417 }
418 // g(t)h(s_0, t)
419 detail::polynomial gh = g * h;
420 detail::polynomial result;
421 for(std::size_t j = 0; j <= num_bits; ++j) {
422 result[j] = gh[2*num_bits - j - 1];
423 }
424 reconstruct_state(result);
425 }
426 static detail::polynomial get_characteristic_polynomial()
427 {
428 const std::size_t num_bits = w*n - r;
429 detail::polynomial helper;
430 helper[num_bits - 1] = 1;
431 mersenne_twister_engine tmp;
432 tmp.reconstruct_state(helper);
433 // Skip the first num_bits elements, since we
434 // already know what they are.
435 for(std::size_t j = 0; j < num_bits; ++j) {
436 if(tmp.i >= n) tmp.twist();
437 if(j == num_bits - 1)
438 assert((tmp.x[tmp.i] & 1) == 1);
439 else
440 assert((tmp.x[tmp.i] & 1) == 0);
441 ++tmp.i;
442 }
443 detail::polynomial phi;
444 phi[num_bits] = 1;
445 detail::polynomial next_bits = tmp.as_polynomial(num_bits);
446 for(std::size_t j = 0; j < num_bits; ++j) {
447 int val = next_bits[j] ^ phi[num_bits-j-1];
448 phi[num_bits-j-1] = val;
449 if(val) {
450 for(std::size_t k = j + 1; k < num_bits; ++k) {
451 phi[num_bits-k-1] ^= next_bits[k-j-1];
452 }
453 }
454 }
455 return phi;
456 }
457 detail::polynomial as_polynomial(std::size_t size) {
458 detail::polynomial result;
459 for(std::size_t j = 0; j < size; ++j) {
460 if(i >= n) twist();
461 result[j] = x[i++] & UIntType(1);
462 }
463 return result;
464 }
465 void reconstruct_state(const detail::polynomial& p)
466 {
467 const UIntType upper_mask = (~static_cast<UIntType>(0)) << r;
468 const UIntType lower_mask = ~upper_mask;
469 const std::size_t num_bits = w*n - r;
470 for(std::size_t j = num_bits - n + 1; j <= num_bits; ++j)
471 x[j % n] = p[j];
472
473 UIntType y0 = 0;
474 for(std::size_t j = num_bits + 1; j >= n - 1; --j) {
475 UIntType y1 = x[j % n] ^ x[(j + m) % n];
476 if(p[j - n + 1])
477 y1 = (y1 ^ a) << UIntType(1) | UIntType(1);
478 else
479 y1 = y1 << UIntType(1);
480 x[(j + 1) % n] = (y0 & upper_mask) | (y1 & lower_mask);
481 y0 = y1;
482 }
483 i = 0;
484 }
485
351 /// \endcond 486 /// \endcond
352 487
353 // state representation: next output is o(x(i)) 488 // state representation: next output is o(x(i))
354 // x[0] ... x[k] x[k+1] ... x[n-1] represents 489 // x[0] ... x[k] x[k+1] ... x[n-1] represents
355 // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) 490 // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1)
356 491
357 UIntType x[n]; 492 UIntType x[n];
358 std::size_t i; 493 std::size_t i;
359 }; 494 };
360 495
361 /// \cond show_private 496 /// \cond show_private
362 497
466 * @blockquote 601 * @blockquote
467 * "Mersenne Twister: A 623-dimensionally equidistributed 602 * "Mersenne Twister: A 623-dimensionally equidistributed
468 * uniform pseudo-random number generator", Makoto Matsumoto 603 * uniform pseudo-random number generator", Makoto Matsumoto
469 * and Takuji Nishimura, ACM Transactions on Modeling and 604 * and Takuji Nishimura, ACM Transactions on Modeling and
470 * Computer Simulation: Special Issue on Uniform Random Number 605 * Computer Simulation: Special Issue on Uniform Random Number
471 * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 606 * Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
472 * @endblockquote 607 * @endblockquote
473 */ 608 */
474 typedef mersenne_twister_engine<uint32_t,32,351,175,19,0xccab8ee7, 609 typedef mersenne_twister_engine<uint32_t,32,351,175,19,0xccab8ee7,
475 11,0xffffffff,7,0x31b6ab00,15,0xffe50000,17,1812433253> mt11213b; 610 11,0xffffffff,7,0x31b6ab00,15,0xffe50000,17,1812433253> mt11213b;
476 611
480 * @blockquote 615 * @blockquote
481 * "Mersenne Twister: A 623-dimensionally equidistributed 616 * "Mersenne Twister: A 623-dimensionally equidistributed
482 * uniform pseudo-random number generator", Makoto Matsumoto 617 * uniform pseudo-random number generator", Makoto Matsumoto
483 * and Takuji Nishimura, ACM Transactions on Modeling and 618 * and Takuji Nishimura, ACM Transactions on Modeling and
484 * Computer Simulation: Special Issue on Uniform Random Number 619 * Computer Simulation: Special Issue on Uniform Random Number
485 * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 620 * Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
486 * @endblockquote 621 * @endblockquote
487 */ 622 */
488 typedef mersenne_twister_engine<uint32_t,32,624,397,31,0x9908b0df, 623 typedef mersenne_twister_engine<uint32_t,32,624,397,31,0x9908b0df,
489 11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253> mt19937; 624 11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253> mt19937;
490 625
540 675
541 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt11213b) 676 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt11213b)
542 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937) 677 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937)
543 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937_64) 678 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937_64)
544 679
680 #include <boost/random/detail/enable_warnings.hpp>
681
545 #endif // BOOST_RANDOM_MERSENNE_TWISTER_HPP 682 #endif // BOOST_RANDOM_MERSENNE_TWISTER_HPP