diff 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
line wrap: on
line diff
--- a/DEPENDENCIES/generic/include/boost/random/mersenne_twister.hpp	Fri Sep 04 12:01:02 2015 +0100
+++ b/DEPENDENCIES/generic/include/boost/random/mersenne_twister.hpp	Mon Sep 07 11:12:49 2015 +0100
@@ -8,9 +8,10 @@
  *
  * See http://www.boost.org for most recent version including documentation.
  *
- * $Id: mersenne_twister.hpp 74867 2011-10-09 23:13:31Z steven_watanabe $
+ * $Id$
  *
  * Revision history
+ *  2013-10-14  fixed some warnings with Wshadow (mgaunard)
  *  2001-02-18  moved to individual header files
  */
 
@@ -28,6 +29,9 @@
 #include <boost/random/detail/seed.hpp>
 #include <boost/random/detail/seed_impl.hpp>
 #include <boost/random/detail/generator_seed_seq.hpp>
+#include <boost/random/detail/polynomial.hpp>
+
+#include <boost/random/detail/disable_warnings.hpp>
 
 namespace boost {
 namespace random {
@@ -40,7 +44,7 @@
  *  "Mersenne Twister: A 623-dimensionally equidistributed uniform
  *  pseudo-random number generator", Makoto Matsumoto and Takuji Nishimura,
  *  ACM Transactions on Modeling and Computer Simulation: Special Issue on
- *  Uniform Random Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 
+ *  Uniform Random Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
  *  @endblockquote
  *
  * @xmlnote
@@ -51,7 +55,7 @@
  *
  * The seeding from an integer was changed in April 2005 to address a
  * <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html">weakness</a>.
- * 
+ *
  * The quality of the generator crucially depends on the choice of the
  * parameters.  User code should employ one of the sensibly parameterized
  * generators such as \mt19937 instead.
@@ -83,7 +87,7 @@
     BOOST_STATIC_CONSTANT(std::size_t, tempering_l = l);
     BOOST_STATIC_CONSTANT(UIntType, initialization_multiplier = f);
     BOOST_STATIC_CONSTANT(UIntType, default_seed = 5489u);
-  
+
     // backwards compatibility
     BOOST_STATIC_CONSTANT(UIntType, parameter_a = a);
     BOOST_STATIC_CONSTANT(std::size_t, output_u = u);
@@ -92,7 +96,7 @@
     BOOST_STATIC_CONSTANT(std::size_t, output_t = t);
     BOOST_STATIC_CONSTANT(UIntType, output_c = c);
     BOOST_STATIC_CONSTANT(std::size_t, output_l = l);
-    
+
     // old Boost.Random concept requirements
     BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
 
@@ -136,7 +140,7 @@
      */
     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister_engine, UIntType, value)
     {
-        // New seeding algorithm from 
+        // New seeding algorithm from
         // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
         // In the previous versions, MSBs of the seed affected only MSBs of the
         // state x[].
@@ -147,8 +151,10 @@
             // Vol. 2, 3rd ed., page 106
             x[i] = (f * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask;
         }
+
+        normalize_state();
     }
-    
+
     /**
      * Seeds a mersenne_twister_engine using values produced by seq.generate().
      */
@@ -157,13 +163,7 @@
         detail::seed_array_int<w>(seq, x);
         i = n;
 
-        // fix up the state if it's all zeroes.
-        if((x[0] & (~static_cast<UIntType>(0) << r)) == 0) {
-            for(std::size_t j = 1; j < n; ++j) {
-                if(x[j] != 0) return;
-            }
-            x[0] = static_cast<UIntType>(1) << (w-1);
-        }
+        normalize_state();
     }
 
     /** Sets the state of the generator using values from an iterator range. */
@@ -173,22 +173,16 @@
         detail::fill_array_int<w>(first, last, x);
         i = n;
 
-        // fix up the state if it's all zeroes.
-        if((x[0] & (~static_cast<UIntType>(0) << r)) == 0) {
-            for(std::size_t j = 1; j < n; ++j) {
-                if(x[j] != 0) return;
-            }
-            x[0] = static_cast<UIntType>(1) << (w-1);
-        }
+        normalize_state();
     }
-  
+
     /** Returns the smallest value that the generator can produce. */
     static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
     { return 0; }
     /** Returns the largest value that the generator can produce. */
     static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
     { return boost::low_bits_mask_t<w>::sig_bits; }
-    
+
     /** Produces the next value of the generator. */
     result_type operator()();
 
