1 // Copyright 2020, 2021 PaGMO development team
2 //
3 // This file is part of the pygmo library.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla
6 // Public License v. 2.0. If a copy of the MPL was not distributed
7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <string>
10 #include <tuple>
11 
12 #include <pybind11/numpy.h>
13 #include <pybind11/pybind11.h>
14 
15 #include <pagmo/algorithm.hpp>
16 #include <pagmo/algorithms/gaco.hpp>
17 #include <pagmo/algorithms/gwo.hpp>
18 #include <pagmo/algorithms/ihs.hpp>
19 #include <pagmo/algorithms/maco.hpp>
20 #include <pagmo/algorithms/nsga2.hpp>
21 #include <pagmo/algorithms/nspso.hpp>
22 #include <pagmo/algorithms/null_algorithm.hpp>
23 #include <pagmo/algorithms/pso.hpp>
24 #include <pagmo/algorithms/pso_gen.hpp>
25 #include <pagmo/algorithms/sade.hpp>
26 #include <pagmo/algorithms/sea.hpp>
27 #include <pagmo/algorithms/sga.hpp>
28 #include <pagmo/algorithms/simulated_annealing.hpp>
29 #include <pagmo/config.hpp>
30 
31 #if defined(PAGMO_WITH_NLOPT)
32 #include <pagmo/algorithms/nlopt.hpp>
33 #endif
34 
35 #include "common_utils.hpp"
36 #include "docstrings.hpp"
37 #include "expose_algorithms.hpp"
38 
39 namespace pygmo
40 {
41 
42 namespace py = pybind11;
43 
expose_algorithms_1(py::module & m,py::class_<pagmo::algorithm> & algo,py::module & a_module)44 void expose_algorithms_1(py::module &m, py::class_<pagmo::algorithm> &algo, py::module &a_module)
45 {
46     // Null algo.
47     auto na = expose_algorithm<pagmo::null_algorithm>(m, algo, a_module, "null_algorithm",
48                                                       null_algorithm_docstring().c_str());
49 
50     // NSGA2
51     auto nsga2_ = expose_algorithm<pagmo::nsga2>(m, algo, a_module, "nsga2", nsga2_docstring().c_str());
52     nsga2_.def(py::init<unsigned, double, double, double, double>(), py::arg("gen") = 1u, py::arg("cr") = 0.95,
53                py::arg("eta_c") = 10., py::arg("m") = 0.01, py::arg("eta_m") = 50.);
54     nsga2_.def(py::init<unsigned, double, double, double, double, unsigned>(), py::arg("gen") = 1u,
55                py::arg("cr") = 0.95, py::arg("eta_c") = 10., py::arg("m") = 0.01, py::arg("eta_m") = 50.,
56                py::arg("seed"));
57     // nsga2 needs an ad hoc exposition for the log as one entry is a vector (ideal_point)
58     nsga2_.def(
59         "get_log",
60         [](const pagmo::nsga2 &a) -> py::list {
61             py::list retval;
62             for (const auto &t : a.get_log()) {
63                 retval.append(py::make_tuple(std::get<0>(t), std::get<1>(t),
64                                              vector_to_ndarr<py::array_t<double>>(std::get<2>(t))));
65             }
66             return retval;
67         },
68         nsga2_get_log_docstring().c_str());
69 
70     nsga2_.def("get_seed", &pagmo::nsga2::get_seed, generic_uda_get_seed_docstring().c_str());
71     nsga2_.def("set_bfe", &pagmo::nsga2::set_bfe, nsga2_set_bfe_docstring().c_str(), py::arg("b"));
72 
73     // GACO
74     auto gaco_ = expose_algorithm<pagmo::gaco>(m, algo, a_module, "gaco", gaco_docstring().c_str());
75     gaco_.def(
76         py::init<unsigned, unsigned, double, double, double, unsigned, unsigned, unsigned, unsigned, double, bool>(),
77         py::arg("gen") = 100u, py::arg("ker") = 63u, py::arg("q") = 1.0, py::arg("oracle") = 0., py::arg("acc") = 0.01,
78         py::arg("threshold") = 1u, py::arg("n_gen_mark") = 7u, py::arg("impstop") = 100000u,
79         py::arg("evalstop") = 100000u, py::arg("focus") = 0., py::arg("memory") = false);
80     gaco_.def(py::init<unsigned, unsigned, double, double, double, unsigned, unsigned, unsigned, unsigned, double, bool,
81                        unsigned>(),
82               py::arg("gen") = 100u, py::arg("ker") = 63u, py::arg("q") = 1.0, py::arg("oracle") = 0.,
83               py::arg("acc") = 0.01, py::arg("threshold") = 1u, py::arg("n_gen_mark") = 7u,
84               py::arg("impstop") = 100000u, py::arg("evalstop") = 100000u, py::arg("focus") = 0.,
85               py::arg("memory") = false, py::arg("seed"));
86     expose_algo_log(gaco_, gaco_get_log_docstring().c_str());
87     gaco_.def("get_seed", &pagmo::gaco::get_seed, generic_uda_get_seed_docstring().c_str());
88     gaco_.def("set_bfe", &pagmo::gaco::set_bfe, gaco_set_bfe_docstring().c_str(), py::arg("b"));
89 
90     // GWO
91     auto gwo_ = expose_algorithm<pagmo::gwo>(m, algo, a_module, "gwo", gwo_docstring().c_str());
92     gwo_.def(py::init<unsigned>(), py::arg("gen") = 1u);
93     gwo_.def(py::init<unsigned, unsigned>(), py::arg("gen") = 1u, py::arg("seed"));
94     expose_algo_log(gwo_, gwo_get_log_docstring().c_str());
95     gwo_.def("get_seed", &pagmo::gwo::get_seed, generic_uda_get_seed_docstring().c_str());
96 
97     // SEA
98     auto sea_ = expose_algorithm<pagmo::sea>(m, algo, a_module, "sea", sea_docstring().c_str());
99     sea_.def(py::init<unsigned>(), py::arg("gen") = 1u);
100     sea_.def(py::init<unsigned, unsigned>(), py::arg("gen") = 1u, py::arg("seed"));
101     expose_algo_log(sea_, sea_get_log_docstring().c_str());
102     sea_.def("get_seed", &pagmo::sea::get_seed, generic_uda_get_seed_docstring().c_str());
103 
104     // PSO
105     auto pso_ = expose_algorithm<pagmo::pso>(m, algo, a_module, "pso", pso_docstring().c_str());
106     pso_.def(py::init<unsigned, double, double, double, double, unsigned, unsigned, unsigned, bool>(),
107              py::arg("gen") = 1u, py::arg("omega") = 0.7298, py::arg("eta1") = 2.05, py::arg("eta2") = 2.05,
108              py::arg("max_vel") = 0.5, py::arg("variant") = 5u, py::arg("neighb_type") = 2u,
109              py::arg("neighb_param") = 4u, py::arg("memory") = false);
110     pso_.def(py::init<unsigned, double, double, double, double, unsigned, unsigned, unsigned, bool, unsigned>(),
111              py::arg("gen") = 1u, py::arg("omega") = 0.7298, py::arg("eta1") = 2.05, py::arg("eta2") = 2.05,
112              py::arg("max_vel") = 0.5, py::arg("variant") = 5u, py::arg("neighb_type") = 2u,
113              py::arg("neighb_param") = 4u, py::arg("memory") = false, py::arg("seed"));
114     expose_algo_log(pso_, pso_get_log_docstring().c_str());
115     pso_.def("get_seed", &pagmo::pso::get_seed, generic_uda_get_seed_docstring().c_str());
116 
117     // PSO (generational)
118     auto pso_gen_ = expose_algorithm<pagmo::pso_gen>(m, algo, a_module, "pso_gen", pso_gen_docstring().c_str());
119     pso_gen_.def(py::init<unsigned, double, double, double, double, unsigned, unsigned, unsigned, bool>(),
120                  py::arg("gen") = 1u, py::arg("omega") = 0.7298, py::arg("eta1") = 2.05, py::arg("eta2") = 2.05,
121                  py::arg("max_vel") = 0.5, py::arg("variant") = 5u, py::arg("neighb_type") = 2u,
122                  py::arg("neighb_param") = 4u, py::arg("memory") = false);
123     pso_gen_.def(py::init<unsigned, double, double, double, double, unsigned, unsigned, unsigned, bool, unsigned>(),
124                  py::arg("gen") = 1u, py::arg("omega") = 0.7298, py::arg("eta1") = 2.05, py::arg("eta2") = 2.05,
125                  py::arg("max_vel") = 0.5, py::arg("variant") = 5u, py::arg("neighb_type") = 2u,
126                  py::arg("neighb_param") = 4u, py::arg("memory") = false, py::arg("seed"));
127     expose_algo_log(pso_gen_, pso_gen_get_log_docstring().c_str());
128     pso_gen_.def("get_seed", &pagmo::pso_gen::get_seed, generic_uda_get_seed_docstring().c_str());
129     pso_gen_.def("set_bfe", &pagmo::pso_gen::set_bfe, pso_gen_set_bfe_docstring().c_str(), py::arg("b"));
130 
131     // SIMULATED ANNEALING
132     auto simulated_annealing_ = expose_algorithm<pagmo::simulated_annealing>(m, algo, a_module, "simulated_annealing",
133                                                                              simulated_annealing_docstring().c_str());
134     simulated_annealing_.def(py::init<double, double, unsigned, unsigned, unsigned, double>(), py::arg("Ts") = 10.,
135                              py::arg("Tf") = 0.1, py::arg("n_T_adj") = 10u, py::arg("n_range_adj") = 1u,
136                              py::arg("bin_size") = 20u, py::arg("start_range") = 1.);
137     simulated_annealing_.def(py::init<double, double, unsigned, unsigned, unsigned, double, unsigned>(),
138                              py::arg("Ts") = 10., py::arg("Tf") = 0.1, py::arg("n_T_adj") = 10u,
139                              py::arg("n_range_adj") = 10u, py::arg("bin_size") = 10u, py::arg("start_range") = 1.,
140                              py::arg("seed"));
141     expose_algo_log(simulated_annealing_, simulated_annealing_get_log_docstring().c_str());
142     simulated_annealing_.def("get_seed", &pagmo::simulated_annealing::get_seed,
143                              generic_uda_get_seed_docstring().c_str());
144     expose_not_population_based(simulated_annealing_, "simulated_annealing");
145 
146     // SGA
147     auto sga_ = expose_algorithm<pagmo::sga>(m, algo, a_module, "sga", sga_docstring().c_str());
148     sga_.def(py::init<unsigned, double, double, double, double, unsigned, std::string, std::string, std::string>(),
149              py::arg("gen") = 1u, py::arg("cr") = 0.9, py::arg("eta_c") = 1., py::arg("m") = 0.02,
150              py::arg("param_m") = 1., py::arg("param_s") = 2u, py::arg("crossover") = "exponential",
151              py::arg("mutation") = "polynomial", py::arg("selection") = "tournament");
152     sga_.def(
153         py::init<unsigned, double, double, double, double, unsigned, std::string, std::string, std::string, unsigned>(),
154         py::arg("gen") = 1u, py::arg("cr") = 0.9, py::arg("eta_c") = 1., py::arg("m") = 0.02, py::arg("param_m") = 1.,
155         py::arg("param_s") = 2u, py::arg("crossover") = "exponential", py::arg("mutation") = "polynomial",
156         py::arg("selection") = "tournament", py::arg("seed"));
157     expose_algo_log(sga_, sga_get_log_docstring().c_str());
158     sga_.def("get_seed", &pagmo::sga::get_seed, generic_uda_get_seed_docstring().c_str());
159 
160     // IHS
161     auto ihs_ = expose_algorithm<pagmo::ihs>(m, algo, a_module, "ihs", ihs_docstring().c_str());
162     ihs_.def(py::init<unsigned, double, double, double, double, double>(), py::arg("gen") = 1u, py::arg("phmcr") = 0.85,
163              py::arg("ppar_min") = 0.35, py::arg("ppar_max") = 0.99, py::arg("bw_min") = 1E-5, py::arg("bw_max") = 1.);
164     ihs_.def(py::init<unsigned, double, double, double, double, double, unsigned>(), py::arg("gen") = 1u,
165              py::arg("phmcr") = 0.85, py::arg("ppar_min") = 0.35, py::arg("ppar_max") = 0.99, py::arg("bw_min") = 1E-5,
166              py::arg("bw_max") = 1., py::arg("seed"));
167     // ihs needs an ad hoc exposition for the log as one entry is a vector (ideal_point)
168     ihs_.def(
169         "get_log",
170         [](const pagmo::ihs &a) -> py::list {
171             py::list retval;
172             for (const auto &t : a.get_log()) {
173                 retval.append(py::make_tuple(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t),
174                                              std::get<4>(t), std::get<5>(t), std::get<6>(t),
175                                              vector_to_ndarr<py::array_t<double>>(std::get<7>(t))));
176             }
177             return retval;
178         },
179         ihs_get_log_docstring().c_str());
180     ihs_.def("get_seed", &pagmo::ihs::get_seed, generic_uda_get_seed_docstring().c_str());
181 
182     // SADE
183     auto sade_ = expose_algorithm<pagmo::sade>(m, algo, a_module, "sade", sade_docstring().c_str());
184     sade_.def(py::init<unsigned, unsigned, unsigned, double, double, bool>(), py::arg("gen") = 1u,
185               py::arg("variant") = 2u, py::arg("variant_adptv") = 1u, py::arg("ftol") = 1e-6, py::arg("xtol") = 1e-6,
186               py::arg("memory") = false);
187     sade_.def(py::init<unsigned, unsigned, unsigned, double, double, bool, unsigned>(), py::arg("gen") = 1u,
188               py::arg("variant") = 2u, py::arg("variant_adptv") = 1u, py::arg("ftol") = 1e-6, py::arg("xtol") = 1e-6,
189               py::arg("memory") = false, py::arg("seed"));
190     expose_algo_log(sade_, sade_get_log_docstring().c_str());
191     sade_.def("get_seed", &pagmo::sade::get_seed, generic_uda_get_seed_docstring().c_str());
192 
193     // MACO
194     auto maco_ = expose_algorithm<pagmo::maco>(m, algo, a_module, "maco", maco_docstring().c_str());
195     maco_.def(py::init<unsigned, unsigned, double, unsigned, unsigned, unsigned, double, bool>(), py::arg("gen") = 1u,
196               py::arg("ker") = 63u, py::arg("q") = 1.0, py::arg("threshold") = 1u, py::arg("n_gen_mark") = 7u,
197               py::arg("evalstop") = 100000u, py::arg("focus") = 0., py::arg("memory") = false);
198     maco_.def(py::init<unsigned, unsigned, double, unsigned, unsigned, unsigned, double, bool, unsigned>(),
199               py::arg("gen") = 1u, py::arg("ker") = 63u, py::arg("q") = 1.0, py::arg("threshold") = 1u,
200               py::arg("n_gen_mark") = 7u, py::arg("evalstop") = 100000u, py::arg("focus") = 0.,
201               py::arg("memory") = false, py::arg("seed"));
202     // maco needs an ad hoc exposition for the log as one entry is a vector (ideal_point)
203     maco_.def(
204         "get_log",
205         [](const pagmo::maco &a) -> py::list {
206             py::list retval;
207             for (const auto &t : a.get_log()) {
208                 retval.append(py::make_tuple(std::get<0>(t), std::get<1>(t),
209                                              vector_to_ndarr<py::array_t<double>>(std::get<2>(t))));
210             }
211             return retval;
212         },
213         maco_get_log_docstring().c_str());
214     maco_.def("get_seed", &pagmo::maco::get_seed, generic_uda_get_seed_docstring().c_str());
215     maco_.def("set_bfe", &pagmo::maco::set_bfe, maco_set_bfe_docstring().c_str(), py::arg("b"));
216 
217     // NSPSO
218     auto nspso_ = expose_algorithm<pagmo::nspso>(m, algo, a_module, "nspso", nspso_docstring().c_str());
219     nspso_.def(py::init<unsigned, double, double, double, double, double, unsigned, std::string, bool>(),
220                py::arg("gen") = 1u, py::arg("omega") = 0.6, py::arg("c1") = 0.01, py::arg("c2") = 0.5,
221                py::arg("chi") = 0.5, py::arg("v_coeff") = 0.5, py::arg("leader_selection_range") = 2u,
222                py::arg("diversity_mechanism") = "crowding distance", py::arg("memory") = false);
223     nspso_.def(py::init<unsigned, double, double, double, double, double, unsigned, std::string, bool, unsigned>(),
224                py::arg("gen") = 1u, py::arg("omega") = 0.6, py::arg("c1") = 0.01, py::arg("c2") = 0.5,
225                py::arg("chi") = 0.5, py::arg("v_coeff") = 0.5, py::arg("leader_selection_range") = 2u,
226                py::arg("diversity_mechanism") = "crowding distance", py::arg("memory") = false, py::arg("seed"));
227     // nspso needs an ad hoc exposition for the log as one entry is a vector (ideal_point)
228     nspso_.def(
229         "get_log",
230         [](const pagmo::nspso &a) -> py::list {
231             py::list retval;
232             for (const auto &t : a.get_log()) {
233                 retval.append(py::make_tuple(std::get<0>(t), std::get<1>(t),
234                                              vector_to_ndarr<py::array_t<double>>(std::get<2>(t))));
235             }
236             return retval;
237         },
238         nspso_get_log_docstring().c_str());
239     nspso_.def("get_seed", &pagmo::nspso::get_seed, generic_uda_get_seed_docstring().c_str());
240     nspso_.def("set_bfe", &pagmo::nspso::set_bfe, nspso_set_bfe_docstring().c_str(), py::arg("b"));
241 
242 #if defined(PAGMO_WITH_NLOPT)
243     // NLopt.
244     auto nlopt_ = expose_algorithm<pagmo::nlopt>(m, algo, a_module, "nlopt", nlopt_docstring().c_str());
245     nlopt_
246         .def(py::init<const std::string &>(), py::arg("solver"))
247         // Properties for the stopping criteria.
248         .def_property("stopval", &pagmo::nlopt::get_stopval, &pagmo::nlopt::set_stopval,
249                       nlopt_stopval_docstring().c_str())
250         .def_property("ftol_rel", &pagmo::nlopt::get_ftol_rel, &pagmo::nlopt::set_ftol_rel,
251                       nlopt_ftol_rel_docstring().c_str())
252         .def_property("ftol_abs", &pagmo::nlopt::get_ftol_abs, &pagmo::nlopt::set_ftol_abs,
253                       nlopt_ftol_abs_docstring().c_str())
254         .def_property("xtol_rel", &pagmo::nlopt::get_xtol_rel, &pagmo::nlopt::set_xtol_rel,
255                       nlopt_xtol_rel_docstring().c_str())
256         .def_property("xtol_abs", &pagmo::nlopt::get_xtol_abs, &pagmo::nlopt::set_xtol_abs,
257                       nlopt_xtol_abs_docstring().c_str())
258         .def_property("maxeval", &pagmo::nlopt::get_maxeval, &pagmo::nlopt::set_maxeval,
259                       nlopt_maxeval_docstring().c_str())
260         .def_property("maxtime", &pagmo::nlopt::get_maxtime, &pagmo::nlopt::set_maxtime,
261                       nlopt_maxtime_docstring().c_str());
262     expose_not_population_based(nlopt_, "nlopt");
263     expose_algo_log(nlopt_, nlopt_get_log_docstring().c_str());
264     nlopt_.def(
265         "get_last_opt_result", [](const pagmo::nlopt &n) { return static_cast<int>(n.get_last_opt_result()); },
266         nlopt_get_last_opt_result_docstring().c_str());
267     nlopt_.def("get_solver_name", &pagmo::nlopt::get_solver_name, nlopt_get_solver_name_docstring().c_str());
268     nlopt_.def_property(
269         "local_optimizer", [](pagmo::nlopt &n) { return n.get_local_optimizer(); },
270         [](pagmo::nlopt &n, const pagmo::nlopt *ptr) {
271             if (ptr) {
272                 n.set_local_optimizer(*ptr);
273             } else {
274                 n.unset_local_optimizer();
275             }
276         },
277         py::return_value_policy::reference_internal, nlopt_local_optimizer_docstring().c_str());
278 #endif
279 }
280 
281 } // namespace pygmo
282