Frederik
Frederik

Reputation: 385

PRNG MTRand mt.seed() not working as intended (?)

In a simulation project where I need different PRNG with common random numbers (reproducability) I am using the Mersenne Twister implementation by Jasper Bedaux (http://www.bedaux.net/mtrand/). Now, the following loop should, in my understanding, produce a unique random number associated to the integer (i.e. the different instances should yield the same random numbers if initialised with the same seed):

#include <iostream>
#include "mtrand.cpp"

int main()
{
  MTRand tester_sh;
  MTRand tester_se;
  std::cout << std::fixed;
  std::cout << "This is a simple test program.\n";
  for (int sh = 1; sh < 3; sh++) {
    for (int se = 1; se < 3; se++) {   
      tester_sh.seed( sh );
      tester_se.seed( se );
      std::cout << "\n" << sh << "\t" << tester_sh() << "\t" << se << "\t" << tester_se() ;
    }
  }  
  return 0;
}

The output I do get, however is:

Output test program

Neither are the random numbers the same, nor does the "resetting" work for the individual generator. [edit: there is a pattern, of course, but I do not understand it / it is not as it should be]

As I am not a programmer, I am more than puzzled and do not know what I should do.

If important, I am compiling the model with cygwin64\bin\x86_64-w64-mingw32-g++.exe and the options -g -Wall -lm -std=gnu++14 -o %Name%.exe %Name%%Ext%, using a current version of cygwin on windows 7, 64bit.

Any help is welcome!

Upvotes: 0

Views: 119

Answers (2)

Jan
Jan

Reputation: 11

Indeed the Mersenne Twister state vector is static in this port, as it is in many implementations, including the original implementation at http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html.

This is not for "some weird reason" and whether it is a "really bad decision" is up for discussion.

In the C++ standard implementation it is not static. The drawback of this is that it is quite easy to (accidentally) create multiple state vectors if you e.g. construct a new MT engine in some class. Every time a new MT engine is constructed, a new state vector is initialized and seeded. Probably most programmers will not realize this and may forget to properly seed each new instance, which may lead to problems with the quality of the pseudo random numbers depending on the implementation of the default seed (chance of repeating sequences), see e.g. http://www.pcg-random.org/posts/cpp-seeding-surprises.html. In normal circumstances you should only use one generator engine, but the problem is programmers might not realize this. Taking the next number from one properly seeded and used MT state vector will probably always be better then initialize and seed a separate state vector (which is also expensive). That is the reason for choosing one static (centralized) state vector: protecting users from accidentally creating multiple state vectors. I agree however that this is not a good solution and is confusing when you are trying by purpose to create two separate state vectors, which is by the way only useful in very specific cases, like studying the behavior of the engine. When you are only looking for good quality random numbers it is probably only harmful to use more than 1 state vector.

Which solution is best depends on what you are trying to accomplish and how well programmers understand the implementation of the RNG.

Anyway, the lines

tester_sh.seed( sh );
tester_se.seed( se );

in the example are with this implementation equivalent to

tester_se.seed( se );

Edit: as geza and Sebastian point out in the comments below, the way the class is designed is not a good choice because it does not reflect the internal working.

Upvotes: 1

geza
geza

Reputation: 29962

It is because of some weird reason, MTRand's state is static, so the state is shared between MTRand instances. A really bad decision.

Perhaps you can fix this with making the state non-static. Or just use a better implementation of MT. (btw, C++11 has std::mersenne_twister_engine)

Upvotes: 3

Related Questions