Generating different sequences of random numbers for different threads with Mersenne Twister (C++)

177 Views Asked by At

I have a Monte Carlo code and need to run many simulations in parallel using MPI. I would like to be sure that the numbers that are generated in each simulation belong to a different sequence.

Here is a very simple "test" that I wrote but I am not sure if it actually tests what I described.

#include <mpi.h>
#include <time.h>
#include <random>

int rank;
//std::random_device rd; std::mt19937 mt(rd()) I used this before
std::mt19937 mt(clock()+rank);

int main(int argc, char* argv[])
{

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);

  std::uniform_int_distribution<int> RandInt(0,100);  
  int xx = RandInt(mt);
  std::cout << rank << ":\t" << xx << "\t" << mt() << std::endl;

  MPI_Finalize();
  return 0;
}

Executing this program three times gave me:

1:  57  3629598283
3:  70  877812043
0:  55  871110422
2:  60  603182895

3:  5   3326625701
2:  72  2574563463
1:  59  1557541786
0:  53  2000448965

0:  16  574716192
1:  53  3847148496
2:  54  3235101660
3:  23  2433046543

Does the way that I wrote this program mean that each thread will instantiate each own random generator? Is this safe and guarantees different sequences of numbers? And also, what is the difference, if any, using the commented line std::random_device rd; std::mt19937 mt(rd()) instead?

EDIT

A few more details about the program.

The random numbers in each run are generated both inside main.cpp and another file mclib.cpp. The random generator is inside a header file mclib.hpp.

main.cpp

#define MAIN
#include "mclib.hpp"
#include <mpi.h> //etc 

int main(){
 MPI_Init(&argc,&argv);
 MPI_Comm_rank(MPI_COMM_WORLD,&rank);

//choose random point
 std::uniform_int_distribution<int> RandInt(0,100);  
 int xx = RandInt(mt);

//calculate energy differences and check metropolis criterion
// double dE = ... 
bool accept = metropolis(dE);


 MPI_Finalize();
 return 0;
}

mclib.cpp

bool metropolis(double dE){
 std::uniform_int_distribution<double> RandDouble(0,1);
double epsilon = RandDouble(mt);
//compare epsilon with boltzmann factor or accept if dE<0
... 
} 

mclib.hpp

#ifdef MAIN
int rank;
std::mt19937 mt(clock()+rank);
#else
extern int rank;
extern std::mt19937 mt;
#endif

Do I need to seed twice for each simulation? Once inside the main.cpp and another inside mclib.cpp?

0

There are 0 best solutions below