/* -*- C++ -*- * * This file is a part of LEMON, a generic C++ optimization library * * Copyright (C) 2003-2006 * 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. * */ #ifndef LEMON_RANDOM_H #define LEMON_RANDOM_H #include #include #include #include #include #include ///\ingroup misc ///\file ///\brief Mersenne Twister random number generator /// ///\author Balazs Dezso 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; } curr[0] = (((curr[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((Result)(result | (result >> shift))); } }; template struct Masker { static Result mask(const Result& result) { return (Result)(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 (Result)(rnd() >> (bits - rest)) << shift; } }; template struct IntConversion { static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return ((Result)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 *= (Result)2.0; return res; } }; template struct ShiftMultiplier { static const Result multiplier() { Result res = ShiftMultiplier::multiplier(); res *= res; if ((exp & 1) == 1) res *= (Result)0.5; return res; } }; template struct ShiftMultiplier { static const Result multiplier() { return (Result)1.0; } }; template struct ShiftMultiplier { static const Result multiplier() { return (Result)(1.0/1048576.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return (Result)(1.0/424967296.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return (Result)(1.0/9007199254740992.0); } }; template struct ShiftMultiplier { static const Result multiplier() { return (Result)(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((Result)(rnd() >> (bits - rest))); } }; template struct RealConversion { static const int bits = std::numeric_limits::digits; static Result convert(RandomCore& rnd) { return Shifting::shift((Result)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()); } template static void init(RandomCore& rnd, Result seed) { rnd.initState(seed); } }; template struct BoolConversion { static bool convert(RandomCore& rnd) { return (rnd() & 1) == 1; } }; } /// \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(). If you want to get random /// number from a the {0, 1, ..., n-1} integer range use the \c /// operator[]. And to get random number from the whole range of an /// integer type you can use the \c integer() or \c uinteger() /// functions. After all you can get random bool with equal chance /// or given probability with the \c boolean() member function. /// ///\code /// int a = rnd[100000]; // 0..99999 /// int b = rnd.uinteger(); // 0 .. 2^31 - 1 /// int c = rnd.integer(); // - 2^31 .. 2^31 - 1 /// double d = rnd(); // [0.0, 1.0) /// double e = rnd(100.0); // [0.0, 100.0) /// double f = rnd(1.0, 2.0); // [1.0, 2.0) /// bool g = rnd.boolean(); // P(g = true) = 0.5 /// bool h = rnd.boolean(0.8); // P(h = true) = 0.8 ///\endcode /// /// The lemon provides a global instance of the random number generator /// which name is \c rnd. Usually it is a good programming convenience /// to use this global generator to get random numbers. /// /// \author Balazs Dezso class Random { private: #if WORD_BIT == 32 typedef unsigned int Word; #elif WORD_BIT == 64 typedef unsigned long Word; #endif _random_bits::RandomCore core; public: /// \brief Constructor /// /// Constructor with constant seeding. Random() { core.initState(); } /// \brief Constructor /// /// 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 /// /// 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. Random(const Random& other) { core.copyState(other.core); } /// \brief Assign operator /// /// Assign operator. The generated sequence will be identical to /// the other sequence. Random& operator=(const Random& other) { if (&other != this) { core.copyState(other.core); } return *this; } /// \brief Returns a random real number /// /// It returns a random real number from the range [0, 1). The default /// result type of this function is double. template Number operator()() { return _random_bits::RealConversion::convert(core); } double operator()() { return operator()(); } /// \brief Returns a random real number /// /// It returns a random real number from the range [0, b). template Number operator()(Number b) { return operator()() * b; } /// \brief Returns a random real number /// /// It returns a random real number from the range [a, b). template Number operator()(Number a, Number b) { return operator()() * (b - a) + a; } /// \brief Returns a random integer from a range /// /// It returns a random integer from the range {0, 1, ..., bound - 1}. template Number operator[](const Number& bound) { return _random_bits::Mapping::map(core, bound); } /// \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 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 bool boolean() { return _random_bits::BoolConversion::convert(core); } /// \brief Returns a random bool /// /// It returns a random bool with given probability of true result bool boolean(double p) { return operator()() < p; } }; /// \brief Global random number generator instance /// /// A global mersenne twister random number generator instance extern Random rnd; } #endif