
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()); } };