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