/* -*- C++ -*- * * This file is a part of LEMON, a generic C++ optimization library * * Copyright (C) 2003-2008 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ /* * This file contains the reimplemented version of the Mersenne Twister * Generator of Matsumoto and Nishimura. * * See the appropriate copyright notice below. * * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The names of its contributors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * * Any feedback is very welcome. * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ #ifndef LEMON_RANDOM_H #define LEMON_RANDOM_H #include #include #include #include #include #include ///\ingroup misc ///\file ///\brief Mersenne Twister random number generator namespace lemon { namespace _random_bits { template ::digits> struct RandomTraits {}; template struct RandomTraits<_Word, 32> { typedef _Word Word; static const int bits = 32; static const int length = 624; static const int shift = 397; static const Word mul = 0x6c078965u; static const Word arrayInit = 0x012BD6AAu; static const Word arrayMul1 = 0x0019660Du; static const Word arrayMul2 = 0x5D588B65u; static const Word mask = 0x9908B0DFu; static const Word loMask = (1u << 31) - 1; static const Word hiMask = ~loMask; static Word tempering(Word rnd) { rnd ^= (rnd >> 11); rnd ^= (rnd << 7) & 0x9D2C5680u; rnd ^= (rnd << 15) & 0xEFC60000u; rnd ^= (rnd >> 18); return rnd; } }; template struct RandomTraits<_Word, 64> { typedef _Word Word; static const int bits = 64; static const int length = 312; static const int shift = 156; static const Word mul = Word(0x5851F42Du) << 32 | Word(0x4C957F2Du); static const Word arrayInit = Word(0x00000000u) << 32 |Word(0x012BD6AAu); static const Word arrayMul1 = Word(0x369DEA0Fu) << 32 |Word(0x31A53F85u); static const Word arrayMul2 = Word(0x27BB2EE6u) << 32 |Word(0x87B0B0FDu); static const Word mask = Word(0xB5026F5Au) << 32 | Word(0xA96619E9u); static const Word loMask = (Word(1u) << 31) - 1; static const Word hiMask = ~loMask; static Word tempering(Word rnd) { rnd ^= (rnd >> 29) & (Word(0x55555555u) << 32 | Word(0x55555555u)); rnd ^= (rnd << 17) & (Word(0x71D67FFFu) << 32 | Word(0xEDA60000u)); rnd ^= (rnd << 37) & (Word(0xFFF7EEE0u) << 32 | Word(0x00000000u)); rnd ^= (rnd >> 43); return rnd; } }; template class RandomCore { public: typedef _Word Word; private: static const int bits = RandomTraits::bits; static const int length = RandomTraits::length; static const int shift = RandomTraits::shift; public: void initState() { static const Word seedArray[4] = { 0x12345u, 0x23456u, 0x34567u, 0x45678u }; initState(seedArray, seedArray + 4); } void initState(Word seed) { static const Word mul = RandomTraits::mul; current = state; Word *curr = state + length - 1; curr[0] = seed; --curr; for (int i = 1; i < length; ++i) { curr[0] = (mul * ( curr[1] ^ (curr[1] >> (bits - 2)) ) + i); --curr; } } template void initState(Iterator begin, Iterator end) { static const Word init = RandomTraits::arrayInit; static const Word mul1 = RandomTraits::arrayMul1; static const Word mul2 = RandomTraits::arrayMul2; Word *curr = state + length - 1; --curr; Iterator it = begin; int cnt = 0; int num; initState(init); num = length > end - begin ? length : end - begin; while (num--) { curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul1)) + *it + cnt; ++it; ++cnt; if (it == end) { it = begin; cnt = 0; } if (curr == state) { curr = state + length - 1; curr[0] = state[0]; } --curr; } num = length - 1; cnt = length - (curr - state) - 1; while (num--) { curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul2)) - cnt; --curr; ++cnt; if (curr == state) { curr = state + length - 1; curr[0] = state[0]; --curr; cnt = 1; } } state[length - 1] = Word(1) << (bits - 1); } void copyState(const RandomCore& other) { std::copy(other.state, other.state + length, state); current = state + (other.current - other.state); } Word operator()() { if (current == state) fillState(); --current; Word rnd = *current; return RandomTraits::tempering(rnd); } private: void fillState() { static const Word mask[2] = { 0x0ul, RandomTraits::mask }; static const Word loMask = RandomTraits::loMask; static const Word hiMask = RandomTraits::hiMask; current = state + length; register Word *curr = state + length - 1; register long num; num = length - shift; while (num--) { curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ curr[- shift] ^ mask[curr[-1] & 1ul]; --curr; } num = shift - 1; while (num--) { curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ curr[length - shift] ^ mask[curr[-1] & 1ul]; --curr; } state[0] = (((state[0] & hiMask) | (curr[length - 1] & loMask)) >> 1) ^ curr[length - shift] ^ mask[curr[length - 1] & 1ul]; } Word *current; Word state[length]; }; template ::digits + 1) / 2> struct Masker { static Result mask(const Result& result) { return Masker:: mask(static_cast(result | (result >> shift))); } }; template struct Masker { static Result mask(const Result& result) { return static_cast(result | (result >> 1)); } }; template ::digits, int shift = 0, bool last = rest <= std::numeric_limits::digits> struct IntConversion { static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return static_cast(rnd() >> (bits - rest)) << shift; } }; template struct IntConversion { static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return (static_cast(rnd()) << shift) | IntConversion::convert(rnd); } }; template ::digits < std::numeric_limits::digits) > struct Mapping { static Result map(RandomCore& rnd, const Result& bound) { Word max = Word(bound - 1); Result mask = Masker::mask(bound - 1); Result num; do { num = IntConversion::convert(rnd) & mask; } while (num > max); return num; } }; template struct Mapping { static Result map(RandomCore& rnd, const Result& bound) { Word max = Word(bound - 1); Word mask = Masker::digits + 1) / 2> ::mask(max); Word num; do { num = rnd() & mask; } while (num > max); return num; } }; template = 0)> struct ShiftMultiplier { static const Result multiplier() { Result res = ShiftMultiplier::multiplier(); res *= res; if ((exp & 1) == 1) res *= static_cast(2.0); return res; } }; template struct ShiftMultiplier { static const Result multiplier() { Result res = ShiftMultiplier::multiplier(); res *= res; if ((exp & 1) == 1) res *= static_cast(0.5); return res; } }; template struct ShiftMultiplier { static const Result multiplier() { return static_cast(1.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return static_cast(1.0/1048576.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return static_cast(1.0/424967296.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return static_cast(1.0/9007199254740992.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return static_cast(1.0/18446744073709551616.0); } }; template struct Shifting { static Result shift(const Result& result) { return result * ShiftMultiplier::multiplier(); } }; template ::digits, int shift = 0, bool last = rest <= std::numeric_limits::digits> struct RealConversion{ static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return Shifting:: shift(static_cast(rnd() >> (bits - rest))); } }; template struct RealConversion { static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return Shifting:: shift(static_cast(rnd())) + RealConversion:: convert(rnd); } }; template struct Initializer { template static void init(RandomCore& rnd, Iterator begin, Iterator end) { std::vector ws; for (Iterator it = begin; it != end; ++it) { ws.push_back(Word(*it)); } rnd.initState(ws.begin(), ws.end()); } static void init(RandomCore& rnd, Result seed) { rnd.initState(seed); } }; template struct BoolConversion { static bool convert(RandomCore& rnd) { return (rnd() & 1) == 1; } }; template struct BoolProducer { Word buffer; int num; BoolProducer() : num(0) {} bool convert(RandomCore& rnd) { if (num == 0) { buffer = rnd(); num = RandomTraits::bits; } bool r = (buffer & 1); buffer >>= 1; --num; return r; } }; } /// \ingroup misc /// /// \brief Mersenne Twister random number generator /// /// The Mersenne Twister is a twisted generalized feedback /// shift-register generator of Matsumoto and Nishimura. The period /// of this generator is \f$ 2^{19937} - 1 \f$ and it is /// equi-distributed in 623 dimensions for 32-bit numbers. The time /// performance of this generator is comparable to the commonly used /// generators. /// /// This implementation is specialized for both 32-bit and 64-bit /// architectures. The generators differ sligthly in the /// initialization and generation phase so they produce two /// completly different sequences. /// /// The generator gives back random numbers of serveral types. To /// get a random number from a range of a floating point type you /// can use one form of the \c operator() or the \c real() member /// function. If you want to get random number from the {0, 1, ..., /// n-1} integer range use the \c operator[] or the \c integer() /// method. And to get random number from the whole range of an /// integer type you can use the argumentless \c integer() or \c /// uinteger() functions. After all you can get random bool with /// equal chance of true and false or given probability of true /// result with the \c boolean() member functions. /// ///\code /// // The commented code is identical to the other /// double a = rnd(); // [0.0, 1.0) /// // double a = rnd.real(); // [0.0, 1.0) /// double b = rnd(100.0); // [0.0, 100.0) /// // double b = rnd.real(100.0); // [0.0, 100.0) /// double c = rnd(1.0, 2.0); // [1.0, 2.0) /// // double c = rnd.real(1.0, 2.0); // [1.0, 2.0) /// int d = rnd[100000]; // 0..99999 /// // int d = rnd.integer(100000); // 0..99999 /// int e = rnd[6] + 1; // 1..6 /// // int e = rnd.integer(1, 1 + 6); // 1..6 /// int b = rnd.uinteger(); // 0 .. 2^31 - 1 /// int c = rnd.integer(); // - 2^31 .. 2^31 - 1 /// bool g = rnd.boolean(); // P(g = true) = 0.5 /// bool h = rnd.boolean(0.8); // P(h = true) = 0.8 ///\endcode /// /// LEMON provides a global instance of the random number /// generator which name is \ref lemon::rnd "rnd". Usually it is a /// good programming convenience to use this global generator to get /// random numbers. class Random { private: // Architecture word typedef unsigned long Word; _random_bits::RandomCore core; _random_bits::BoolProducer bool_producer; public: /// \brief Default constructor /// /// Constructor with constant seeding. Random() { core.initState(); } /// \brief Constructor with seed /// /// Constructor with seed. The current number type will be converted /// to the architecture word type. template Random(Number seed) { _random_bits::Initializer::init(core, seed); } /// \brief Constructor with array seeding /// /// Constructor with array seeding. The given range should contain /// any number type and the numbers will be converted to the /// architecture word type. template Random(Iterator begin, Iterator end) { typedef typename std::iterator_traits::value_type Number; _random_bits::Initializer::init(core, begin, end); } /// \brief Copy constructor /// /// Copy constructor. The generated sequence will be identical to /// the other sequence. It can be used to save the current state /// of the generator and later use it to generate the same /// sequence. Random(const Random& other) { core.copyState(other.core); } /// \brief Assign operator /// /// Assign operator. The generated sequence will be identical to /// the other sequence. It can be used to save the current state /// of the generator and later use it to generate the same /// sequence. Random& operator=(const Random& other) { if (&other != this) { core.copyState(other.core); } return *this; } /// \brief Returns a random real number from the range [0, 1) /// /// It returns a random real number from the range [0, 1). The /// default Number type is \c double. template Number real() { return _random_bits::RealConversion::convert(core); } double real() { return real(); } /// \brief Returns a random real number the range [0, b) /// /// It returns a random real number from the range [0, b). template Number real(Number b) { return real() * b; } /// \brief Returns a random real number from the range [a, b) /// /// It returns a random real number from the range [a, b). template Number real(Number a, Number b) { return real() * (b - a) + a; } /// \brief Returns a random real number from the range [0, 1) /// /// It returns a random double from the range [0, 1). double operator()() { return real(); } /// \brief Returns a random real number from the range [0, b) /// /// It returns a random real number from the range [0, b). template Number operator()(Number b) { return real() * b; } /// \brief Returns a random real number from the range [a, b) /// /// It returns a random real number from the range [a, b). template Number operator()(Number a, Number b) { return real() * (b - a) + a; } /// \brief Returns a random integer from a range /// /// It returns a random integer from the range {0, 1, ..., b - 1}. template Number integer(Number b) { return _random_bits::Mapping::map(core, b); } /// \brief Returns a random integer from a range /// /// It returns a random integer from the range {a, a + 1, ..., b - 1}. template Number integer(Number a, Number b) { return _random_bits::Mapping::map(core, b - a) + a; } /// \brief Returns a random integer from a range /// /// It returns a random integer from the range {0, 1, ..., b - 1}. template Number operator[](Number b) { return _random_bits::Mapping::map(core, b); } /// \brief Returns a random non-negative integer /// /// It returns a random non-negative integer uniformly from the /// whole range of the current \c Number type. The default result /// type of this function is unsigned int. template Number uinteger() { return _random_bits::IntConversion::convert(core); } unsigned int uinteger() { return uinteger(); } /// \brief Returns a random integer /// /// It returns a random integer uniformly from the whole range of /// the current \c Number type. The default result type of this /// function is \c int. template Number integer() { static const int nb = std::numeric_limits::digits + (std::numeric_limits::is_signed ? 1 : 0); return _random_bits::IntConversion::convert(core); } int integer() { return integer(); } /// \brief Returns a random bool /// /// It returns a random bool. The generator holds a buffer for /// random bits. Every time when it become empty the generator makes /// a new random word and fill the buffer up. bool boolean() { return bool_producer.convert(core); } ///\name Non-uniform distributions /// ///@{ /// \brief Returns a random bool /// /// It returns a random bool with given probability of true result. bool boolean(double p) { return operator()() < p; } /// Standard Gauss distribution /// Standard Gauss distribution. /// \note The Cartesian form of the Box-Muller /// transformation is used to generate a random normal distribution. /// \todo Consider using the "ziggurat" method instead. double gauss() { double V1,V2,S; do { V1=2*real()-1; V2=2*real()-1; S=V1*V1+V2*V2; } while(S>=1); return std::sqrt(-2*std::log(S)/S)*V1; } /// Gauss distribution with given mean and standard deviation /// Gauss distribution with given mean and standard deviation. /// \sa gauss() double gauss(double mean,double std_dev) { return gauss()*std_dev+mean; } /// Exponential distribution with given mean /// This function generates an exponential distribution random number /// with mean 1/lambda. /// double exponential(double lambda=1.0) { return -std::log(1.0-real())/lambda; } /// Gamma distribution with given integer shape /// This function generates a gamma distribution random number. /// ///\param k shape parameter (k>0 integer) double gamma(int k) { double s = 0; for(int i=0;i()); return s; } /// Gamma distribution with given shape and scale parameter /// This function generates a gamma distribution random number. /// ///\param k shape parameter (k>0) ///\param theta scale parameter /// double gamma(double k,double theta=1.0) { double xi,nu; const double delta = k-std::floor(k); const double v0=E/(E-delta); do { double V0=1.0-real(); double V1=1.0-real(); double V2=1.0-real(); if(V2<=v0) { xi=std::pow(V1,1.0/delta); nu=V0*std::pow(xi,delta-1.0); } else { xi=1.0-std::log(V1); nu=V0*std::exp(-xi); } } while(nu>std::pow(xi,delta-1.0)*std::exp(-xi)); return theta*(xi-gamma(int(std::floor(k)))); } /// Weibull distribution /// This function generates a Weibull distribution random number. /// ///\param k shape parameter (k>0) ///\param lambda scale parameter (lambda>0) /// double weibull(double k,double lambda) { return lambda*pow(-std::log(1.0-real()),1.0/k); } /// Pareto distribution /// This function generates a Pareto distribution random number. /// ///\param k shape parameter (k>0) ///\param x_min location parameter (x_min>0) /// double pareto(double k,double x_min) { return exponential(gamma(k,1.0/x_min)); } ///@} ///\name Two dimensional distributions /// ///@{ /// Uniform distribution on the full unit circle /// Uniform distribution on the full unit circle. /// dim2::Point disc() { double V1,V2; do { V1=2*real()-1; V2=2*real()-1; } while(V1*V1+V2*V2>=1); return dim2::Point(V1,V2); } /// A kind of two dimensional Gauss distribution /// This function provides a turning symmetric two-dimensional distribution. /// Both coordinates are of standard normal distribution, but they are not /// independent. /// /// \note The coordinates are the two random variables provided by /// the Box-Muller method. dim2::Point gauss2() { double V1,V2,S; do { V1=2*real()-1; V2=2*real()-1; S=V1*V1+V2*V2; } while(S>=1); double W=std::sqrt(-2*std::log(S)/S); return dim2::Point(W*V1,W*V2); } /// A kind of two dimensional exponential distribution /// This function provides a turning symmetric two-dimensional distribution. /// The x-coordinate is of conditionally exponential distribution /// with the condition that x is positive and y=0. If x is negative and /// y=0 then, -x is of exponential distribution. The same is true for the /// y-coordinate. dim2::Point exponential2() { double V1,V2,S; do { V1=2*real()-1; V2=2*real()-1; S=V1*V1+V2*V2; } while(S>=1); double W=-std::log(S)/S; return dim2::Point(W*V1,W*V2); } ///@} }; extern Random rnd; } #endif