(C++)  1.1.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
RouletteSampler.hh
1 #ifndef GRAIL_ROULETTE_SAMPLER_H
2 #define GRAIL_ROULETTE_SAMPLER_H
3 
4 #include <memory>
5 #include <random>
6 #include <numeric>
7 
8 namespace grail
9 {
10  namespace evolution
11  {
13  template<class T>
15  {
16  public:
18  RouletteSampler(const std::vector<std::unique_ptr<T>>& individuals);
19 
20  void Initialize(const std::vector<std::unique_ptr<T>>& individuals);
21 
22  std::vector<T*> SampleMany(size_t count, std::mt19937_64& randGen);
23  std::vector<size_t> SampleManyIndices(size_t count, std::mt19937_64& randGen);
24  T* Sample(std::mt19937_64& randGen);
25  size_t SampleIndex(std::mt19937_64& randGen);
26  size_t SampleIndexWithReturn(std::mt19937_64& randGen) const;
27 
28  private:
29  std::vector<T*> data{};
30  double totalFitness = 0.0;
31  size_t RemoveIndex(size_t index);
32  };
33 
34  template<class T>
35  inline size_t RouletteSampler<T>::RemoveIndex(size_t index)
36  {
37  totalFitness -= data[index]->GetFitness();
38  data.erase(data.begin() + index);
39  return index;
40  }
41 
42  template<class T>
43  inline void RouletteSampler<T>::Initialize(const std::vector<std::unique_ptr<T>>& individuals)
44  {
45  data.clear();
46  totalFitness = 0.0;
47  for (auto& individual : individuals)
48  {
49  totalFitness += individual->GetFitness();
50  data.push_back(individual.get());
51  }
52  }
53 
54  template<class T>
55  inline RouletteSampler<T>::RouletteSampler()
56  : totalFitness{ 0.0 }
57  {
58  }
59 
60  template<class T>
61  inline RouletteSampler<T>::RouletteSampler(const std::vector<std::unique_ptr<T>>& individuals)
62  {
63  Initialize(individuals);
64  }
65 
66  template<class T>
67  inline size_t RouletteSampler<T>::SampleIndex(std::mt19937_64& randGen)
68  {
69  return RemoveIndex(SampleIndexWithReturn(randGen));
70  }
71 
72  template<class T>
73  inline size_t RouletteSampler<T>::SampleIndexWithReturn(std::mt19937_64& randGen) const
74  {
75  if (totalFitness <= std::numeric_limits<double>::epsilon())
76  return std::uniform_int_distribution<size_t>(0, data.size())(randGen);
77 
78  double val = std::uniform_real_distribution<double>(0, totalFitness)(randGen);
79  for (size_t i = 0; i < data.size(); ++i)
80  {
81  if (val < data[i]->GetFitness())
82  return i;
83 
84  val -= data[i]->GetFitness();
85  }
86  return data.size() - 1;
87  }
88 
89  template<class T>
90  inline std::vector<size_t> RouletteSampler<T>::SampleManyIndices(size_t count, std::mt19937_64& randGen)
91  {
92  std::vector<size_t> retData;
93  if (count >= data.size())
94  {
95  retData.resize(data.size());
96  std::iota(retData.begin(), retData.end(), 0);
97  }
98  else
99  {
100  for (size_t i = 0; i < count; ++i)
101  retData.push_back(SampleIndex(randGen));
102  }
103  return retData;
104  }
105 
106  template<class T>
107  inline T* RouletteSampler<T>::Sample(std::mt19937_64& randGen)
108  {
109  if (data.size() == 0)
110  return nullptr;
111 
112  size_t index = SampleIndexWithReturn(randGen);
113  T* individual = data[index];
114  RemoveIndex(index);
115  return individual;
116  }
117 
118  template<class T>
119  inline std::vector<T*> RouletteSampler<T>::SampleMany(size_t count, std::mt19937_64& randGen)
120  {
121  if (count >= data.size())
122  return std::vector<T*>(data);
123 
124  std::vector<T*> retData;
125  for (size_t i = 0; i < count; ++i)
126  retData.push_back(Sample(randGen));
127  return retData;
128  }
129  }
130 }
131 #endif // GRAIL_ROULETTE_SAMPLER_H
Definition: RouletteSampler.hh:15