Random Number Library Parallel Generators

Introduction

Stochastic simulations on parallel machines face an additional problem over simulations on a single CPU: we not only need one random number stream but uncorrelated random number streams for each CPU. Since massively parallel machines with 65536 CPUs exist, this can be a formidable challenge.

The Scalable Parallel Pseuo Random Number Generators Library (SPRNG) is a C-library that was designed to solve this challenge. As explained in detail in the SPRNG paper, there are several methods of creating independent parallel random number streams, using parametrization of the generator, or cycle division techniques.

Since the method to create independent streams depends on the choice of generator, no generic seeding can be implemented, but the seeding mechanism is specific to the generator. However, a common interface is possible, and we follow the design of the SPRNG library by requiring the following two parameters next to a global seed

Any parallel random number generator has to guarantee that generators created with the same values of total_streams, global_seed but different values for stream_number produce independent non-overlapping sequences of random numbers. In a parallel application, typically the node number is chosen as stream_number and the total number of nodes as total_streams.

Parallel Uniform Random Number Generator

A parallel uniform random number generator is a UniformRandomNumberGenerator that provides not one but many independent streams (sequences) of uniform random numbers. To enable a non-intrusive refinement of the UniformRandomNumberGenerator concept to a ParallelUniformRandomNumberGenerator

In the following table,

Furthermore, parallel uniform random number generators seeded with the same values of num, total must produce independent non-overlapping sequences of random numbers, if all other arguments besides v are equivalent, including where applicable, the values of the range [first,last).

ParallelUniformRandomNumberGenerator requirements
ExpressionReturn type Note
seed(v,num,total)void default parallel seeding of v
seed(v,num,total,first,last)void parallel seeding of v from two iterators. The semantics is identical to that of the seeding of a UniformRandomNumberGenerator from a pair of iterators, with the only distinction that for identical elements in the range [first,last) and identical values of total but different values of num, independent non-overlapping sequences of random numbers will be produced by the generator.

Named parameter interface

To simplify seeding of parallel random number generators, the generators provided in this library implement a named parameter interface:

ParallelUniformRandomNumberGenerator requirements
ExpressionReturn type Note
X::max_streamsint the maximum number of independent streams provided by X.
X(named parameters)X creates an object of type X with the named parameter arguments given in the table below.
v.seed(optional named parameters)void seeds v with the named parameter arguments given in the table below.
v.seed(first,last,optional named parameters)void seeds v with the range of values given by [first,last), and the named parameter arguments given in the table below.

using the following parameters:

Named parameters for seeding of a ParallelUniformRandomNumberGenerator
Parameter nameDefaultLegal values
total_streams1 0 <= total_streams < X::max_streams
stream_number0 0 <= stream_number < total_streams
global_seed0

Parallel uniform random number generators created with the same values of total_streams, global_seed but different values for stream_number will produce independent non-overlapping sequences of random numbers.

Header <boost/random/parallel/keyword.hpp>

#include <boost/parameter/keyword.hpp>

namespace boost {  namespace random { namespace parallel {
  
  BOOST_PARAMETER_KEYWORD(tag,stream_number)
  BOOST_PARAMETER_KEYWORD(tag,total_streams)
  BOOST_PARAMETER_KEYWORD(tag,global_seed)
  
} } }
defines the named parameters for seeding for parallel random number generators according to the above
table.

Parallel seeding functions

The headers <boost/parallel/seed.hpp> and <boost/parallel/mpi.hpp> provide default implementations of the parallel seeding functions required by the ParallelUniformRandomNumberGenerator concept, and additional convencience functions.

Header <boost/random/parallel/seed.hpp>

provides default implementations of the parallel seeding functions.

Synopsis

namespace boost { namespace random { namespace parallel {
  
  template <class PRNG>
  void seed(PRNG& prng, unsigned int num, unsigned int total);
  
  template <class PRNG, class Iterator>
  void seed(PRNG& prng, unsigned int num, unsigned int total, Iterator& first, Iterator const& last);

  template <class PRNG, class SeedType>
  void seed(PRNG& prng, unsigned int num, unsigned int total, SeedType const& s);

} } }

Seeding functions