@@ -208,8 +202,15 @@
      */
     void discard(boost::uintmax_t z)
     {
-        for(boost::uintmax_t j = 0; j < z; ++j) {
-            (*this)();
+#ifndef BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD
+#define BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD 10000000
+#endif
+        if(z > BOOST_RANDOM_MERSENNE_TWISTER_DISCARD_THRESHOLD) {
+            discard_many(z);
+        } else {
+            for(boost::uintmax_t j = 0; j < z; ++j) {
+                (*this)();
+            }
         }
     }
 
@@ -223,7 +224,7 @@
         mt.print(os);
         return os;
     }
-    
+
     /** Reads a mersenne_twister_engine from a @c std::istream */
     template<class CharT, class Traits>
     friend std::basic_istream<CharT,Traits>&
@@ -244,19 +245,19 @@
      * Returns true if the two generators are in the same state,
      * and will thus produce identical sequences.
      */
-    friend bool operator==(const mersenne_twister_engine& x,
-                           const mersenne_twister_engine& y)
+    friend bool operator==(const mersenne_twister_engine& x_,
+                           const mersenne_twister_engine& y_)
     {
-        if(x.i < y.i) return x.equal_imp(y);
-        else return y.equal_imp(x);
+        if(x_.i < y_.i) return x_.equal_imp(y_);
+        else return y_.equal_imp(x_);
     }
-    
+
     /**
      * Returns true if the two generators are in different states.
      */
-    friend bool operator!=(const mersenne_twister_engine& x,
-                           const mersenne_twister_engine& y)
-    { return !(x == y); }
+    friend bool operator!=(const mersenne_twister_engine& x_,
+                           const mersenne_twister_engine& y_)
+    { return !(x_ == y_); }
 
 private:
     /// \cond show_private
