0

Using boost::random I'm trying to sample sets of uniformly distributed integers from different ranges, but using the same underlying random number generator. For each range I am defining a different function returning the the random numbers. However, it seems that each function returns the same number.

An example illustrating the approach:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/random.hpp>

struct RandomNumberGenerator {
  boost::mt19937 generator;

  RandomNumberGenerator(long seed) {
    generator.seed(seed);
  }

  boost::function<int()> getRandomFunctionInt(int min, int max) {
    boost::uniform_int<> uni_dist(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > uni(generator, uni_dist);

    boost::function<int()> f;
    f = boost::bind(uni_dist, generator);
    return f;
  }
};

int main (int argc, char* argv[]) {
  RandomNumberGenerator rng(1729);
  boost::function<int()> runif1 = rng.getRandomFunctionInt(0,  1000);
  boost::function<int()> runif2 = rng.getRandomFunctionInt(0, 10000);

  for (int i=0; i<10; ++i) {
    std::cout << runif1() << ", " << runif2() << std::endl;
  }
}

The output was:

212, 2121
623, 6226
259, 2590
[...]

Is there any way to un-correlate the functions? For the sake of reproducibility of my experiment I would like to work with a single seed.

mrhd
  • 58
  • 5

1 Answers1

0
f = boost::bind(uni_dist, generator);

You need to pass a reference to the generator. Right now, you're passing a copy of the generator, which means that each f object has a copy of the generator in its initial state.

f = boost::bind(uni_dist, boost::ref(generator));

A different version using Lambdas would make the ambiguity more visible (and easier to detect/resolve):

f = [uni_dist, this] {return uni_dist(generator);};

Also, c++11 introduced the <random> header, which provides all the same functions and more that boost's random headers provide, so there's not really any reason to keep using the boost version anymore.

Xirema
  • 19,889
  • 4
  • 32
  • 68
  • Thanks for pointing out my rookie mistake... answer accepted and appreciated! Switching to the standard `` header is good advice as well. +1 for the solution using lambda functions - one small catch, though: in C++11 member vars (like `generator`) cannot be captured directly, had to resort to a local variable and capture that one: `boost::mt19937 &g = generator` – mrhd Jun 22 '16 at 21:54
  • @mrhd I think member variables can be captured if you capture `this`. I've revised the answer to account for that. – Xirema Jun 22 '16 at 22:08
  • Thanks for the update, your solution is more concise. I realize now that it was really the boost::bind() that made a copy since you did not need to pass by reference in `uni_dist(generator)`. – mrhd Jun 23 '16 at 07:56