3 * \remark This file is part of VITA.
5 * \copyright Copyright (C) 2013-2023 EOS di Manlio Morini.
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/
13#if !defined(VITA_FITNESS_H)
14# error "Don't include this file directly, include the specific .h instead"
17#if !defined(VITA_FITNESS_TCC)
18#define VITA_FITNESS_TCC
21/// Fills the fitness with `n` copies of value `v`.
23/// \param[in] s dimension of the the fitness vector
24/// \param[in] v default value
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.
30/// The tag also helps to clarify the meaning of the other arguments.
33basic_fitness_t<T>::basic_fitness_t(with_size s, T v) : vect_(s(), v)
39/// Builds an empty fitness values.
42/// This is equivalent to building the object starting from an empty
46basic_fitness_t<T>::basic_fitness_t() : vect_()
52/// Builds a fitness from a list of values.
55basic_fitness_t<T>::basic_fitness_t(std::initializer_list<T> l) : vect_(l)
60/// Builds a fitness from a vector of values.
63basic_fitness_t<T>::basic_fitness_t(values_t v) : vect_(std::move(v))
68/// \return the size of the fitness vector
71std::size_t basic_fitness_t<T>::size() const
77/// \param[in] i index of an element
78/// \return the `i`-th element of the fitness vector
81T basic_fitness_t<T>::operator[](std::size_t i) const
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);
93/// \param[in] i index of an element
94/// \return a reference to the `i`-th element of the fitness vector
97T &basic_fitness_t<T>::operator[](std::size_t i)
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()`
108typename basic_fitness_t<T>::iterator basic_fitness_t<T>::begin()
110 return std::begin(vect_);
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()`
118typename basic_fitness_t<T>::const_iterator basic_fitness_t<T>::begin() const
120 return vect_.cbegin();
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
129typename basic_fitness_t<T>::iterator basic_fitness_t<T>::end()
131 return std::end(vect_);
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
140typename basic_fitness_t<T>::const_iterator basic_fitness_t<T>::end() const
146/// Equality comparison operator.
148/// \param[in] lhs first term of comparison
149/// \param[in] rhs second term of comparision
150/// \return `true` for equal fitness values
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.
156/// \relates basic_fitness_t
159bool operator==(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
161 return std::equal(std::begin(lhs), std::end(lhs),
162 std::begin(rhs), std::end(rhs));
166/// \param[in] lhs first term of comparison
167/// \param[in] rhs second term of comparision
168/// \return `true` for different fitness values
170/// \relates basic_fitness_t
173bool operator!=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
175 return !operator==(lhs, rhs);
179/// Lexicographic ordering.
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
186/// Behaves as if using algorithm lexicographical_compare, which compares
187/// the elements sequentially, stopping at the first mismatch.
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.
199/// \relates basic_fitness_t
202bool operator<(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
204 return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
205 std::begin(rhs), std::end(rhs));
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];
215/// Lexicographic ordering.
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`
223/// \see basic_fitness_t::operator<
225/// \relates basic_fitness_t
228bool operator>(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
230 return operator<(rhs, lhs);
234/// Lexicographic ordering.
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`
242/// \see basic_fitness_t::operator<
244/// \relates basic_fitness_t
247bool operator>=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
249 return !operator<(lhs, rhs);
253/// Lexicographic ordering.
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`
261/// \see basic_fitness_t::operator<
263/// \relates basic_fitness_t
266bool operator<=(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
268 return !operator>(lhs, rhs);
272/// Pareto dominance comparison.
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`
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`.
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
288/// \relates basic_fitness_t
291bool dominating(const basic_fitness_t<T> &lhs, const basic_fitness_t<T> &rhs)
293 bool one_better(lhs.size() && !rhs.size());
295 const auto n(std::min(lhs.size(), rhs.size()));
296 for (std::size_t i(0); i < n; ++i)
299 else if (lhs[i] < rhs[i])
306/// \param[in] in input stream
307/// \return `true` if the object has been loaded correctly
310/// If the load operation isn't successful the current basic_fitness_t isn't
314bool basic_fitness_t<T>::load(std::istream &in)
317 if (!std::getline(in >> std::ws, line))
320 std::istringstream line_in(line);
324 while (load_float_from_stream(line_in, &elem))
332/// \param[out] out output stream
333/// \return `true` if object has been saved correctly
336bool basic_fitness_t<T>::save(std::ostream &out) const
338 for (const auto &i : vect_)
340 save_float_to_stream(out, i);
350/// Standard output operator for basic_fitness_t.
352/// \relates basic_fitness_t
355std::ostream &operator<<(std::ostream &o, basic_fitness_t<T> f)
359 std::copy(f.begin(), f.end(), infix_iterator<T>(o, ", "));
365/// \param[in] f a fitness
366/// \return the sum of `this` and `f`
369basic_fitness_t<T> &basic_fitness_t<T>::operator+=(const basic_fitness_t<T> &f)
371 const auto n(size());
372 for (std::size_t i(0); i < n; ++i)
373 operator[](i) += f[i];
379/// \param[in] lhs first addend
380/// \param[in] rhs second addend
381/// \return the sum of `lhs` and `rhs`
383/// \relates basic_fitness_t
386basic_fitness_t<T> operator+(basic_fitness_t<T> lhs,
387 const basic_fitness_t<T> &rhs)
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
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.
400/// \param[in] f a fitness
401/// \return the difference of `this` and `f`
404basic_fitness_t<T> &basic_fitness_t<T>::operator-=(const basic_fitness_t<T> &f)
406 const auto n(size());
407 for (std::size_t i(0); i < n; ++i)
408 operator[](i) -= f[i];
414/// \param[in] lhs minuend
415/// \param[in] rhs subtrahend
416/// \return difference between `lhs` and `rhs`
418/// \relates basic_fitness_t
421basic_fitness_t<T> operator-(basic_fitness_t<T> lhs,
422 const basic_fitness_t<T> &rhs)
428/// \param[in] f a fitness
429/// \return product of `this` and `f`
432basic_fitness_t<T> &basic_fitness_t<T>::operator*=(const basic_fitness_t &f)
434 const auto n(size());
435 for (std::size_t i(0); i < n; ++i)
436 operator[](i) *= f[i];
442/// \param[in] lhs first factor
443/// \param[in] rhs second factor
444/// \return the product of `lhs` and `rhs`
446/// \relates basic_fitness_t
449basic_fitness_t<T> operator*(basic_fitness_t<T> lhs,
450 const basic_fitness_t<T> &rhs)
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
461/// \relates basic_fitness_t
464basic_fitness_t<T> operator/(basic_fitness_t<T> f, T v)
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
478/// \relates basic_fitness_t
481basic_fitness_t<T> operator*(basic_fitness_t<T> f, T v)
490/// \param[in] f a fitness value
491/// \return a new vector obtained taking the absolute value of each
494/// \relates basic_fitness_t
497basic_fitness_t<T> abs(basic_fitness_t<T> f)
504 // An alternative is:
505 // std::transform(std::begin(f), std::end(f), std::begin(f),
506 // static_cast<T (*)(T)>(std::abs));
510/// \param[in] f a fitness
511/// \return a new vector obtained "rounding" each component of `f`
513/// \relates basic_fitness_t
516basic_fitness_t<T> round_to(basic_fitness_t<T> f)
525/// \param[in] f a fitness
526/// \return a new vector obtained taking the square root of each component
529/// \relates basic_fitness_t
532basic_fitness_t<T> sqrt(basic_fitness_t<T> f)
535 f_i = std::sqrt(f_i);
541/// \param[in] f fitness to check
542/// \return `true` if every component of the fitness is finite
544/// \relates basic_fitness_t
547bool isfinite(const basic_fitness_t<T> &f)
549 return std::all_of(std::begin(f), std::end(f),
550 static_cast<bool (*)(T)>(std::isfinite));
554/// \param[in] f fitness to check
555/// \return `true` if a component of the fitness is `NAN`
557/// \relates basic_fitness_t
560bool isnan(const basic_fitness_t<T> &f)
562 return std::any_of(std::begin(f), std::end(f),
563 [](T v) { return std::isnan(v); });
567/// \param[in] f fitness to check
568/// \return `true` if each component of the fitness vector is small
570/// \relates basic_fitness_t
573bool issmall(const basic_fitness_t<T> &f)
575 return std::all_of(std::begin(f), std::end(f),
576 static_cast<bool (*)(T)>(vita::issmall));
580/// \param[in] f a fitness to check
581/// \return `true` if every element of `f` is nonnegative
583/// \relates basic_fitness_t
585template<class T> bool isnonnegative(const basic_fitness_t<T> &f)
587 return std::all_of(std::begin(f), std::end(f),
588 static_cast<bool (*)(T)>(vita::isnonnegative));
592/// \see vita::almost_equal function for scalar types.
594/// \relates basic_fitness_t
597bool almost_equal(const basic_fitness_t<T> &f1,
598 const basic_fitness_t<T> &f2, T ae_epsilon)
600 Expects(f1.size() == f2.size());
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))
611/// Taxicab distance between two vectors.
613/// \param[in] f1 first fitness value
614/// \param[in] f2 second fitness value
615/// \return the distance between `f1` and `f2`
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
622/// \relates basic_fitness_t
625double distance(const basic_fitness_t<T> &f1, const basic_fitness_t<T> &f2)
627 Expects(f1.size() == f2.size());
629 return std::inner_product(f1.begin(), f1.end(), f2.begin(), 0.0,
631 [](T a, T b) { return std::fabs(a - b); });
636/// \param[in] f1 first fitness value
637/// \param[in] f2 second fitness value
638/// \return the fitness vector obtained joining `f1` and `f2`
640/// \relates basic_fitness_t
643basic_fitness_t<T> combine(const basic_fitness_t<T> &f1,
644 const basic_fitness_t<T> &f2)
646 typename basic_fitness_t<T>::values_t ret;
647 ret.reserve(f1.size() + f2.size());
649 ret.insert(std::end(ret), std::begin(f1), std::end(f1));
650 ret.insert(std::end(ret), std::begin(f2), std::end(f2));
655#endif // include guard