
I'm looking for a random distribution which allows me to generate enums with specified probabilities. As a simple example I could have: //The enum. typedef enum {vt_car, vt_bus, vt_walk, vt_cycle} vehicle_types; //What I want to generate and the associated probabilities. boost::array<vehicle_types, 4> items = {vt_car, vt_bus, vt_walk, vt_cycle}; boost::array<double, 4> probabilities = {0.1, 0.2, 0.3, 0.4} //The random distribution. EnumGenerator eg(items, probabilities); //Generate some vehicles boost::mt19937 rng; eg(rng); eg(rng); eg(rng); I can't seem to find anything that does this. Is it there and I'm just missing it, or am I the only person who needs to do this? Thanks, Kevin Martin

At 1:12 PM +0100 5/3/08, Kevin Martin wrote:
I'm looking for a random distribution which allows me to generate enums with specified probabilities.
As a simple example I could have:
//The enum. typedef enum {vt_car, vt_bus, vt_walk, vt_cycle} vehicle_types;
//What I want to generate and the associated probabilities. boost::array<vehicle_types, 4> items = {vt_car, vt_bus, vt_walk, vt_cycle}; boost::array<double, 4> probabilities = {0.1, 0.2, 0.3, 0.4}
This should be pretty easy to write. I would be tempted to pass in a "const boost::array < std::pair<vehicle_type, double>, N>", which would give return values and probabilities; and use a std::vector<double> to calculate cumulative probabilities, and for each call to the RNG, do a binary search in the vector to find the right spot, and then return the associated value. -- -- Marshall Marshall Clow Idio Software <mailto:marshall@idio.com> It is by caffeine alone I set my mind in motion. It is by the beans of Java that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning. It is by caffeine alone I set my mind in motion.

On 4 May 2008, at 00:57, Marshall Clow wrote:
This should be pretty easy to write. I would be tempted to pass in a "const boost::array < std::pair<vehicle_type, double>, N>", which would give return values and probabilities; and use a std::vector<double> to calculate cumulative probabilities, and for each call to the RNG, do a binary search in the vector to find the right spot, and then return the associated value.
That's not quite, but almost what I did, after mailing yesterday. I allow the probabilities (but not the objects) to be changed. For what I'm actually doing, I need to alter the probabilities quite a lot so it seemed silly to have to construct a new object. I tried to write it so it fits in as much as possible with boost/ random so it should be useful for someone else in same situation. Thanks, Kevin Martin template<typename DataType, int NumData>class relative_frequency { public: typedef DataType result_type; //for number generator typedef int input_type; //for random distribution typedef boost::array<DataType, NumData> data_array; typedef boost::array<double, NumData> rf_array; typedef boost::array<int, NumData> f_array; private: data_array mData; //the items rf_array mProb; //cumulative frequencies public: //we are completely independent in invocations inline void reset() {} //Find the cf we are in and return the appropriate object. template<class Engine>result_type operator() const ( Engine &urng) { double val = urng()/double(urng.max()-urng.min()); int pos = std::upper_bound(mProb.begin(), mProb.end(), val) - mProb.begin(); //if there is some kind of nasty double based rounding error, we may have gone right //to the end, in which case we choose the last element if(pos == NumData) --pos; return *(mData.begin() + pos); } //construct with data and rfreq or data and freq relative_frequency_distribution(const data_array &data, const rf_array &rfreq) : mData(data) { SetRFrequencies(rfreq); } relative_frequency_distribution(const data_array &data, const f_array &freq) : mData(data) { SetFrequencies(freq); } //set the frequencies and relative frequencies void SetFrequencies(const f_array &freq) { //Construct a rf array and call SetRFrequencies rf_array rfreq; double total = accumulate(freq.begin(), freq.end(), 0); for(int i=0;i!=rfreq.size();++i) { rfreq[i] = double(freq[i])/total; } SetRFrequencies(rfreq); } void SetRFrequencies(const rf_array &rfreq) { //We just sum this up to get the cdf std::partial_sum(rfreq.begin(), rfreq.end(), mProb.begin()); } };
participants (2)
-
Kevin Martin
-
Marshall Clow