[Lemon-commits] Alpar Juttner: Merge #602
Lemon HG
hg at lemon.cs.elte.hu
Fri Mar 23 16:14:07 CET 2018
details: http://lemon.cs.elte.hu/hg/lemon/rev/57167d92e96c
changeset: 1389:57167d92e96c
user: Alpar Juttner <alpar [at] cs.elte.hu>
date: Fri Mar 23 15:43:30 2018 +0100
description:
Merge #602
diffstat:
lemon/random.h | 1106 ++++++++++++++++++++++++++------------------------
test/random_test.cc | 28 +
2 files changed, 605 insertions(+), 529 deletions(-)
diffs (truncated from 1200 to 300 lines):
diff --git a/lemon/random.h b/lemon/random.h
--- a/lemon/random.h
+++ b/lemon/random.h
@@ -111,7 +111,6 @@
static const Word loMask = (1u << 31) - 1;
static const Word hiMask = ~loMask;
-
static Word tempering(Word rnd) {
rnd ^= (rnd >> 11);
rnd ^= (rnd << 7) & 0x9D2C5680u;
@@ -243,7 +242,6 @@
private:
-
void fillState() {
static const Word mask[2] = { 0x0ul, RandomTraits<Word>::mask };
static const Word loMask = RandomTraits<Word>::loMask;
@@ -271,7 +269,6 @@
}
-
Word *current;
Word state[length];
@@ -296,7 +293,7 @@
template <typename Result, typename Word,
int rest = std::numeric_limits<Result>::digits, int shift = 0,
- bool last = rest <= std::numeric_limits<Word>::digits>
+ bool last = (rest <= std::numeric_limits<Word>::digits)>
struct IntConversion {
static const int bits = std::numeric_limits<Word>::digits;
@@ -465,543 +462,594 @@
}
};
- }
+ /// \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 is a template implementation of both 32-bit and
+ /// 64-bit architecture optimized versions. The generators differ
+ /// sligthly in the initialization and generation phase so they
+ /// produce two completly different sequences.
+ ///
+ /// \alert Do not use this class directly, but instead one of \ref
+ /// Random, \ref Random32 or \ref Random64.
+ ///
+ /// 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. Finally, you can get random bool with
+ /// equal chance of true and false or with given probability of true
+ /// result using the \c boolean() member functions.
+ ///
+ /// Various non-uniform distributions are also supported: normal (Gauss),
+ /// exponential, gamma, Poisson, etc.; and a few two-dimensional
+ /// distributions, too.
+ ///
+ ///\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<int>(); // 0 .. 2^31 - 1
+ /// int c = rnd.integer<int>(); // - 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:
+ /// \ref lemon::rnd "rnd". In most cases, it is a good practice
+ /// to use this global generator to get random numbers.
+ ///
+ /// \sa \ref Random, \ref Random32 or \ref Random64.
+ template<class Word>
+ class Random {
+ private:
+
+ _random_bits::RandomCore<Word> core;
+ _random_bits::BoolProducer<Word> bool_producer;
+
+
+ public:
+
+ ///\name Initialization
+ ///
+ /// @{
+
+ /// \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 <typename Number>
+ Random(Number seed) {
+ _random_bits::Initializer<Number, Word>::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 <typename Iterator>
+ Random(Iterator begin, Iterator end) {
+ typedef typename std::iterator_traits<Iterator>::value_type Number;
+ _random_bits::Initializer<Number, Word>::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 Seeding random sequence
+ ///
+ /// Seeding the random sequence. The current number type will be
+ /// converted to the architecture word type.
+ template <typename Number>
+ void seed(Number seed) {
+ _random_bits::Initializer<Number, Word>::init(core, seed);
+ }
+
+ /// \brief Seeding random sequence
+ ///
+ /// Seeding the random sequence. The given range should contain
+ /// any number type and the numbers will be converted to the
+ /// architecture word type.
+ template <typename Iterator>
+ void seed(Iterator begin, Iterator end) {
+ typedef typename std::iterator_traits<Iterator>::value_type Number;
+ _random_bits::Initializer<Number, Word>::init(core, begin, end);
+ }
+
+ /// \brief Seeding from file or from process id and time
+ ///
+ /// By default, this function calls the \c seedFromFile() member
+ /// function with the <tt>/dev/urandom</tt> file. If it does not success,
+ /// it uses the \c seedFromTime().
+ /// \return Currently always \c true.
+ bool seed() {
+#ifndef LEMON_WIN32
+ if (seedFromFile("/dev/urandom", 0)) return true;
+#endif
+ if (seedFromTime()) return true;
+ return false;
+ }
+
+ /// \brief Seeding from file
+ ///
+ /// Seeding the random sequence from file. The linux kernel has two
+ /// devices, <tt>/dev/random</tt> and <tt>/dev/urandom</tt> which
+ /// could give good seed values for pseudo random generators (The
+ /// difference between two devices is that the <tt>random</tt> may
+ /// block the reading operation while the kernel can give good
+ /// source of randomness, while the <tt>urandom</tt> does not
+ /// block the input, but it could give back bytes with worse
+ /// entropy).
+ /// \param file The source file
+ /// \param offset The offset, from the file read.
+ /// \return \c true when the seeding successes.
+#ifndef LEMON_WIN32
+ bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0)
+#else
+ bool seedFromFile(const std::string& file = "", int offset = 0)
+#endif
+ {
+ std::ifstream rs(file.c_str());
+ const int size = 4;
+ Word buf[size];
+ if (offset != 0 && !rs.seekg(offset)) return false;
+ if (!rs.read(reinterpret_cast<char*>(buf), sizeof(buf))) return false;
+ seed(buf, buf + size);
+ return true;
+ }
+
+ /// \brief Seeding from process id and time
+ ///
+ /// Seeding from process id and time. This function uses the
+ /// current process id and the current time for initialize the
+ /// random sequence.
+ /// \return Currently always \c true.
+ bool seedFromTime() {
+#ifndef LEMON_WIN32
+ timeval tv;
+ gettimeofday(&tv, 0);
+ seed(getpid() + tv.tv_sec + tv.tv_usec);
+#else
+ seed(bits::getWinRndSeed());
+#endif
+ return true;
+ }
+
+ /// @}
+
+ ///\name Uniform Distributions
+ ///
+ /// @{
+
+ /// \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 <typename Number>
+ Number real() {
+ return _random_bits::RealConversion<Number, Word>::convert(core);
+ }
+
+ double real() {
+ return real<double>();
+ }
+
+ /// \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<double>();
+ }
+
+ /// \brief Returns a random real number from the range [0, b)
+ ///
+ /// It returns a random real number from the range [0, b).
+ double operator()(double b) {
+ return real<double>() * b;
+ }
+
+ /// \brief Returns a random real number from the range [a, b)
+ ///
+ /// It returns a random real number from the range [a, b).
+ double operator()(double a, double b) {
+ return real<double>() * (b - a) + a;
+ }
+
+ /// \brief Returns a random integer from a range
+ ///
+ /// It returns a random integer from the range {0, 1, ..., b - 1}.
+ template <typename Number>
+ Number integer(Number b) {
+ return _random_bits::Mapping<Number, Word>::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 <typename Number>
+ Number integer(Number a, Number b) {
+ return _random_bits::Mapping<Number, Word>::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 <typename Number>
+ Number operator[](Number b) {
More information about the Lemon-commits
mailing list