Search code examples
c++randomboostboost-random

How to reuse and reinitialize c++ discrete_distribution in class?


I am writing a discrete distribution random number generator in a c++ class. The requirements are:

  1. I don't want to create a discrete_distribution object each time I use it. I know distribution object is lightweight, but my weight array is so long that the cost is still too high. Also, I need to use the distribution object in different functions in this class.
  2. I need to change the distribution (weight array) from time to time
  3. I don't know the exact distribution (weight array) when the class is constructed

Currently I have two solutions, after initialize random number engine with random_device rd; mt19937 engine; in class and engine(rd()) in initialize list.

One is to create the discrete_distribution object with discrete_distribution<> *d=new discrete_distribution<>(weight_array,weight_array+weight_array_size) and store the pointer in the class. Each time I call (*d)(engine) to generate a random number, and I just need to delete the distribution and make a new one to update the weight array.

Another way is to define discrete_distribution<> d in class and update weight array with d=discrete_distribution<>(weight_array,weight_array+weight_array_size), so that we can generate random number with d(engine) and don't need to worry about pointers.

But it seems that both ways are not classical way to use c++ objects. Are they wrong? Are there any drawbacks to write code this way?

Thanks


Solution

  • Another way is to define discrete_distribution<> d in class and update weight array with d=discrete_distribution<>(weight_array,weight_array+weight_array_size), so that we can generate random number with d(engine) and don't need to worry about pointers.

    This is perfectly fine, common C++ style to deal with object instances.

    In fact many types do not have modifier members because they are assignable.

    In this case you could, however use the params() member to change the weights:

    Live On Coliru

    #include <boost/random.hpp>
    #include <boost/random/random_device.hpp>
    #include <boost/range/algorithm/copy.hpp>
    #include <iostream>
    
    namespace br = boost::random;
    
    struct X {
        using Weight = double;
        br::mt19937                            engine { br::random_device{}() };
        br::discrete_distribution<int, Weight> dist   { {0.2, 0.2, 0.2, 0.2, 0.2} };
    
        void sample() {
            for (auto i : {1,2,3,4})
                std::cout << "#" << i << ":" << dist(engine) << " ";
            std::cout << "\n";
        }
    
        void show_probabilities() {
            boost::copy(dist.param().probabilities(), std::ostream_iterator<Weight>(std::cout << "probabilities: ", " "));
            std::cout << "\n";
        }
    
        void reprogram(std::initializer_list<Weight> probabilities) {
            dist.param(probabilities);
        }
    };
    
    int main() {
        X x;
        x.show_probabilities();
        x.sample();
    
        x.reprogram({0.01, 0.99});
    
        x.show_probabilities();
        x.sample();
    }
    

    Printing something like

    probabilities: 0.2 0.2 0.2 0.2 0.2 
    #1:1 #2:2 #3:0 #4:4 
    probabilities: 0.01 0.99 
    #1:1 #2:1 #3:1 #4:1