GENEIAL  0.2=/
 All Classes Pages
Population.hpp
1 #pragma once
2 
3 #include <geneial/namespaces.h>
4 #include <geneial/core/population/Population.h>
5 #include <geneial/core/fitness/Fitness.h>
6 
7 #include <cassert>
8 #include <iostream>
9 #include <algorithm>
10 #include <set>
11 #include <utility>
12 #include <memory>
13 
14 
15 geneial_private_namespace(geneial)
16 {
17 geneial_private_namespace(population)
18 {
19 using ::geneial::population::chromosome::BaseChromosome;
20 using ::geneial::population::management::BaseManager;
21 using ::geneial::Fitness;
22 
23 geneial_export_namespace
24 {
25 
26 template<typename FITNESS_TYPE>
27 Population<FITNESS_TYPE>::Population() :
28  _fitnessMap(),
29  _hashMap(),
30 // _fitnessCache(),
31  _age(0)
32 {
33 }
34 
35 template<typename FITNESS_TYPE>
36 Population<FITNESS_TYPE>::~Population()
37 {
38 }
39 
40 template<typename FITNESS_TYPE>
41 void Population<FITNESS_TYPE>::print(std::ostream& os) const
42 {
43  os << "Population: Age (" << _age << "), #Chromosomes (" << _fitnessMap.size() << "):" << std::endl;
44  os << " Chromosomes" << std::endl;
45 
46  std::for_each (_fitnessMap.cbegin(), _fitnessMap.cend(), [&os](const typename Population<FITNESS_TYPE>::fitnessmap_value_type &c){
47  os << *(c.second);
48  });
49 }
50 
54 template<typename FITNESS_TYPE>
55 typename Population<FITNESS_TYPE>::population_size Population<FITNESS_TYPE>::getSize() const
56 {
57  return _fitnessMap.size();
58 }
59 
60 template<typename FITNESS_TYPE>
61 unsigned int Population<FITNESS_TYPE>::getAge() const
62 {
63  return _age;
64 }
65 
66 template<typename FITNESS_TYPE>
67 void Population<FITNESS_TYPE>::setAge(unsigned int age)
68 {
69  _age = age;
70 }
71 
75 template<typename FITNESS_TYPE>
76 void Population<FITNESS_TYPE>::doAge()
77 {
78  //For each Chromosome increment age
79  std::for_each (_hashMap.cbegin(), _hashMap.cend(), [](const typename Population<FITNESS_TYPE>::hashmap_value_type &c){
80  c.second->doAge();
81  });
82 
83  //Age the population itself
84  ++_age;
85 }
86 
95 template<typename FITNESS_TYPE>
96 inline unsigned int Population<FITNESS_TYPE>::removeDuplicates(chromosome_container &toCheck)
97 {
98  unsigned int removed = 0;
99  std::set<typename BaseChromosome<FITNESS_TYPE>::chromsome_hash> tmpHashSet;
100 
101  for (auto it = toCheck.begin(); it != toCheck.end();)
102  {
103  const typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue = (*it)->getHash();
104  //Check whether hash is already contained in the container, or in the population
105  if (tmpHashSet.find(hashValue) != tmpHashSet.end() || hashExists(hashValue))
106  {
107  it = toCheck.erase(it);
108  removed++;
109  }
110  else
111  {
112  tmpHashSet.insert(hashValue);
113  ++it;
114  }
115  }
116 
117  return removed;
118 }
119 
120 template<typename FITNESS_TYPE>
121 typename BaseChromosome<FITNESS_TYPE>::ptr Population<FITNESS_TYPE>::getOldestChromosome()
122 {
123  typename BaseChromosome<FITNESS_TYPE>::ptr oldest;
124  for (const auto& fmv : _fitnessMap)
125  {
126  if (!oldest)
127  {
128  oldest = fmv.second;
129  }
130  else
131  {
132  if (oldest->getAge() < fmv.second->getAge())
133  {
134  oldest = fmv.second;
135  }
136  }
137  }
138  return oldest;
139 }
140 
141 template<typename FITNESS_TYPE>
142 typename BaseChromosome<FITNESS_TYPE>::ptr Population<FITNESS_TYPE>::getYoungestChromosome()
143 {
144  typename BaseChromosome<FITNESS_TYPE>::ptr youngest;
145  for (const auto& fmv : _fitnessMap)
146  {
147  if (!youngest)
148  {
149  youngest = fmv.second;
150  }
151  else
152  {
153  if (youngest->getAge() > fmv.second->getAge())
154  {
155  youngest = fmv.second;
156  }
157  }
158  }
159  return youngest;
160 }
161 
162 template<typename FITNESS_TYPE>
163 inline bool Population<FITNESS_TYPE>::insertChromosome(const typename BaseChromosome<FITNESS_TYPE>::ptr& chromosome)
164 {
165  //Insert into hash map
166  typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue = chromosome->getHash();
167  if (!hashExists(hashValue))
168  {
169  _insertChromosome(chromosome, hashValue);
170  return true;
171  }
172  else
173  {
174  return false;
175  }
176 }
177 
178 template<typename FITNESS_TYPE>
179 inline void Population<FITNESS_TYPE>::_insertChromosome(const typename BaseChromosome<FITNESS_TYPE>::ptr& chromosome,
180  typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue)
181 {
182 // const auto it = this->_fitnessCache.find(chromosome->getHash());
183 
184 // if(it != this->_fitnessCache.end())
185 // {
186 // chromosome->setFitness(std::move(std::unique_ptr<Fitness<FITNESS_TYPE>>(new Fitness<FITNESS_TYPE>(it->second))));
187 // }
188 
189  // TODO(bewo) enable this by setting @{
190 // _fitnessCache[hashValue] = chromosome->getFitness().get();
191  // @}
192 
193  assert(chromosome);
194  //Insert into fitness map
195  fitnessmap_value_type fitness_map_value(chromosome->getFitness().get(), chromosome);
196  _fitnessMap.insert(fitness_map_value);
197 
198  hashmap_value_type hash_map_value(hashValue, chromosome);
199  _hashMap.insert(hash_map_value);
200 }
201 
202 template<typename FITNESS_TYPE>
203 inline unsigned int Population<FITNESS_TYPE>::insertChromosomeContainer(chromosome_container &container)
204 {
205  std::vector<typename BaseChromosome<FITNESS_TYPE>::chromsome_hash> hashCache;
206  hashCache.reserve(container.size());
207  for (typename chromosome_container::iterator it = container.begin(); it != container.end();)
208  {
209  const typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue = (*it)->getHash();
210  const bool inHashCache = std::find(hashCache.begin(), hashCache.end(), hashValue) != hashCache.end();
211  if (!hashExists(hashValue) && !inHashCache)
212  {
213  hashCache.emplace_back(hashValue);
214  it++;
215  }
216  else
217  {
218  //getManager().deleteOrHoldOffReference(*it);
219  it = container.erase(it);
220  }
221  }
222 
223  for (size_t i = 0; i < container.size(); i++)
224  {
225  if (!container[i]->hasFitness())
226  {
227  getManager().getExecutionManager().addTask([i,&container]
228  {
229 // const auto it = this->_fitnessCache.find(chromosome->getHash());
230 // if(it == this->_fitnessCache.end())
231 // {
232  container[i]->getFitness().get();
233 // }
234 // else
235 // {
236 // //std::cout << "fitness_cache hit"<<std::endl;
237 // //TODO (bewo) If the user defined Fitness Evaluator might choose to override Fitness, we have a problem here..
238 // chromosome->setFitness(std::move(std::unique_ptr<Fitness<FITNESS_TYPE>>(new Fitness<FITNESS_TYPE>(it->second))));
239 // }
240  });
241  }
242  }
243 
244  getManager().getExecutionManager().waitForTasks();
245 
246  unsigned int i = 0;
247  std::for_each(container.cbegin(),container.cend(),
248  [&i,this,&hashCache]
249  (const typename chromosome_container::value_type &it)
250  {
251  this->_insertChromosome(it, hashCache[i]);
252  ++i;
253  }
254  );
255  return hashCache.size(); //TODO (bewo): This is a safe world assumption
256 }
257 
258 template<typename FITNESS_TYPE>
259 inline void Population<FITNESS_TYPE>::removeChromosome(const typename BaseChromosome<FITNESS_TYPE>::ptr &chromosome)
260 {
261  const FITNESS_TYPE fitness = chromosome->getFitness().get();
262 
263  const auto hash = chromosome->getHash();
264  const auto range = _fitnessMap.equal_range(fitness);
265 
266  bool candidateFound = false;
267 
268  auto it = range.first;
269  assert(range.first != _fitnessMap.end());
270 
271  //we might have multiple chromosomes with the same key, advance until pointer is candidateFound
272  while (!candidateFound && it != range.second)
273  {
274  if (it->second == chromosome)
275  {
276  candidateFound = true;
277  }
278  else
279  {
280  ++it;
281  }
282  }
283 
284  assert(candidateFound);
285  const auto hit = _hashMap.find(hash);
286  assert(hit != _hashMap.end());
287 
288  _fitnessMap.erase(it);
289  _hashMap.erase(hit);
290 
291  //assert(_fitnessMap.find(hash) == _fitnessMap.end());
292  //assert(_hashMap.find(hash) == _hashMap.end());
293 
294 }
295 
296 template<typename FITNESS_TYPE>
297 inline bool Population<FITNESS_TYPE>::hashExists(const typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue)
298 {
299  return (_hashMap.find(hashValue) != _hashMap.end());
300 }
301 
302 template<typename FITNESS_TYPE>
303 inline typename BaseChromosome<FITNESS_TYPE>::ptr Population<FITNESS_TYPE>::getChromosomeByHash(
304  const typename BaseChromosome<FITNESS_TYPE>::chromsome_hash hashValue)
305 {
306  const auto it = _hashMap.find - (hashValue);
307  if (it == _hashMap.end())
308  {
309  typename BaseChromosome<FITNESS_TYPE>::ptr null_ptr(nullptr);
310  return (null_ptr);
311  }
312  else
313  {
314  return *it;
315  }
316 }
317 
318 template<typename FITNESS_TYPE>
319 inline void Population<FITNESS_TYPE>::replacePopulation(chromosome_container &replacementPopulation)
320 {
321  clearChromosomes();
322  insertChromosomeContainer(replacementPopulation);
323 }
324 
325 template<typename FITNESS_TYPE>
326 inline void Population<FITNESS_TYPE>::removeChromosomeContainer(const chromosome_container &container)
327 {
328  for(const auto& chromosomomeToRemove: container)
329  {
330  removeChromosome(chromosomomeToRemove);
331  }
332 }
333 
334 template<typename FITNESS_TYPE>
335 inline void Population<FITNESS_TYPE>::clearChromosomes()
336 {
337  _fitnessMap.clear();
338  _hashMap.clear();
339 }
340 
341 } /* geneial_export_namespace */
342 } /* private namespace population */
343 } /* private namespace geneial */