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 #define BOOST_TEST_MODULE bee_colony_test
30 #define BOOST_TEST_DYN_LINK
31 #include <boost/test/unit_test.hpp>
32
33 #include <boost/lexical_cast.hpp>
34 #include <boost/test/tools/floating_point_comparison.hpp>
35 #include <iostream>
36 #include <stdexcept>
37 #include <string>
38 #include <tuple>
39
40 #include <pagmo/algorithm.hpp>
41 #include <pagmo/algorithms/bee_colony.hpp>
42 #include <pagmo/io.hpp>
43 #include <pagmo/population.hpp>
44 #include <pagmo/problems/ackley.hpp>
45 #include <pagmo/problems/griewank.hpp>
46 #include <pagmo/problems/hock_schittkowsky_71.hpp>
47 #include <pagmo/problems/inventory.hpp>
48 #include <pagmo/problems/rastrigin.hpp>
49 #include <pagmo/problems/rosenbrock.hpp>
50 #include <pagmo/problems/schwefel.hpp>
51 #include <pagmo/problems/zdt.hpp>
52 #include <pagmo/s11n.hpp>
53 #include <pagmo/types.hpp>
54
55 using namespace pagmo;
56
BOOST_AUTO_TEST_CASE(bee_colony_algorithm_construction)57 BOOST_AUTO_TEST_CASE(bee_colony_algorithm_construction)
58 {
59 bee_colony user_algo{1234u, 10u, 23u};
60 BOOST_CHECK(user_algo.get_verbosity() == 0u);
61 BOOST_CHECK(user_algo.get_seed() == 23u);
62 BOOST_CHECK((user_algo.get_log() == bee_colony::log_type{}));
63
64 BOOST_CHECK_THROW((bee_colony{1234u, 0u, 23u}), std::invalid_argument);
65 }
66
BOOST_AUTO_TEST_CASE(bee_colony_evolve_test)67 BOOST_AUTO_TEST_CASE(bee_colony_evolve_test)
68 {
69 // Here we only test that evolution is deterministic if the
70 // seed is controlled for all variants
71 problem prob{rosenbrock{10u}};
72 population pop1{prob, 5u, 23u};
73 population pop2{prob, 5u, 23u};
74 population pop3{prob, 5u, 23u};
75
76 bee_colony user_algo1{10u, 4u, 23u};
77 user_algo1.set_verbosity(1u);
78 pop1 = user_algo1.evolve(pop1);
79
80 BOOST_CHECK(user_algo1.get_log().size() > 0u);
81
82 bee_colony user_algo2{10u, 4u, 23u};
83 user_algo2.set_verbosity(1u);
84 pop2 = user_algo2.evolve(pop2);
85
86 BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
87
88 user_algo2.set_seed(23u);
89 pop3 = user_algo2.evolve(pop3);
90
91 BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
92
93 // We then check that the evolve throws if called on unsuitable problems
94 BOOST_CHECK_THROW(bee_colony{10u}.evolve(population{problem{rosenbrock{}}, 1u}), std::invalid_argument);
95 BOOST_CHECK_THROW(bee_colony{10u}.evolve(population{problem{zdt{}}, 15u}), std::invalid_argument);
96 BOOST_CHECK_THROW(bee_colony{10u}.evolve(population{problem{hock_schittkowsky_71{}}, 15u}), std::invalid_argument);
97 BOOST_CHECK_THROW(bee_colony{10u}.evolve(population{problem{inventory{}}, 15u}), std::invalid_argument);
98 // And a clean exit for 0 generations
99 population pop{rosenbrock{25u}, 10u};
100 BOOST_CHECK(bee_colony{0u}.evolve(pop).get_x()[0] == pop.get_x()[0]);
101
102 // To cover the case of fitness < 0
103 struct my_problem {
104 my_problem(unsigned dim = 2u) : m_dim(dim){};
105 vector_double fitness(const vector_double &x) const
106 {
107 double sum = 0.;
108 for (decltype(m_dim) i = 0u; i < m_dim; ++i) {
109 sum += x[i];
110 }
111 vector_double fit{sum};
112 return fit;
113 }
114 std::pair<vector_double, vector_double> get_bounds() const
115 {
116 vector_double lb(m_dim, -1.);
117 vector_double ub(m_dim, 1.);
118 return {lb, ub};
119 }
120 unsigned m_dim;
121 };
122 BOOST_CHECK_NO_THROW(user_algo1.evolve(population{my_problem(3u), 10u, 23u}));
123 }
124
BOOST_AUTO_TEST_CASE(bee_colony_setters_getters_test)125 BOOST_AUTO_TEST_CASE(bee_colony_setters_getters_test)
126 {
127 bee_colony user_algo{10u, 10u, 1u};
128 user_algo.set_verbosity(11u);
129 BOOST_CHECK(user_algo.get_verbosity() == 11u);
130 user_algo.set_seed(5u);
131 BOOST_CHECK(user_algo.get_seed() == 5u);
132 BOOST_CHECK(user_algo.get_gen() == 10u);
133 BOOST_CHECK(user_algo.get_name().find("Artificial Bee Colony") != std::string::npos);
134 BOOST_CHECK(user_algo.get_extra_info().find("Limit") != std::string::npos);
135 BOOST_CHECK_NO_THROW(user_algo.get_log());
136 }
137
BOOST_AUTO_TEST_CASE(bee_colony_serialization_test)138 BOOST_AUTO_TEST_CASE(bee_colony_serialization_test)
139 {
140 // We test the serialization of a pagmo algorithm when constructed with bee_colony
141 // Make one evolution
142 problem prob{rosenbrock{25u}};
143 population pop{prob, 10u, 23u};
144 algorithm algo{bee_colony{10u, 10u, 23u}};
145 algo.set_verbosity(1u); // allows the log to be filled
146 pop = algo.evolve(pop);
147
148 // Store the string representation of p.
149 std::stringstream ss;
150 auto before_text = boost::lexical_cast<std::string>(algo);
151 auto before_log = algo.extract<bee_colony>()->get_log();
152 // Now serialize, deserialize and compare the result.
153 {
154 boost::archive::binary_oarchive oarchive(ss);
155 oarchive << algo;
156 }
157 // Change the content of p before deserializing.
158 algo = algorithm{};
159 {
160 boost::archive::binary_iarchive iarchive(ss);
161 iarchive >> algo;
162 }
163 auto after_text = boost::lexical_cast<std::string>(algo);
164 auto after_log = algo.extract<bee_colony>()->get_log();
165 BOOST_CHECK_EQUAL(before_text, after_text);
166 BOOST_CHECK(before_log == after_log);
167 // so we implement a close check
168 BOOST_CHECK(before_log.size() > 0u);
169 for (auto i = 0u; i < before_log.size(); ++i) {
170 BOOST_CHECK_EQUAL(std::get<0>(before_log[i]), std::get<0>(after_log[i]));
171 BOOST_CHECK_EQUAL(std::get<1>(before_log[i]), std::get<1>(after_log[i]));
172 BOOST_CHECK_CLOSE(std::get<2>(before_log[i]), std::get<2>(after_log[i]), 1e-8);
173 BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8);
174 }
175 }
176