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_S_POLICY_HPP
30 #define PAGMO_S_POLICY_HPP
31 
32 #include <cassert>
33 #include <iostream>
34 #include <memory>
35 #include <string>
36 #include <type_traits>
37 #include <typeindex>
38 #include <typeinfo>
39 #include <utility>
40 
41 #include <boost/type_traits/integral_constant.hpp>
42 
43 #include <pagmo/config.hpp>
44 #include <pagmo/detail/support_xeus_cling.hpp>
45 #include <pagmo/detail/type_name.hpp>
46 #include <pagmo/detail/typeid_name_extract.hpp>
47 #include <pagmo/detail/visibility.hpp>
48 #include <pagmo/s11n.hpp>
49 #include <pagmo/type_traits.hpp>
50 #include <pagmo/types.hpp>
51 
52 #define PAGMO_S11N_S_POLICY_EXPORT_KEY(s)                                                                              \
53     BOOST_CLASS_EXPORT_KEY2(pagmo::detail::s_pol_inner<s>, "udsp " #s)                                                 \
54     BOOST_CLASS_TRACKING(pagmo::detail::s_pol_inner<s>, boost::serialization::track_never)
55 
56 #define PAGMO_S11N_S_POLICY_IMPLEMENT(s) BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::detail::s_pol_inner<s>)
57 
58 #define PAGMO_S11N_S_POLICY_EXPORT(s)                                                                                  \
59     PAGMO_S11N_S_POLICY_EXPORT_KEY(s)                                                                                  \
60     PAGMO_S11N_S_POLICY_IMPLEMENT(s)
61 
62 namespace pagmo
63 {
64 
65 // Check if T has a select() member function conforming to the UDSP requirements.
66 template <typename T>
67 class has_select
68 {
69     template <typename U>
70     using select_t = decltype(std::declval<const U &>().select(
71         std::declval<const individuals_group_t &>(), std::declval<const vector_double::size_type &>(),
72         std::declval<const vector_double::size_type &>(), std::declval<const vector_double::size_type &>(),
73         std::declval<const vector_double::size_type &>(), std::declval<const vector_double::size_type &>(),
74         std::declval<const vector_double &>()));
75     static const bool implementation_defined = std::is_same<detected_t<select_t, T>, individuals_group_t>::value;
76 
77 public:
78     static const bool value = implementation_defined;
79 };
80 
81 template <typename T>
82 const bool has_select<T>::value;
83 
84 namespace detail
85 {
86 
87 // Specialise this to true in order to disable all the UDSP checks and mark a type
88 // as a UDSP regardless of the features provided by it.
89 // NOTE: this is needed when implementing the machinery for Python s_policies.
90 // NOTE: leave this as an implementation detail for now.
91 template <typename>
92 struct disable_udsp_checks : std::false_type {
93 };
94 
95 } // namespace detail
96 
97 // Detect UDSPs
98 template <typename T>
99 class is_udsp
100 {
101     static const bool implementation_defined
102         = detail::disjunction<detail::conjunction<std::is_same<T, uncvref_t<T>>, std::is_default_constructible<T>,
103                                                   std::is_copy_constructible<T>, std::is_move_constructible<T>,
104                                                   std::is_destructible<T>, has_select<T>>,
105                               detail::disable_udsp_checks<T>>::value;
106 
107 public:
108     // Value of the type trait.
109     static const bool value = implementation_defined;
110 };
111 
112 template <typename T>
113 const bool is_udsp<T>::value;
114 
115 namespace detail
116 {
117 
118 struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner_base {
~s_pol_inner_basepagmo::detail::s_pol_inner_base119     virtual ~s_pol_inner_base() {}
120     virtual std::unique_ptr<s_pol_inner_base> clone() const = 0;
121     virtual individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
122                                        const vector_double::size_type &, const vector_double::size_type &,
123                                        const vector_double::size_type &, const vector_double::size_type &,
124                                        const vector_double &) const = 0;
125     virtual std::string get_name() const = 0;
126     virtual std::string get_extra_info() const = 0;
127     virtual std::type_index get_type_index() const = 0;
128     virtual const void *get_ptr() const = 0;
129     virtual void *get_ptr() = 0;
130 
131 private:
132     friend class boost::serialization::access;
133     template <typename Archive>
serializepagmo::detail::s_pol_inner_base134     void serialize(Archive &, unsigned)
135     {
136     }
137 };
138 
139 template <typename T>
140 struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner final : s_pol_inner_base {
141     // We just need the def ctor, delete everything else.
142     s_pol_inner() = default;
143     s_pol_inner(const s_pol_inner &) = delete;
144     s_pol_inner(s_pol_inner &&) = delete;
145     s_pol_inner &operator=(const s_pol_inner &) = delete;
146     s_pol_inner &operator=(s_pol_inner &&) = delete;
147     // Constructors from T.
s_pol_innerpagmo::detail::s_pol_inner148     explicit s_pol_inner(const T &x) : m_value(x) {}
s_pol_innerpagmo::detail::s_pol_inner149     explicit s_pol_inner(T &&x) : m_value(std::move(x)) {}
150     // The clone method, used in the copy constructor of s_policy.
clonepagmo::detail::s_pol_inner151     std::unique_ptr<s_pol_inner_base> clone() const final
152     {
153         return std::make_unique<s_pol_inner>(m_value);
154     }
155     // The mandatory select() method.
selectpagmo::detail::s_pol_inner156     individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &nx,
157                                const vector_double::size_type &nix, const vector_double::size_type &nobj,
158                                const vector_double::size_type &nec, const vector_double::size_type &nic,
159                                const vector_double &tol) const final
160     {
161         return m_value.select(inds, nx, nix, nobj, nec, nic, tol);
162     }
163     // Optional methods.
get_namepagmo::detail::s_pol_inner164     std::string get_name() const final
165     {
166         return get_name_impl(m_value);
167     }
get_extra_infopagmo::detail::s_pol_inner168     std::string get_extra_info() const final
169     {
170         return get_extra_info_impl(m_value);
171     }
172     template <typename U, enable_if_t<has_name<U>::value, int> = 0>
get_name_implpagmo::detail::s_pol_inner173     static std::string get_name_impl(const U &value)
174     {
175         return value.get_name();
176     }
177     template <typename U, enable_if_t<!has_name<U>::value, int> = 0>
get_name_implpagmo::detail::s_pol_inner178     static std::string get_name_impl(const U &)
179     {
180         return detail::type_name<U>();
181     }
182     template <typename U, enable_if_t<has_extra_info<U>::value, int> = 0>
get_extra_info_implpagmo::detail::s_pol_inner183     static std::string get_extra_info_impl(const U &value)
184     {
185         return value.get_extra_info();
186     }
187     template <typename U, enable_if_t<!has_extra_info<U>::value, int> = 0>
get_extra_info_implpagmo::detail::s_pol_inner188     static std::string get_extra_info_impl(const U &)
189     {
190         return "";
191     }
192     // Get the type at runtime.
get_type_indexpagmo::detail::s_pol_inner193     std::type_index get_type_index() const final
194     {
195         return std::type_index(typeid(T));
196     }
197     // Raw getters for the internal instance.
get_ptrpagmo::detail::s_pol_inner198     const void *get_ptr() const final
199     {
200         return &m_value;
201     }
get_ptrpagmo::detail::s_pol_inner202     void *get_ptr() final
203     {
204         return &m_value;
205     }
206 
207 private:
208     friend class boost::serialization::access;
209     // Serialization
210     template <typename Archive>
serializepagmo::detail::s_pol_inner211     void serialize(Archive &ar, unsigned)
212     {
213         detail::archive(ar, boost::serialization::base_object<s_pol_inner_base>(*this), m_value);
214     }
215 
216 public:
217     T m_value;
218 };
219 
220 } // namespace detail
221 
222 } // namespace pagmo
223 
224 // Disable Boost.Serialization tracking for the implementation
225 // details of s_policy.
226 BOOST_CLASS_TRACKING(pagmo::detail::s_pol_inner_base, boost::serialization::track_never)
227 
228 namespace pagmo
229 {
230 
231 // Selection policy.
232 class PAGMO_DLL_PUBLIC s_policy
233 {
234     // Enable the generic ctor only if T is not an s_policy (after removing
235     // const/reference qualifiers), and if T is a udsp.
236     template <typename T>
237     using generic_ctor_enabler = enable_if_t<
238         detail::conjunction<detail::negation<std::is_same<s_policy, uncvref_t<T>>>, is_udsp<uncvref_t<T>>>::value, int>;
239     // Implementation of the generic ctor.
240     void generic_ctor_impl();
241 
242 public:
243     // Default constructor.
244     s_policy();
245     // Constructor from a UDSP.
246     template <typename T, generic_ctor_enabler<T> = 0>
s_policy(T && x)247     explicit s_policy(T &&x) : m_ptr(std::make_unique<detail::s_pol_inner<uncvref_t<T>>>(std::forward<T>(x)))
248     {
249         generic_ctor_impl();
250     }
251     // Copy constructor.
252     s_policy(const s_policy &);
253     // Move constructor.
254     s_policy(s_policy &&) noexcept;
255     // Move assignment operator
256     s_policy &operator=(s_policy &&) noexcept;
257     // Copy assignment operator
258     s_policy &operator=(const s_policy &);
259     // Assignment from a UDSP.
260     template <typename T, generic_ctor_enabler<T> = 0>
operator =(T && x)261     s_policy &operator=(T &&x)
262     {
263         return (*this) = s_policy(std::forward<T>(x));
264     }
265 
266     // Extraction and related.
267     template <typename T>
extract() const268     const T *extract() const noexcept
269     {
270 #if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT)
271         return detail::typeid_name_extract<T>(*this);
272 #else
273         auto p = dynamic_cast<const detail::s_pol_inner<T> *>(ptr());
274         return p == nullptr ? nullptr : &(p->m_value);
275 #endif
276     }
277     template <typename T>
extract()278     T *extract() noexcept
279     {
280 #if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT)
281         return detail::typeid_name_extract<T>(*this);
282 #else
283         auto p = dynamic_cast<detail::s_pol_inner<T> *>(ptr());
284         return p == nullptr ? nullptr : &(p->m_value);
285 #endif
286     }
287     template <typename T>
is() const288     bool is() const noexcept
289     {
290         return extract<T>() != nullptr;
291     }
292 
293     // Select.
294     individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
295                                const vector_double::size_type &, const vector_double::size_type &,
296                                const vector_double::size_type &, const vector_double::size_type &,
297                                const vector_double &) const;
298 
299     // Name.
get_name() const300     std::string get_name() const
301     {
302         return m_name;
303     }
304     // Extra info.
305     std::string get_extra_info() const;
306 
307     // Check if the s_policy is valid.
308     bool is_valid() const;
309 
310     // Get the type at runtime.
311     std::type_index get_type_index() const;
312 
313     // Get a const pointer to the UDSP.
314     const void *get_ptr() const;
315 
316     // Get a mutable pointer to the UDSP.
317     void *get_ptr();
318 
319 private:
320     friend class boost::serialization::access;
321     // Serialisation support.
322     template <typename Archive>
save(Archive & ar,unsigned) const323     void save(Archive &ar, unsigned) const
324     {
325         detail::to_archive(ar, m_ptr, m_name);
326     }
327     template <typename Archive>
load(Archive & ar,unsigned)328     void load(Archive &ar, unsigned)
329     {
330         try {
331             detail::from_archive(ar, m_ptr, m_name);
332         } catch (...) {
333             *this = s_policy{};
334             throw;
335         }
336     }
BOOST_SERIALIZATION_SPLIT_MEMBER()337     BOOST_SERIALIZATION_SPLIT_MEMBER()
338 
339     // Just two small helpers to make sure that whenever we require
340     // access to the pointer it actually points to something.
341     detail::s_pol_inner_base const *ptr() const
342     {
343         assert(m_ptr.get() != nullptr);
344         return m_ptr.get();
345     }
ptr()346     detail::s_pol_inner_base *ptr()
347     {
348         assert(m_ptr.get() != nullptr);
349         return m_ptr.get();
350     }
351     // Helper to check the inputs and outputs of the select() function.
352     PAGMO_DLL_LOCAL void verify_select_input(const individuals_group_t &, const vector_double::size_type &,
353                                              const vector_double::size_type &, const vector_double::size_type &,
354                                              const vector_double::size_type &, const vector_double::size_type &,
355                                              const vector_double &) const;
356     PAGMO_DLL_LOCAL void verify_select_output(const individuals_group_t &, vector_double::size_type,
357                                               vector_double::size_type) const;
358 
359     // Pointer to the inner base s_pol.
360     std::unique_ptr<detail::s_pol_inner_base> m_ptr;
361     // Various properties determined at construction time
362     // from the udsp. These will be constant for the lifetime
363     // of s_policy, but we cannot mark them as such because we want to be
364     // able to assign and deserialise s_policies.
365     std::string m_name;
366 };
367 
368 #if !defined(PAGMO_DOXYGEN_INVOKED)
369 
370 // Stream operator.
371 PAGMO_DLL_PUBLIC std::ostream &operator<<(std::ostream &, const s_policy &);
372 
373 #endif
374 
375 } // namespace pagmo
376 
377 // Add some repr support for CLING
378 PAGMO_IMPLEMENT_XEUS_CLING_REPR(s_policy)
379 
380 #endif
381