If you want to pick an elem
from the vector v
with a probability proportional to the value of a member, you need to implement a selection scheme known as fitness-proportionate or roulette-wheel selection.
To implement this, you can first create a "roulette-wheel" based on the values of the data member:
std::vector<double> wheel, probs;
// extract the probabilities
std::transform(std::begin(v), std::end(v),
std::back_inserter(probs),
[](auto const & e) { return e.probability ; });
// then create the roulette wheel
std::partial_sum(std::begin(probs), std::end(probs),
std::back_inserter(wheel));
Now to make a single choice, you can spin the wheel
, and see which index of the wheel it lands on. Given the construction of wheel
, the probability of landing on any index is proportional to the probability
value of the elem
at that same index in v
.
// create the random spinner, and uniformly distributed tip
std::mt19937 spinner;
std::uniform_real_distribution<double> tip(0., 1.); // since the sum is 1.
// In general, the second argument can be wheel.back()
// spin the wheel and selects an elem
auto spin = [&] {
auto choice = std::lower_bound(std::begin(wheel), std::end(wheel),
tip(spinner));
return v[std::distance(std::begin(wheel), choice)];
};
Now you can generate a new vector of whatever size you want.
// spin the wheel N times to generate next population
std::vector<elem> new_v;
std::generate_n(std::back_inserter(new_v), N, spin);
Note that if you want to generate a new vector without repeating elements, you will have to put in a little more effort to ensure that the choices are still randomly distributed. This choice will also be affected by the size of the new vector you want to generate.