mersenne twister with different seeds


I would like to implement mersenne twister for my simulation : I have different abjects and I want to have a different seeds for each of them. I would like to check the uniformity in this work.
1
2
3
4
5
6
7
8
9
10
11
12
#include <random>

class Object
{
  public:
    Object(int seed) : rng(seed) {}
  private:
    std::mt19937 rng;
}

//Usage
Object A1(10), A2(483);//2 objects containing generators with different seeds 
Thank you for your reply.
I am wondering, A1(10) 10 is the seed?
Sorry I am qite new in C++ and how is the seed generate?
I am wondering if you can help me.
Last edited on
A1(10) 10 is the seed?

Yes. 10 is passed to Object's constructor. Object passes seed to rng's constructor. rng is an instance of std::mt19937.
http://www.cplusplus.com/reference/random/mt19937/

Note: This requires a C++11 compiler.


> I would like to check the uniformity in this work.

Then you should let the mersenne twister go through its warm-up sequence first.
Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <random>
#include <ctime>
#include <algorithm>

// initialize the rng with a seed
// for the same seed, will generate the same sequence of pseudo random numbers
std::mt19937 initialize_twister( int seed = std::time(nullptr) )
{
    static constexpr std::size_t NDISCARD = 1024 ;

    std::minstd_rand lcg(seed) ;
    lcg.discard(NDISCARD) ;

    std::size_t seeds[ std::mt19937::state_size ] ;
    std::generate_n( seeds, std::mt19937::state_size, lcg ) ;

    std::seed_seq seed_sequence( std::begin(seeds), std::end(seeds) ) ;
    std::mt19937 twister { seed_sequence } ; // warm-up
    twister.discard(NDISCARD) ; // more warm-up

    return twister ;
}

struct object
{
    object() = default ;
    object( int seed ) : twister( initialize_twister(seed) ) {}

    std::mt19937 twister = initialize_twister() ;
};


Use std::random_device for the initial seed if the implementation supports it.
http://en.cppreference.com/w/cpp/numeric/random/random_device
thanks for your answers, but if I use the warm-up then how can I have a different seeds, my simulation should have a different seeds indeed.?
could please specify for me how to keep both (uniformity - different seeds ) n my work?
Also when I run the code I got this error, I run in ubuntu with g++

ameneh@ameneh:~/mtrand$ g++ -std=c++0x ami.cpp -o s
ami.cpp:16:14: error: expected initializer before ‘initialize_twister’
Last edited on
> how can I have a different seeds, my simulation should have a different seeds indeed.?
> I run in ubuntu with g++

Use std::random_device to generate the initial seed.


> Also when I run the code I got this error

Initialize the non-static data member in the constructor


> could please specify for me how to keep both (uniformity - different seeds ) n my work?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <random>
#include <ctime>
#include <algorithm>

// initialize the rng with a seed
// for the same seed, will generate the same sequence of pseudo random numbers
std::mt19937 initialize_twister( std::size_t seed )
{
    static constexpr std::size_t NDISCARD = 1024 ;

    std::minstd_rand lcg(seed) ;
    lcg.discard(NDISCARD) ;

    std::size_t seeds[ std::mt19937::state_size ] ;
    std::generate_n( seeds, std::mt19937::state_size, lcg ) ;

    std::seed_seq seed_sequence( std::begin(seeds), std::end(seeds) ) ;
    std::mt19937 twister { seed_sequence } ; // warm-up
    twister.discard(NDISCARD) ; // more warm-up

    return twister ;
}

struct object
{
    object() : twister( initialize_twister( rand_dev() ) ) {}
    object( std::size_t seed ) : twister( initialize_twister(seed) ) {}
    
    int next() { return distribution(twister) ; }
    std::mt19937 twister ;
    
    static std::random_device rand_dev ;
    static std::uniform_int_distribution<int> distribution ;
};

std::random_device object::rand_dev ;
std::uniform_int_distribution<int> object::distribution( 1000, 9999 ) ;

int main()
{
    {
        object a ; // random seed
        for( int i = 0 ; i < 10 ; ++i ) std::cout << a.next() << ' ' ; 
        std::cout <<  "  (random seed)\n" ;
    }
    
    {
        object b(2345) ; //  seed is 2345
        for( int i = 0 ; i < 10 ; ++i ) std::cout << b.next() << ' ' ; 
        std::cout << "  (seeded with 2345)\n" ;
    }
    
    {
        object c(777777) ; //  seed is 77777
        for( int i = 0 ; i < 10 ; ++i ) std::cout << c.next() << ' ' ; 
        std::cout << "  (seeded with 77777)\n" ;
    }
    
    {
        object d(2345) ; //  seed is 2345 (generates the same sequence as object b) 
        for( int i = 0 ; i < 10 ; ++i ) std::cout << d.next() << ' ' ; 
        std::cout << "  (seeded with 2345)\n" ;
    }
}

http://coliru.stacked-crooked.com/a/2031ee3bb7c4b964
Thanks for your help, I have questions,
std::minstd_rand lcg(seed) in this part lcg is generate the seeds? could you please explain to me what is lcg, is it the liner random number or something else?
> could you please explain to me what is lcg

http://www.cplusplus.com/reference/random/linear_congruential_engine/


> std::minstd_rand lcg(seed) in this part lcg is generate the seeds?

Yes. http://www.cplusplus.com/reference/random/minstd_rand/

This inexpensive lcg is used to generate the predictable (repeatable) seed sequence from the single seed that it has been fed. That seed sequence is used for the initial warm-up of the twister.
Yes I agree, why in the code dicard the NDISCARDafter geeting the seed? twister.discard(NDISCARD)
I would like to understand the logic behind the warm up.
I am really appreciate your answer.
then the other generator is also can be use for prepare the seed ?
static std::random_device rand_dev ; in this line the random_device is also preparing the seed then what is the different between these two parts?
thanks in advance
Last edited on
> I would like to understand the logic behind the warm up.

When certain seeds are used (seeds with low entropy, typically those with long runs of zero or one bits), shift-register-based pseudo random number generators (like the Mersenne Twister) tend to generate an initial sequence with poor randomness attributes. The internal state of std::mt19937 consists of std::mt19937::state_size (624 IIRC) numbers, and the idea of warm-up is to exercise the engine long enough (by generating and discarding numbers) till this state becomes sufficiently statistically random (without underlying bit patterns). As a rough rule, the longer the period of the engine, the more should be the length of the initial warm-up sequence.

The generating function for std::seed_seq is the defaukt Mersenne Twister warm-up sequence; so the extra warm-up of discarding some number of values (NDISCARD) before using the engine is probably unnecessary for strictly conforming implementations.


> in this line the random_device is also preparing the seed then what is the different between these two parts?

The random_device is generating a seed if and only if a seed value is not provided (when constructing the object).
If a seed value is provided, that seed is used (generate a repeatable quasi-random sequence).
Topic archived. No new replies allowed.