Vita
team.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2013-2023 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_TEAM_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_TEAM_TCC)
18#define VITA_TEAM_TCC
19
20template<class T>
21team<T>::team() : individuals_(), signature_()
22{
23}
24
25template<class T>
26team<T>::team(unsigned n) : individuals_(n), signature_()
27{
28}
29
30///
31/// Creates a team of individuals that will cooperate to solve a task.
32///
33/// \param[in] p current problem
34///
35template<class T>
36team<T>::team(const problem &p) : signature_()
37{
38 Expects(p.env.team.individuals);
39
40 auto n(p.env.team.individuals);
41 individuals_.reserve(n);
42
43 for (decltype(n) i(0); i < n; ++i)
44 individuals_.emplace_back(p);
45
46 Ensures(is_valid());
47}
48
49///
50/// Builds a team containing the individuals of a given vector.
51///
52/// \param[in] v a vector of individuals
53///
54template<class T>
55team<T>::team(std::vector<T> v) : individuals_(std::move(v)), signature_()
56{
57 Ensures(is_valid());
58}
59
60///
61/// Mutates the individuals in `this` team and returns the number of mutations
62/// performed.
63///
64/// \param[in] pgm probability of gene mutation
65/// \param[in] prb current problem
66/// \return number of mutations performed
67///
68template<class T>
69unsigned team<T>::mutation(double pgm, const problem &prb)
70{
71 Expects(0.0 <= pgm);
72 Expects(pgm <= 1.0);
73
74 /*
75 const auto nm(random::element(individuals_).mutation(pgm, prb));
76 if (nm)
77 signature_.clear();
78
79 return nm;
80 */
81
82 unsigned nm(0);
83 for (auto &i : individuals_)
84 nm += i.mutation(pgm, prb);
85
86 if (nm)
87 signature_.clear();
88
89 return nm;
90}
91
92///
93/// \param[in] lhs first parent
94/// \param[in] rhs second parent
95/// \return the result of the crossover (we only generate a single
96/// offspring)
97///
98/// \see individual::crossover for further details.
99///
100template<class T>
101team<T> crossover(const team<T> &lhs, const team<T> &rhs)
102{
103 Expects(lhs.individuals() == rhs.individuals());
104
105/*
106 const auto j(random::sup(lhs.individuals()));
107
108 auto ret(lhs);
109 ret.individuals_[j] = crossover(lhs[j], rhs[j])
110 ret.signature_.clear();
111*/
112
113 const auto sup(lhs.individuals());
114 team<T> ret(sup);
115
116 for (unsigned i(0); i < sup; ++i)
117 ret.individuals_[i] = crossover(lhs[i], rhs[i]);
118
119 // Clearing signature isn't required.
120
121 Ensures(ret.is_valid());
122 return ret;
123}
124
125///
126/// \return an iterator pointing to the first individual of the team
127///
128template<class T>
129typename team<T>::const_iterator team<T>::begin() const
130{
131 return individuals_.begin();
132}
133
134///
135/// \return an iterator pointing to a end-of-team sentry
136///
137template<class T>
138typename team<T>::const_iterator team<T>::end() const
139{
140 return individuals_.end();
141}
142
143///
144/// \param[in] i index of a member of the team
145/// \return the `i`-th member of the team
146///
147template<class T>
148const T &team<T>::operator[](unsigned i) const
149{
150 Expects(i < individuals());
151 return individuals_[i];
152}
153
154///
155/// \return `true` if the team is empty, `false` otherwise
156///
157template<class T>
158bool team<T>::empty() const
159{
160 return individuals_.empty();
161}
162
163///
164/// \return number of individuals of the team.
165///
166template<class T>
167unsigned team<T>::individuals() const
168{
169 return static_cast<unsigned>(individuals_.size());
170}
171
172///
173/// \return the number of active symbols in the team
174/// \see team::size()
175///
176template<class T>
177unsigned team<T>::active_symbols() const
178{
179 return std::accumulate(begin(), end(), 0,
180 [](unsigned n, const T &ind)
181 {
182 return n + ind.active_symbols();
183 });
184}
185
186///
187/// Signature maps syntactically distinct (but logically equivalent)
188/// teams to the same value.
189///
190/// \return the signature of `this` team
191///
192/// In other words identical teams, at genotypic level, have the same
193/// signature; different teams at the genotipic level may be mapped
194/// to the same signature since the value of terminals is considered and not
195/// the index.
196///
197/// This is a very interesting property, useful for comparison, information
198/// retrieval, entropy calculation...
199///
200template<class T>
201hash_t team<T>::signature() const
202{
203 if (signature_.empty())
204 signature_ = hash();
205
206 return signature_;
207}
208
209///
210/// \return the signature of `this` team
211///
212///
213template<class T>
214hash_t team<T>::hash() const
215{
216 hash_t ret;
217
218 for_each(begin(), end(),
219 [&ret](const T &i) { ret.combine(i.signature()); });
220
221 return ret;
222}
223
224///
225/// \param[in] lhs first term of comparison
226/// \param[in] rhs second term of comparision
227/// \return `true` if the two teams are equal (individual by individual)
228///
229/// \note Age is not checked.
230///
231/// \relates team<T>
232///
233template<class T>
234bool operator==(const team<T> &lhs, const team<T> &rhs)
235{
236 const auto sup(lhs.individuals());
237 if (sup != rhs.individuals())
238 return false;
239
240 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
241}
242
243///
244/// \param[in] lhs first term of comparison
245/// \param[in] rhs second term of comparision
246/// \return `true` if the two teams aren't equal
247///
248/// \relates team<T>
249///
250template<class T>
251bool operator!=(const team<T> &lhs, const team<T> &rhs)
252{
253 return !(lhs == rhs);
254}
255
256///
257/// \param[in] lhs first term of comparison
258/// \param[in] rhs second term of comparision
259/// \return a numeric measurement of the difference between `x` and
260/// `this` (the number of different genes between teams)
261///
262/// \relates team<T>
263///
264template<class T>
265unsigned distance(const team<T> &lhs, const team<T> &rhs)
266{
267 Expects(lhs.individuals() == rhs.individuals());
268
269 const auto sup(lhs.individuals());
270 unsigned d(0);
271 for (auto i(decltype(sup){0}); i < sup; ++i)
272 d += distance(lhs[i], rhs[i]);
273
274 return d;
275}
276
277///
278/// \return the age of the team (average age of the team members)
279///
280template<class T>
281unsigned team<T>::age() const
282{
283 const unsigned age_sum(std::accumulate(begin(), end(), 0,
284 [](unsigned sum, const T &i)
285 {
286 return sum + i.age();
287 }));
288
289 return age_sum / individuals();
290}
291
292///
293/// Increments the age of every element of the team
294///
295template<class T>
296void team<T>::inc_age()
297{
298 for (auto &i : individuals_)
299 i.inc_age();
300}
301
302///
303/// \return `true` if the team passes the internal consistency check
304///
305template<class T>
306bool team<T>::is_valid() const
307{
308 return signature_.empty() || signature_ == hash();
309}
310
311///
312/// \param[in] ss active symbol set
313/// \param[in] in input stream
314/// \return `true` if team was loaded correctly
315///
316/// \note
317/// If the load operation isn't successful the current team isn't modified.
318///
319template<class T>
320bool team<T>::load(std::istream &in, const symbol_set &ss)
321{
322 unsigned n;
323 if (!(in >> n) || !n)
324 return false;
325
326 decltype(individuals_) v;
327 v.reserve(n);
328
329 for (unsigned j(0); j < n; ++j)
330 {
331 T i;
332 if (!i.load(in, ss))
333 return false;
334 v.push_back(i);
335 }
336
337 individuals_ = v;
338
339 // We don't save/load signature: it can be easily calculated on the fly.
340 signature_.clear();
341
342 return true;
343}
344
345///
346/// \param[out] out output stream
347/// \return `true` if team was saved correctly
348///
349template<class T>
350bool team<T>::save(std::ostream &out) const
351{
352 out << individuals() << '\n';
353 if (!out.good())
354 return false;
355
356 if (std::any_of(begin(), end(),
357 [&](const T &i) { return !i.save(out); }))
358 return false;
359
360 return out.good();
361}
362
363///
364/// \param[out] s output stream
365/// \param[in] t team to print
366/// \return output stream including `t`
367///
368/// \relates team<T>
369///
370template<class T>
371std::ostream &operator<<(std::ostream &s, const team<T> &t)
372{
373 const auto format(out::print_format_flag(s));
374
375 for (const auto &i : t)
376 {
377 if (format == out::in_line_f)
378 s << '{';
379
380 s << i;
381
382 if (format == out::in_line_f)
383 s << '}';
384 else
385 s << '\n';
386 }
387
388 return s;
389}
390
391#endif // include guard