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 pso_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 <limits> // std::numeric_limits<double>::infinity();
37 #include <string>
38
39 #include <pagmo/algorithm.hpp>
40 #include <pagmo/algorithms/pso.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/rng.hpp>
47
48 using namespace pagmo;
49
BOOST_AUTO_TEST_CASE(construction)50 BOOST_AUTO_TEST_CASE(construction)
51 {
52 BOOST_CHECK_NO_THROW(pso{});
53 pso user_algo{100, 0.79, 2., 2., 0.1, 5u, 2u, 4u, 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() == pso::log_type{}));
57
58 BOOST_CHECK_NO_THROW((pso{100, 0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}));
59
60 BOOST_CHECK_THROW((pso{100, -0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
61 BOOST_CHECK_THROW((pso{100, 2.3, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
62
63 BOOST_CHECK_THROW((pso{100, 0.79, -1., 2., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
64 BOOST_CHECK_THROW((pso{100, 0.79, 2., -1., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
65 BOOST_CHECK_THROW((pso{100, 0.79, 5., 2., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
66 BOOST_CHECK_THROW((pso{100, 0.79, 2., 5., 0.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
67
68 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., -2.3, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
69 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 1.1, 5u, 2u, 4u, false, 23u}), std::invalid_argument);
70
71 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 0.1, 8u, 2u, 4u, false, 23u}), std::invalid_argument);
72 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 0.1, 0u, 2u, 4u, false, 23u}), std::invalid_argument);
73
74 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 0.1, 5u, 6u, 4u, false, 23u}), std::invalid_argument);
75 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 0.1, 5u, 0u, 4u, false, 23u}), std::invalid_argument);
76
77 BOOST_CHECK_THROW((pso{100, 0.79, 2., 2., 0.1, 5u, 2u, 0u, false, 23u}), std::invalid_argument);
78 }
79
BOOST_AUTO_TEST_CASE(evolve_test)80 BOOST_AUTO_TEST_CASE(evolve_test)
81 {
82 // We then check that the evolve throws if called on unsuitable problems
83 BOOST_CHECK_THROW(pso{10u}.evolve(population{problem{rosenbrock{}}}), std::invalid_argument);
84 BOOST_CHECK_THROW(pso{10u}.evolve(population{problem{zdt{}}, 15u}), std::invalid_argument);
85 BOOST_CHECK_THROW(pso{10u}.evolve(population{problem{hock_schittkowsky_71{}}, 15u}), std::invalid_argument);
86 BOOST_CHECK_THROW(pso{10u}.evolve(population{problem{inventory{}}, 15u}), std::invalid_argument);
87 // And a clean exit for 0 generations
88 population pop{rosenbrock{2u}, 20u};
89 BOOST_CHECK(pso{0u}.evolve(pop).get_x()[0] == pop.get_x()[0]);
90
91 // We check that evolution is deterministic if the
92 // seed is controlled and for all algoritmic variants:
93 for (unsigned variant = 1u; variant <= 6u; ++variant) {
94 for (unsigned neighb_type = 1u; neighb_type <= 4u; ++neighb_type) {
95 problem prob{rosenbrock{10u}};
96 population pop1{prob, 5u, 23u};
97 pso user_algo1{10u, 0.79, 2., 2., 0.1, variant, neighb_type, 4u, false, 23u};
98 user_algo1.set_verbosity(1u);
99 pop1 = user_algo1.evolve(pop1);
100
101 population pop2{prob, 5u, 23u};
102 pso user_algo2{10u, 0.79, 2., 2., 0.1, variant, neighb_type, 4u, false, 23u};
103 user_algo2.set_verbosity(1u);
104 pop2 = user_algo2.evolve(pop2);
105 BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
106
107 population pop3{prob, 5u, 23u};
108 user_algo2.set_seed(23u);
109 pop3 = user_algo2.evolve(pop3);
110 BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
111 }
112 }
113 // And with active memory
114 for (unsigned variant = 1u; variant <= 6u; ++variant) {
115 for (unsigned neighb_type = 1u; neighb_type <= 4u; ++neighb_type) {
116 problem prob{rosenbrock{10u}};
117 population pop1{prob, 5u, 23u};
118 pso user_algo1{10u, 0.79, 2., 2., 0.1, variant, neighb_type, 4u, true, 23u};
119 user_algo1.set_verbosity(1u);
120 pop1 = user_algo1.evolve(pop1);
121
122 population pop2{prob, 5u, 23u};
123 pso user_algo2{10u, 0.79, 2., 2., 0.1, variant, neighb_type, 4u, true, 23u};
124 user_algo2.set_verbosity(1u);
125 pop2 = user_algo2.evolve(pop2);
126 BOOST_CHECK(user_algo1.get_log() == user_algo2.get_log());
127
128 population pop3{prob, 5u, 23u};
129 pso user_algo3{10u, 0.79, 2., 2., 0.1, variant, neighb_type, 4u, true, 0u};
130 user_algo3.set_verbosity(1u);
131 user_algo3.set_seed(23u);
132 pop3 = user_algo3.evolve(pop3);
133 BOOST_CHECK(user_algo1.get_log() == user_algo3.get_log());
134 }
135 }
136 }
BOOST_AUTO_TEST_CASE(setters_getters_test)137 BOOST_AUTO_TEST_CASE(setters_getters_test)
138 {
139 pso user_algo{5000u, 0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u};
140 user_algo.set_verbosity(200u);
141 BOOST_CHECK(user_algo.get_verbosity() == 200u);
142 user_algo.set_seed(23u);
143 BOOST_CHECK(user_algo.get_seed() == 23u);
144 BOOST_CHECK(user_algo.get_name().find("Particle Swarm") != std::string::npos);
145 BOOST_CHECK(user_algo.get_extra_info().find("Verbosity") != std::string::npos);
146 BOOST_CHECK_NO_THROW(user_algo.get_log());
147 }
148
BOOST_AUTO_TEST_CASE(serialization_test)149 BOOST_AUTO_TEST_CASE(serialization_test)
150 {
151 // Make one evolution
152 problem prob{rosenbrock{25u}};
153 population pop{prob, 5u, 23u};
154 algorithm algo{pso{500u, 0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}};
155 algo.set_verbosity(23u);
156 pop = algo.evolve(pop);
157
158 // Store the string representation of p.
159 std::stringstream ss;
160 auto before_text = boost::lexical_cast<std::string>(algo);
161 auto before_log = algo.extract<pso>()->get_log();
162 // Now serialize, deserialize and compare the result.
163 {
164 boost::archive::binary_oarchive oarchive(ss);
165 oarchive << algo;
166 }
167 // Change the content of p before deserializing.
168 algo = algorithm{};
169 {
170 boost::archive::binary_iarchive iarchive(ss);
171 iarchive >> algo;
172 }
173 auto after_text = boost::lexical_cast<std::string>(algo);
174 auto after_log = algo.extract<pso>()->get_log();
175 BOOST_CHECK_EQUAL(before_text, after_text);
176 BOOST_CHECK(before_log == after_log);
177 // so we implement a close check
178 for (auto i = 0u; i < before_log.size(); ++i) {
179 BOOST_CHECK_EQUAL(std::get<0>(before_log[i]), std::get<0>(after_log[i]));
180 BOOST_CHECK_EQUAL(std::get<1>(before_log[i]), std::get<1>(after_log[i]));
181 BOOST_CHECK_CLOSE(std::get<2>(before_log[i]), std::get<2>(after_log[i]), 1e-8);
182 BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8);
183 BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8);
184 BOOST_CHECK_CLOSE(std::get<5>(before_log[i]), std::get<5>(after_log[i]), 1e-8);
185 }
186 }
187