Search code examples
c++randomc++11distributionpiecewise

Problems with std::piecewise_constant_distribution and std::vector


Given a bunch of strings I'm trying to create a program that can mimic a pseudo-random behaviour with weighted distribution based on my input.

So far I came up with this

#include <iostream>
#include <random>
#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <initializer_list>

#define N 100

int main()
{
    std::vector<std::string> interval{"Bread", "Castle", "Sun"};
    std::vector<float> weights { 0.40f, 0.50f, 0.10f };
    std::piecewise_constant_distribution<> dist(interval.begin(),
                                                interval.end(),
                                                weights.begin());

    std::random_device rd;
    std::mt19937 gen(rd()) ;

    for(int i = 0; i<N;i++)
    {
        std::cout << dist(gen) << "\n";
    }

    return(0);

}

But this thing doesn't works and I have no clue why, the usual usage of std::piecewise_constant_distribution , according to online examples, it's with std::arrays, but I'm trying to implement it using std::vector, this is the main difference that I found.

With Clang++ the output of the error is

/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/random.tcc:2409:10: error: no matching member function for
      call to 'push_back'
                _M_int.push_back(*__bbegin);
                ~~~~~~~^~~~~~~~~

but I can't understand it because there is no explicit .push_back in my code, I also don't get from what is coming from because debugging a templated class it's a nightmare and I'm just starting with this one.

Anyone having any idea why code doesn't work ?


Solution

  • The default result type of std::piecewise_constant_distribution is RealType (double here). It seems like you're trying to choose from 3 string options with various weights, but this isn't what std::piecewise_constant_distribution is for. It's designed to generate uniform random values from numeric intervals with the given weighting. If you modify your example and change interval to:

    std::vector<double> interval {1, 3, 5, 10, 15, 20};
    

    Everything will compile happily. By the looks of it, you want std::discrete_distribution:

    ...
    
    std::vector<std::string> interval{"Bread", "Castle", "Sun"};
    std::vector<float> weights { 0.40f, 0.50f, 0.10f };
    std::discrete_distribution<> dist(weights.begin(), weights.end());
    
    std::mt19937 gen(rd());
    
    for(int i = 0; i<N;i++)
    {
        std::cout << interval[dist(gen)] << "\n";
    }
    
    ...