I'm writing code for initializing particle positions in a phase space using a density function. I would like to randomly sample their locations according to an arbitrary distribution, and the easiest way to do this that I found was to make a small class with everything needed to sample according to an array of probabilities that I give it. However, I've found that I get the same sequence of numbers every time I run the code.
vose *sampler = new vose(density, init_grid_count);
for (unsigned int i=0; i<20; i++)
{
unsigned int index = sampler->alias_method();
cout << index << '\t';
}
This is the definition of the function I use
unsigned int vose::alias_method()
{
double x = uniform(mt);
unsigned int i = floor(array_size*x)+1;
double y = array_size*x+1-i;
if (y<distribution[i])
return i;
else
return alias[i];
}
I found that if I do the same loop in the constructor for the class so that it runs when I initialize the vose
object, it behaves as expected. This means that it generates a different random sequence each time. So why is it that when I do this in the constructor it works right, but when I use it in a member function it outputs the same sequence every time?
The problem is not that my compiler doesn't support the seed generation. I'm using the <chrono>
library and when I print out the seed in the constructor, it is different every time. In case you think there could be something off in the constructor, here it is.
vose::vose(double *array, unsigned int size)
{
//Initialize
auto seed = chrono::high_resolution_clock::now().time_since_epoch().count();
mt19937 mt(seed); // Seeds Mersenne Twister with Device RNG
uniform_real_distribution<double> uniform(0, 1);
distribution = array;
array_size = size;
alias = new unsigned int[size];
for (unsigned int i = 0; i<size; i++)
{
alias[i] = i+1;
}
}
Edit: To be perfectly clear, everything works right when I run the method in the constructor. However, that's obviously not where I mean ultimately to run it so I need to figure out how to have a method run in the main section of code.
Edit: In response to the possibility that I hid the generator or something, here is the class declaration in the header file.
class vose
{
public:
vose(double*, unsigned int);
void demo();
unsigned int alias_method();
private:
std::mt19937 mt;
// I struggled with this for a while, you don't give it args
// until you use it since it's not a function, it's a strange class
std::uniform_real_distribution<double> uniform;
double *distribution;
unsigned int array_size;
unsigned int *alias;
};