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_POPULATION_H)
14# error "Don't include this file directly, include the specific .h instead"
17#if !defined(VITA_POPULATION_TCC)
18#define VITA_POPULATION_TCC
21/// Creates a random population.
23/// \param[in] p current problem
26population<T>::population(const problem &p) : prob_(&p), pop_(1),
29 const auto n(p.env.individuals);
39/// Resets layer `l` of the population.
41/// \param[in] l a layer of the population
43/// \warning If layer `l` is nonexistent/empty the method doesn't work!
46void population<T>::init_layer(unsigned l)
48 Expects(l < layers());
52 std::generate_n(std::back_inserter(pop_[l]), allowed(l),
53 [this] {return T(get_problem()); });
57/// \return number of active layers
60/// The number of active layers is a dynamic value (almost monotonically
61/// increasing with the generation number).
64unsigned population<T>::layers() const
66 return static_cast<unsigned>(pop_.size());
70/// Adds a new layer to the population.
72/// The new layer is inserted as the lower layer and randomly initialized.
75void population<T>::add_layer()
78 Expects(individuals(0));
80 const auto individuals(get_problem().env.individuals);
82 pop_.insert(pop_.begin(), layer_t());
83 pop_[0].reserve(individuals);
85 allowed_.insert(allowed_.begin(), individuals);
91void population<T>::remove_layer(unsigned l)
93 Expects(l < layers());
95 pop_.erase(std::next(pop_.begin(), l));
96 allowed_.erase(std::next(allowed_.begin(), l));
100/// Adds individual `i` to layer `l`.
102/// \param[in] l index of a layer
103/// \param[in] i an individual
106void population<T>::add_to_layer(unsigned l, const T &i)
108 Expects(l < layers());
110 if (individuals(l) < allowed(l))
111 pop_[l].push_back(i);
115/// Removes the last individual of layer `l`.
117/// \param[in] l index of a layer
120void population<T>::pop_from_layer(unsigned l)
122 Expects(l < layers());
127/// \param[in] c coordinates of an individual
128/// \return a reference to the individual at coordinates `c`
131T &population<T>::operator[](coord c)
133 Expects(c.layer < layers());
134 Expects(c.index < individuals(c.layer));
135 return pop_[c.layer][c.index];
139/// \param[in] c coordinates of an individual
140/// \return a constant reference to the individual at coordinates `c`
143const T &population<T>::operator[](coord c) const
145 Expects(c.layer < layers());
146 Expects(c.index < individuals(c.layer));
147 return pop_[c.layer][c.index];
151/// \param[in] l a layer
152/// \return the number of individuals allowed in layer `l`
154/// \note `for each l individuals(l) < allowed(l)`
157unsigned population<T>::allowed(unsigned l) const
159 Expects(l < layers());
164/// Sets the number of programs allowed in layer `l`.
166/// \param[in] l a layer
167/// \param[in] n number of programs allowed in layer `l`
169/// If layer `l` contains more programs than the amount allowed, the surplus
173void population<T>::set_allowed(unsigned l, unsigned n)
175 Expects(l < layers());
176 Expects(n <= pop_[l].capacity());
178 const auto &env(get_problem().env);
179 // Unless explicitly allowed by the environment, do not drop under a
180 // predefined number of individuals.
181 const auto min(std::min(env.min_individuals, env.individuals));
182 n = std::max(n, min);
184 if (individuals(l) > n)
186 const auto delta(individuals(l) - n);
188 // We should consider the remove-erase idiom for deleting delta random
191 pop_[l].erase(pop_[l].end() - delta, pop_[l].end());
200/// \param[in] l a layer
201/// \return the number of individuals in layer `l`
204unsigned population<T>::individuals(unsigned l) const
206 Expects(l < layers());
207 return static_cast<unsigned>(pop_[l].size());
211/// \return the number of individuals in the population
214unsigned population<T>::individuals() const
216 using ret_t = decltype(individuals());
218 return std::accumulate(pop_.begin(), pop_.end(), ret_t(0),
219 [](auto accumulator, const auto &layer)
222 + static_cast<ret_t>(layer.size());
227/// \return a constant reference to the active problem
230const problem &population<T>::get_problem() const
237/// \return a `const_iterator` pointing to the first individual of the
241typename population<T>::const_iterator population<T>::begin() const
243 return const_iterator(*this, true);
247/// \return an iterator pointing one element past the last individual of the
251typename population<T>::const_iterator population<T>::end() const
253 return const_iterator(*this, false);
257/// Increments the age of each individual of the population
260void population<T>::inc_age()
268/// \return `true` if the object passes the internal consistency check
271bool population<T>::is_valid() const
273 for (const auto &l : pop_)
274 for (const auto &i : l)
278 if (layers() != allowed_.size())
280 vitaERROR << "Number of layers doesn't match allowed array size";
284 const auto n(layers());
285 for (auto l(decltype(n){0}); l < n; ++l)
287 if (allowed(l) < individuals(l))
290 if (pop_[l].capacity() < allowed(l))
296 vitaERROR << "Undefined `problem`";
304/// \param[in] prob current problem
305/// \param[in] in input stream
306/// \return `true` if population was loaded correctly
308/// \note The current population isn't changed if the load operation fails.
311bool population<T>::load(std::istream &in, const problem &prob)
314 if (!(in >> n_layers) || !n_layers)
318 p.pop_.reserve(n_layers);
319 p.allowed_.reserve(n_layers);
321 for (decltype(n_layers) l(0); l < n_layers; ++l)
323 if (!(in >> p.allowed_[l]))
330 for (decltype(n_elem) i(0); i < n_elem; ++i)
331 if (!p[{l, i}].load(in, prob.sset))
340/// \param[out] out output stream
341/// \return `true` if population was saved correctly
344bool population<T>::save(std::ostream &out) const
346 const auto n(layers());
350 for (auto l(decltype(n){0}); l < n; ++l)
352 out << allowed(l) << ' ' << individuals(l) << '\n';
354 for (const auto &prg : pop_[l])
362/// \param[in] p a population
363/// \return the index of a random individual in `p`
365/// \related population
368typename population<T>::coord pickup(const population<T> &p)
370 const auto n_layers(p.layers());
373 return {0, random::sup(p.individuals(0))};
375 // With multiple layers we cannot be sure that every layer has the same
376 // number of individuals. So the simple (and fast) solution:
378 // const auto l(random::sup(n_layers));
379 // return return {l, random::sup(p.individuals(l)};
381 // isn't appropriate.
383 std::vector<unsigned> s(n_layers);
384 std::generate(s.begin(), s.end(),
385 [&p, l = 0] () mutable { return p.individuals(l++); });
387 std::discrete_distribution<unsigned> dd(s.begin(), s.end());
388 const auto l(dd(random::engine));
389 return {l, random::sup(s[l])};
393/// \param[in] p a population
394/// \param[in] target coordinates of a reference individual
395/// \return the coordinates of a random individual *near* `target`
397/// \related population
399/// Other parameters from the environment:
400/// * mate_zone - restricts the selection of individuals to a segment of the
404typename population<T>::coord pickup(const population<T> &p,
405 typename population<T>::coord target)
407 const auto mate_zone(p.get_problem().env.mate_zone);
408 const auto individuals(p.individuals(target.layer));
410 return {target.layer, random::ring(target.index, mate_zone, individuals)};
414/// \param[in,out] s output stream
415/// \param[in] pop population to be listed
416/// \return the output stream
419std::ostream &operator<<(std::ostream &s, const population<T> &pop)
423 for (const auto &l : pop)
425 s << std::string(70, '-') << "\nLayer " << n_layer
426 << std::string(70, '-') << '\n';
428 for (const auto &i : l)
436#endif // include guard