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 de1220_test
30 #define BOOST_TEST_DYN_LINK
31 #include <boost/test/unit_test.hpp>
32 
33 #include <iostream>
34 #include <numeric>
35 #include <string>
36 
37 #include <boost/lexical_cast.hpp>
38 #include <boost/test/tools/floating_point_comparison.hpp>
39 
40 #include <pagmo/algorithm.hpp>
41 #include <pagmo/algorithms/de1220.hpp>
42 #include <pagmo/io.hpp>
43 #include <pagmo/population.hpp>
44 #include <pagmo/problems/hock_schittkowsky_71.hpp>
45 #include <pagmo/problems/inventory.hpp>
46 #include <pagmo/problems/rosenbrock.hpp>
47 #include <pagmo/problems/zdt.hpp>
48 #include <pagmo/s11n.hpp>
49 #include <pagmo/types.hpp>
50 
51 using namespace pagmo;
52 
BOOST_AUTO_TEST_CASE(construction_test)53 BOOST_AUTO_TEST_CASE(construction_test)
54 {
55     std::vector<unsigned> mutation_variants(18);
56     std::iota(mutation_variants.begin(), mutation_variants.end(), 1u);
57     de1220 user_algo(53u, mutation_variants, 1u, 1e-6, 1e-6, false, 23u);
58     BOOST_CHECK(user_algo.get_verbosity() == 0u);
59     BOOST_CHECK(user_algo.get_seed() == 23u);
60     BOOST_CHECK((user_algo.get_log() == de1220::log_type{}));
61 
62     BOOST_CHECK_THROW((de1220{53u, {3u, 5u, 0u, 14u}, 1u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
63     BOOST_CHECK_THROW((de1220{53u, {4u, 5u, 15u, 22u, 7u}, 1u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
64     BOOST_CHECK_THROW((de1220{53u, mutation_variants, 0u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
65     BOOST_CHECK_THROW((de1220{53u, mutation_variants, 3u, 1e-6, 1e-6, false, 23u}), std::invalid_argument);
66 }
67 
BOOST_AUTO_TEST_CASE(evolve_test)68 BOOST_AUTO_TEST_CASE(evolve_test)
69 {
70     // We consider all variants
71     std::vector<unsigned> mutation_variants(18);
72     std::iota(mutation_variants.begin(), mutation_variants.end(), 1u);
73     // Here we only test that evolution is deterministic if the
74     // seed is controlled for all variants
75     {
76         problem prob{rosenbrock{25u}};
77         population pop1{prob, 15u, 23u};
78         population pop2{prob, 15u, 23u};
79         population pop3{prob, 15u, 23u};
80 
81         for (unsigned i = 1u; i <= 2u; ++i) {
82             de1220 user_algo1(10u, mutation_variants, i, 1e-6, 1e-6, false, 41u);
83             user_algo1.set_verbosity(1u);
84             pop1 = user_algo1.evolve(pop1);
85 
86             BOOST_CHECK(user_algo1.get_log().size() > 0u);
87 
88             de1220 user_algo2{10u, mutation_variants, i, 1e-6, 1e-6, false, 41u};
89             user_algo2.set_verbosity(1u);
90             pop2 = user_algo2.evolve(pop2);
91 
92             BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
93 
94             user_algo2.set_seed(41u);
95             pop3 = user_algo2.evolve(pop3);
96 
97             BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
98         }
99     }
100 
101     // Here we check that the exit condition of ftol and xtol actually provoke an exit within 5000 gen (rosenbrock{2} is
102     // used)
103     { // xtol
104         de1220 user_algo(300u, mutation_variants, 2, 1e-3, 1e-45, false, 41u);
105         user_algo.set_verbosity(1u);
106         problem prob{rosenbrock{2u}};
107         population pop{prob, 20u, 23u};
108         pop = user_algo.evolve(pop);
109         BOOST_CHECK(user_algo.get_log().size() < 300u);
110     }
111     { // ftol
112         de1220 user_algo(300u, mutation_variants, 1, 1e-45, 1e-3, false, 41u);
113         user_algo.set_verbosity(1u);
114         problem prob{rosenbrock{2u}};
115         population pop{prob, 20u, 23u};
116         pop = user_algo.evolve(pop);
117         BOOST_CHECK(user_algo.get_log().size() < 300u);
118     }
119 
120     // We then check that the evolve throws if called on unsuitable problems
121     BOOST_CHECK_THROW(de1220{10u}.evolve(population{problem{rosenbrock{}}, 6u}), std::invalid_argument);
122     BOOST_CHECK_THROW(de1220{10u}.evolve(population{problem{zdt{}}, 15u}), std::invalid_argument);
123     BOOST_CHECK_THROW(de1220{10u}.evolve(population{problem{hock_schittkowsky_71{}}, 15u}), std::invalid_argument);
124     BOOST_CHECK_THROW(de1220{10u}.evolve(population{problem{inventory{}}, 15u}), std::invalid_argument);
125     // And a clean exit for 0 generations
126     population pop{rosenbrock{25u}, 10u};
127     BOOST_CHECK(de1220{0u}.evolve(pop).get_x()[0] == pop.get_x()[0]);
128 }
129 
BOOST_AUTO_TEST_CASE(setters_getters_test)130 BOOST_AUTO_TEST_CASE(setters_getters_test)
131 {
132     // We consider all variants
133     std::vector<unsigned> mutation_variants(18);
134     std::iota(mutation_variants.begin(), mutation_variants.end(), 1u);
135     de1220 user_algo(10000u, mutation_variants, 1, 1e-6, 1e-6, false, 41u);
136     user_algo.set_verbosity(23u);
137     BOOST_CHECK(user_algo.get_verbosity() == 23u);
138     user_algo.set_seed(23u);
139     BOOST_CHECK(user_algo.get_seed() == 23u);
140     BOOST_CHECK(user_algo.get_name().find("1220") != std::string::npos);
141     BOOST_CHECK(user_algo.get_extra_info().find("Allowed variants") != std::string::npos);
142     BOOST_CHECK_NO_THROW(user_algo.get_log());
143 }
144 
BOOST_AUTO_TEST_CASE(serialization_test)145 BOOST_AUTO_TEST_CASE(serialization_test)
146 {
147     // Make one evolution
148     problem prob{rosenbrock{2u}};
149     population pop{prob, 15u, 23u};
150     std::vector<unsigned> mutation_variants(18);
151     std::iota(mutation_variants.begin(), mutation_variants.end(), 1u);
152     algorithm algo(de1220{10000u, mutation_variants, 1, 1e-6, 1e-6, false, 41u});
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<de1220>()->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<de1220>()->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_EQUAL(std::get<1>(before_log[i]), std::get<1>(after_log[i]));
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]), std::get<7>(after_log[i]), 1e-8);
186     }
187 }
188