@@ -333,6 +334,35 @@
     }
 
     /**
+     * Converts an arbitrary array into a valid generator state.
+     * First we normalize x[0], so that it contains the same
+     * value we would get by running the generator forwards
+     * and then in reverse.  (The low order r bits are redundant).
+     * Then, if the state consists of all zeros, we set the
+     * high order bit of x[0] to 1.  This function only needs to
+     * be called by seed, since the state transform preserves
+     * this relationship.
+     */
+    void normalize_state()
+    {
+        const UIntType upper_mask = (~static_cast<UIntType>(0)) << r;
+        const UIntType lower_mask = ~upper_mask;
+        UIntType y0 = x[m-1] ^ x[n-1];
+        if(y0 & (static_cast<UIntType>(1) << (w-1))) {
+            y0 = ((y0 ^ a) << 1) | 1;
+        } else {
+            y0 = y0 << 1;
+        }
+        x[0] = (x[0] & upper_mask) | (y0 & lower_mask);
+
+        // fix up the state if it's all zeroes.
+        for(std::size_t j = 0; j < n; ++j) {
+            if(x[j] != 0) return;
+        }
+        x[0] = static_cast<UIntType>(1) << (w-1);
+    }
+
+    /**
      * Given a pointer to the last element of the rewind array,
      * and the current size of the rewind array, finds an element
      * relative to the next available slot in the rewind array.
@@ -348,13 +378,118 @@
         }
     }
 
+    /**
+     * Optimized algorithm for large jumps.
+     *
+     * Hiroshi Haramoto, Makoto Matsumoto, and Pierre L'Ecuyer. 2008.
+     * A Fast Jump Ahead Algorithm for Linear Recurrences in a Polynomial
+     * Space. In Proceedings of the 5th international conference on
+     * Sequences and Their Applications (SETA '08).
+     * DOI=10.1007/978-3-540-85912-3_26
+     */
+    void discard_many(boost::uintmax_t z)
+    {
+        // Compute the minimal polynomial, phi(t)
+        // This depends only on the transition function,
+        // which is constant.  The characteristic
+        // polynomial is the same as the minimal
+        // polynomial for a maximum period generator
+        // (which should be all specializations of
+        // mersenne_twister.)  Even if it weren't,
+        // the characteristic polynomial is guaranteed
+        // to be a multiple of the minimal polynomial,
+        // which is good enough.
+        detail::polynomial phi = get_characteristic_polynomial();
+
+        // calculate g(t) = t^z % phi(t)
+        detail::polynomial g = mod_pow_x(z, phi);
+
+        // h(s_0, t) = \sum_{i=0}^{2k-1}o(s_i)t^{2k-i-1}
+        detail::polynomial h;
+        const std::size_t num_bits = w*n - r;
+        for(std::size_t j = 0; j < num_bits * 2; ++j) {
+            // Yes, we're advancing the generator state
+            // here, but it doesn't matter because
+            // we're going to overwrite it completely
+            // in reconstruct_state.
+            if(i >= n) twist();
+            h[2*num_bits - j - 1] = x[i++] & UIntType(1);
+        }
+        // g(t)h(s_0, t)
+        detail::polynomial gh = g * h;
+        detail::polynomial result;
+        for(std::size_t j = 0; j <= num_bits; ++j) {
+            result[j] = gh[2*num_bits - j - 1];
+        }
+        reconstruct_state(result);
+    }
+    static detail::polynomial get_characteristic_polynomial()
+    {
+        const std::size_t num_bits = w*n - r;
+        detail::polynomial helper;
+        helper[num_bits - 1] = 1;
+        mersenne_twister_engine tmp;
+        tmp.reconstruct_state(helper);
+        // Skip the first num_bits elements, since we
+        // already know what they are.
+        for(std::size_t j = 0; j < num_bits; ++j) {
+            if(tmp.i >= n) tmp.twist();
+            if(j == num_bits - 1)
+                assert((tmp.x[tmp.i] & 1) == 1);
+            else
+                assert((tmp.x[tmp.i] & 1) == 0);
+            ++tmp.i;
+        }
+        detail::polynomial phi;
+        phi[num_bits] = 1;
+        detail::polynomial next_bits = tmp.as_polynomial(num_bits);
+        for(std::size_t j = 0; j < num_bits; ++j) {
+            int val = next_bits[j] ^ phi[num_bits-j-1];
+            phi[num_bits-j-1] = val;
+            if(val) {
+                for(std::size_t k = j + 1; k < num_bits; ++k) {
+                    phi[num_bits-k-1] ^= next_bits[k-j-1];
+                }
+            }
+        }
+        return phi;
+    }
+    detail::polynomial as_polynomial(std::size_t size) {
+        detail::polynomial result;
+        for(std::size_t j = 0; j < size; ++j) {
+            if(i >= n) twist();
+            result[j] = x[i++] & UIntType(1);
+        }
+        return result;
+    }
+    void reconstruct_state(const detail::polynomial& p)
+    {
+        const UIntType upper_mask = (~static_cast<UIntType>(0)) << r;
+        const UIntType lower_mask = ~upper_mask;
+        const std::size_t num_bits = w*n - r;
+        for(std::size_t j = num_bits - n + 1; j <= num_bits; ++j)
+            x[j % n] = p[j];
+
+        UIntType y0 = 0;
+        for(std::size_t j = num_bits + 1; j >= n - 1; --j) {
+            UIntType y1 = x[j % n] ^ x[(j + m) % n];
+            if(p[j - n + 1])
+                y1 = (y1 ^ a) << UIntType(1) | UIntType(1);
+            else
+                y1 = y1 << UIntType(1);
+            x[(j + 1) % n] = (y0 & upper_mask) | (y1 & lower_mask);
+            y0 = y1;
+        }
+        i = 0;
+    }
+
     /// \endcond
 
     // state representation: next output is o(x(i))
     //   x[0]  ... x[k] x[k+1] ... x[n-1]   represents
     //  x(i-k) ... x(i) x(i+1) ... x(i-k+n-1)
 
-    UIntType x[n]; 
+    UIntType x[n];
     std::size_t i;
 };
 
@@ -468,7 +603,7 @@
  *  uniform pseudo-random number generator", Makoto Matsumoto
  *  and Takuji Nishimura, ACM Transactions on Modeling and
  *  Computer Simulation: Special Issue on Uniform Random Number
- *  Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 
+ *  Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
  *  @endblockquote
  */
 typedef mersenne_twister_engine<uint32_t,32,351,175,19,0xccab8ee7,
@@ -482,7 +617,7 @@
  *  uniform pseudo-random number generator", Makoto Matsumoto
  *  and Takuji Nishimura, ACM Transactions on Modeling and
  *  Computer Simulation: Special Issue on Uniform Random Number
- *  Generation, Vol. 8, No. 1, January 1998, pp. 3-30. 
+ *  Generation, Vol. 8, No. 1, January 1998, pp. 3-30.
  *  @endblockquote
  */
 typedef mersenne_twister_engine<uint32_t,32,624,397,31,0x9908b0df,
@@ -542,4 +677,6 @@
 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937)
 BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937_64)
 
+#include <boost/random/detail/enable_warnings.hpp>
+
 #endif // BOOST_RANDOM_MERSENNE_TWISTER_HPP