简体   繁体   中英

boost::random::variate_generator - Change parameters after construction

Is it possible to change the parameters of the distribution after the variate generator has been constructed? Let's take for example this simple setup

typedef boost::mt19937 base_gen_type;
typedef boost::uniform_int<int> dist_type;
typedef boost::variate_generator<base_gen_type &, dist_type> var_gen_type;

unsigned seed = 1337;
int a = 0, b = 42;

base_gen_type base_gen(seed);
dist_type dist(a, b);
var_gen_type rng(base_gen, dist);

If I wanted to change a and b , would this need a new var_gen_type object? The state of the base_gen would of course be unaffected but I wonder if there is a less complicated way.

Using dist_type & as a template parameter did not work.

From the documentation: "Note that all pseudo-random number generators described below are CopyConstructible and Assignable. Copying or assigning a generator will copy all its internal state, so the original and the copy will generate the identical sequence of random numbers." So you can for sure reuse the "rng" name by resigning new value.

There is nothing you can use to change the boost distribution though, you need to construct the new object. I think this is due to the distributions being of different type which in turn changes the type of the range generator.

But if you want to change the range of the distribution you can access it via calling:

distribution_type& distribution()

which returns the reference to the private member according to 1.58 source

This makes perfect sense as if you want to use the different type of distribution the holding type declaration will be different as well.

#include <boost/random.hpp>
#include <iostream>

typedef boost::mt19937 base_gen_type;
typedef boost::uniform_int<int> dist_type;
typedef boost::variate_generator<base_gen_type &, dist_type> var_gen_type;

int main(){
unsigned seed = 1337;
int a = 0, b = 1;

  base_gen_type base_gen(seed);
  dist_type dist(a, b);
  var_gen_type rng(base_gen, dist);
  for(int i = 0; i < 10 ; i++) {
    std::cout << rng() << " " << std::endl; 
  }

  dist_type newdist(0,3);
  rng.distribution() = newdist;

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

}

this produces:

0 
1 
0 
0 
0 
1 
0 
0 
0 
0 
2 
2 
1 
1 
3 
1 
2 
1 
0 
3 

So that is the way to change the distribution assigned for range.

In terms of changing the actual type it is not stored by pointer so maybe the better way to use it is via calling the generator with different distributions like this:

boost::random::mt19937 rng;         // produces randomness out of thin air
                                    // see pseudo-random number generators
boost::random::uniform_int_distribution<> six(1,6);
                                    // distribution that maps to 1..6
                                    // see random number distributions
int x = six(rng);                   // simulate rolling a die

The last example is from boost random documentation here . This way you can pass the same generator to different range distributions.

The final way is not to modify the entire distribution but change just a parameters (it may be useful if the distribution depends on its previous values) for this just swap this lines:

dist_type newdist(0,3);
rng.distribution() = newdist;

to this:

rng.distribution().param(dist_type::param_type(0,3));

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM