Ultra 0.9.4
Loading...
Searching...
No Matches
analyzer.tcc
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_ANALYZER_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(ULTRA_ANALYZER_TCC)
18#define ULTRA_ANALYZER_TCC
19
20namespace internal
21{
22
23inline void merge_ct(auto &destination, const auto &source)
24{
25 for (const auto &[ct, n] : source)
26 destination[ct] += n;
27}
28
29} // namespace internal
30
31template<class C> concept has_active_crossover_type = requires(const C &c)
32{
33 { c.active_crossover_type() } -> std::convertible_to<int>;
34};
35
36template<Individual I, Fitness F>
37group_stat<I, F>::group_stat(population_uid id) : uid(id)
38{
39}
40
47template<Individual I, Fitness F>
48void group_stat<I, F>::add(const I &ind, const F &f)
49{
50 age.add(ind.age());
51
52 const std::size_t len(active_slots(ind));
53
54 length.add(len);
55
56 using std::isfinite;
57 if (isfinite(f))
58 fitness.add(f);
59
60 if constexpr (has_active_crossover_type<I>)
61 ++crossover_type[ind.active_crossover_type()];
62}
63
64template<Individual I, Fitness F>
65void group_stat<I, F>::merge(group_stat gs)
66{
67 age.merge(gs.age);
68 fitness.merge(gs.fitness);
69 length.merge(gs.length);
70
71 internal::merge_ct(crossover_type, gs.crossover_type);
72}
73
79template<Individual I, Fitness F>
80template<LayeredPopulation P, Evaluator E> analyzer<I, F>::analyzer(
81 const P &pop, const E &eva)
82{
83 const auto gather_subgroup_stats([&eva](auto layer_iter)
84 {
85 group_stat<I, F> ret(layer_iter->uid());
86
87 for (const auto &ind : *layer_iter)
88 ret.add(ind, eva(ind));
89
90 return ret;
91 });
92
93 const auto range(pop.range_of_layers());
94 std::vector<std::future<group_stat<I, F>>> tasks;
95 for (auto l(range.begin()); l != range.end(); ++l)
96 tasks.push_back(std::async(std::launch::async, gather_subgroup_stats, l));
97
98 for (auto &task : tasks)
99 group_stat_.push_back(task.get());
100}
101
105template<Individual I, Fitness F>
107{
108 *this = {};
109}
110
111template<Individual I, Fitness F>
112const group_stat<I, F> *analyzer<I, F>::group(population_uid uid) const
113{
114 const auto iter(std::ranges::find_if(group_stat_,
115 [uid](const auto &grp)
116 {
117 return grp.uid == uid;
118 }));
119
120 return iter == group_stat_.end() ? nullptr : std::addressof(*iter);
121}
122
123template<Individual I, Fitness F>
124group_stat<I, F> *analyzer<I, F>::group(population_uid uid)
125{
126 // My goodness... however, nobody ever got fired for following Scott Meyers.
127 return const_cast<group_stat<I, F> *>(std::as_const(*this).group(uid));
128}
129
133template<Individual I, Fitness F>
134group_stat<I, F> analyzer<I, F>::overall_group_stat() const
135{
136 group_stat<I, F> ret;
137
138 for (const auto &gs : group_stat_)
139 ret.merge(gs);
140
141 return ret;
142}
143
148template<Individual I, Fitness F>
149auto analyzer<I, F>::crossover_types() const
150{
151 decltype(group_stat<I, F>::crossover_type) ret;
152 for (const auto &gs : group_stat_)
153 internal::merge_ct(ret, gs.crossover_type);
154
155 return ret;
156}
157
162template<Individual I, Fitness F>
163const auto &analyzer<I, F>::crossover_types(population_uid g) const
164{
165 const auto *ptr(group(g));
166 assert(ptr);
167
168 return ptr->crossover_type;
169}
170
175template<Individual I, Fitness F>
176template<Population P>
177const auto &analyzer<I, F>::crossover_types(const P &g) const
178{
179 return crossover_types(g.uid());
180}
181
186template<Individual I, Fitness F>
188{
190 for (const auto &gs : group_stat_)
191 ret.merge(gs.age);
192
193 return ret;
194}
195
201template<Individual I, Fitness F>
202const distribution<double> &analyzer<I, F>::age_dist(population_uid g) const
203{
204 const auto *ptr(group(g));
205 assert(ptr);
206
207 return ptr->age;
208}
209
215template<Individual I, Fitness F>
216template<Population P>
218{
219 return age_dist(g.uid());
220}
221
226template<Individual I, Fitness F>
228{
229 distribution<F> ret;
230 for (const auto &gs : group_stat_)
231 ret.merge(gs.fitness);
232
233 return ret;
234}
235
241template<Individual I, Fitness F>
242const distribution<F> &analyzer<I, F>::fit_dist(population_uid g) const
243{
244 const auto *ptr(group(g));
245 assert(ptr);
246
247 return ptr->fitness;
248}
249
255template<Individual I, Fitness F>
256template<Population P>
258{
259 return fit_dist(g.uid());
260}
261
266template<Individual I, Fitness F>
268{
270 for (const auto &gs : group_stat_)
271 ret.merge(gs.length);
272
273 return ret;
274}
275
281template<Individual I, Fitness F>
282const distribution<double> &analyzer<I, F>::length_dist(population_uid g) const
283{
284 const auto *ptr(group(g));
285 assert(ptr);
286
287 return ptr->length;
288}
289
295template<Individual I, Fitness F>
296template<Population P>
298{
299 return length_dist(g.uid());
300}
301
305template<Individual I, Fitness F>
306bool analyzer<I, F>::is_valid() const
307{
308 const auto ad(age_dist());
309 const auto cts(crossover_types());
310 const auto fd(fit_dist());
311 const auto ld(length_dist());
312
313 for (const auto &g : group_stat_)
314 {
315 if (g.age.min() < ad.min())
316 return false;
317 if (g.age.max() > ad.max())
318 return false;
319
320 if (!g.fitness.empty())
321 {
322 if (fd.empty())
323 return false;
324
325 if (g.fitness.min() < fd.min())
326 return false;
327 if (g.fitness.max() > fd.max())
328 return false;
329 }
330
331 if (g.length.min() < ld.min())
332 return false;
333 if (g.length.max() > ld.max())
334 return false;
335
336 if constexpr (has_active_crossover_type<I>)
337 {
338 std::size_t sum_cross(0);
339
340 for (auto [type,num] : g.crossover_type)
341 {
342 sum_cross += num;
343
344 if (type >= I::NUM_CROSSOVERS)
345 return false;
346
347 if (num > cts.at(type))
348 return false;
349 }
350
351 if (sum_cross != g.age.size())
352 return false;
353 }
354 else
355 {
356 if (!g.crossover_type.empty())
357 return false;
358 }
359
360 if (g.age.size() != g.length.size())
361 return false;
362 if (g.fitness.size() > g.age.size()) // could be smaller, invalid fitness
363 return false; // values are skipped
364 }
365
366 return true;
367}
368
378template<Individual I, Fitness F>
379void analyzer<I, F>::add(const I &ind, const F &f, population_uid uid)
380{
381 if (auto *selected = group(uid))
382 selected->add(ind, f);
383 else
384 {
385 group_stat_.emplace_back(uid);
386 group_stat_.back().add(ind, f);
387 }
388}
389
390#endif // include guard
distribution< double > age_dist() const
Definition analyzer.h:188
distribution< double > length_dist() const
Definition analyzer.h:268
auto crossover_types() const
Definition analyzer.h:150
bool is_valid() const
Definition analyzer.h:307
distribution< F > fit_dist() const
Definition analyzer.h:228
void clear()
Definition analyzer.h:107
Definition distribution.h:36
Definition analyzer.tcc:31
Definition analyzer.h:30
void add(const I &, const F &)
Definition analyzer.h:49