template <class PRNG>
void seed(PRNG& prng, unsigned int num, unsigned int total);
provides a default implementation of the default parallel seeding function by asssuming a named parameter seeding interface. It is implemented as prng.seed(stream_number=num, total_streams=total);.
template <class PRNG, class Iterator>
void seed(PRNG& prng, unsigned int num, unsigned int total, Iterator& first, Iterator const& last);
provides a default implementation of the parallel seeding from a pair iterators by asssuming a named parameter seeding interface. It is implemented as prng.seed(first,last,stream_number=num, total_streams=total);.
template <class PRNG, class SeedType>
void seed(PRNG& prng, unsigned int num, unsigned int total, SeedType const& s);
provides a convenience function for parallel seeding from a single global seed by asssuming a named parameter seeding interface. It is implemented as prng.seed(global_seed=s, stream_number=num, total_streams=total);.

Header <boost/random/parallel/mpi.hpp>

provides convenience seeding functions for applications based on the candidate Boost.MPI library. The num and total parameters are obtained from a boost::parallel::mpi::communicator. MPI communicator.

Synopsis

namespace boost { namespace random { namespace parallel {
  template <class PRNG>
  void seed(PRNG& prng, boost::parallel::mpi::communicator const& c)

  template <class PRNG, class SeedType>
  void seed(PRNG& prng, boost::parallel::mpi::communicator const& c, SeedType const& s)

  template <class PRNG, class Iterator>
  void seed(PRNG& prng, boost::parallel::mpi::communicator const& c, Iterator& first, Iterator const& last)

  template <class PRNG, class SeedType>
  void broadcast_seed( PRNG& prng, boost::parallel::mpi::communicator const& c, int root, SeedType s)

} } }

MPI seed functions

template <class PRNG>
void seed(PRNG& prng, boost::parallel::mpi::communicator const& c)

template <class PRNG, class SeedType>
void seed(PRNG& prng, boost::parallel::mpi::communicator const& c, SeedType const& s)

template <class PRNG, class Iterator>
void seed(PRNG& prng, boost::parallel::mpi::communicator const& c, Iterator& first, Iterator const& last)
call the corresponding seed functions from the <boost/parallel/seed.hpp>, using the communicator rank c.rank() and size c.size() as num and total arguments.
template <class PRNG, class SeedType>
void broadcast_seed( PRNG& prng, boost::parallel::mpi::communicator const& c, int root, SeedType s)
broadcasts the global seed s from the root rank given by the root argument and then calls the seed function with the same arguments.

64-bit linear congruential generator lcg64

Header <boost/random/parallel/lcg64.hpp>

namespace boost {
namespace random {

template<uint64_t a, uint64_t val>
class lcg64
{
  typedef uint64_t result_type;
  static const bool has_fixed_range = true;
  static const result_type min_value;
  static const result_type max_value;
  static const result_type max_streams = 146138719;
  
  lcg64(optional named parameters);
  template<class It> lcg64(It& first, It last,optional named parameters);

  void seed(optional named parameters);
  template<class It> void seed(It& first, It last,optional named parameters);
  result_type operator()();
  static bool validation(result_type);
};
}

typedef random::lcg64< /* ... */> lcg64a;
typedef random::lcg64< /* ... */> lcg64b;
typedef random::lcg64< /* ... */> lcg64c;
}

Description

This header provides a parallel 64-bit linear congruential generator template, and three well-tested choices of multipliers. As for other linear congruential generators, the recursion relation (n+1) := (a * x(n) + c) mod m is used. In this implementation, m=264 and the multiplier a, which is given as template parameter is different for the three generators . The prime additive constant c is chosen depending on the stream number, thus giving independent sequences for each stream.

The WELL generators

Header <boost/random/parallel/well.hpp>

namespace boost {
namespace random {

template<class UIntType, int statesize, UIntType val, class F1, class F2
       , class F3, class F4, class F5, class F6, class F7, class F8
       , int p1,  int p2,  int p3, UIntType mask=statesize-1, class RNG=mt19937>
class well
{
  typedef UIntType result_type;
  static const bool has_fixed_range = true;
  static const result_type min_value;
  static const result_type max_value;
 
  well(optional named parameters);
  template<class It> well(It& first, It last,optional named parameters);

  void seed(optional named parameters);
  template<class It> void seed(It& first, It last,optional named parameters);
  result_type operator()();
  static bool validation(result_type);
};
typedef well< /* ... */> well512a;
typedef well< /* ... */> well1024a;
}
}

Description

Instantiations of class template well model a pseudo-random number generator, whose algorithm is described in
"Improved Long-Period Generators Based on Linear Recurrences Modulo 2" , F. Panneton, P. L'Ecuyer and M. Matsumoto, submitted to ACM TOMS
Two well-tested and validated generators well512a and well1024a are provided as specializations.

The parallel seeding is based on cycle division:


Matthias Troyer, 2006-07-06