Vita
analyzer.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2013-2022 EOS di Manlio Morini.
6 *
7 * \license
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
10 * You can obtain one at http://mozilla.org/MPL/2.0/
11 */
12
13#if !defined(VITA_ANALYZER_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_ANALYZER_TCC)
18#define VITA_ANALYZER_TCC
19
20///
21/// New empty analyzer.
22///
23template<class T>
24analyzer<T>::analyzer()
25{
26 clear();
27}
28
29///
30/// Resets gathered statics.
31///
32template<class T>
33void analyzer<T>::clear()
34{
35 age_.clear();
36 fit_.clear();
37 length_.clear();
38
39 functions_ = sym_counter();
40 terminals_ = sym_counter();
41
42 sym_counter_.clear();
43 group_stat_.clear();
44}
45
46///
47/// \return a constant reference to the first statistical symbol we have
48/// informations about
49///
50template<class T>
51typename analyzer<T>::const_iterator analyzer<T>::begin() const
52{
53 return sym_counter_.begin();
54}
55
56///
57/// \return a constant reference (sentry) used for loops
58///
59template<class T>
60typename analyzer<T>::const_iterator analyzer<T>::end() const
61{
62 return sym_counter_.end();
63}
64
65///
66/// \param[in] eff effective / noneffective functions
67/// \return number of functions in the population
68///
69template<class T>
70std::uintmax_t analyzer<T>::functions(bool eff) const
71{
72 return functions_.counter[eff];
73}
74
75///
76/// \param[in] eff effective / noneffective terminals
77/// \return number of terminals in the population
78///
79template<class T>
80std::uintmax_t analyzer<T>::terminals(bool eff) const
81{
82 return terminals_.counter[eff];
83}
84
85///
86/// \return statistics about the age distribution of the individuals
87///
88template<class T>
89const distribution<double> &analyzer<T>::age_dist() const
90{
91 return age_;
92}
93
94///
95/// \param[in] g a group
96/// \return statistics about the age distribution of individuals in group
97/// `g`
98///
99template<class T>
100const distribution<double> &analyzer<T>::age_dist(unsigned g) const
101{
102 const auto gi(group_stat_.find(g));
103 assert(gi != group_stat_.end());
104
105 return gi->second.age;
106}
107
108///
109/// \return statistics about the fitness distribution of the individuals
110///
111template<class T>
112const distribution<fitness_t> &analyzer<T>::fit_dist() const
113{
114 return fit_;
115}
116
117///
118/// \param[in] g a group
119/// \return statistics about the fitness distribution of individuals in
120/// group `g`
121///
122template<class T>
123const distribution<fitness_t> &analyzer<T>::fit_dist(unsigned g) const
124{
125 const auto gi(group_stat_.find(g));
126 assert(gi != group_stat_.end());
127
128 return gi->second.fitness;
129}
130
131///
132/// \return statistic about the length distribution of the individuals
133///
134template<class T>
135const distribution<double> &analyzer<T>::length_dist() const
136{
137 return length_;
138}
139
140///
141/// \param[in] sym symbol we are gathering statistics about
142/// \param[in] active is this an active gene?
143///
144/// Used by `count(const T &)`.
145///
146template<class T>
147void analyzer<T>::count(const symbol *sym, bool active)
148{
149 Expects(sym);
150
151 ++sym_counter_[sym].counter[active];
152
153 if (sym->terminal())
154 ++terminals_.counter[active];
155 else
156 ++functions_.counter[active];
157}
158
159///
160/// \return `true` if the object passes the internal consistency check
161///
162template<class T>
163bool analyzer<T>::is_valid() const
164{
165 return std::all_of(sym_counter_.begin(), sym_counter_.end(),
166 [](const auto &e)
167 {
168 return e.second.counter[true] <= e.second.counter[false];
169 });
170}
171
172///
173/// Adds a new individual to the pool used to calculate statistics.
174///
175/// \param[in] ind new individual
176/// \param[in] f fitness of the new individual
177/// \param[in] g a group of the population
178///
179/// The optional `g` parameter can be used to group information (e.g. for the
180/// ALPS algorithm it's used for layer specific statistics).
181///
182template<class T>
183void analyzer<T>::add(const T &ind, const fitness_t &f, unsigned g)
184{
185 age_.add(ind.age());
186 group_stat_[g].age.add(ind.age());
187
188 length_.add(count(ind));
189
190 if (isfinite(f))
191 {
192 fit_.add(f);
193 group_stat_[g].fitness.add(f);
194 }
195}
196
197///
198/// \tparam T type of individual
199///
200/// \param[in] ind individual to be analyzed
201/// \return effective length of individual we gathered statistics about
202///
203template<class T>
204std::size_t analyzer<T>::count(const T &ind)
205{
206 return count_team(ind, is_team<T>());
207}
208
209///
210/// Specialization of `count_team(T)` for non-team.
211///
212template<class T>
213template<class U>
214std::size_t analyzer<T>::count_team(const U &ind, std::false_type)
215{
216 return count_introns(ind, has_introns<T>());
217}
218
219///
220/// Specialization of `count_team(T)` for teams.
221///
222template<class T>
223std::size_t analyzer<T>::count_team(const T &t, std::true_type)
224{
225 return std::accumulate(t.begin(), t.end(), std::size_t{0},
226 [=](auto s, const auto &ind)
227 {
228 return s + count_team(ind, std::false_type());
229 });
230}
231
232///
233/// Specialization of `count_introns(U)` for individuals with introns.
234///
235template<class T>
236template<class U>
237std::size_t analyzer<T>::count_introns(const U &ind, std::true_type)
238{
239 for (index_t i(0); i < ind.size(); ++i)
240 for (category_t c(0); c < ind.categories(); ++c)
241 count(ind[{i, c}].sym, false);
242
243 return count_introns(ind, std::false_type());
244}
245
246///
247/// Specialization of `count_introns(U)` for individuals without introns.
248///
249template<class T>
250template<class U>
251std::size_t analyzer<T>::count_introns(const U &ind, std::false_type)
252{
253 std::size_t length(0);
254 for (const auto &g : ind)
255 {
256 count(g.sym, true);
257 ++length;
258 }
259
260 return length;
261}
262
263///
264/// \param[in] ind individual to be analyzed
265/// \return effective length of individual we gathered statistics about
266///
267template<>
268inline std::size_t analyzer<i_de>::count(const i_de &ind)
269{
270 return ind.parameters();
271}
272
273///
274/// \param[in] ind individual to be analyzed
275/// \return effective length of individual we gathered statistics about
276///
277template<>
278inline std::size_t analyzer<i_ga>::count(const i_ga &ind)
279{
280 return ind.parameters();
281}
282
283#endif // include guard