Vita
fitness.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_FITNESS_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_FITNESS_TCC)
18#define VITA_FITNESS_TCC
19
20///
21/// Fills the fitness with `n` copies of value `v`.
22///
23/// \param[in] s dimension of the the fitness vector
24/// \param[in] v default value
25///
26/// Both Herb Sutter and Scott Meyers recommend to avoid class designs where
27/// a `initializer_list` constructor overload can cause ambiguities to the
28/// programmer. We use a tag to avoid such situations.
29///
30/// The tag also helps to clarify the meaning of the other arguments.
31///
32template<class T>
33basic_fitness_t<T>::basic_fitness_t(with_size s, T v) : vect_(s(), v)
34{
35 Expects(s());
36}
37
38///
39/// Builds an empty fitness values.
40///
41/// \note
42/// This is equivalent to building the object starting from an empty
43// initializer list.
44///
45template<class T>
46basic_fitness_t<T>::basic_fitness_t() : vect_()
47{
48 Ensures(!size());
49}
50
51///
52/// Builds a fitness from a list of values.
53///
54template<class T>
55basic_fitness_t<T>::basic_fitness_t(std::initializer_list<T> l) : vect_(l)
56{
57}
58
59///
60/// Builds a fitness from a vector of values.
61///
62template<class T>
63basic_fitness_t<T>::basic_fitness_t(values_t v) : vect_(std::move(v))
64{
65}
66
67///
68/// \return the size of the fitness vector
69///
70template<class T>
71std::size_t basic_fitness_t<T>::size() const
72{
73 return vect_.size();
74}
75
76///
77/// \param[in] i index of an element
78/// \return the `i`-th element of the fitness vector
79///
80template<class T>
81T basic_fitness_t<T>::operator[](std::size_t i) const
82{
83 // This assert could be considered a bit too strict. In general taking the
84 // address of one past the last element is allowed, e.g.
85 // std::copy(&f[0], &f[N], &dest);
86 // but here the assertion will signal this use case. The workaround is:
87 // std::copy(f.begin(), f.end(), &dest);
88 Expects(i < size());
89 return vect_[i];
90}
91
92///
93/// \param[in] i index of an element
94/// \return a reference to the `i`-th element of the fitness vector
95///
96template<class T>
97T &basic_fitness_t<T>::operator[](std::size_t i)
98{
99 Expects(i < size());
100 return vect_[i];
101}
102
103///
104/// \return returns an iterator to the first element of the container. If the
105/// container is empty, the returned iterator will be equal to `end()`
106///
107template<class T>
108typename basic_fitness_t<T>::iterator basic_fitness_t<T>::begin()
109{
110 return std::begin(vect_);
111}
112
113///
114/// \return returns an iterator to the first element of the container. If the
115/// container is empty, the returned iterator will be equal to `end()`
116///
117template<class T>
118typename basic_fitness_t<T>::const_iterator basic_fitness_t<T>::begin() const
119{
120 return vect_.cbegin();
121}
122
123///
124/// \return returns an iterator to the element following the last element of
125/// the container. This element acts as a placeholder; attempting to
126// access it results in undefined behavior
127///
128template<class T>
129typename basic_fitness_t<T>::iterator basic_fitness_t<T>::end()
130{
131 return std::end(vect_);
132}
133
134///
135/// \return returns an iterator to the element following the last element of
136/// the container. This element acts as a placeholder; attempting to
137/// access it results in undefined behavior
138///
139template<class T>
140typename basic_fitness_t<T>::const_iterator basic_fitness_t<T>::end() const
141{
142 return vect_.cend();
143}
144
145///
146/// Equality comparison operator.
147///
148/// \param[in] lhs first term of comparison
149/// \param[in] rhs second term of comparision
150/// \return `true` for equal fitness values
151///
152/// Operation is performed by first comparing sizes and, if they match,
153/// the elements are compared sequentially using algorithm `std::equal`, which
154/// stops at the first mismatch.
155///
156/// \relates basic_fitness_t
157///
158template<class T>
159bool operator==(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
160{
161 return std::equal(std::begin(lhs), std::end(lhs),
162 std::begin(rhs), std::end(rhs));
163}
164
165///
166/// \param[in] lhs first term of comparison
167/// \param[in] rhs second term of comparision
168/// \return `true` for different fitness values
169///
170/// \relates basic_fitness_t
171///
172template<class T>
173bool operator!=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
174{
175 return !operator==(lhs, rhs);
176}
177
178///
179/// Lexicographic ordering.
180///
181/// \param[in] lhs first term of comparison
182/// \param[in] rhs second term of comparision
183/// \return `true` if the contents of the `lhs` are lexicographically
184/// less than the contents of `rhs`, `false` otherwise
185///
186/// Behaves as if using algorithm lexicographical_compare, which compares
187/// the elements sequentially, stopping at the first mismatch.
188///
189/// \note
190/// A lexicographical comparison is the kind of comparison generally used
191/// to sort words alphabetically in dictionaries; it involves comparing
192/// sequentially the elements that have the same position in both ranges
193/// against each other until one element is not equivalent to the other.
194/// The result of comparing these first non-matching elements is the result
195/// of the lexicographical comparison.
196/// If both sequences compare equal until one of them ends, the shorter
197/// sequence is lexicographically less than the longer one.
198///
199/// \relates basic_fitness_t
200///
201template<class T>
202bool operator<(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
203{
204 return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
205 std::begin(rhs), std::end(rhs));
206
207 // An alternative implementation:
208 // > for (std::size_t i(0); i < size(); ++i)
209 // > if (operator[](i) != f[i])
210 // > return operator[](i) > f[i];
211 // > return false;
212}
213
214///
215/// Lexicographic ordering.
216///
217/// \param[in] lhs first term of comparison
218/// \param[in] rhs second term of comparision
219/// \return `true` if the contents of the `lhs` are lexicographically
220/// greater than or equal the contents of `rhs`, `false`
221/// otherwise
222///
223/// \see basic_fitness_t::operator<
224///
225/// \relates basic_fitness_t
226///
227template<class T>
228bool operator>(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
229{
230 return operator<(rhs, lhs);
231}
232
233///
234/// Lexicographic ordering.
235///
236/// \param[in] lhs first term of comparison
237/// \param[in] rhs second term of comparision
238/// \return `true` if the contents of the `lhs` are lexicographically
239/// greater than or equal to the contents of `rhs`, `false`
240/// otherwise
241///
242/// \see basic_fitness_t::operator<
243///
244/// \relates basic_fitness_t
245///
246template<class T>
247bool operator>=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
248{
249 return !operator<(lhs, rhs);
250}
251
252///
253/// Lexicographic ordering.
254///
255/// \param[in] lhs first term of comparison
256/// \param[in] rhs second term of comparision
257/// \return `true` if the contents of the `lhs` are lexicographically
258/// less than or equal to the contents of `rhs`, `false`
259/// otherwise
260///
261/// \see basic_fitness_t::operator<
262///
263/// \relates basic_fitness_t
264///
265template<class T>
266bool operator<=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
267{
268 return !operator>(lhs, rhs);
269}
270
271///
272/// Pareto dominance comparison.
273///
274/// \param[in] lhs first term of comparison
275/// \param[in] rhs second term of comparison
276/// \return `true` if `lhs` is a Pareto improvement of `rhs`
277///
278/// `lhs` dominates `rhs` (is a Pareto improvement) if:
279/// - each component of `lhs` is not strictly worst (less) than the
280/// correspondig component of `rhs`;
281/// - there is at least one component in which `lhs` is better than `rhs`.
282///
283/// \note
284/// An interesting property is that if a vector `x` does not dominate a
285/// vector `y`, this does not imply that `y` dominates `x` (they can be both
286/// non-dominated).
287///
288/// \relates basic_fitness_t
289///
290template<class T>
291bool dominating(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
292{
293 bool one_better(lhs.size() && !rhs.size());
294
295 const auto n(std::min(lhs.size(), rhs.size()));
296 for (std::size_t i(0); i < n; ++i)
297 if (lhs[i] > rhs[i])
298 one_better = true;
299 else if (lhs[i] < rhs[i])
300 return false;
301
302 return one_better;
303}
304
305///
306/// \param[in] in input stream
307/// \return `true` if the object has been loaded correctly
308///
309/// \note
310/// If the load operation isn't successful the current basic_fitness_t isn't
311/// changed.
312///
313template<class T>
314bool basic_fitness_t<T>::load(std::istream &in)
315{
316 std::string line;
317 if (!std::getline(in >> std::ws, line))
318 return false;
319
320 std::istringstream line_in(line);
321
322 values_t tmp;
323 value_type elem;
324 while (load_float_from_stream(line_in, &elem))
325 tmp.push_back(elem);
326
327 *this = tmp;
328 return true;
329}
330
331///
332/// \param[out] out output stream
333/// \return `true` if object has been saved correctly
334///
335template<class T>
336bool basic_fitness_t<T>::save(std::ostream &out) const
337{
338 for (const auto &i : vect_)
339 {
340 save_float_to_stream(out, i);
341 out << ' ';
342 }
343
344 out << '\n';
345
346 return out.good();
347}
348
349///
350/// Standard output operator for basic_fitness_t.
351///
352/// \relates basic_fitness_t
353///
354template<class T>
355std::ostream &operator<<(std::ostream &o, basic_fitness_t<T> f)
356{
357 o << '(';
358
359 std::copy(f.begin(), f.end(), infix_iterator<T>(o, ", "));
360
361 return o << ')';
362}
363
364///
365/// \param[in] f a fitness
366/// \return the sum of `this` and `f`
367///
368template<class T>
369basic_fitness_t<T> &basic_fitness_t<T>::operator+=(const basic_fitness_t<T> &f)
370{
371 const auto n(size());
372 for (std::size_t i(0); i < n; ++i)
373 operator[](i) += f[i];
374
375 return *this;
376}
377
378///
379/// \param[in] lhs first addend
380/// \param[in] rhs second addend
381/// \return the sum of `lhs` and `rhs`
382///
383/// \relates basic_fitness_t
384///
385template<class T>
386basic_fitness_t<T> operator+(basic_fitness_t<T> lhs,
387 const basic_fitness_t<T> &rhs)
388{
389 // operator+ shouldn't be a member function otherwise it won't work as
390 // naturally as user may expect (i.e. asymmetry in implicit conversion from
391 // other types).
392 // Implementing `+` in terms of `+=` makes the code simpler and guarantees
393 // consistent semantics as the two functions are less likely to diverge
394 // during maintenance.
395 return lhs += rhs;
396}
397
398
399///
400/// \param[in] f a fitness
401/// \return the difference of `this` and `f`
402///
403template<class T>
404basic_fitness_t<T> &basic_fitness_t<T>::operator-=(const basic_fitness_t<T> &f)
405{
406 const auto n(size());
407 for (std::size_t i(0); i < n; ++i)
408 operator[](i) -= f[i];
409
410 return *this;
411}
412
413///
414/// \param[in] lhs minuend
415/// \param[in] rhs subtrahend
416/// \return difference between `lhs` and `rhs`
417///
418/// \relates basic_fitness_t
419///
420template<class T>
421basic_fitness_t<T> operator-(basic_fitness_t<T> lhs,
422 const basic_fitness_t<T> &rhs)
423{
424 return lhs -= rhs;
425}
426
427///
428/// \param[in] f a fitness
429/// \return product of `this` and `f`
430///
431template<class T>
432basic_fitness_t<T> &basic_fitness_t<T>::operator*=(const basic_fitness_t &f)
433{
434 const auto n(size());
435 for (std::size_t i(0); i < n; ++i)
436 operator[](i) *= f[i];
437
438 return *this;
439}
440
441///
442/// \param[in] lhs first factor
443/// \param[in] rhs second factor
444/// \return the product of `lhs` and `rhs`
445///
446/// \relates basic_fitness_t
447///
448template<class T>
449basic_fitness_t<T> operator*(basic_fitness_t<T> lhs,
450 const basic_fitness_t<T> &rhs)
451{
452 return lhs *= rhs;
453}
454
455///
456/// \param[in] f a fitness value
457/// \param[in] v a scalar
458/// \return a new vector obtained dividing each component of `f` by the
459/// scalar value `v`
460///
461/// \relates basic_fitness_t
462///
463template<class T>
464basic_fitness_t<T> operator/(basic_fitness_t<T> f, T v)
465{
466 for (auto &f_i : f)
467 f_i /= v;
468
469 return f;
470}
471
472///
473/// \param[in] f a fitness value
474/// \param[in] v a scalar
475/// \return a new vector obtained multiplying each component of `f` by the
476/// scalar value `v`
477///
478/// \relates basic_fitness_t
479///
480template<class T>
481basic_fitness_t<T> operator*(basic_fitness_t<T> f, T v)
482{
483 for (auto &f_i : f)
484 f_i *= v;
485
486 return f;
487}
488
489///
490/// \param[in] f a fitness value
491/// \return a new vector obtained taking the absolute value of each
492/// component of `f`
493///
494/// \relates basic_fitness_t
495///
496template<class T>
497basic_fitness_t<T> abs(basic_fitness_t<T> f)
498{
499 for (auto &f_i : f)
500 f_i = std::abs(f_i);
501
502 return f;
503
504 // An alternative is:
505 // std::transform(std::begin(f), std::end(f), std::begin(f),
506 // static_cast<T (*)(T)>(std::abs));
507}
508
509///
510/// \param[in] f a fitness
511/// \return a new vector obtained "rounding" each component of `f`
512///
513/// \relates basic_fitness_t
514///
515template<class T>
516basic_fitness_t<T> round_to(basic_fitness_t<T> f)
517{
518 for (auto &f_i : f)
519 f_i = round_to(f_i);
520
521 return f;
522}
523
524///
525/// \param[in] f a fitness
526/// \return a new vector obtained taking the square root of each component
527/// of `f`
528///
529/// \relates basic_fitness_t
530///
531template<class T>
532basic_fitness_t<T> sqrt(basic_fitness_t<T> f)
533{
534 for (auto &f_i : f)
535 f_i = std::sqrt(f_i);
536
537 return f;
538}
539
540///
541/// \param[in] f fitness to check
542/// \return `true` if every component of the fitness is finite
543///
544/// \relates basic_fitness_t
545///
546template<class T>
547bool isfinite(const basic_fitness_t<T> &f)
548{
549 return std::all_of(std::begin(f), std::end(f),
550 static_cast<bool (*)(T)>(std::isfinite));
551}
552
553///
554/// \param[in] f fitness to check
555/// \return `true` if a component of the fitness is `NAN`
556///
557/// \relates basic_fitness_t
558///
559template<class T>
560bool isnan(const basic_fitness_t<T> &f)
561{
562 return std::any_of(std::begin(f), std::end(f),
563 [](T v) { return std::isnan(v); });
564}
565
566///
567/// \param[in] f fitness to check
568/// \return `true` if each component of the fitness vector is small
569///
570/// \relates basic_fitness_t
571///
572template<class T>
573bool issmall(const basic_fitness_t<T> &f)
574{
575 return std::all_of(std::begin(f), std::end(f),
576 static_cast<bool (*)(T)>(vita::issmall));
577}
578
579///
580/// \param[in] f a fitness to check
581/// \return `true` if every element of `f` is nonnegative
582///
583/// \relates basic_fitness_t
584///
585template<class T> bool isnonnegative(const basic_fitness_t<T> &f)
586{
587 return std::all_of(std::begin(f), std::end(f),
588 static_cast<bool (*)(T)>(vita::isnonnegative));
589}
590
591///
592/// \see vita::almost_equal function for scalar types.
593///
594/// \relates basic_fitness_t
595///
596template<class T>
597bool almost_equal(const basic_fitness_t<T> &f1,
598 const basic_fitness_t<T> &f2, T ae_epsilon)
599{
600 Expects(f1.size() == f2.size());
601
602 const auto n(f1.size());
603 for (std::size_t i(0); i < n; ++i)
604 if (!almost_equal(f1[i], f2[i], ae_epsilon))
605 return false;
606
607 return true;
608}
609
610///
611/// Taxicab distance between two vectors.
612///
613/// \param[in] f1 first fitness value
614/// \param[in] f2 second fitness value
615/// \return the distance between `f1` and `f2`
616///
617/// The taxicab distance between two vectors in an n-dimensional real vector
618/// space with fixed Cartesian coordinate system, is the sum of the lengths of
619/// the projections of the line segment between the points onto the coordinate
620/// axes.
621///
622/// \relates basic_fitness_t
623///
624template<class T>
625double distance(const basic_fitness_t<T> &f1, const basic_fitness_t<T> &f2)
626{
627 Expects(f1.size() == f2.size());
628
629 return std::inner_product(f1.begin(), f1.end(), f2.begin(), 0.0,
630 std::plus<>(),
631 [](T a, T b) { return std::fabs(a - b); });
632}
633
634
635///
636/// \param[in] f1 first fitness value
637/// \param[in] f2 second fitness value
638/// \return the fitness vector obtained joining `f1` and `f2`
639///
640/// \relates basic_fitness_t
641///
642template<class T>
643basic_fitness_t<T> combine(const basic_fitness_t<T> &f1,
644 const basic_fitness_t<T> &f2)
645{
646 typename basic_fitness_t<T>::values_t ret;
647 ret.reserve(f1.size() + f2.size());
648
649 ret.insert(std::end(ret), std::begin(f1), std::end(f1));
650 ret.insert(std::end(ret), std::begin(f2), std::end(f2));
651
652 return ret;
653}
654
655#endif // include guard