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 sade_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 <string>
37
38 #include <pagmo/algorithm.hpp>
39 #include <pagmo/algorithms/sade.hpp>
40 #include <pagmo/io.hpp>
41 #include <pagmo/population.hpp>
42 #include <pagmo/problems/hock_schittkowsky_71.hpp>
43 #include <pagmo/problems/inventory.hpp>
44 #include <pagmo/problems/rosenbrock.hpp>
45 #include <pagmo/problems/zdt.hpp>
46 #include <pagmo/s11n.hpp>
47 #include <pagmo/types.hpp>
48
49 using namespace pagmo;
50
BOOST_AUTO_TEST_CASE(construction_test)51 BOOST_AUTO_TEST_CASE(construction_test)
52 {
53 sade user_algo{53u, 2u, 1u, 1e-6, 1e-6, false, 23u};
54 BOOST_CHECK(user_algo.get_verbosity() == 0u);
55 BOOST_CHECK(user_algo.get_seed() == 23u);
56 BOOST_CHECK((user_algo.get_log() == sade::log_type{}));
57
58 BOOST_CHECK_THROW((sade{53u, 0u, 1u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
59 BOOST_CHECK_THROW((sade{53u, 23u, 1u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
60 BOOST_CHECK_THROW((sade{53u, 2u, 0u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
61 BOOST_CHECK_THROW((sade{53u, 2u, 3u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
62 }
63
BOOST_AUTO_TEST_CASE(evolve_test)64 BOOST_AUTO_TEST_CASE(evolve_test)
65 {
66 // Here we only test that evolution is deterministic if the
67 // seed is controlled for all variants
68 {
69 problem prob{rosenbrock{25u}};
70 population pop1{prob, 15u, 23u};
71 population pop2{prob, 15u, 23u};
72 population pop3{prob, 15u, 23u};
73
74 for (unsigned j = 1u; j <= 2u; ++j) {
75 for (unsigned i = 1u; i <= 18u; ++i) {
76 sade user_algo1{10u, i, j, 1e-6, 1e-6, false, 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 sade user_algo2{10u, i, j, 1e-6, 1e-6, false, 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 }
94 }
95 // Here we check that the exit condition of ftol and xtol actually provoke an exit within 300u gen (rosenbrock{2} is
96 // used)
97 {
98 sade user_algo{300u, 2, 1, 1e-3, 1e-16, false, 23u};
99 user_algo.set_verbosity(1u);
100 problem prob{rosenbrock{2u}};
101 population pop{prob, 20u, 23u};
102 pop = user_algo.evolve(pop);
103 BOOST_CHECK(user_algo.get_log().size() < 5000u);
104 }
105 {
106 sade user_algo{300u, 2, 1, 1e-16, 1e-3, false, 23u};
107 user_algo.set_verbosity(1u);
108 problem prob{rosenbrock{2u}};
109 population pop{prob, 20u, 23u};
110 pop = user_algo.evolve(pop);
111 BOOST_CHECK(user_algo.get_log().size() < 300u);
112 }
113
114 // We then check that the evolve throws if called on unsuitable problems
115 BOOST_CHECK_THROW(sade{10u}.evolve(population{problem{rosenbrock{}}, 6u}), std::invalid_argument);
116 BOOST_CHECK_THROW(sade{10u}.evolve(population{problem{zdt{}}, 15u}), std::invalid_argument);
117 BOOST_CHECK_THROW(sade{10u}.evolve(population{problem{hock_schittkowsky_71{}}, 15u}), std::invalid_argument);
118 BOOST_CHECK_THROW(sade{10u}.evolve(population{problem{inventory{}}, 15u}), std::invalid_argument);
119 // And a clean exit for 0 generations
120 population pop{rosenbrock{25u}, 10u};
121 BOOST_CHECK(sade{0u}.evolve(pop).get_x()[0] == pop.get_x()[0]);
122 }
123
BOOST_AUTO_TEST_CASE(setters_getters_test)124 BOOST_AUTO_TEST_CASE(setters_getters_test)
125 {
126 sade user_algo{10000000u, 2, 1, 1e-6, 1e-6, false, 23u};
127 user_algo.set_verbosity(23u);
128 BOOST_CHECK(user_algo.get_verbosity() == 23u);
129 user_algo.set_seed(23u);
130 BOOST_CHECK(user_algo.get_seed() == 23u);
131 BOOST_CHECK(user_algo.get_name().find("Self-adaptive") != std::string::npos);
132 BOOST_CHECK(user_algo.get_extra_info().find("Self adaptation variant") != std::string::npos);
133 BOOST_CHECK_NO_THROW(user_algo.get_log());
134 }
135
BOOST_AUTO_TEST_CASE(serialization_test)136 BOOST_AUTO_TEST_CASE(serialization_test)
137 {
138 // Make one evolution
139 problem prob{rosenbrock{2u}};
140 population pop{prob, 15u, 23u};
141 algorithm algo{sade{10000000u, 2, 1, 1e-3, 1e-3, false, 23u}};
142 algo.set_verbosity(1u);
143 pop = algo.evolve(pop);
144
145 // Store the string representation of p.
146 std::stringstream ss;
147 auto before_text = boost::lexical_cast<std::string>(algo);
148 auto before_log = algo.extract<sade>()->get_log();
149 // Now serialize, deserialize and compare the result.
150 {
151 boost::archive::binary_oarchive oarchive(ss);
152 oarchive << algo;
153 }
154 // Change the content of p before deserializing.
155 algo = algorithm{};
156 {
157 boost::archive::binary_iarchive iarchive(ss);
158 iarchive >> algo;
159 }
160 auto after_text = boost::lexical_cast<std::string>(algo);
161 auto after_log = algo.extract<sade>()->get_log();
162 BOOST_CHECK_EQUAL(before_text, after_text);
163 BOOST_CHECK(before_log == after_log);
164 // so we implement a close check
165 BOOST_CHECK(before_log.size() > 0u);
166 for (auto i = 0u; i < before_log.size(); ++i) {
167 BOOST_CHECK_EQUAL(std::get<0>(before_log[i]), std::get<0>(after_log[i]));
168 BOOST_CHECK_EQUAL(std::get<1>(before_log[i]), std::get<1>(after_log[i]));
169 BOOST_CHECK_CLOSE(std::get<2>(before_log[i]), std::get<2>(after_log[i]), 1e-8);
170 BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8);
171 BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8);
172 BOOST_CHECK_CLOSE(std::get<5>(before_log[i]), std::get<5>(after_log[i]), 1e-8);
173 BOOST_CHECK_CLOSE(std::get<6>(before_log[i]), std::get<6>(after_log[i]), 1e-8);
174 }
175 }
176