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 <cstddef>
10 #include <exception>
11 #include <limits>
12 #include <memory>
13 #include <string>
14 #include <tuple>
15 #include <vector>
16
17 #include <pybind11/numpy.h>
18 #include <pybind11/pybind11.h>
19
20 #include <pagmo/algorithm.hpp>
21 #include <pagmo/archipelago.hpp>
22 #include <pagmo/batch_evaluators/default_bfe.hpp>
23 #include <pagmo/batch_evaluators/member_bfe.hpp>
24 #include <pagmo/batch_evaluators/thread_bfe.hpp>
25 #include <pagmo/bfe.hpp>
26 #include <pagmo/config.hpp>
27 #include <pagmo/detail/gte_getter.hpp>
28 #include <pagmo/exceptions.hpp>
29 #include <pagmo/island.hpp>
30 #include <pagmo/islands/thread_island.hpp>
31 #include <pagmo/population.hpp>
32 #include <pagmo/r_policy.hpp>
33 #include <pagmo/rng.hpp>
34 #include <pagmo/s_policy.hpp>
35 #include <pagmo/threading.hpp>
36 #include <pagmo/topology.hpp>
37 #include <pagmo/types.hpp>
38 #include <pagmo/utils/constrained.hpp>
39 #include <pagmo/utils/generic.hpp>
40 #include <pagmo/utils/genetic_operators.hpp>
41 #include <pagmo/utils/gradients_and_hessians.hpp>
42 #include <pagmo/utils/hv_algos/hv_bf_approx.hpp>
43 #include <pagmo/utils/hv_algos/hv_bf_fpras.hpp>
44 #include <pagmo/utils/hv_algos/hv_hv2d.hpp>
45 #include <pagmo/utils/hv_algos/hv_hv3d.hpp>
46 #include <pagmo/utils/hv_algos/hv_hvwfg.hpp>
47 #include <pagmo/utils/hypervolume.hpp>
48 #include <pagmo/utils/multi_objective.hpp>
49
50 #include "algorithm.hpp"
51 #include "bfe.hpp"
52 #include "common_utils.hpp"
53 #include "docstrings.hpp"
54 #include "expose_algorithms.hpp"
55 #include "expose_bfes.hpp"
56 #include "expose_islands.hpp"
57 #include "expose_problems.hpp"
58 #include "expose_r_policies.hpp"
59 #include "expose_s_policies.hpp"
60 #include "expose_topologies.hpp"
61 #include "island.hpp"
62 #include "problem.hpp"
63 #include "r_policy.hpp"
64 #include "s11n_wrappers.hpp"
65 #include "s_policy.hpp"
66 #include "topology.hpp"
67
68 namespace py = pybind11;
69 namespace pg = pagmo;
70
71 namespace pygmo
72 {
73
74 namespace detail
75 {
76
77 namespace
78 {
79
80 // NOTE: we need to provide a custom raii waiter in the island. The reason is the following.
81 // When we call wait() from Python, the calling thread will be holding the GIL and then we will be waiting
82 // for evolutions in the island to finish. During this time, no
83 // Python code will be executed because the GIL is locked. This means that if we have a Python thread doing background
84 // work (e.g., managing the task queue in pythonic islands), it will have to wait before doing any progress. By
85 // unlocking the GIL before calling thread_island::wait(), we give the chance to other Python threads to continue
86 // doing some work.
87 // NOTE: here we have 2 RAII classes interacting with the GIL. The GIL releaser is the *second* one,
88 // and it is the one that is responsible for unlocking the Python interpreter while wait() is running.
89 // The *first* one, the GIL thread ensurer, does something else: it makes sure that we can call the Python
90 // interpreter from the current C++ thread. In a normal situation, in which islands are just instantiated
91 // from the main thread, the gte object is superfluous. However, if we are interacting with islands from a
92 // separate C++ thread, then we need to make sure that every time we call into the Python interpreter (e.g., by
93 // using the GIL releaser below) we inform Python we are about to call from a separate thread. This is what
94 // the GTE object does. This use case is, for instance, what happens with the PADE algorithm when, algo, prob,
95 // etc. are all C++ objects (when at least one object is pythonic, we will not end up using the thread island).
96 // NOTE: by ordering the class members in this way we ensure that gte is constructed before gr, which is essential
97 // (otherwise we might be calling into the interpreter with a releaser before informing Python we are calling
98 // from a separate thread).
99 struct py_wait_locks {
100 gil_thread_ensurer gte;
101 gil_releaser gr;
102 };
103
104 } // namespace
105
106 } // namespace detail
107
108 } // namespace pygmo
109
PYBIND11_MODULE(core,m)110 PYBIND11_MODULE(core, m)
111 {
112 using namespace pybind11::literals;
113
114 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9
115 // This function needs to be called before doing anything with threads.
116 // https://docs.python.org/3/c-api/init.html
117 // NOTE: this is deprecated and does nothing since Python 3.9.
118 PyEval_InitThreads();
119 #endif
120
121 // Disable automatic function signatures in the docs.
122 // NOTE: the 'options' object needs to stay alive
123 // throughout the whole definition of the module.
124 py::options options;
125 options.disable_function_signatures();
126
127 // Export the pagmo version.
128 m.attr("_pagmo_version_major") = PAGMO_VERSION_MAJOR;
129 m.attr("_pagmo_version_minor") = PAGMO_VERSION_MINOR;
130 m.attr("_pagmo_version_patch") = PAGMO_VERSION_PATCH;
131
132 // Expose some internal functions for testing.
133 m.def("_callable", &pygmo::callable);
134 m.def("_callable_attribute", &pygmo::callable_attribute);
135 m.def("_str", &pygmo::str);
136 m.def("_type", &pygmo::type);
137 m.def("_builtins", &pygmo::builtins);
138 m.def("_deepcopy", &pygmo::deepcopy);
139 m.def("_max_unsigned", []() {
140 // Small helper function to get the max value of unsigned.
141 return std::numeric_limits<unsigned>::max();
142 });
143
144 // The random_device_next() helper.
145 m.def("_random_device_next", []() { return pg::random_device::next(); });
146
147 // Global random number generator
148 m.def(
149 "set_global_rng_seed", [](unsigned seed) { pg::random_device::set_seed(seed); },
150 pygmo::set_global_rng_seed_docstring().c_str(), py::arg("seed"));
151
152 // Override the default implementation of the island factory.
153 pg::detail::island_factory
154 = [](const pg::algorithm &algo, const pg::population &pop, std::unique_ptr<pg::detail::isl_inner_base> &ptr) {
155 if (algo.get_thread_safety() >= pg::thread_safety::basic
156 && pop.get_problem().get_thread_safety() >= pg::thread_safety::basic) {
157 // Both algo and prob have at least the basic thread safety guarantee. Use the thread island.
158 ptr = std::make_unique<pg::detail::isl_inner<pg::thread_island>>();
159 } else {
160 // NOTE: here we are re-implementing a piece of code that normally
161 // is pure C++. We are calling into the Python interpreter, so, in order to handle
162 // the case in which we are invoking this code from a separate C++ thread, we construct a GIL ensurer
163 // in order to guard against concurrent access to the interpreter. The idea here is that this piece
164 // of code normally would provide a basic thread safety guarantee, and in order to continue providing
165 // it we use the ensurer.
166 pygmo::gil_thread_ensurer gte;
167 auto py_island = py::module::import("pygmo").attr("mp_island");
168 ptr = std::make_unique<pg::detail::isl_inner<py::object>>(py_island());
169 }
170 };
171
172 // Override the default implementation of default_bfe.
173 pg::detail::default_bfe_impl = [](const pg::problem &p, const pg::vector_double &dvs) -> pg::vector_double {
174 // The member function batch_fitness() of p, if present, has priority.
175 if (p.has_batch_fitness()) {
176 return pg::member_bfe{}(p, dvs);
177 }
178
179 // Otherwise, we run the generic thread-based bfe, if the problem
180 // is thread-safe enough.
181 if (p.get_thread_safety() >= pg::thread_safety::basic) {
182 return pg::thread_bfe{}(p, dvs);
183 }
184
185 // NOTE: in this last bit of the implementation we need to call
186 // into the Python interpreter. In order to ensure that default_bfe
187 // still works also from a C++ thread of which Python knows nothing about,
188 // we will be using a thread ensurer, so that the thread safety
189 // guarantee provided by default_bfe is still respected.
190 // NOTE: the original default_bfe code is thread safe in the sense that the
191 // code directly implemented within that class is thread safe. Invoking the call
192 // operator of default_bfe might still end up being thread unsafe if p
193 // itself is thread unsafe (the same happens, e.g., in a thread-safe algorithm
194 // which uses a thread-unsafe problem in its evolve()).
195 pygmo::gil_thread_ensurer gte;
196 // Otherwise, we go for the multiprocessing bfe.
197 return pygmo::ndarr_to_vector<pg::vector_double>(
198 py::cast<py::array_t<double>>(py::module::import("pygmo").attr("mp_bfe")().attr("__call__")(
199 p, pygmo::vector_to_ndarr<py::array_t<double>>(dvs))));
200 };
201
202 // Override the default RAII waiter. We need to use shared_ptr because we don't want to move/copy/destroy
203 // the locks when invoking this from island::wait(), we need to instaniate exactly 1 py_wait_lock and have it
204 // destroyed at the end of island::wait().
205 pg::detail::wait_raii_getter = []() { return std::make_shared<pygmo::detail::py_wait_locks>(); };
206
207 // NOTE: set the gte getter.
208 pg::detail::gte_getter = []() { return std::make_shared<pygmo::gil_thread_ensurer>(); };
209
210 // Register pagmo's custom exceptions.
211 py::register_exception_translator([](std::exception_ptr p) {
212 try {
213 if (p) {
214 std::rethrow_exception(p);
215 }
216 } catch (const pg::not_implemented_error &nie) {
217 PyErr_SetString(PyExc_NotImplementedError, nie.what());
218 }
219 });
220
221 // The thread_safety enum.
222 py::enum_<pg::thread_safety>(m, "thread_safety", pygmo::thread_safety_docstring().c_str())
223 .value("none", pg::thread_safety::none, pygmo::thread_safety_none_docstring().c_str())
224 .value("basic", pg::thread_safety::basic, pygmo::thread_safety_basic_docstring().c_str())
225 .value("constant", pg::thread_safety::constant, pygmo::thread_safety_constant_docstring().c_str());
226
227 // The evolve_status enum.
228 py::enum_<pg::evolve_status>(m, "evolve_status", pygmo::evolve_status_docstring().c_str())
229 .value("idle", pg::evolve_status::idle, pygmo::evolve_status_idle_docstring().c_str())
230 .value("busy", pg::evolve_status::busy, pygmo::evolve_status_busy_docstring().c_str())
231 .value("idle_error", pg::evolve_status::idle_error, pygmo::evolve_status_idle_error_docstring().c_str())
232 .value("busy_error", pg::evolve_status::busy_error, pygmo::evolve_status_busy_error_docstring().c_str());
233
234 // Migration type enum.
235 py::enum_<pg::migration_type>(m, "migration_type", pygmo::migration_type_docstring().c_str())
236 .value("p2p", pg::migration_type::p2p, pygmo::migration_type_p2p_docstring().c_str())
237 .value("broadcast", pg::migration_type::broadcast, pygmo::migration_type_broadcast_docstring().c_str());
238
239 // Migrant handling policy enum.
240 py::enum_<pg::migrant_handling>(m, "migrant_handling", pygmo::migrant_handling_docstring().c_str())
241 .value("preserve", pg::migrant_handling::preserve, pygmo::migrant_handling_preserve_docstring().c_str())
242 .value("evict", pg::migrant_handling::evict, pygmo::migrant_handling_evict_docstring().c_str());
243
244 // Generic utilities
245 m.def(
246 "random_decision_vector",
247 [](const pg::problem &p) -> py::array_t<double> {
248 using reng_t = pg::detail::random_engine_type;
249 reng_t tmp_rng(static_cast<reng_t::result_type>(pg::random_device::next()));
250 auto retval = pg::random_decision_vector(p, tmp_rng);
251 return pygmo::vector_to_ndarr<py::array_t<double>>(retval);
252 },
253 pygmo::random_decision_vector_docstring().c_str(), py::arg("prob"));
254 m.def(
255 "batch_random_decision_vector",
256 [](const pg::problem &p, pg::vector_double::size_type n) -> py::array_t<double> {
257 using reng_t = pg::detail::random_engine_type;
258 reng_t tmp_rng(static_cast<reng_t::result_type>(pg::random_device::next()));
259 auto retval = pg::batch_random_decision_vector(p, n, tmp_rng);
260 return pygmo::vector_to_ndarr<py::array_t<double>>(retval);
261 },
262 pygmo::batch_random_decision_vector_docstring().c_str(), py::arg("prob"), py::arg("n"));
263 // Genetic operators
264 m.def(
265 "sbx_crossover",
266 [](const py::array_t<double> &parent1, const py::array_t<double> &parent2, const py::iterable &bounds,
267 pg::vector_double::size_type nix, const double p_cr, const double eta_c, unsigned seed) {
268 auto pg_bounds = pygmo::iterable_to_bounds(bounds);
269 using reng_t = pg::detail::random_engine_type;
270 reng_t tmp_rng(static_cast<reng_t::result_type>(seed));
271 auto retval = pagmo::sbx_crossover(pygmo::ndarr_to_vector<pg::vector_double>(parent1),
272 pygmo::ndarr_to_vector<pg::vector_double>(parent2), pg_bounds, nix, p_cr,
273 eta_c, tmp_rng);
274 return py::make_tuple(pygmo::vector_to_ndarr<py::array_t<double>>(retval.first),
275 pygmo::vector_to_ndarr<py::array_t<double>>(retval.second));
276 },
277 pygmo::sbx_crossover_docstring().c_str(), py::arg("parent1"), py::arg("parent2"), py::arg("bounds"),
278 py::arg("nix"), py::arg("p_cr"), py::arg("eta_c"), py::arg("seed"));
279
280 m.def(
281 "polynomial_mutation",
282 [](const py::array_t<double> &dv, const py::iterable &bounds, pg::vector_double::size_type nix,
283 const double p_m, const double eta_m, unsigned seed) {
284 auto pg_bounds = pygmo::iterable_to_bounds(bounds);
285 using reng_t = pg::detail::random_engine_type;
286 reng_t tmp_rng(static_cast<reng_t::result_type>(seed));
287 auto dv_c = pygmo::ndarr_to_vector<pg::vector_double>(dv);
288 pagmo::polynomial_mutation(dv_c, pg_bounds, nix, p_m, eta_m, tmp_rng);
289 return pygmo::vector_to_ndarr<py::array_t<double>>(dv_c);
290 },
291 pygmo::polynomial_mutation_docstring().c_str(), py::arg("dv"), py::arg("bounds"), py::arg("nix"),
292 py::arg("p_m"), py::arg("eta_m"), py::arg("seed"));
293 // Hypervolume class
294 py::class_<pg::hypervolume> hv_class(m, "hypervolume", "Hypervolume Class");
295 hv_class
296 .def(py::init([](const py::array_t<double> &points) {
297 return std::make_unique<pg::hypervolume>(
298 pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(points), true);
299 }),
300 py::arg("points"), pygmo::hv_init2_docstring().c_str())
301 .def(py::init([](const pg::population &pop) { return std::make_unique<pg::hypervolume>(pop, true); }),
302 py::arg("pop"), pygmo::hv_init1_docstring().c_str())
303 .def(
304 "compute",
305 [](const pg::hypervolume &hv, const py::array_t<double> &r_point) {
306 return hv.compute(pygmo::ndarr_to_vector<pg::vector_double>(r_point));
307 },
308 py::arg("ref_point"))
309 .def(
310 "compute",
311 [](const pg::hypervolume &hv, const py::array_t<double> &r_point, pg::hv_algorithm &hv_algo) {
312 return hv.compute(pygmo::ndarr_to_vector<pg::vector_double>(r_point), hv_algo);
313 },
314 pygmo::hv_compute_docstring().c_str(), py::arg("ref_point"), py::arg("hv_algo"))
315 .def(
316 "exclusive",
317 [](const pg::hypervolume &hv, unsigned p_idx, const py::array_t<double> &r_point) {
318 return hv.exclusive(p_idx, pygmo::ndarr_to_vector<pg::vector_double>(r_point));
319 },
320 py::arg("idx"), py::arg("ref_point"))
321 .def(
322 "exclusive",
323 [](const pg::hypervolume &hv, unsigned p_idx, const py::array_t<double> &r_point,
324 pg::hv_algorithm &hv_algo) {
325 return hv.exclusive(p_idx, pygmo::ndarr_to_vector<pg::vector_double>(r_point), hv_algo);
326 },
327 pygmo::hv_exclusive_docstring().c_str(), py::arg("idx"), py::arg("ref_point"), py::arg("hv_algo"))
328 .def(
329 "least_contributor",
330 [](const pg::hypervolume &hv, const py::array_t<double> &r_point) {
331 return hv.least_contributor(pygmo::ndarr_to_vector<pg::vector_double>(r_point));
332 },
333 py::arg("ref_point"))
334 .def(
335 "least_contributor",
336 [](const pg::hypervolume &hv, const py::array_t<double> &r_point, pg::hv_algorithm &hv_algo) {
337 return hv.least_contributor(pygmo::ndarr_to_vector<pg::vector_double>(r_point), hv_algo);
338 },
339 pygmo::hv_least_contributor_docstring().c_str(), py::arg("ref_point"), py::arg("hv_algo"))
340 .def(
341 "greatest_contributor",
342 [](const pg::hypervolume &hv, const py::array_t<double> &r_point) {
343 return hv.greatest_contributor(pygmo::ndarr_to_vector<pg::vector_double>(r_point));
344 },
345 py::arg("ref_point"))
346 .def(
347 "greatest_contributor",
348 [](const pg::hypervolume &hv, const py::array_t<double> &r_point, pg::hv_algorithm &hv_algo) {
349 return hv.greatest_contributor(pygmo::ndarr_to_vector<pg::vector_double>(r_point), hv_algo);
350 },
351 pygmo::hv_greatest_contributor_docstring().c_str(), py::arg("ref_point"), py::arg("hv_algo"))
352 .def(
353 "contributions",
354 [](const pg::hypervolume &hv, const py::array_t<double> &r_point) {
355 return pygmo::vector_to_ndarr<py::array_t<double>>(
356 hv.contributions(pygmo::ndarr_to_vector<pg::vector_double>(r_point)));
357 },
358 py::arg("ref_point"))
359 .def(
360 "contributions",
361 [](const pg::hypervolume &hv, const py::array_t<double> &r_point, pg::hv_algorithm &hv_algo) {
362 return pygmo::vector_to_ndarr<py::array_t<double>>(
363 hv.contributions(pygmo::ndarr_to_vector<pg::vector_double>(r_point), hv_algo));
364 },
365 pygmo::hv_contributions_docstring().c_str(), py::arg("ref_point"), py::arg("hv_algo"))
366 .def("get_points",
367 [](const pg::hypervolume &hv) { return pygmo::vvector_to_ndarr<py::array_t<double>>(hv.get_points()); })
368 .def(
369 "refpoint",
370 [](const pg::hypervolume &hv, double offset) {
371 return pygmo::vector_to_ndarr<py::array_t<double>>(hv.refpoint(offset));
372 },
373 pygmo::hv_refpoint_docstring().c_str(), py::arg("offset") = 0)
374 .def_property("copy_points", &pg::hypervolume::get_copy_points, &pg::hypervolume::set_copy_points);
375
376 // Hypervolume algorithms
377 py::class_<pg::hv_algorithm> hv_algorithm_class(m, "_hv_algorithm");
378 hv_algorithm_class.def("get_name", &pg::hv_algorithm::get_name);
379
380 py::class_<pg::hvwfg, pg::hv_algorithm> hvwfg_class(m, "hvwfg", pygmo::hvwfg_docstring().c_str());
381 hvwfg_class.def(py::init<unsigned>(), py::arg("stop_dimension") = 2);
382
383 py::class_<pg::bf_approx, pg::hv_algorithm> bf_approx_class(m, "bf_approx", pygmo::bf_approx_docstring().c_str());
384 bf_approx_class
385 .def(py::init<bool, unsigned, double, double, double, double, double, double>(), py::arg("use_exact") = true,
386 py::arg("trivial_subcase_size") = 1u, py::arg("eps") = 1e-2, py::arg("delta") = 1e-6,
387 py::arg("delta_multiplier") = 0.775, py::arg("alpha") = 0.2, py::arg("initial_delta_coeff") = 0.1,
388 py::arg("gamma") = 0.25)
389 .def(py::init<bool, unsigned, double, double, double, double, double, double, unsigned>(),
390 py::arg("use_exact") = true, py::arg("trivial_subcase_size") = 1u, py::arg("eps") = 1e-2,
391 py::arg("delta") = 1e-6, py::arg("delta_multiplier") = 0.775, py::arg("alpha") = 0.2,
392 py::arg("initial_delta_coeff") = 0.1, py::arg("gamma") = 0.25, py::arg("seed"));
393
394 py::class_<pg::bf_fpras, pg::hv_algorithm> bf_fpras_class(m, "bf_fpras", pygmo::bf_fpras_docstring().c_str());
395 bf_fpras_class.def(py::init<double, double>(), py::arg("eps") = 1e-2, py::arg("delta") = 1e-2)
396 .def(py::init<double, double, unsigned>(), py::arg("eps") = 1e-2, py::arg("delta") = 1e-2, py::arg("seed"));
397
398 py::class_<pg::hv2d, pg::hv_algorithm> hv2d_class(m, "hv2d", pygmo::hv2d_docstring().c_str());
399 hv2d_class.def(py::init<>());
400
401 py::class_<pg::hv3d, pg::hv_algorithm> hv3d_class(m, "hv3d", pygmo::hv3d_docstring().c_str());
402 hv3d_class.def(py::init<>());
403
404 // Multi-objective utilities
405 m.def(
406 "fast_non_dominated_sorting",
407 [](const py::array_t<double> &x) -> py::tuple {
408 auto fnds = pg::fast_non_dominated_sorting(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(x));
409 // the non-dominated fronts
410 py::list ndf_py;
411 for (const auto &front : std::get<0>(fnds)) {
412 ndf_py.append(pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(front));
413 }
414 // the domination list
415 py::list dl_py;
416 for (const auto &item : std::get<1>(fnds)) {
417 dl_py.append(pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(item));
418 }
419 return py::make_tuple(ndf_py, dl_py, pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(std::get<2>(fnds)),
420 pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(std::get<3>(fnds)));
421 },
422 pygmo::fast_non_dominated_sorting_docstring().c_str(), py::arg("points"));
423
424 m.def(
425 "pareto_dominance",
426 [](const py::array_t<double> &obj1, const py::array_t<double> &obj2) {
427 return pg::pareto_dominance(pygmo::ndarr_to_vector<pg::vector_double>(obj1),
428 pygmo::ndarr_to_vector<pg::vector_double>(obj2));
429 },
430 pygmo::pareto_dominance_docstring().c_str(), py::arg("obj1"), py::arg("obj2"));
431
432 m.def(
433 "non_dominated_front_2d",
434 [](const py::array_t<double> &points) {
435 return pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(
436 pg::non_dominated_front_2d(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(points)));
437 },
438 pygmo::non_dominated_front_2d_docstring().c_str(), py::arg("points"));
439
440 m.def(
441 "crowding_distance",
442 [](const py::array_t<double> &points) {
443 return pygmo::vector_to_ndarr<py::array_t<double>>(
444 pg::crowding_distance(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(points)));
445 },
446 pygmo::crowding_distance_docstring().c_str(), py::arg("points"));
447
448 m.def(
449 "sort_population_mo",
450 [](const py::array_t<double> &input_f) {
451 return pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(
452 pg::sort_population_mo(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(input_f)));
453 },
454 pygmo::sort_population_mo_docstring().c_str(), py::arg("points"));
455
456 m.def(
457 "select_best_N_mo",
458 [](const py::array_t<double> &input_f, unsigned N) {
459 return pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(
460 pg::select_best_N_mo(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(input_f), N));
461 },
462 pygmo::select_best_N_mo_docstring().c_str(), py::arg("points"), py::arg("N"));
463
464 m.def(
465 "decomposition_weights",
466 [](pg::vector_double::size_type n_f, pg::vector_double::size_type n_w, const std::string &method,
467 unsigned seed) {
468 using reng_t = pg::detail::random_engine_type;
469 reng_t tmp_rng(static_cast<reng_t::result_type>(seed));
470 return pygmo::vvector_to_ndarr<py::array_t<double>>(pg::decomposition_weights(n_f, n_w, method, tmp_rng));
471 },
472 pygmo::decomposition_weights_docstring().c_str(), py::arg("n_f"), py::arg("n_w"), py::arg("method"),
473 py::arg("seed"));
474
475 m.def(
476 "decompose_objectives",
477 [](const py::array_t<double> &objs, const py::array_t<double> &weights, const py::array_t<double> &ref_point,
478 const std::string &method) {
479 return pygmo::vector_to_ndarr<py::array_t<double>>(pg::decompose_objectives(
480 pygmo::ndarr_to_vector<pg::vector_double>(objs), pygmo::ndarr_to_vector<pg::vector_double>(weights),
481 pygmo::ndarr_to_vector<pg::vector_double>(ref_point), method));
482 },
483 pygmo::decompose_objectives_docstring().c_str(), py::arg("objs"), py::arg("weights"), py::arg("ref_point"),
484 py::arg("method"));
485
486 m.def(
487 "nadir",
488 [](const py::array_t<double> &p) {
489 return pygmo::vector_to_ndarr<py::array_t<double>>(
490 pg::nadir(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(p)));
491 },
492 pygmo::nadir_docstring().c_str(), py::arg("points"));
493
494 m.def(
495 "ideal",
496 [](const py::array_t<double> &p) {
497 return pygmo::vector_to_ndarr<py::array_t<double>>(
498 pg::ideal(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(p)));
499 },
500 pygmo::ideal_docstring().c_str(), py::arg("points"));
501
502 // Gradient and Hessians utilities
503 m.def(
504 "estimate_sparsity",
505 [](const py::object &func, const py::array_t<double> &x,
506 double dx) -> py::array_t<pg::vector_double::size_type> {
507 auto f = [&func](const pg::vector_double &x_) {
508 return pygmo::ndarr_to_vector<pg::vector_double>(
509 py::cast<py::array_t<double>>(func(pygmo::vector_to_ndarr<py::array_t<double>>(x_))));
510 };
511 return pygmo::sp_to_ndarr(pg::estimate_sparsity(f, pygmo::ndarr_to_vector<pg::vector_double>(x), dx));
512 },
513 pygmo::estimate_sparsity_docstring().c_str(), py::arg("callable"), py::arg("x"), py::arg("dx") = 1e-8);
514
515 m.def(
516 "estimate_gradient",
517 [](const py::object &func, const py::array_t<double> &x, double dx) -> py::array_t<double> {
518 auto f = [&func](const pg::vector_double &x_) {
519 return pygmo::ndarr_to_vector<pg::vector_double>(
520 py::cast<py::array_t<double>>(func(pygmo::vector_to_ndarr<py::array_t<double>>(x_))));
521 };
522 return pygmo::vector_to_ndarr<py::array_t<double>>(
523 pg::estimate_gradient(f, pygmo::ndarr_to_vector<pg::vector_double>(x), dx));
524 },
525 pygmo::estimate_gradient_docstring().c_str(), py::arg("callable"), py::arg("x"), py::arg("dx") = 1e-8);
526
527 m.def(
528 "estimate_gradient_h",
529 [](const py::object &func, const py::array_t<double> &x, double dx) -> py::array_t<double> {
530 auto f = [&func](const pg::vector_double &x_) {
531 return pygmo::ndarr_to_vector<pg::vector_double>(
532 py::cast<py::array_t<double>>(func(pygmo::vector_to_ndarr<py::array_t<double>>(x_))));
533 };
534 return pygmo::vector_to_ndarr<py::array_t<double>>(
535 pg::estimate_gradient_h(f, pygmo::ndarr_to_vector<pg::vector_double>(x), dx));
536 },
537 pygmo::estimate_gradient_h_docstring().c_str(), py::arg("callable"), py::arg("x"), py::arg("dx") = 1e-2);
538
539 // Constrained optimization utilities
540 m.def(
541 "compare_fc",
542 [](const py::array_t<double> &f1, const py::array_t<double> &f2, pg::vector_double::size_type nec,
543 const py::array_t<double> &tol) {
544 return pg::compare_fc(pygmo::ndarr_to_vector<pg::vector_double>(f1),
545 pygmo::ndarr_to_vector<pg::vector_double>(f2), nec,
546 pygmo::ndarr_to_vector<pg::vector_double>(tol));
547 },
548 pygmo::compare_fc_docstring().c_str(), py::arg("f1"), py::arg("f2"), py::arg("nec"), py::arg("tol"));
549
550 m.def(
551 "sort_population_con",
552 [](const py::array_t<double> &input_f, pg::vector_double::size_type nec, const py::array_t<double> &tol) {
553 return pygmo::vector_to_ndarr<py::array_t<pg::pop_size_t>>(
554 pg::sort_population_con(pygmo::ndarr_to_vvector<std::vector<pg::vector_double>>(input_f), nec,
555 pygmo::ndarr_to_vector<pg::vector_double>(tol)));
556 },
557 pygmo::sort_population_con_docstring().c_str(), py::arg("input_f"), py::arg("nec"), py::arg("tol"));
558
559 // Add the submodules.
560 auto problems_module = m.def_submodule("problems");
561 auto algorithms_module = m.def_submodule("algorithms");
562 auto islands_module = m.def_submodule("islands");
563 auto batch_evaluators_module = m.def_submodule("batch_evaluators");
564 auto topologies_module = m.def_submodule("topologies");
565 auto r_policies_module = m.def_submodule("r_policies");
566 auto s_policies_module = m.def_submodule("s_policies");
567
568 // Population class.
569 py::class_<pg::population> pop_class(m, "population", pygmo::population_docstring().c_str());
570 pop_class
571 // Def ctor.
572 .def(py::init<>())
573 // Ctors from problem.
574 // NOTE: we expose only the ctors from pagmo::problem, not from C++ or Python UDPs. An __init__ wrapper
575 // on the Python side will take care of cting a pagmo::problem from the input UDP, and then invoke this ctor.
576 // This way we avoid having to expose a different ctor for every exposed C++ prob. Same idea with
577 // the bfe argument.
578 .def(py::init<const pg::problem &, pg::population::size_type, unsigned>())
579 .def(py::init<const pg::problem &, const pg::bfe &, pg::population::size_type, unsigned>())
580 // repr().
581 .def("__repr__", &pygmo::ostream_repr<pg::population>)
582 // Copy and deepcopy.
583 .def("__copy__", &pygmo::generic_copy_wrapper<pg::population>)
584 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::population>, "memo"_a)
585 // Pickle support.
586 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::population>,
587 &pygmo::pickle_setstate_wrapper<pg::population>))
588 .def(
589 "push_back",
590 [](pg::population &pop, const py::array_t<double> &x, const py::object &f) {
591 if (f.is_none()) {
592 pop.push_back(pygmo::ndarr_to_vector<pg::vector_double>(x));
593 } else {
594 pop.push_back(pygmo::ndarr_to_vector<pg::vector_double>(x),
595 pygmo::ndarr_to_vector<pg::vector_double>(py::cast<py::array_t<double>>(f)));
596 }
597 },
598 pygmo::population_push_back_docstring().c_str(), py::arg("x"), py::arg("f") = py::none())
599 .def(
600 "random_decision_vector",
601 [](const pg::population &pop) {
602 return pygmo::vector_to_ndarr<py::array_t<double>>(pop.random_decision_vector());
603 },
604 pygmo::population_random_decision_vector_docstring().c_str())
605 .def(
606 "best_idx",
607 [](const pg::population &pop, const py::array_t<double> &tol) {
608 return pop.best_idx(pygmo::ndarr_to_vector<pg::vector_double>(tol));
609 },
610 py::arg("tol"))
611 .def(
612 "best_idx", [](const pg::population &pop, double tol) { return pop.best_idx(tol); }, py::arg("tol"))
613 .def(
614 "best_idx", [](const pg::population &pop) { return pop.best_idx(); },
615 pygmo::population_best_idx_docstring().c_str())
616 .def(
617 "worst_idx",
618 [](const pg::population &pop, const py::array_t<double> &tol) {
619 return pop.worst_idx(pygmo::ndarr_to_vector<pg::vector_double>(tol));
620 },
621 py::arg("tol"))
622 .def(
623 "worst_idx", [](const pg::population &pop, double tol) { return pop.worst_idx(tol); }, py::arg("tol"))
624 .def(
625 "worst_idx", [](const pg::population &pop) { return pop.worst_idx(); },
626 pygmo::population_worst_idx_docstring().c_str())
627 .def("__len__", &pg::population::size)
628 .def(
629 "set_xf",
630 [](pg::population &pop, pg::population::size_type i, const py::array_t<double> &x,
631 const py::array_t<double> &f) {
632 pop.set_xf(i, pygmo::ndarr_to_vector<pg::vector_double>(x),
633 pygmo::ndarr_to_vector<pg::vector_double>(f));
634 },
635 pygmo::population_set_xf_docstring().c_str())
636 .def(
637 "set_x",
638 [](pg::population &pop, pg::population::size_type i, const py::array_t<double> &x) {
639 pop.set_x(i, pygmo::ndarr_to_vector<pg::vector_double>(x));
640 },
641 pygmo::population_set_x_docstring().c_str())
642 .def(
643 "get_f",
644 [](const pg::population &pop) { return pygmo::vvector_to_ndarr<py::array_t<double>>(pop.get_f()); },
645 pygmo::population_get_f_docstring().c_str())
646 .def(
647 "get_x",
648 [](const pg::population &pop) { return pygmo::vvector_to_ndarr<py::array_t<double>>(pop.get_x()); },
649 pygmo::population_get_x_docstring().c_str())
650 .def(
651 "get_ID",
652 [](const pg::population &pop) {
653 return pygmo::vector_to_ndarr<py::array_t<unsigned long long>>(pop.get_ID());
654 },
655 pygmo::population_get_ID_docstring().c_str())
656 .def("get_seed", &pg::population::get_seed, pygmo::population_get_seed_docstring().c_str())
657 .def_property_readonly(
658 "champion_x",
659 [](const pg::population &pop) { return pygmo::vector_to_ndarr<py::array_t<double>>(pop.champion_x()); },
660 pygmo::population_champion_x_docstring().c_str())
661 .def_property_readonly(
662 "champion_f",
663 [](const pg::population &pop) { return pygmo::vector_to_ndarr<py::array_t<double>>(pop.champion_f()); },
664 pygmo::population_champion_f_docstring().c_str())
665 .def_property_readonly(
666 "problem", [](pg::population &pop) -> pg::problem & { return pop.get_problem(); },
667 py::return_value_policy::reference_internal, pygmo::population_problem_docstring().c_str());
668
669 // Archi.
670 py::class_<pg::archipelago> archi_class(m, "archipelago", pygmo::archipelago_docstring().c_str());
671 archi_class
672 // Def ctor.
673 .def(py::init<>())
674 .def(py::init<const pg::topology &>())
675 // repr().
676 .def("__repr__", &pygmo::ostream_repr<pg::archipelago>)
677 // Copy and deepcopy.
678 .def("__copy__", &pygmo::generic_copy_wrapper<pg::archipelago>)
679 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::archipelago>, "memo"_a)
680 // Pickle support.
681 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::archipelago>,
682 &pygmo::pickle_setstate_wrapper<pg::archipelago>))
683 // Size.
684 .def("__len__", &pg::archipelago::size)
685 .def(
686 "evolve", [](pg::archipelago &archi, unsigned n) { archi.evolve(n); },
687 pygmo::archipelago_evolve_docstring().c_str(), py::arg("n") = 1u)
688 .def("wait", &pg::archipelago::wait, pygmo::archipelago_wait_docstring().c_str())
689 .def("wait_check", &pg::archipelago::wait_check, pygmo::archipelago_wait_check_docstring().c_str())
690 .def(
691 "__getitem__",
692 [](pg::archipelago &archi, pg::archipelago::size_type n) -> pg::island & { return archi[n]; },
693 pygmo::archipelago_getitem_docstring().c_str(), py::return_value_policy::reference_internal)
694 // NOTE: docs for push_back() are in the Python reimplementation.
695 .def("_push_back", [](pg::archipelago &archi, const pg::island &isl) { archi.push_back(isl); })
696 // Champions.
697 .def(
698 "get_champions_f",
699 [](const pg::archipelago &archi) -> py::list {
700 py::list retval;
701 auto fs = archi.get_champions_f();
702 for (const auto &f : fs) {
703 retval.append(pygmo::vector_to_ndarr<py::array_t<double>>(f));
704 }
705 return retval;
706 },
707 pygmo::archipelago_get_champions_f_docstring().c_str())
708 .def(
709 "get_champions_x",
710 [](const pg::archipelago &archi) -> py::list {
711 py::list retval;
712 auto xs = archi.get_champions_x();
713 for (const auto &x : xs) {
714 retval.append(pygmo::vector_to_ndarr<py::array_t<double>>(x));
715 }
716 return retval;
717 },
718 pygmo::archipelago_get_champions_x_docstring().c_str())
719 .def(
720 "get_migrants_db",
721 [](const pg::archipelago &archi) -> py::list {
722 py::list retval;
723 const auto tmp = archi.get_migrants_db();
724 for (const auto &ig : tmp) {
725 retval.append(pygmo::inds_to_tuple(ig));
726 }
727 return retval;
728 },
729 pygmo::archipelago_get_migrants_db_docstring().c_str())
730 .def(
731 "set_migrants_db",
732 [](pg::archipelago &archi, const py::list &mig) {
733 pg::archipelago::migrants_db_t mig_db;
734
735 for (auto o : mig) {
736 mig_db.push_back(pygmo::iterable_to_inds(py::cast<py::iterable>(o)));
737 }
738
739 archi.set_migrants_db(mig_db);
740 },
741 pygmo::archipelago_set_migrants_db_docstring().c_str())
742 .def(
743 "get_migration_log",
744 [](const pg::archipelago &archi) -> py::list {
745 py::list retval;
746 const auto tmp = archi.get_migration_log();
747 for (const auto &le : tmp) {
748 retval.append(py::make_tuple(std::get<0>(le), std::get<1>(le),
749 pygmo::vector_to_ndarr<py::array_t<double>>(std::get<2>(le)),
750 pygmo::vector_to_ndarr<py::array_t<double>>(std::get<3>(le)),
751 std::get<4>(le), std::get<5>(le)));
752 }
753 return retval;
754 },
755 pygmo::archipelago_get_migration_log_docstring().c_str())
756 .def("get_topology", &pg::archipelago::get_topology, pygmo::archipelago_get_topology_docstring().c_str())
757 .def("_set_topology", &pg::archipelago::set_topology)
758 .def("set_migration_type", &pg::archipelago::set_migration_type,
759 pygmo::archipelago_set_migration_type_docstring().c_str(), py::arg("mt"))
760 .def("set_migrant_handling", &pg::archipelago::set_migrant_handling,
761 pygmo::archipelago_set_migrant_handling_docstring().c_str(), py::arg("mh"))
762 .def("get_migration_type", &pg::archipelago::get_migration_type,
763 pygmo::archipelago_get_migration_type_docstring().c_str())
764 .def("get_migrant_handling", &pg::archipelago::get_migrant_handling,
765 pygmo::archipelago_get_migrant_handling_docstring().c_str())
766 .def_property_readonly("status", &pg::archipelago::status, pygmo::archipelago_status_docstring().c_str());
767
768 // Problem class.
769 py::class_<pg::problem> problem_class(m, "problem", pygmo::problem_docstring().c_str());
770 problem_class
771 // Def ctor.
772 .def(py::init<>())
773 // repr().
774 .def("__repr__", &pygmo::ostream_repr<pg::problem>)
775 // Copy and deepcopy.
776 .def("__copy__", &pygmo::generic_copy_wrapper<pg::problem>)
777 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::problem>, "memo"_a)
778 // Pickle support.
779 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::problem>, &pygmo::pickle_setstate_wrapper<pg::problem>))
780 // UDP extraction.
781 .def("_py_extract", &pygmo::generic_py_extract<pg::problem>)
782 // Problem methods.
783 .def(
784 "fitness",
785 [](const pg::problem &p, const py::array_t<double> &dv) {
786 return pygmo::vector_to_ndarr<py::array_t<double>>(
787 p.fitness(pygmo::ndarr_to_vector<pg::vector_double>(dv)));
788 },
789 pygmo::problem_fitness_docstring().c_str(), py::arg("dv"))
790 .def(
791 "get_bounds",
792 [](const pg::problem &p) {
793 return py::make_tuple(pygmo::vector_to_ndarr<py::array_t<double>>(p.get_lb()),
794 pygmo::vector_to_ndarr<py::array_t<double>>(p.get_ub()));
795 },
796 pygmo::problem_get_bounds_docstring().c_str())
797 .def(
798 "get_lb", [](const pg::problem &p) { return pygmo::vector_to_ndarr<py::array_t<double>>(p.get_lb()); },
799 pygmo::problem_get_lb_docstring().c_str())
800 .def(
801 "get_ub", [](const pg::problem &p) { return pygmo::vector_to_ndarr<py::array_t<double>>(p.get_ub()); },
802 pygmo::problem_get_ub_docstring().c_str())
803 .def(
804 "batch_fitness",
805 [](const pg::problem &p, const py::array_t<double> &dvs) {
806 return pygmo::vector_to_ndarr<py::array_t<double>>(
807 p.batch_fitness(pygmo::ndarr_to_vector<pg::vector_double>(dvs)));
808 },
809 pygmo::problem_batch_fitness_docstring().c_str(), py::arg("dvs"))
810 .def("has_batch_fitness", &pg::problem::has_batch_fitness, pygmo::problem_has_batch_fitness_docstring().c_str())
811 .def(
812 "gradient",
813 [](const pg::problem &p, const py::array_t<double> &dv) {
814 return pygmo::vector_to_ndarr<py::array_t<double>>(
815 p.gradient(pygmo::ndarr_to_vector<pg::vector_double>(dv)));
816 },
817 pygmo::problem_gradient_docstring().c_str(), py::arg("dv"))
818 .def("has_gradient", &pg::problem::has_gradient, pygmo::problem_has_gradient_docstring().c_str())
819 .def(
820 "gradient_sparsity", [](const pg::problem &p) { return pygmo::sp_to_ndarr(p.gradient_sparsity()); },
821 pygmo::problem_gradient_sparsity_docstring().c_str())
822 .def("has_gradient_sparsity", &pg::problem::has_gradient_sparsity,
823 pygmo::problem_has_gradient_sparsity_docstring().c_str())
824 .def(
825 "hessians",
826 [](const pg::problem &p, const py::array_t<double> &dv) -> py::list {
827 py::list retval;
828 for (const auto &v : p.hessians(pygmo::ndarr_to_vector<pg::vector_double>(dv))) {
829 retval.append(pygmo::vector_to_ndarr<py::array_t<double>>(v));
830 }
831 return retval;
832 },
833 pygmo::problem_hessians_docstring().c_str(), py::arg("dv"))
834 .def("has_hessians", &pg::problem::has_hessians, pygmo::problem_has_hessians_docstring().c_str())
835 .def(
836 "hessians_sparsity",
837 [](const pg::problem &p) -> py::list {
838 py::list retval;
839 for (const auto &sp : p.hessians_sparsity()) {
840 retval.append(pygmo::sp_to_ndarr(sp));
841 }
842 return retval;
843 },
844 pygmo::problem_hessians_sparsity_docstring().c_str())
845 .def("has_hessians_sparsity", &pg::problem::has_hessians_sparsity,
846 pygmo::problem_has_hessians_sparsity_docstring().c_str())
847 .def("get_nobj", &pg::problem::get_nobj, pygmo::problem_get_nobj_docstring().c_str())
848 .def("get_nx", &pg::problem::get_nx, pygmo::problem_get_nx_docstring().c_str())
849 .def("get_nix", &pg::problem::get_nix, pygmo::problem_get_nix_docstring().c_str())
850 .def("get_ncx", &pg::problem::get_ncx, pygmo::problem_get_ncx_docstring().c_str())
851 .def("get_nf", &pg::problem::get_nf, pygmo::problem_get_nf_docstring().c_str())
852 .def("get_nec", &pg::problem::get_nec, pygmo::problem_get_nec_docstring().c_str())
853 .def("get_nic", &pg::problem::get_nic, pygmo::problem_get_nic_docstring().c_str())
854 .def("get_nc", &pg::problem::get_nc, pygmo::problem_get_nc_docstring().c_str())
855 .def("get_fevals", &pg::problem::get_fevals, pygmo::problem_get_fevals_docstring().c_str())
856 .def("increment_fevals", &pg::problem::increment_fevals, pygmo::problem_increment_fevals_docstring().c_str(),
857 py::arg("n"))
858 .def("get_gevals", &pg::problem::get_gevals, pygmo::problem_get_gevals_docstring().c_str())
859 .def("get_hevals", &pg::problem::get_hevals, pygmo::problem_get_hevals_docstring().c_str())
860 .def("set_seed", &pg::problem::set_seed, pygmo::problem_set_seed_docstring().c_str(), py::arg("seed"))
861 .def("has_set_seed", &pg::problem::has_set_seed, pygmo::problem_has_set_seed_docstring().c_str())
862 .def("is_stochastic", &pg::problem::is_stochastic,
863 "is_stochastic()\n\nAlias for :func:`~pygmo.problem.has_set_seed()`.\n")
864 .def(
865 "feasibility_x",
866 [](const pg::problem &p, const py::array_t<double> &x) {
867 return p.feasibility_x(pygmo::ndarr_to_vector<pg::vector_double>(x));
868 },
869 pygmo::problem_feasibility_x_docstring().c_str(), py::arg("x"))
870 .def(
871 "feasibility_f",
872 [](const pg::problem &p, const py::array_t<double> &f) {
873 return p.feasibility_f(pygmo::ndarr_to_vector<pg::vector_double>(f));
874 },
875 pygmo::problem_feasibility_f_docstring().c_str(), py::arg("f"))
876 .def("get_name", &pg::problem::get_name, pygmo::problem_get_name_docstring().c_str())
877 .def("get_extra_info", &pg::problem::get_extra_info, pygmo::problem_get_extra_info_docstring().c_str())
878 .def("get_thread_safety", &pg::problem::get_thread_safety, pygmo::problem_get_thread_safety_docstring().c_str())
879 .def_property(
880 "c_tol",
881 [](const pg::problem &prob) { return pygmo::vector_to_ndarr<py::array_t<double>>(prob.get_c_tol()); },
882 [](pg::problem &prob, const py::object &c_tol) {
883 try {
884 prob.set_c_tol(py::cast<double>(c_tol));
885 } catch (const py::cast_error &) {
886 prob.set_c_tol(pygmo::ndarr_to_vector<pg::vector_double>(py::cast<py::array_t<double>>(c_tol)));
887 }
888 },
889 pygmo::problem_c_tol_docstring().c_str());
890
891 // Expose the C++ problems.
892 pygmo::expose_problems_0(m, problem_class, problems_module);
893 pygmo::expose_problems_1(m, problem_class, problems_module);
894
895 // Finalize.
896 problem_class.def(py::init<const py::object &>(), py::arg("udp"));
897
898 // Algorithm class.
899 py::class_<pg::algorithm> algorithm_class(m, "algorithm", pygmo::algorithm_docstring().c_str());
900 algorithm_class
901 // Def ctor.
902 .def(py::init<>())
903 // repr().
904 .def("__repr__", &pygmo::ostream_repr<pg::algorithm>)
905 // Copy and deepcopy.
906 .def("__copy__", &pygmo::generic_copy_wrapper<pg::algorithm>)
907 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::algorithm>, "memo"_a)
908 // Pickle support.
909 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::algorithm>, &pygmo::pickle_setstate_wrapper<pg::algorithm>))
910 // UDA extraction.
911 .def("_py_extract", &pygmo::generic_py_extract<pg::algorithm>)
912 // Algorithm methods.
913 .def("evolve", &pg::algorithm::evolve, pygmo::algorithm_evolve_docstring().c_str(), py::arg("pop"))
914 .def("set_seed", &pg::algorithm::set_seed, pygmo::algorithm_set_seed_docstring().c_str(), py::arg("seed"))
915 .def("has_set_seed", &pg::algorithm::has_set_seed, pygmo::algorithm_has_set_seed_docstring().c_str())
916 .def("set_verbosity", &pg::algorithm::set_verbosity, pygmo::algorithm_set_verbosity_docstring().c_str(),
917 py::arg("level"))
918 .def("has_set_verbosity", &pg::algorithm::has_set_verbosity,
919 pygmo::algorithm_has_set_verbosity_docstring().c_str())
920 .def("is_stochastic", &pg::algorithm::is_stochastic,
921 "is_stochastic()\n\nAlias for :func:`~pygmo.algorithm.has_set_seed()`.\n")
922 .def("get_name", &pg::algorithm::get_name, pygmo::algorithm_get_name_docstring().c_str())
923 .def("get_extra_info", &pg::algorithm::get_extra_info, pygmo::algorithm_get_extra_info_docstring().c_str())
924 .def("get_thread_safety", &pg::algorithm::get_thread_safety,
925 pygmo::algorithm_get_thread_safety_docstring().c_str());
926
927 // Expose the C++ algos.
928 pygmo::expose_algorithms_0(m, algorithm_class, algorithms_module);
929 pygmo::expose_algorithms_1(m, algorithm_class, algorithms_module);
930
931 // Finalize.
932 algorithm_class.def(py::init<const py::object &>(), py::arg("uda"));
933
934 // bfe class.
935 py::class_<pg::bfe> bfe_class(m, "bfe", pygmo::bfe_docstring().c_str());
936 bfe_class
937 // Def ctor.
938 .def(py::init<>())
939 // repr().
940 .def("__repr__", &pygmo::ostream_repr<pg::bfe>)
941 // Copy and deepcopy.
942 .def("__copy__", &pygmo::generic_copy_wrapper<pg::bfe>)
943 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::bfe>, "memo"_a)
944 // Pickle support.
945 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::bfe>, &pygmo::pickle_setstate_wrapper<pg::bfe>))
946 // UDBFE extraction.
947 .def("_py_extract", &pygmo::generic_py_extract<pg::bfe>)
948 // Bfe methods.
949 .def("_call_impl",
950 [](const pg::bfe &b, const pg::problem &prob, const py::array_t<double> &dvs) {
951 return pygmo::vector_to_ndarr<py::array_t<double>>(
952 b(prob, pygmo::ndarr_to_vector<pg::vector_double>(dvs)));
953 })
954 .def("get_name", &pg::bfe::get_name, pygmo::bfe_get_name_docstring().c_str())
955 .def("get_extra_info", &pg::bfe::get_extra_info, pygmo::bfe_get_extra_info_docstring().c_str())
956 .def("get_thread_safety", &pg::bfe::get_thread_safety, pygmo::bfe_get_thread_safety_docstring().c_str());
957
958 // Expose the C++ bfes.
959 pygmo::expose_bfes(m, bfe_class, batch_evaluators_module);
960
961 // Finalize.
962 bfe_class.def(py::init<const py::object &>(), py::arg("udbfe"));
963
964 // Island class.
965 py::class_<pg::island> island_class(m, "island", pygmo::island_docstring().c_str());
966 island_class
967 // Def ctor.
968 .def(py::init<>())
969 // Ctor from algo, pop, and policies.
970 .def(py::init<const pg::algorithm &, const pg::population &, const pg::r_policy &, const pg::s_policy &>())
971 // repr().
972 .def("__repr__", &pygmo::ostream_repr<pg::island>)
973 // Copy and deepcopy.
974 .def("__copy__", &pygmo::generic_copy_wrapper<pg::island>)
975 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::island>, "memo"_a)
976 // Pickle support.
977 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::island>, &pygmo::pickle_setstate_wrapper<pg::island>))
978 // UDI extraction.
979 .def("_py_extract", &pygmo::generic_py_extract<pg::island>)
980 .def(
981 "evolve", [](pg::island &isl, unsigned n) { isl.evolve(n); }, pygmo::island_evolve_docstring().c_str(),
982 py::arg("n") = 1u)
983 .def("wait", &pg::island::wait, pygmo::island_wait_docstring().c_str())
984 .def("wait_check", &pg::island::wait_check, pygmo::island_wait_check_docstring().c_str())
985 .def("get_population", &pg::island::get_population, pygmo::island_get_population_docstring().c_str())
986 .def("get_algorithm", &pg::island::get_algorithm, pygmo::island_get_algorithm_docstring().c_str())
987 .def("set_population", &pg::island::set_population, pygmo::island_set_population_docstring().c_str(),
988 py::arg("pop"))
989 .def("set_algorithm", &pg::island::set_algorithm, pygmo::island_set_algorithm_docstring().c_str(),
990 py::arg("algo"))
991 .def("get_name", &pg::island::get_name, pygmo::island_get_name_docstring().c_str())
992 .def("get_extra_info", &pg::island::get_extra_info, pygmo::island_get_extra_info_docstring().c_str())
993 .def("get_r_policy", &pg::island::get_r_policy, pygmo::island_get_r_policy_docstring().c_str())
994 .def("get_s_policy", &pg::island::get_s_policy, pygmo::island_get_s_policy_docstring().c_str())
995 .def_property_readonly("status", &pg::island::status, pygmo::island_status_docstring().c_str());
996
997 // Expose the C++ islands.
998 pygmo::expose_islands(m, island_class, islands_module);
999
1000 // Finalize.
1001 island_class.def(py::init<const py::object &, const pg::algorithm &, const pg::population &, const pg::r_policy &,
1002 const pg::s_policy &>());
1003
1004 // Replacement policy class.
1005 py::class_<pg::r_policy> r_policy_class(m, "r_policy", pygmo::r_policy_docstring().c_str());
1006 r_policy_class
1007 // Def ctor.
1008 .def(py::init<>())
1009 // repr().
1010 .def("__repr__", &pygmo::ostream_repr<pg::r_policy>)
1011 // Copy and deepcopy.
1012 .def("__copy__", &pygmo::generic_copy_wrapper<pg::r_policy>)
1013 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::r_policy>, "memo"_a)
1014 // Pickle support.
1015 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::r_policy>, &pygmo::pickle_setstate_wrapper<pg::r_policy>))
1016 // UDRP extraction.
1017 .def("_py_extract", &pygmo::generic_py_extract<pg::r_policy>)
1018 // r_policy methods.
1019 .def(
1020 "replace",
1021 [](const pg::r_policy &r, const py::iterable &inds, const pg::vector_double::size_type &nx,
1022 const pg::vector_double::size_type &nix, const pg::vector_double::size_type &nobj,
1023 const pg::vector_double::size_type &nec, const pg::vector_double::size_type &nic,
1024 const py::array_t<double> &tol, const py::iterable &mig) {
1025 return pygmo::inds_to_tuple(r.replace(pygmo::iterable_to_inds(inds), nx, nix, nobj, nec, nic,
1026 pygmo::ndarr_to_vector<pg::vector_double>(tol),
1027 pygmo::iterable_to_inds(mig)));
1028 },
1029 pygmo::r_policy_replace_docstring().c_str(), py::arg("inds"), py::arg("nx"), py::arg("nix"),
1030 py::arg("nobj"), py::arg("nec"), py::arg("nic"), py::arg("tol"), py::arg("mig"))
1031 .def("get_name", &pg::r_policy::get_name, pygmo::r_policy_get_name_docstring().c_str())
1032 .def("get_extra_info", &pg::r_policy::get_extra_info, pygmo::r_policy_get_extra_info_docstring().c_str());
1033
1034 // Expose the C++ replacement policies.
1035 pygmo::expose_r_policies(m, r_policy_class, r_policies_module);
1036
1037 // Finalize.
1038 r_policy_class.def(py::init<const py::object &>(), py::arg("udrp"));
1039
1040 // Selection policy class.
1041 py::class_<pg::s_policy> s_policy_class(m, "s_policy", pygmo::s_policy_docstring().c_str());
1042 s_policy_class
1043 // Def ctor.
1044 .def(py::init<>())
1045 // repr().
1046 .def("__repr__", &pygmo::ostream_repr<pg::s_policy>)
1047 // Copy and deepcopy.
1048 .def("__copy__", &pygmo::generic_copy_wrapper<pg::s_policy>)
1049 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::s_policy>, "memo"_a)
1050 // Pickle support.
1051 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::s_policy>, &pygmo::pickle_setstate_wrapper<pg::s_policy>))
1052 // UDSP extraction.
1053 .def("_py_extract", &pygmo::generic_py_extract<pg::s_policy>)
1054 // s_policy methods.
1055 .def(
1056 "select",
1057 [](const pg::s_policy &s, const py::iterable &inds, const pg::vector_double::size_type &nx,
1058 const pg::vector_double::size_type &nix, const pg::vector_double::size_type &nobj,
1059 const pg::vector_double::size_type &nec, const pg::vector_double::size_type &nic,
1060 const py::array_t<double> &tol) {
1061 return pygmo::inds_to_tuple(s.select(pygmo::iterable_to_inds(inds), nx, nix, nobj, nec, nic,
1062 pygmo::ndarr_to_vector<pg::vector_double>(tol)));
1063 },
1064 pygmo::s_policy_select_docstring().c_str(), py::arg("inds"), py::arg("nx"), py::arg("nix"), py::arg("nobj"),
1065 py::arg("nec"), py::arg("nic"), py::arg("tol"))
1066 .def("get_name", &pg::s_policy::get_name, pygmo::s_policy_get_name_docstring().c_str())
1067 .def("get_extra_info", &pg::s_policy::get_extra_info, pygmo::s_policy_get_extra_info_docstring().c_str());
1068
1069 // Expose the C++ selection policies.
1070 pygmo::expose_s_policies(m, s_policy_class, s_policies_module);
1071
1072 // Finalize.
1073 s_policy_class.def(py::init<const py::object &>(), py::arg("udsp"));
1074
1075 // Topology class.
1076 py::class_<pg::topology> topology_class(m, "topology", pygmo::topology_docstring().c_str());
1077 topology_class
1078 // Def ctor.
1079 .def(py::init<>())
1080 // repr().
1081 .def("__repr__", &pygmo::ostream_repr<pg::topology>)
1082 // Copy and deepcopy.
1083 .def("__copy__", &pygmo::generic_copy_wrapper<pg::topology>)
1084 .def("__deepcopy__", &pygmo::generic_deepcopy_wrapper<pg::topology>, "memo"_a)
1085 // Pickle support.
1086 .def(py::pickle(&pygmo::pickle_getstate_wrapper<pg::topology>, &pygmo::pickle_setstate_wrapper<pg::topology>))
1087 // UDT extraction.
1088 .def("_py_extract", &pygmo::generic_py_extract<pg::topology>)
1089 // Topology methods.
1090 .def(
1091 "get_connections",
1092 [](const pg::topology &t, std::size_t n) -> py::tuple {
1093 auto ret = t.get_connections(n);
1094 return py::make_tuple(pygmo::vector_to_ndarr<py::array_t<std::size_t>>(ret.first),
1095 pygmo::vector_to_ndarr<py::array_t<double>>(ret.second));
1096 },
1097 pygmo::topology_get_connections_docstring().c_str(), py::arg("n"))
1098 .def(
1099 "push_back", [](pg::topology &t, unsigned n) { t.push_back(n); },
1100 pygmo::topology_push_back_docstring().c_str(), py::arg("n") = std::size_t(1))
1101 .def(
1102 "to_networkx", [](const pg::topology &t) { return pygmo::bgl_graph_t_to_networkx(t.to_bgl()); },
1103 pygmo::topology_to_networkx_docstring().c_str())
1104 .def("get_name", &pg::topology::get_name, pygmo::topology_get_name_docstring().c_str())
1105 .def("get_extra_info", &pg::topology::get_extra_info, pygmo::topology_get_extra_info_docstring().c_str());
1106
1107 // Expose the C++ topologies.
1108 pygmo::expose_topologies(m, topology_class, topologies_module);
1109
1110 // Finalize.
1111 topology_class.def(py::init<const py::object &>(), py::arg("udt"));
1112 }
1113