1 /* Copyright 2017-2021 PaGMO development team
2 
3 This file is part of the PaGMO library.
4 
5 The PaGMO library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8   * the GNU Lesser General Public License as published by the Free
9     Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11 
12 or
13 
14   * the GNU General Public License as published by the Free Software
15     Foundation; either version 3 of the License, or (at your option) any
16     later version.
17 
18 or both in parallel, as here.
19 
20 The PaGMO library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the PaGMO library.  If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PAGMO_POPULATION_HPP
30 #define PAGMO_POPULATION_HPP
31 
32 #include <cassert>
33 #include <iostream>
34 #include <string>
35 #include <type_traits>
36 #include <utility>
37 #include <vector>
38 
39 #include <pagmo/bfe.hpp>
40 #include <pagmo/detail/island_fwd.hpp>
41 #include <pagmo/detail/support_xeus_cling.hpp>
42 #include <pagmo/detail/visibility.hpp>
43 #include <pagmo/problem.hpp>
44 #include <pagmo/rng.hpp>
45 #include <pagmo/s11n.hpp>
46 #include <pagmo/type_traits.hpp>
47 #include <pagmo/types.hpp>
48 
49 namespace pagmo
50 {
51 /// Population class.
52 /**
53  * \image html pop_no_text.png
54  *
55  * This class represents a population of individuals, i.e., potential
56  * candidate solutions to a given problem. In pagmo an
57  * individual is determined by:
58  * - a unique ID used to track it across generations and migrations,
59  * - a chromosome (a decision vector),
60  * - the fitness of the chromosome as evaluated by a pagmo::problem,
61  * and thus including objectives, equality constraints and inequality
62  * constraints if present.
63  *
64  * A special mechanism is implemented to track the best individual that has ever
65  * been part of the population. Such an individual is called *champion* and its
66  * decision vector and fitness vector are automatically kept updated. The *champion* is
67  * not necessarily an individual currently in the population. The *champion* is
68  * only defined and accessible via the population interface if the pagmo::problem
69  * currently contained in the pagmo::population is single objective.
70  *
71  * \verbatim embed:rst:leading-asterisk
72  * .. warning::
73  *
74  *    A moved-from :cpp:class:`pagmo::population` is destructible and assignable. Any other operation will result
75  *    in undefined behaviour.
76  *
77  * \endverbatim
78  */
79 class PAGMO_DLL_PUBLIC population
80 {
81     // Make friends with island for direct
82     // access to the population's members during
83     // evolution.
84     friend class PAGMO_DLL_PUBLIC island;
85 
86 public:
87     /// The size type of the population.
88     typedef pop_size_t size_type;
89     // Default constructor
90     population();
91 
92 private:
93     void prob_ctor_impl(size_type);
94     // Enable the generic ctor only if T is not a population (after removing
95     // const/reference qualifiers).
96     template <typename T>
97     using generic_ctor_enabler
98         = enable_if_t<detail::conjunction<detail::negation<std::is_same<population, uncvref_t<T>>>,
99                                           std::is_constructible<problem, T &&>>::value,
100                       int>;
101 
102 public:
103     /// Constructor from a problem.
104     /**
105      * \verbatim embed:rst:leading-asterisk
106      * .. note::
107      *
108      *    This constructor is enabled only if, after the removal of cv/reference qualifiers,
109      *    ``T`` is not :cpp:class:`pagmo::population`, and if :cpp:class:`pagmo::problem` is constructible from ``T``.
110      *
111      * \endverbatim
112      *
113      * Constructs a population with \p pop_size individuals associated
114      * to the problem \p x and setting the population random seed
115      * to \p seed. The input problem \p x can be either a pagmo::problem or a user-defined problem
116      * (UDP).
117      *
118      * @param x the problem the population refers to.
119      * @param pop_size population size (i.e. number of individuals therein).
120      * @param seed seed of the random number generator used, for example, to
121      * create new random individuals within the bounds.
122      *
123      * @throws unspecified any exception thrown by random_decision_vector(), push_back(), or by the
124      * invoked constructor of pagmo::problem.
125      */
126     template <typename T, generic_ctor_enabler<T> = 0>
population(T && x,size_type pop_size=0u,unsigned seed=pagmo::random_device::next ())127     explicit population(T &&x, size_type pop_size = 0u, unsigned seed = pagmo::random_device::next())
128         : m_prob(std::forward<T>(x)), m_e(seed), m_seed(seed)
129     {
130         prob_ctor_impl(pop_size);
131     }
132 
133 private:
134     // Implementation of the ctor from bfe. Distinguish the two cases
135     // in which bfe or a udbfe were provided.
136     void constructor_from_bfe_impl(const bfe &, size_type, const std::true_type &);
137     template <typename U>
constructor_from_bfe_impl(U && b,size_type pop_size,const std::false_type &)138     void constructor_from_bfe_impl(U &&b, size_type pop_size, const std::false_type &)
139     {
140         constructor_from_bfe_impl(bfe(std::forward<U>(b)), pop_size, std::true_type{});
141     }
142 
143 public:
144     /// Constructor from a problem and a batch fitness evaluator.
145     /**
146      * \verbatim embed:rst:leading-asterisk
147      * .. note::
148      *
149      *    This constructor is enabled only if :cpp:class:`pagmo::problem` is constructible from ``T``,
150      *    and :cpp:class:`pagmo::bfe` is constructible from ``U``.
151      *
152      * Constructs a population with *pop_size* individuals associated
153      * to the problem *x* and setting the population random seed
154      * to *seed*. The input problem *x* can be either a :cpp:class:`pagmo::problem` or a user-defined problem
155      * (UDP). The fitnesses of the individuals will be evaluated with the input
156      * :cpp:class:`pagmo::bfe` or UDBFE *b*.
157      *
158      * \endverbatim
159      *
160      * @param x the problem the population refers to.
161      * @param b the (user-defined) batch fitness evaluator that will be used to evaluate the fitnesses of the
162      * individuals.
163      * @param pop_size population size (i.e. number of individuals therein).
164      * @param seed seed of the random number generator used, for example, to
165      * create new random individuals within the bounds.
166      *
167      * @throws unspecified any exception thrown by batch_random_decision_vector(), the public API of the (user-defined)
168      * batch fitness evaluator, push_back(), or by the invoked constructor of pagmo::problem.
169      */
170     template <
171         typename T, typename U,
172         enable_if_t<detail::conjunction<std::is_constructible<problem, T &&>, std::is_constructible<bfe, U &&>>::value,
173                     int> = 0>
population(T && x,U && b,size_type pop_size=0u,unsigned seed=pagmo::random_device::next ())174     explicit population(T &&x, U &&b, size_type pop_size = 0u, unsigned seed = pagmo::random_device::next())
175         : m_prob(std::forward<T>(x)), m_e(seed), m_seed(seed)
176     {
177         constructor_from_bfe_impl(std::forward<U>(b), pop_size, std::is_same<uncvref_t<U>, bfe>{});
178     }
179 
180     // Copy constructor.
181     population(const population &);
182     // Move constructor.
183     population(population &&) noexcept;
184     // Copy assignment operator.
185     population &operator=(const population &);
186     // Move assignment operator.
187     population &operator=(population &&) noexcept;
188     // Destructor.
189     ~population();
190 
191 private:
192     // Internal implementation of push_back().
193     template <typename T, typename U>
194     void push_back_impl(T &&, U &&);
195     // Short routine to update the champion. Does nothing if the problem is MO
196     PAGMO_DLL_LOCAL void update_champion(vector_double, vector_double);
197 
198 public:
199     // Adds one decision vector (chromosome) to the population.
200     void push_back(const vector_double &);
201     // Adds one decision vector (chromosome) to the population (move overload).
202     void push_back(vector_double &&);
203     // Adds one decision vector/fitness vector to the population.
204     void push_back(const vector_double &, const vector_double &);
205     // Adds one decision vector/fitness vector to the population (move overload).
206     void push_back(vector_double &&, vector_double &&);
207 
208     // Creates a random decision vector
209     vector_double random_decision_vector() const;
210 
211     // Index of the best individual
212     size_type best_idx() const;
213     // Index of the best individual (accounting for a vector tolerance)
214     size_type best_idx(const vector_double &) const;
215     // Index of the best individual (accounting for a scalar tolerance)
216     size_type best_idx(double) const;
217 
218     // Index of the worst individual
219     size_type worst_idx() const;
220     // Index of the worst individual (accounting for a vector tolerance)
221     size_type worst_idx(const vector_double &) const;
222     // Index of the worst individual (accounting for a scalar tolerance)
223     size_type worst_idx(double) const;
224 
225     // Champion decision vector
226     vector_double champion_x() const;
227     // Champion fitness
228     vector_double champion_f() const;
229 
230     /// Number of individuals in the population
231     /**
232      * @return the number of individuals in the population
233      */
size() const234     size_type size() const
235     {
236         assert(m_f.size() == m_ID.size());
237         assert(m_x.size() == m_ID.size());
238         return m_ID.size();
239     }
240 
241     // Sets the \f$i\f$-th individual decision vector, and fitness
242     void set_xf(size_type, const vector_double &, const vector_double &);
243     // Sets the \f$i\f$-th individual's chromosome
244     void set_x(size_type, const vector_double &);
245 
246     /// Const getter for the pagmo::problem.
247     /**
248      * @return a const reference to the internal pagmo::problem.
249      */
get_problem() const250     const problem &get_problem() const
251     {
252         return m_prob;
253     }
254 
255     /// Getter for the pagmo::problem.
256     /**
257      * \verbatim embed:rst:leading-asterisk
258      * .. warning::
259      *
260      *    The ability to extract a mutable reference to the problem is provided solely in order to
261      *    allow calling non-const methods on the problem. Assigning the population's problem via a reference
262      *    returned by this method is undefined behaviour.
263      *
264      * \endverbatim
265      *
266      * @return a reference to the internal pagmo::problem.
267      */
get_problem()268     problem &get_problem()
269     {
270         return m_prob;
271     }
272 
273     /// Const getter for the fitness vectors.
274     /**
275      * @return a const reference to the vector of fitness vectors.
276      */
get_f() const277     const std::vector<vector_double> &get_f() const
278     {
279         return m_f;
280     }
281 
282     /// Const getter for the decision vectors.
283     /**
284      * @return a const reference to the vector of decision vectors.
285      */
get_x() const286     const std::vector<vector_double> &get_x() const
287     {
288         return m_x;
289     }
290 
291     /// Const getter for the individual IDs.
292     /**
293      * @return a const reference to the vector of individual IDs.
294      */
get_ID() const295     const std::vector<unsigned long long> &get_ID() const
296     {
297         return m_ID;
298     }
299 
300     /// Getter for the seed of the population random engine.
301     /**
302      * @return the seed of the population's random engine.
303      */
get_seed() const304     unsigned get_seed() const
305     {
306         return m_seed;
307     }
308 
309 private:
310     friend class boost::serialization::access;
311     // Save to archive.
312     template <typename Archive>
save(Archive & ar,unsigned) const313     void save(Archive &ar, unsigned) const
314     {
315         detail::to_archive(ar, m_prob, m_ID, m_x, m_f, m_champion_x, m_champion_f, m_e, m_seed);
316     }
317     // Load from archive.
318     template <typename Archive>
load(Archive & ar,unsigned)319     void load(Archive &ar, unsigned)
320     {
321         try {
322             detail::from_archive(ar, m_prob, m_ID, m_x, m_f, m_champion_x, m_champion_f, m_e, m_seed);
323             // LCOV_EXCL_START
324         } catch (...) {
325             *this = population{};
326             throw;
327         }
328         // LCOV_EXCL_STOP
329     }
330     BOOST_SERIALIZATION_SPLIT_MEMBER()
331 
332     void clear();
333 
334     // Problem.
335     problem m_prob;
336     // ID of the various decision vectors
337     std::vector<unsigned long long> m_ID;
338     // Decision vectors.
339     std::vector<vector_double> m_x;
340     // Fitness vectors.
341     std::vector<vector_double> m_f;
342     // The Champion chromosome
343     vector_double m_champion_x;
344     // The Champion fitness
345     vector_double m_champion_f;
346     // Random engine.
347     mutable detail::random_engine_type m_e;
348     // Seed.
349     unsigned m_seed;
350 };
351 
352 // Streaming operator for the class pagmo::population.
353 PAGMO_DLL_PUBLIC std::ostream &operator<<(std::ostream &, const population &);
354 
355 } // namespace pagmo
356 
357 // Add some repr support for CLING
358 PAGMO_IMPLEMENT_XEUS_CLING_REPR(population)
359 
360 #endif
361