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 ihs_test
30 #define BOOST_TEST_DYN_LINK
31 #include <boost/test/unit_test.hpp>
32
33 #include <boost/lexical_cast.hpp>
34 #include <pagmo/algorithm.hpp>
35 #include <pagmo/algorithms/ihs.hpp>
36 #include <pagmo/io.hpp>
37 #include <pagmo/population.hpp>
38 #include <pagmo/problems/hock_schittkowsky_71.hpp>
39 #include <pagmo/problems/inventory.hpp>
40 #include <pagmo/problems/minlp_rastrigin.hpp>
41 #include <pagmo/problems/null_problem.hpp>
42 #include <pagmo/problems/rosenbrock.hpp>
43 #include <pagmo/problems/zdt.hpp>
44
45 using namespace pagmo;
46 using namespace std;
47
BOOST_AUTO_TEST_CASE(ihs_algorithm_construction)48 BOOST_AUTO_TEST_CASE(ihs_algorithm_construction)
49 {
50 {
51 // Here we construct a valid ihs uda
52 ihs user_algo{1u, 0.85, 0.35, 0.99, 1e-5, 1., 42u};
53 BOOST_CHECK(user_algo.get_verbosity() == 0u);
54 BOOST_CHECK(user_algo.get_seed() == 42u);
55 BOOST_CHECK((user_algo.get_log() == ihs::log_type{}));
56 }
57
58 // Here we construct invalid ihs udas and test that construction fails
59 BOOST_CHECK_THROW((ihs{1u, 1.2, 0.35, 0.99, 1e-5, 1., 42u}), std::invalid_argument);
60 BOOST_CHECK_THROW((ihs{1u, -0.2, 0.35, 0.99, 1e-5, 1., 42u}), std::invalid_argument);
61 BOOST_CHECK_THROW((ihs{1u, 0.85, 23., 0.99, 1e-5, 1., 42u}), std::invalid_argument);
62 BOOST_CHECK_THROW((ihs{1u, 0.85, -22.4, 0.99, 1e-5, 1., 42u}), std::invalid_argument);
63 BOOST_CHECK_THROW((ihs{1u, 0.85, 0.35, 12., 1e-5, 1., 42u}), std::invalid_argument);
64 BOOST_CHECK_THROW((ihs{1u, 0.85, 0.35, -0.2, 1e-5, 1., 42u}), std::invalid_argument);
65 BOOST_CHECK_THROW((ihs{1u, 0.85, 0.35, 0.34, 1e-5, 1., 42u}), std::invalid_argument);
66 BOOST_CHECK_THROW((ihs{1u, 0.85, 0.35, 0.99, -0.43, 1., 42u}), std::invalid_argument);
67 BOOST_CHECK_THROW((ihs{1u, 0.85, 0.35, 0.99, 0.4, 0.3, 42u}), std::invalid_argument);
68 }
69
70 struct mo_many {
71 /// Fitness
fitnessmo_many72 vector_double fitness(const vector_double &) const
73 {
74 return {0., 0., 0., 0., 0., 0.};
75 }
get_nobjmo_many76 vector_double::size_type get_nobj() const
77 {
78 return 6u;
79 }
80 /// Problem bounds
get_boundsmo_many81 std::pair<vector_double, vector_double> get_bounds() const
82 {
83 return {{0., 0.}, {1., 1.}};
84 }
85 };
86
BOOST_AUTO_TEST_CASE(ihs_evolve_test)87 BOOST_AUTO_TEST_CASE(ihs_evolve_test)
88 {
89 // We test for unsuitable populations
90 {
91 population pop{rosenbrock{25u}};
92 BOOST_CHECK_THROW(ihs{15u}.evolve(pop), std::invalid_argument);
93 population pop2{null_problem{2u, 3u, 4u}, 20u};
94 BOOST_CHECK_THROW(ihs{15u}.evolve(pop2), std::invalid_argument);
95 population pop3{inventory{}, 20u};
96 BOOST_CHECK_THROW(ihs{15u}.evolve(pop3), std::invalid_argument);
97 }
98 // And a clean exit for 0 generations
99 {
100 population pop1{rosenbrock{25u}, 10u};
101 BOOST_CHECK(ihs{0u}.evolve(pop1).get_x()[0] == pop1.get_x()[0]);
102 }
103 // Here we only test that evolution is deterministic if the
104 // seed is controlled
105 std::vector<problem> prob_list;
106 prob_list.push_back(problem(rosenbrock{10u}));
107 prob_list.push_back(problem(zdt{1u}));
108 prob_list.push_back(problem(hock_schittkowsky_71{}));
109 prob_list.push_back(problem(minlp_rastrigin{}));
110 for (auto &prob : prob_list) {
111 prob.set_c_tol(1e-4);
112 population pop1{prob, 20u, 42u};
113 population pop2{prob, 20u, 42u};
114 population pop3{prob, 20u, 42u};
115 ihs uda1{1000u, 0.85, 0.35, 0.99, 1e-5, 1., 42u};
116 ihs uda2{1000u, 0.85, 0.35, 0.99, 1e-5, 1., 42u};
117 uda1.set_verbosity(100u);
118 uda2.set_verbosity(100u);
119 pop1 = uda1.evolve(pop1);
120 BOOST_CHECK(uda1.get_log().size() > 0u);
121 pop2 = uda2.evolve(pop2);
122 BOOST_CHECK(uda1.get_log() == uda2.get_log());
123 uda2.set_seed(42u);
124 pop3 = uda2.evolve(pop3);
125 BOOST_CHECK(uda1.get_log() == uda2.get_log());
126 }
127 // We test a call on many objectives (>5) to trigger the relative lines cropping the screen output
128 ihs uda1{100u, 0.85, 0.35, 0.99, 1e-5, 1., 42u};
129 uda1.set_verbosity(10u);
130 population pop{problem{mo_many{}}, 56u, 23u};
131 uda1.evolve(pop);
132 BOOST_CHECK(std::get<7>(uda1.get_log()[0]).size() == 6u);
133 }
134
BOOST_AUTO_TEST_CASE(ihs_setters_getters_test)135 BOOST_AUTO_TEST_CASE(ihs_setters_getters_test)
136 {
137 ihs user_algo{1u, 0.85, 0.35, 0.99, 1e-5, 1., 42u};
138 user_algo.set_verbosity(23u);
139 BOOST_CHECK(user_algo.get_verbosity() == 23u);
140 user_algo.set_seed(23u);
141 BOOST_CHECK(user_algo.get_seed() == 23u);
142 BOOST_CHECK(user_algo.get_name().find("Improved Harmony Search") != std::string::npos);
143 BOOST_CHECK(user_algo.get_extra_info().find("Maximum distance bandwidth") != std::string::npos);
144 BOOST_CHECK_NO_THROW(user_algo.get_log());
145 }
146
BOOST_AUTO_TEST_CASE(ihs_serialization_test)147 BOOST_AUTO_TEST_CASE(ihs_serialization_test)
148 {
149 // Make one evolution
150 problem prob{rosenbrock{25u}};
151 population pop{prob, 10u, 23u};
152 algorithm algo{ihs{100u, 0.85, 0.35, 0.99, 1e-5, 1., 42u}};
153 algo.set_verbosity(1u);
154 pop = algo.evolve(pop);
155
156 // Store the string representation of p.
157 std::stringstream ss;
158 auto before_text = boost::lexical_cast<std::string>(algo);
159 auto before_log = algo.extract<ihs>()->get_log();
160 // Now serialize, deserialize and compare the result.
161 {
162 boost::archive::binary_oarchive oarchive(ss);
163 oarchive << algo;
164 }
165 // Change the content of p before deserializing.
166 algo = algorithm{};
167 {
168 boost::archive::binary_iarchive iarchive(ss);
169 iarchive >> algo;
170 }
171 auto after_text = boost::lexical_cast<std::string>(algo);
172 auto after_log = algo.extract<ihs>()->get_log();
173 BOOST_CHECK_EQUAL(before_text, after_text);
174 BOOST_CHECK(before_log == after_log);
175 // so we implement a close check
176 BOOST_CHECK(before_log.size() > 0u);
177 for (auto i = 0u; i < before_log.size(); ++i) {
178 BOOST_CHECK_EQUAL(std::get<0>(before_log[i]), std::get<0>(after_log[i]));
179 BOOST_CHECK_CLOSE(std::get<1>(before_log[i]), std::get<1>(after_log[i]), 1e-8);
180 BOOST_CHECK_CLOSE(std::get<2>(before_log[i]), std::get<2>(after_log[i]), 1e-8);
181 BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8);
182 BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8);
183 BOOST_CHECK_EQUAL(std::get<5>(before_log[i]), std::get<5>(after_log[i]));
184 BOOST_CHECK_CLOSE(std::get<6>(before_log[i]), std::get<6>(after_log[i]), 1e-8);
185 BOOST_CHECK_CLOSE(std::get<7>(before_log[i])[0], std::get<7>(after_log[i])[0], 1e-8);
186 }
187 }
188
BOOST_AUTO_TEST_CASE(ihs_integer_test)189 BOOST_AUTO_TEST_CASE(ihs_integer_test)
190 {
191 // We test that on integer problems the evolution returns integer results.
192 minlp_rastrigin udp(0u, 10u);
193 problem prob(udp);
194 population pop(prob, 20u, 32u);
195 ihs uda{10u, 0.99, 0.99, 0.99, 1e-5, 5, 42u};
196 algorithm algo(uda);
197 pop = algo.evolve(pop);
198 for (auto x : pop.get_x()) {
199 for (auto c : x) {
200 BOOST_CHECK_EQUAL(static_cast<int>(c), c);
201 }
202 }
203 }
204