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