/* -*- 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 ///\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()); } 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() 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 /// /// The 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. /// /// \author Balazs Dezso class Random { private: // architecture word typedef unsigned long Word; _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. 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 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 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); } ///\name Nonuniform 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 standard deviation and mean 0 /// \sa gauss() /// double gauss(double std_dev) { return gauss()*std_dev; } /// 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 -log(real())/lambda; } ///@} }; extern Random rnd; } #endif