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