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 <memory>
10 #include <string>
11 #include <typeindex>
12 #include <typeinfo>
13
14 #include <pybind11/pybind11.h>
15
16 #include <pagmo/population.hpp>
17 #include <pagmo/threading.hpp>
18
19 #include "algorithm.hpp"
20 #include "common_utils.hpp"
21 #include "s11n_wrappers.hpp"
22
23 namespace pagmo
24 {
25
26 namespace detail
27 {
28
29 namespace py = pybind11;
30
algo_inner(const py::object & o)31 algo_inner<py::object>::algo_inner(const py::object &o)
32 {
33 // Forbid the use of a pygmo.algorithm as a UDA.
34 // The motivation here is consistency with C++. In C++, the use of
35 // a pagmo::algorithm as a UDA is forbidden and prevented by the fact
36 // that the generic constructor from UDA is disabled if the input
37 // object is a pagmo::algorithm (the copy/move constructor is
38 // invoked instead). In order to achieve an equivalent behaviour
39 // in pygmo, we throw an error if o is a algorithm, and instruct
40 // the user to employ the standard copy/deepcopy facilities
41 // for creating a copy of the input algorithm.
42 if (pygmo::type(o).equal(py::module::import("pygmo").attr("algorithm"))) {
43 pygmo::py_throw(
44 PyExc_TypeError,
45 ("a pygmo.algorithm cannot be used as a UDA for another pygmo.algorithm (if you need to copy an "
46 "algorithm please use the standard Python copy()/deepcopy() functions)"));
47 }
48 // Check that o is an instance of a class, and not a type.
49 check_not_type(o, "algorithm");
50 check_mandatory_method(o, "evolve", "algorithm");
51 m_value = pygmo::deepcopy(o);
52 }
53
clone() const54 std::unique_ptr<algo_inner_base> algo_inner<py::object>::clone() const
55 {
56 // This will make a deep copy using the ctor above.
57 return std::make_unique<algo_inner>(m_value);
58 }
59
evolve(const population & pop) const60 population algo_inner<py::object>::evolve(const population &pop) const
61 {
62 return py::cast<population>(m_value.attr("evolve")(pop));
63 }
64
set_seed(unsigned n)65 void algo_inner<py::object>::set_seed(unsigned n)
66 {
67 auto ss = pygmo::callable_attribute(m_value, "set_seed");
68 if (ss.is_none()) {
69 pygmo::py_throw(PyExc_NotImplementedError,
70 ("set_seed() has been invoked but it is not implemented "
71 "in the user-defined Python algorithm '"
72 + pygmo::str(m_value) + "' of type '" + pygmo::str(pygmo::type(m_value))
73 + "': the method is either not present or not callable")
74 .c_str());
75 }
76 ss(n);
77 }
78
has_set_seed() const79 bool algo_inner<py::object>::has_set_seed() const
80 {
81 auto ss = pygmo::callable_attribute(m_value, "set_seed");
82 if (ss.is_none()) {
83 return false;
84 }
85 auto hss = pygmo::callable_attribute(m_value, "has_set_seed");
86 if (hss.is_none()) {
87 return true;
88 }
89 return py::cast<bool>(hss());
90 }
91
get_thread_safety() const92 thread_safety algo_inner<py::object>::get_thread_safety() const
93 {
94 return thread_safety::none;
95 }
96
get_name() const97 std::string algo_inner<py::object>::get_name() const
98 {
99 return getter_wrapper<std::string>(m_value, "get_name", pygmo::str(pygmo::type(m_value)));
100 }
101
get_extra_info() const102 std::string algo_inner<py::object>::get_extra_info() const
103 {
104 return getter_wrapper<std::string>(m_value, "get_extra_info", std::string{});
105 }
106
set_verbosity(unsigned n)107 void algo_inner<py::object>::set_verbosity(unsigned n)
108 {
109 auto sv = pygmo::callable_attribute(m_value, "set_verbosity");
110 if (sv.is_none()) {
111 pygmo::py_throw(PyExc_NotImplementedError,
112 ("set_verbosity() has been invoked but it is not implemented "
113 "in the user-defined Python algorithm '"
114 + pygmo::str(m_value) + "' of type '" + pygmo::str(pygmo::type(m_value))
115 + "': the method is either not present or not callable")
116 .c_str());
117 }
118 sv(n);
119 }
120
has_set_verbosity() const121 bool algo_inner<py::object>::has_set_verbosity() const
122 {
123 auto sv = pygmo::callable_attribute(m_value, "set_verbosity");
124 if (sv.is_none()) {
125 return false;
126 }
127 auto hsv = pygmo::callable_attribute(m_value, "has_set_verbosity");
128 if (hsv.is_none()) {
129 return true;
130 }
131 return py::cast<bool>(hsv());
132 }
133
get_type_index() const134 std::type_index algo_inner<py::object>::get_type_index() const
135 {
136 return std::type_index(typeid(py::object));
137 }
138
get_ptr() const139 const void *algo_inner<py::object>::get_ptr() const
140 {
141 return &m_value;
142 }
143
get_ptr()144 void *algo_inner<py::object>::get_ptr()
145 {
146 return &m_value;
147 }
148
149 template <typename Archive>
save(Archive & ar,unsigned) const150 void algo_inner<py::object>::save(Archive &ar, unsigned) const
151 {
152 pygmo::inner_class_save<algo_inner_base>(ar, *this);
153 }
154
155 template <typename Archive>
load(Archive & ar,unsigned)156 void algo_inner<py::object>::load(Archive &ar, unsigned)
157 {
158 pygmo::inner_class_load<algo_inner_base>(ar, *this);
159 }
160
161 } // namespace detail
162
163 } // namespace pagmo
164
165 PAGMO_S11N_ALGORITHM_IMPLEMENT(pybind11::object)
166