1

I am working on algorithm which contain a random initial state. So the output of this algorithm is not robust in each time I run it. This causes a lot of headache for me while I catch a wrong output and want to debug it to see where the problem was because when I run it again, the problem may not re-produced due the random factor of the algorithm. I am using C++ random generator as follow:

    std::random_device rd;
    std::mt19937 rnd_generator(rd());
    std::uniform_int_distribution<> rnd_distribution(0, data_size - 1);

    auto get_random_index = [&](){
        return rnd_distribution(rnd_generator);
    };

How I can imitate the last random sequence generated by this function? For example, Can I give it some kind of static seed that I can re enter it and get the exactly same random sequence? I am asking because I think it is common problem so there may be some nice and efficient well-known way.

Humam Helfawi
  • 17,706
  • 12
  • 64
  • 134
  • 1
    Don't use `random_device`, then. Seed the `mt19937` with a fixed seed. – T.C. Dec 09 '15 at 13:50
  • You're not seeding your MT properly. You need to at least be using `std::seed_seq`. 4 bytes is not enough to seed MT's huge internal state. – Simple Dec 09 '15 at 13:59

4 Answers4

6

save the result of the call to rd() and use that to initialise rnd_generator on the next pass

example:

#include <iostream>
#include <random>


auto main() -> int
{
    using namespace std;

    random_device rd;
    auto seed = rd();

    for (int pass = 0 ; pass < 3 ; ++pass)
    {
        mt19937 rnd_generator(seed);
        uniform_int_distribution<> rnd_distribution(0, 9);

        for (int i = 0 ; i < 5 ; ++i)
        {
            cout << rnd_distribution(rnd_generator) << ", ";
        }
        cout << endl;
    }

    return 0;
}

example output:

9, 5, 3, 5, 4,
9, 5, 3, 5, 4,
9, 5, 3, 5, 4,
Richard Hodges
  • 64,204
  • 6
  • 75
  • 124
3

std::mt19937 rnd_generator(rd()); seeds the PRNG each time with a different random seed. If you want to have the same random sequence while you are testing then you can just hard code a seed instead of using rd().

std::mt19937 rnd_generator(0);  // each run will use the seed value of 0
NathanOliver
  • 150,499
  • 26
  • 240
  • 331
  • Thanks, the problem with this solution is if I test all my samples on the same seed, some problems may not occurs at all. Especially, when the sample set is small. – Humam Helfawi Dec 09 '15 at 13:53
  • OP should probably be using `std::seed_seq` at least; even that is sub-optimal. MT has a huge internal state. – Simple Dec 09 '15 at 13:53
  • However, it may be the only solution so i have to set it as static then change it many times and test them all in each time – Humam Helfawi Dec 09 '15 at 13:54
  • @HumamHelfawi You could run test with different hard coded seeds to make sure you are catching different cases – NathanOliver Dec 09 '15 at 13:55
  • @NathanOliver yes that is – Humam Helfawi Dec 09 '15 at 13:55
  • You can also print out your seed for each run, then you can reproduce only if you need it (i.e. an error occurred) or keep running. c.f. the answer from @Simple. – Nils_M Dec 09 '15 at 13:56
1

You can print an RNG engine to a std::ostream to serialise it and then read it from a std::istream to deserialise it. Note that due to your use of std::uniform_int_distribution<>, you will not reproduce the same sequence of numbers when using different compilers.

Simple
  • 12,634
  • 2
  • 38
  • 43
0

The std::mt19937 is the source of your randomness. It makes sense to use a consitant seed (a uint_least32_t I think) for testing, but it's also fine to use random_device() (which is function that gives a 'random' uint_least32_t).

The problem is you're creating it in the wrong place. Design your code so that the interesting logic is seperate from random sources. Making providing randomness the caller's/class-creators problem is called Dependency Injection and makes code testable.

Something like this:

    class ThingDooer final
    {
        std::mt19937 _prng;
    public:
        // ThingDooer(uint_least32_t seed);
        // ThingDooer() : ThingDoor(std::_Random_device()) {}; // these two or
        ThingDooer(std::mt19937 prng);
        void DoThing();
    };

One of the first things I did in C++ (It's terrible and reads like C#) was wrapping std::mt19937 in an IRandom interface so that I could provide mock implementations with exactly specified numbers. This might be overkill for you of course. Neverless, without dragging in a mocking libary, I'll still show an idea of what we might mock:

    class RandallRandom : public IRandom final
    {
    public:
        RandallRandom();
        int32_t Next() { return 4; }
    };
Community
  • 1
  • 1
Nathan Cooper
  • 5,499
  • 4
  • 32
  • 60