Boost logo

Boost Users :

From: Kevin Martin (kev82_at_[hidden])
Date: 2008-05-04 13:10:42


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net