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