Skip to the content.

Random Number Generation

Generating random numbers for use in parallel algorithms can be quite tricky. Simple utilities like rand() and C++’s built-in generators are not thread safe. You could instead choose to instantiate a thread-local random number generator for each thread, but this comes with a different problem. Due to the nondeterminism in scheduling parallel computations, the results, even if the generators were seeded deterministically, could vary from one run to the next.

To address this, Parlay comes with a simple solution for generating reproducable random numbers in parallel. The key is the parlay::random_generator class, which can be supplied to any of C++’s random number generators as the source of random bits.

For example, to generate uniform random integers, write

parlay::random_generator gen;
std::uniform_int_distribution<vertex> dis(0, n-1);

then generate random numbers by invoking dis(gen). Note that each distribution should only be used by one thread at a time (they are not thread safe).

The generator can be supplied with a non-default seed as an optional argument.

parlay::random_generator gen(42);

To generate random numbers in parallel, the generator supports an operator[], which creates another generator seeded from the current state and a given seed. For example, to generate random numbers in parallel, you could write

parlay::random_generator gen;
std::uniform_int_distribution<vertex> dis(0, n-1);
auto result = parlay::tabulate(n, [&](size_t i) {
  auto r = gen[i];
  return dis(r);
});

The quality of randomness should be good enough for simple randomized algorithms, but should not be relied upon for anything that requires high-quality randomness.