Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
Module.cpp
Go to the documentation of this file.
1
23#include "Pyston/Helpers.h"
26#include <boost/python.hpp>
27#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
28
29#if BOOST_VERSION < 105600
30#include <boost/units/detail/utility.hpp>
31using boost::units::detail::demangle;
32#else
33using boost::core::demangle;
34#endif
35
36namespace py = boost::python;
37
38#if BOOST_VERSION < 106300
39namespace boost {
40namespace python {
41namespace converter {
42
43template <class T>
45 if (!x)
46 return python::detail::none();
47 else if (shared_ptr_deleter* d = std::get_deleter<shared_ptr_deleter>(x))
48 return xincref(get_pointer(d->owner));
49 else
50 return converter::registered<std::shared_ptr<T> const&>::converters.to_python(&x);
51}
52
53} // namespace converter
54} // namespace python
55} // namespace boost
56#endif
57
58namespace Pyston {
59
60// Sadly these have to be global
61PyObject* pyRecoverableError = nullptr;
62PyObject* pyUnrecoverableError = nullptr;
63
64template <typename T>
66
67 using NodeType = py::class_<Node<T>, boost::noncopyable>;
68
74 template <typename To>
75 static void defCastOperations(NodeType& node) {
76 node.def("__add__", makeBinaryFunction<To(To, To)>("+", std::plus<To>()))
77 .def("__sub__", makeBinaryFunction<To(To, To)>("-", std::minus<To>()))
78 .def("__mul__", makeBinaryFunction<To(To, To)>("*", std::multiplies<To>()))
79 .def("__truediv__", makeBinaryFunction<To(To, To)>("/", std::divides<To>()))
80 .def("__radd__", makeBinaryFunction<To(To, To)>("+", std::plus<To>(), true))
81 .def("__rsub__", makeBinaryFunction<To(To, To)>("-", std::minus<To>(), true))
82 .def("__rmul__", makeBinaryFunction<To(To, To)>("x", std::multiplies<To>(), true))
83 .def("__rtruediv__", makeBinaryFunction<To(To, To)>("/", std::divides<To>(), true));
84 }
85
89 template <typename Y>
90 static void specialized(NodeType& node, void*);
91
95 template <typename Y>
96 static void specialized(NodeType& node, typename std::enable_if<std::is_floating_point<Y>::value>::type* = nullptr) {
97 node.def("__pow__", makeFunction<T(T, T)>("^", Pow<T>()))
98 .def("__rpow__", makeBinaryFunction<T(T, T)>("^", Pow<T>(), true))
99 .def("__round__", makeFunction<T(T)>("round", Round<T>()))
100 .def("__abs__", makeFunction<T(T)>("abs", Abs<T>()));
101
102 // Functions
103 // When using numpy methods, numpy will delegate to these
104 // Taken from here, although there are a bunch not implemented:
105 // https://numpy.org/devdocs/reference/ufuncs.html
106 node.def("exp", makeFunction<T(T)>("exp", Exp<T>()))
107 .def("exp2", makeFunction<T(T)>("exp2", Exp2<T>()))
108 .def("log", makeFunction<T(T)>("log", Log<T>()))
109 .def("log2", makeFunction<T(T)>("log2", Log2<T>()))
110 .def("log10", makeFunction<T(T)>("log10", Log10<T>()))
111 .def("sqrt", makeFunction<T(T)>("sqrt", Sqrt<T>()))
112 .def("sin", makeFunction<T(T)>("sin", Sin<T>()))
113 .def("cos", makeFunction<T(T)>("cos", Cos<T>()))
114 .def("tan", makeFunction<T(T)>("tan", Tan<T>()))
115 .def("arcsin", makeFunction<T(T)>("arcsin", ArcSin<T>()))
116 .def("arccos", makeFunction<T(T)>("arccos", ArcCos<T>()))
117 .def("arctan", makeFunction<T(T)>("arctan", ArcTan<T>()))
118 .def("arctan2", makeBinaryFunction<T(T, T)>("arctan2", ArcTan2<T>()))
119 .def("sinh", makeFunction<T(T)>("sinh", Sinh<T>()))
120 .def("cosh", makeFunction<T(T)>("cosh", Cosh<T>()))
121 .def("tanh", makeFunction<T(T)>("tanh", Tanh<T>()))
122 .def("arcsinh", makeFunction<T(T)>("arcsinh", ArcSinh<T>()))
123 .def("arccosh", makeFunction<T(T)>("arccosh", ArcCosh<T>()))
124 .def("arctanh", makeFunction<T(T)>("arctanh", ArcTanh<T>()))
125 .def("fmod", makeFunction<T(T, T)>("fmod", Fmod<T>()));
126 }
127
131 template <typename Y>
132 static void specialized(NodeType& node, typename std::enable_if<std::is_same<Y, bool>::value>::type* = nullptr) {
133 // Upcast to double and int
134 defCastOperations<double>(node);
135 defCastOperations<int64_t>(node);
136 }
137
141 template <typename Y>
142 static void
145 node.def("__abs__", makeFunction<T(T)>("abs", Abs<T>()));
146 // Upcast to double
147 defCastOperations<double>(node);
148 node.def("__pow__", makeBinaryFunction<double(double, double)>("^", Pow<double>()))
149 .def("__rpow__", makeBinaryFunction<double(double, double)>("^", Pow<double>(), true));
150 }
151
152 static void general(NodeType& node) {
153 // https://docs.python.org/3/reference/datamodel.html#basic-customization
154 node.def("__lt__", makeFunction<bool(T, T)>("<", std::less<T>()))
155 .def("__le__", makeFunction<bool(T, T)>("<=", std::less_equal<T>()))
156 .def("__eq__", makeFunction<bool(T, T)>("==", std::equal_to<T>()))
157 .def("__ne__", makeFunction<bool(T, T)>("!=", std::not_equal_to<T>()))
158 .def("__gt__", makeFunction<bool(T, T)>(">", std::greater<T>()))
159 .def("__ge__", makeFunction<bool(T, T)>(">=", std::greater_equal<T>()));
160
161 // https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
162 node.def("__add__", makeFunction<T(T, T)>("+", std::plus<T>()))
163 .def("__sub__", makeFunction<T(T, T)>("-", std::minus<T>()))
164 .def("__mul__", makeFunction<T(T, T)>("*", std::multiplies<T>()))
165 .def("__truediv__", makeFunction<T(T, T)>("/", std::divides<T>()))
166 .def("__div__", makeFunction<T(T, T)>("/", std::divides<T>()))
167 .def("__radd__", makeBinaryFunction<T(T, T)>("+", std::plus<T>(), true))
168 .def("__rsub__", makeBinaryFunction<T(T, T)>("-", std::minus<T>(), true))
169 .def("__rmul__", makeBinaryFunction<T(T, T)>("*", std::multiplies<T>(), true))
170 .def("__rtruediv__", makeBinaryFunction<T(T, T)>("/", std::divides<T>(), true))
171 .def("__rdiv__", makeBinaryFunction<T(T, T)>("/", std::divides<T>(), true))
172 .def("__neg__", makeFunction<T(T)>("-", std::negate<T>()))
173 .def("__pos__", makeFunction<T(T)>("+", (Identity<T>())));
174
175 // Can not be used in conditionals!
176#if PY_MAJOR_VERSION >= 3
177#define AS_BOOL_METHOD "__bool__"
178#else
179#define AS_BOOL_METHOD "__nonzero__"
180#endif
181 node.def(AS_BOOL_METHOD,
182 py::make_function(ExceptionRaiser<T>("Can not use variable placeholders in conditionals", true),
183 py::default_call_policies(),
184 boost::mpl::vector<void, const std::shared_ptr<Node<T>>>()));
185 }
186
187 static void Do() {
188 auto node_name = std::string("Node<") + demangle(typeid(T).name()) + ">";
189 NodeType node(node_name.c_str(), "AST Node", py::no_init);
190
191 // Operators and method applicable to all types
192 general(node);
193
194 // Operators and method applicable only to a given type
195 // i.e. __floordiv__ is not applicable to float
196 specialized<T>(node);
197
198 // Register convertion between shared pointer and Node
199 py::register_ptr_to_python<std::shared_ptr<Node<T>>>();
200#if BOOST_VERSION < 106300
201 py::implicitly_convertible<std::shared_ptr<Placeholder<T>>, std::shared_ptr<Node<T>>>();
202#endif
203 // Custom conversion so primitive values can be converted to a node
204 py::converter::registry::push_back(&NodeConverter<T>::isConvertible, &NodeConverter<T>::construct,
205 py::type_id<std::shared_ptr<Node<T>>>());
206
207 // Triggers the building of a tree
208 auto placeholder_name = std::string("Placeholder<") + demangle(typeid(T).name()) + ">";
209 py::class_<Placeholder<T>, py::bases<Node<T>>>(placeholder_name.c_str(), "Variable placeholder", py::no_init);
210 py::register_ptr_to_python<std::shared_ptr<Placeholder<T>>>();
211 }
212};
213
217struct VariantToPython : public boost::static_visitor<boost::python::object> {
218 template <typename Content>
219 py::object operator()(Content c) const {
220 return py::object(c);
221 }
222};
223
224py::object attributeSetGetter(const AttributeSet& attr_set, const std::string& name) {
225 auto vi = attr_set.find(name);
226 if (vi == attr_set.end()) {
227 throw UnrecoverableError("AttributeSet has no attribute '" + name + "'");
228 }
229 return boost::apply_visitor(VariantToPython(), vi->second);
230}
231
236 py::class_<Placeholder<AttributeSet>, boost::noncopyable> node("AttributeSet", "AST Node", py::no_init);
237
238 // Register convertion between shared pointer and Node
239 py::register_ptr_to_python<std::shared_ptr<Placeholder<AttributeSet>>>();
240
241 // Register __getattr__
242 node.def("__getattr__", &Placeholder<AttributeSet>::get);
243
244 // Register AttributeSet so it can be used directly from Python for
245 // non-compiled expressions
246 py::class_<AttributeSet> attr_set("AttributeSet", "Attribute set", py::no_init);
247 attr_set.def("__getattr__", &attributeSetGetter);
248}
249
256static PyObject* createExceptionClass(const std::string& name) {
257 std::string scope = py::extract<std::string>(py::scope().attr("__name__"));
258 std::string qname = scope + "." + name;
259 PyObject* excType = PyErr_NewException(const_cast<char*>(qname.c_str()), PyExc_RuntimeError, nullptr);
260 if (!excType)
261 py::throw_error_already_set();
262 py::scope().attr(name.c_str()) = py::handle<>(py::borrowed(excType));
263 return excType;
264}
265
270 PyErr_SetString(pyRecoverableError, e.what());
271}
272
277 PyErr_SetString(pyUnrecoverableError, e.what());
278}
279
284
285 // AttributeSet is a bit special
287
288 // Vector types
289 py::class_<std::vector<double>>("_DoubleVector").def(py::vector_indexing_suite<std::vector<double>>());
290 py::class_<std::vector<int64_t>>("_IntVector").def(py::vector_indexing_suite<std::vector<int64_t>>());
291
292 // Exceptions
293 pyRecoverableError = createExceptionClass("RecoverableError");
294 pyUnrecoverableError = createExceptionClass("UnrecoverableError");
295
296 // Exception translation
297 py::register_exception_translator<RecoverableError>(&translateRecoverable);
298 py::register_exception_translator<UnrecoverableError>(&translateUnrecoverable);
299}
300
301} // end of namespace Pyston
#define AS_BOOL_METHOD
T c_str(T... args)
T end(T... args)
T find(T... args)
PyObject * pyRecoverableError
Definition Module.cpp:61
py::object attributeSetGetter(const AttributeSet &attr_set, const std::string &name)
Definition Module.cpp:224
static boost::python::object makeFunction(const std::string &repr, std::function< Signature > functor)
Definition Helpers.h:104
void translateRecoverable(const RecoverableError &e)
Definition Module.cpp:269
void translateUnrecoverable(const UnrecoverableError &e)
Definition Module.cpp:276
static boost::python::object makeBinaryFunction(const std::string &repr, std::function< Signature > functor, bool reversed=false)
Definition Helpers.h:124
PyObject * pyUnrecoverableError
Definition Module.cpp:62
BOOST_PYTHON_MODULE(pyston)
Definition Module.cpp:280
static PyObject * createExceptionClass(const std::string &name)
Definition Module.cpp:256
void RegisterAttributeSet()
Definition Module.cpp:235
PyObject * shared_ptr_to_python(std::shared_ptr< T > const &x)
Definition Module.cpp:44
Definition array.h:33
static void specialized(NodeType &node, typename std::enable_if< std::is_floating_point< Y >::value >::type *=nullptr)
Definition Module.cpp:96
py::class_< Node< T >, boost::noncopyable > NodeType
Definition Module.cpp:67
static void Do()
Definition Module.cpp:187
static void specialized(NodeType &node, void *)
static void general(NodeType &node)
Definition Module.cpp:152
static void defCastOperations(NodeType &node)
Definition Module.cpp:75
static void specialized(NodeType &node, typename std::enable_if< std::is_integral< Y >::value &&!std::is_same< Y, bool >::value >::type *=nullptr)
Definition Module.cpp:143
static void specialized(NodeType &node, typename std::enable_if< std::is_same< Y, bool >::value >::type *=nullptr)
Definition Module.cpp:132
py::object operator()(Content c) const
Definition Module.cpp:219