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 #if defined(_MSC_VER)
30
31 // Disable warnings from MSVC.
32 #pragma warning(disable : 4822)
33
34 #endif
35
36 #define BOOST_TEST_MODULE s_policy_test
37 #define BOOST_TEST_DYN_LINK
38 #include <boost/test/unit_test.hpp>
39
40 #include <initializer_list>
41 #include <iostream>
42 #include <limits>
43 #include <memory>
44 #include <sstream>
45 #include <stdexcept>
46 #include <string>
47 #include <type_traits>
48 #include <typeindex>
49 #include <typeinfo>
50 #include <utility>
51
52 #include <boost/algorithm/string/predicate.hpp>
53 #include <boost/lexical_cast.hpp>
54
55 #include <pagmo/detail/type_name.hpp>
56 #include <pagmo/s11n.hpp>
57 #include <pagmo/s_policies/select_best.hpp>
58 #include <pagmo/s_policy.hpp>
59 #include <pagmo/types.hpp>
60
61 using namespace pagmo;
62
BOOST_AUTO_TEST_CASE(type_traits_tests)63 BOOST_AUTO_TEST_CASE(type_traits_tests)
64 {
65 BOOST_CHECK(!is_udsp<void>::value);
66 BOOST_CHECK(!is_udsp<int>::value);
67 BOOST_CHECK(!is_udsp<double>::value);
68
69 struct udsp00 {
70 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
71 const vector_double::size_type &, const vector_double::size_type &,
72 const vector_double::size_type &, const vector_double::size_type &,
73 const vector_double &) const;
74 };
75
76 BOOST_CHECK(is_udsp<udsp00>::value);
77 BOOST_CHECK(!is_udsp<const udsp00>::value);
78 BOOST_CHECK(!is_udsp<const udsp00 &>::value);
79 BOOST_CHECK(!is_udsp<udsp00 &>::value);
80
81 struct no_udsp00 {
82 void select(const individuals_group_t &, const vector_double::size_type &, const vector_double::size_type &,
83 const vector_double::size_type &, const vector_double::size_type &,
84 const vector_double::size_type &, const vector_double &) const;
85 };
86
87 BOOST_CHECK(!is_udsp<no_udsp00>::value);
88
89 struct no_udsp01 {
90 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
91 const vector_double::size_type &, const vector_double::size_type &,
92 const vector_double::size_type &, const vector_double::size_type &,
93 const vector_double &);
94 };
95
96 BOOST_CHECK(!is_udsp<no_udsp01>::value);
97
98 struct no_udsp02 {
99 no_udsp02() = delete;
100 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
101 const vector_double::size_type &, const vector_double::size_type &,
102 const vector_double::size_type &, const vector_double::size_type &,
103 const vector_double &) const;
104 };
105
106 BOOST_CHECK(!is_udsp<no_udsp02>::value);
107 }
108
109 struct udsp1 {
selectudsp1110 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
111 const vector_double::size_type &, const vector_double::size_type &,
112 const vector_double::size_type &, const vector_double::size_type &,
113 const vector_double &) const
114 {
115 return inds;
116 }
117 std::string foo = "hello world";
118 };
119
120 struct udsp2 {
121 udsp2() = default;
udsp2udsp2122 udsp2(const udsp2 &other) : foo{new std::string{*other.foo}} {}
123 udsp2(udsp2 &&) = default;
selectudsp2124 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
125 const vector_double::size_type &, const vector_double::size_type &,
126 const vector_double::size_type &, const vector_double::size_type &,
127 const vector_double &) const
128 {
129 return inds;
130 }
get_nameudsp2131 std::string get_name() const
132 {
133 return "frobniz";
134 }
135 std::unique_ptr<std::string> foo = std::unique_ptr<std::string>{new std::string{"hello world"}};
136 };
137
BOOST_AUTO_TEST_CASE(basic_tests)138 BOOST_AUTO_TEST_CASE(basic_tests)
139 {
140 s_policy r;
141
142 BOOST_CHECK(r.is<select_best>());
143 BOOST_CHECK(!r.is<udsp1>());
144
145 BOOST_CHECK(r.extract<select_best>() != nullptr);
146 BOOST_CHECK(r.extract<udsp1>() == nullptr);
147
148 BOOST_CHECK(static_cast<const s_policy &>(r).extract<select_best>() != nullptr);
149 BOOST_CHECK(static_cast<const s_policy &>(r).extract<udsp1>() == nullptr);
150
151 BOOST_CHECK(r.get_name() == "Select best");
152 BOOST_CHECK(!r.get_extra_info().empty());
153
154 BOOST_CHECK(s_policy(udsp1{}).get_extra_info().empty());
155 BOOST_CHECK(s_policy(udsp1{}).get_name() == detail::type_name<udsp1>());
156
157 // Constructors, assignments.
158 // Generic constructor with copy.
159 udsp1 r1;
160 s_policy s_pol1{r1};
161 BOOST_CHECK(r1.foo == "hello world");
162 BOOST_CHECK(s_pol1.extract<udsp1>()->foo == "hello world");
163 // Generic constructor with move.
164 udsp2 r2;
165 s_policy s_pol2{std::move(r2)};
166 BOOST_CHECK(r2.foo.get() == nullptr);
167 BOOST_CHECK(s_pol2.extract<udsp2>()->foo.get() != nullptr);
168 BOOST_CHECK(*s_pol2.extract<udsp2>()->foo == "hello world");
169 // Copy constructor.
170 udsp2 r3;
171 s_policy s_pol3{r3}, s_pol4{s_pol3};
172 BOOST_CHECK(*s_pol4.extract<udsp2>()->foo == "hello world");
173 BOOST_CHECK(s_pol4.extract<udsp2>()->foo.get() != s_pol3.extract<udsp2>()->foo.get());
174 BOOST_CHECK(s_pol4.get_name() == "frobniz");
175 // Move constructor.
176 s_policy s_pol5{std::move(s_pol4)};
177 BOOST_CHECK(*s_pol5.extract<udsp2>()->foo == "hello world");
178 BOOST_CHECK(s_pol5.get_name() == "frobniz");
179 // Revive s_pol4 via copy assignment.
180 s_pol4 = s_pol5;
181 BOOST_CHECK(*s_pol4.extract<udsp2>()->foo == "hello world");
182 BOOST_CHECK(s_pol4.get_name() == "frobniz");
183 // Revive s_pol4 via move assignment.
184 s_policy s_pol6{std::move(s_pol4)};
185 s_pol4 = std::move(s_pol5);
186 BOOST_CHECK(*s_pol4.extract<udsp2>()->foo == "hello world");
187 BOOST_CHECK(s_pol4.get_name() == "frobniz");
188 // Self move-assignment.
189 s_pol4 = std::move(*&s_pol4);
190 BOOST_CHECK(*s_pol4.extract<udsp2>()->foo == "hello world");
191 BOOST_CHECK(s_pol4.get_name() == "frobniz");
192
193 // Minimal iostream test.
194 {
195 std::ostringstream oss;
196 oss << r;
197 BOOST_CHECK(!oss.str().empty());
198 }
199
200 // Minimal serialization test.
201 {
202 std::string before;
203 std::stringstream ss;
204 {
205 before = boost::lexical_cast<std::string>(r);
206 boost::archive::binary_oarchive oarchive(ss);
207 oarchive << r;
208 }
209 r = s_policy{udsp1{}};
210 BOOST_CHECK(r.is<udsp1>());
211 BOOST_CHECK(before != boost::lexical_cast<std::string>(r));
212 {
213 boost::archive::binary_iarchive iarchive(ss);
214 iarchive >> r;
215 }
216 BOOST_CHECK(before == boost::lexical_cast<std::string>(r));
217 BOOST_CHECK(r.is<select_best>());
218 }
219
220 std::cout << s_policy{} << '\n';
221 }
222
BOOST_AUTO_TEST_CASE(optional_tests)223 BOOST_AUTO_TEST_CASE(optional_tests)
224 {
225 // get_name().
226 struct udsp_00 {
227 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
228 const vector_double::size_type &, const vector_double::size_type &,
229 const vector_double::size_type &, const vector_double::size_type &,
230 const vector_double &) const
231 {
232 return inds;
233 }
234 std::string get_name() const
235 {
236 return "frobniz";
237 }
238 };
239 BOOST_CHECK_EQUAL(s_policy{udsp_00{}}.get_name(), "frobniz");
240 struct udsp_01 {
241 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
242 const vector_double::size_type &, const vector_double::size_type &,
243 const vector_double::size_type &, const vector_double::size_type &,
244 const vector_double &) const
245 {
246 return inds;
247 }
248 // Missing const.
249 std::string get_name()
250 {
251 return "frobniz";
252 }
253 };
254 BOOST_CHECK(s_policy{udsp_01{}}.get_name() != "frobniz");
255
256 // get_extra_info().
257 struct udsp_02 {
258 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
259 const vector_double::size_type &, const vector_double::size_type &,
260 const vector_double::size_type &, const vector_double::size_type &,
261 const vector_double &) const
262 {
263 return inds;
264 }
265 std::string get_extra_info() const
266 {
267 return "frobniz";
268 }
269 };
270 BOOST_CHECK_EQUAL(s_policy{udsp_02{}}.get_extra_info(), "frobniz");
271 struct udsp_03 {
272 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
273 const vector_double::size_type &, const vector_double::size_type &,
274 const vector_double::size_type &, const vector_double::size_type &,
275 const vector_double &) const
276 {
277 return inds;
278 }
279 // Missing const.
280 std::string get_extra_info()
281 {
282 return "frobniz";
283 }
284 };
285 BOOST_CHECK(s_policy{udsp_03{}}.get_extra_info().empty());
286 }
287
BOOST_AUTO_TEST_CASE(stream_operator)288 BOOST_AUTO_TEST_CASE(stream_operator)
289 {
290 struct udsp_00 {
291 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
292 const vector_double::size_type &, const vector_double::size_type &,
293 const vector_double::size_type &, const vector_double::size_type &,
294 const vector_double &) const
295 {
296 return inds;
297 }
298 };
299 {
300 std::ostringstream oss;
301 oss << s_policy{udsp_00{}};
302 BOOST_CHECK(!oss.str().empty());
303 }
304 struct udsp_01 {
305 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
306 const vector_double::size_type &, const vector_double::size_type &,
307 const vector_double::size_type &, const vector_double::size_type &,
308 const vector_double &) const
309 {
310 return inds;
311 }
312 std::string get_extra_info() const
313 {
314 return "bartoppo";
315 }
316 };
317 {
318 std::ostringstream oss;
319 oss << s_policy{udsp_01{}};
320 const auto st = oss.str();
321 BOOST_CHECK(boost::contains(st, "bartoppo"));
322 BOOST_CHECK(boost::contains(st, "Extra info:"));
323 }
324 }
325
BOOST_AUTO_TEST_CASE(selection)326 BOOST_AUTO_TEST_CASE(selection)
327 {
328 s_policy r0;
329
330 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {}, {}}, 0, 0, 0, 0, 0, {}), std::invalid_argument,
331 [](const std::invalid_argument &ia) {
332 return boost::contains(
333 ia.what(),
334 "an invalid group of individuals was passed to a selection policy of type 'Select "
335 "best': the sets of individuals IDs, decision vectors and fitness vectors "
336 "must all have the same sizes, but instead their sizes are 1, 0 and 0");
337 });
338
339 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 0, 0, 0, 0, 0, {}), std::invalid_argument,
340 [](const std::invalid_argument &ia) {
341 return boost::contains(
342 ia.what(),
343 "a problem dimension of zero was passed to a selection policy of type 'Select best'");
344 });
345
346 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 2, 0, 0, 0, {}), std::invalid_argument,
347 [](const std::invalid_argument &ia) {
348 return boost::contains(ia.what(),
349 "the integer dimension (2) passed to a selection policy of type "
350 "'Select best' is larger than the supplied problem dimension (1)");
351 });
352
353 BOOST_CHECK_EXCEPTION(
354 r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 0, 0, 0, {}), std::invalid_argument,
355 [](const std::invalid_argument &ia) {
356 return boost::contains(
357 ia.what(),
358 "an invalid number of objectives (0) was passed to a selection policy of type 'Select best'");
359 });
360
361 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0,
362 std::numeric_limits<vector_double::size_type>::max(), 0, 0, {}),
363 std::invalid_argument, [](const std::invalid_argument &ia) {
364 return boost::contains(
365 ia.what(), "the number of objectives ("
366 + std::to_string(std::numeric_limits<vector_double::size_type>::max())
367 + ") passed to a selection policy of type 'Select best' is too large");
368 });
369
370 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1,
371 std::numeric_limits<vector_double::size_type>::max(), 0, {}),
372 std::invalid_argument, [](const std::invalid_argument &ia) {
373 return boost::contains(
374 ia.what(), "the number of equality constraints ("
375 + std::to_string(std::numeric_limits<vector_double::size_type>::max())
376 + ") passed to a selection policy of type 'Select best' is too large");
377 });
378
379 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1, 0,
380 std::numeric_limits<vector_double::size_type>::max(), {}),
381 std::invalid_argument, [](const std::invalid_argument &ia) {
382 return boost::contains(
383 ia.what(), "the number of inequality constraints ("
384 + std::to_string(std::numeric_limits<vector_double::size_type>::max())
385 + ") passed to a selection policy of type 'Select best' is too large");
386 });
387
388 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1, 1, 1, {}), std::invalid_argument,
389 [](const std::invalid_argument &ia) {
390 return boost::contains(
391 ia.what(),
392 "the vector of tolerances passed to a selection policy of type 'Select best' has "
393 "a dimension (0) which is inconsistent with the total number of constraints (2)");
394 });
395
396 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0, 1}, {{1.}, {}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {}),
397 std::invalid_argument, [](const std::invalid_argument &ia) {
398 return boost::contains(
399 ia.what(), "not all the individuals passed to a selection policy of type 'Select "
400 "best' have the expected dimension (1)");
401 });
402
403 BOOST_CHECK_EXCEPTION(r0.select(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {}}}, 1, 0, 1, 0, 0, {}),
404 std::invalid_argument, [](const std::invalid_argument &ia) {
405 return boost::contains(
406 ia.what(), "not all the individuals passed to a selection policy of type 'Select "
407 "best' have the expected fitness dimension (1)");
408 });
409
410 struct fail_0 {
411 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
412 const vector_double::size_type &, const vector_double::size_type &,
413 const vector_double::size_type &, const vector_double::size_type &,
414 const vector_double &) const
415 {
416 return individuals_group_t{{0}, {}, {}};
417 }
418 std::string get_name() const
419 {
420 return "fail_0";
421 }
422 };
423
424 BOOST_CHECK_EXCEPTION(
425 s_policy{fail_0{}}.select(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {}),
426 std::invalid_argument, [](const std::invalid_argument &ia) {
427 return boost::contains(ia.what(),
428 "an invalid group of individuals was returned by a selection policy of type "
429 "'fail_0': the sets of individuals IDs, decision vectors and fitness vectors "
430 "must all have the same sizes, but instead their sizes are 1, 0 and 0");
431 });
432
433 struct fail_1 {
434 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
435 const vector_double::size_type &, const vector_double::size_type &,
436 const vector_double::size_type &, const vector_double::size_type &,
437 const vector_double &) const
438 {
439 return individuals_group_t{{0, 1}, {{1}, {}}, {{1}, {1}}};
440 }
441 std::string get_name() const
442 {
443 return "fail_1";
444 }
445 };
446
447 BOOST_CHECK_EXCEPTION(
448 s_policy{fail_1{}}.select(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {}),
449 std::invalid_argument, [](const std::invalid_argument &ia) {
450 return boost::contains(ia.what(), "not all the individuals returned by a selection "
451 "policy of type 'fail_1' have the expected dimension (1)");
452 });
453
454 struct fail_2 {
455 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &,
456 const vector_double::size_type &, const vector_double::size_type &,
457 const vector_double::size_type &, const vector_double::size_type &,
458 const vector_double &) const
459 {
460 return individuals_group_t{{0, 1}, {{1}, {1}}, {{1}, {}}};
461 }
462 std::string get_name() const
463 {
464 return "fail_2";
465 }
466 };
467
468 BOOST_CHECK_EXCEPTION(
469 s_policy{fail_2{}}.select(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {}),
470 std::invalid_argument, [](const std::invalid_argument &ia) {
471 return boost::contains(ia.what(), "not all the individuals returned by a selection policy of type "
472 "'fail_2' have the expected fitness dimension (1)");
473 });
474 }
475
476 struct udsp_a {
selectudsp_a477 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &,
478 const vector_double::size_type &, const vector_double::size_type &,
479 const vector_double::size_type &, const vector_double::size_type &,
480 const vector_double &) const
481 {
482 return inds;
483 }
get_nameudsp_a484 std::string get_name() const
485 {
486 return "abba";
487 }
get_extra_infoudsp_a488 std::string get_extra_info() const
489 {
490 return "dabba";
491 }
492 template <typename Archive>
serializeudsp_a493 void serialize(Archive &ar, unsigned)
494 {
495 ar &state;
496 }
497 int state = 42;
498 };
499
500 PAGMO_S11N_S_POLICY_EXPORT(udsp_a)
501
502 // Serialization tests.
BOOST_AUTO_TEST_CASE(s11n)503 BOOST_AUTO_TEST_CASE(s11n)
504 {
505 s_policy s_pol0{udsp_a{}};
506 BOOST_CHECK(s_pol0.extract<udsp_a>()->state == 42);
507 s_pol0.extract<udsp_a>()->state = -42;
508 // Store the string representation.
509 std::stringstream ss;
510 auto before = boost::lexical_cast<std::string>(s_pol0);
511 // Now serialize, deserialize and compare the result.
512 {
513 boost::archive::binary_oarchive oarchive(ss);
514 oarchive << s_pol0;
515 }
516 // Change the content of p before deserializing.
517 s_pol0 = s_policy{};
518 {
519 boost::archive::binary_iarchive iarchive(ss);
520 iarchive >> s_pol0;
521 }
522 auto after = boost::lexical_cast<std::string>(s_pol0);
523 BOOST_CHECK_EQUAL(before, after);
524 BOOST_CHECK(s_pol0.is<udsp_a>());
525 BOOST_CHECK(s_pol0.extract<udsp_a>()->state = -42);
526 }
527
BOOST_AUTO_TEST_CASE(is_valid)528 BOOST_AUTO_TEST_CASE(is_valid)
529 {
530 s_policy p0;
531 BOOST_CHECK(p0.is_valid());
532 s_policy p1(std::move(p0));
533 BOOST_CHECK(!p0.is_valid());
534 p0 = s_policy{udsp_a{}};
535 BOOST_CHECK(p0.is_valid());
536 p1 = std::move(p0);
537 BOOST_CHECK(!p0.is_valid());
538 p0 = s_policy{udsp_a{}};
539 BOOST_CHECK(p0.is_valid());
540 }
541
BOOST_AUTO_TEST_CASE(generic_assignment)542 BOOST_AUTO_TEST_CASE(generic_assignment)
543 {
544 s_policy p0;
545 BOOST_CHECK(p0.is<select_best>());
546 BOOST_CHECK(&(p0 = udsp_a{}) == &p0);
547 BOOST_CHECK(p0.is_valid());
548 BOOST_CHECK(p0.is<udsp_a>());
549 p0 = udsp1{};
550 BOOST_CHECK(p0.is<udsp1>());
551 BOOST_CHECK((!std::is_assignable<s_policy, void>::value));
552 BOOST_CHECK((!std::is_assignable<s_policy, int &>::value));
553 BOOST_CHECK((!std::is_assignable<s_policy, const int &>::value));
554 BOOST_CHECK((!std::is_assignable<s_policy, int &&>::value));
555 }
556
BOOST_AUTO_TEST_CASE(type_index)557 BOOST_AUTO_TEST_CASE(type_index)
558 {
559 s_policy p0;
560 BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(select_best)));
561 p0 = s_policy{udsp1{}};
562 BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udsp1)));
563 }
564
BOOST_AUTO_TEST_CASE(get_ptr)565 BOOST_AUTO_TEST_CASE(get_ptr)
566 {
567 s_policy p0;
568 BOOST_CHECK(p0.get_ptr() == p0.extract<select_best>());
569 BOOST_CHECK(static_cast<const s_policy &>(p0).get_ptr()
570 == static_cast<const s_policy &>(p0).extract<select_best>());
571 p0 = s_policy{udsp1{}};
572 BOOST_CHECK(p0.get_ptr() == p0.extract<udsp1>());
573 BOOST_CHECK(static_cast<const s_policy &>(p0).get_ptr() == static_cast<const s_policy &>(p0).extract<udsp1>());
574 }
575