7#ifndef __eigenpy_ufunc_hpp__ 8#define __eigenpy_ufunc_hpp__ 10#include "eigenpy/register.hpp" 11#include "eigenpy/user-type.hpp" 12#include "eigenpy/utils/python-compat.hpp" 17#ifdef NPY_1_19_API_VERSION 18#define EIGENPY_NPY_CONST_UFUNC_ARG const 20#define EIGENPY_NPY_CONST_UFUNC_ARG 24void matrix_multiply(
char **args, npy_intp
const *dimensions,
25 npy_intp
const *steps) {
32 npy_intp dm = dimensions[0];
33 npy_intp dn = dimensions[1];
34 npy_intp dp = dimensions[2];
37 npy_intp is1_m = steps[0];
38 npy_intp is1_n = steps[1];
39 npy_intp is2_n = steps[2];
40 npy_intp is2_p = steps[3];
41 npy_intp os_m = steps[4];
42 npy_intp os_p = steps[5];
48 for (m = 0; m < dm; m++) {
49 for (p = 0; p < dp; p++) {
50 SpecialMethods<T>::dotfunc(ip1, is1_n, ip2, is2_n, op, dn, NULL);
68void gufunc_matrix_multiply(
char **args,
69 npy_intp EIGENPY_NPY_CONST_UFUNC_ARG *dimensions,
70 npy_intp EIGENPY_NPY_CONST_UFUNC_ARG *steps,
71 void *NPY_UNUSED(func)) {
76 npy_intp dN = dimensions[0];
79 npy_intp s0 = steps[0];
80 npy_intp s1 = steps[1];
81 npy_intp s2 = steps[2];
87 for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1, args[2] += s2) {
88 matrix_multiply<T>(args, dimensions + 1, steps + 3);
92#define EIGENPY_REGISTER_BINARY_OPERATOR(name, op) \ 93 template <typename T1, typename T2, typename R> \ 94 void binary_op_##name( \ 95 char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \ 96 EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void * ) { \ 97 npy_intp is0 = steps[0], is1 = steps[1], os = steps[2], n = *dimensions; \ 98 char *i0 = args[0], *i1 = args[1], *o = args[2]; \ 100 for (k = 0; k < n; k++) { \ 101 T1 &x = *static_cast<T1 *>(static_cast<void *>(i0)); \ 102 T2 &y = *static_cast<T2 *>(static_cast<void *>(i1)); \ 103 R &res = *static_cast<R *>(static_cast<void *>(o)); \ 111 template <typename T> \ 112 void binary_op_##name( \ 113 char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \ 114 EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void *data) { \ 115 binary_op_##name<T, T, T>(args, dimensions, steps, data); \ 118EIGENPY_REGISTER_BINARY_OPERATOR(add, +)
119EIGENPY_REGISTER_BINARY_OPERATOR(subtract, -)
120EIGENPY_REGISTER_BINARY_OPERATOR(multiply, *)
121EIGENPY_REGISTER_BINARY_OPERATOR(divide, /)
122EIGENPY_REGISTER_BINARY_OPERATOR(equal, ==)
123EIGENPY_REGISTER_BINARY_OPERATOR(not_equal, !=)
124EIGENPY_REGISTER_BINARY_OPERATOR(less, <)
125EIGENPY_REGISTER_BINARY_OPERATOR(greater, >)
126EIGENPY_REGISTER_BINARY_OPERATOR(less_equal, <=)
127EIGENPY_REGISTER_BINARY_OPERATOR(greater_equal, >=)
129#define EIGENPY_REGISTER_UNARY_OPERATOR(name, op) \ 130 template <typename T, typename R> \ 131 void unary_op_##name( \ 132 char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \ 133 EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void * ) { \ 134 npy_intp is = steps[0], os = steps[1], n = *dimensions; \ 135 char *i = args[0], *o = args[1]; \ 137 for (k = 0; k < n; k++) { \ 138 T &x = *static_cast<T *>(static_cast<void *>(i)); \ 139 R &res = *static_cast<R *>(static_cast<void *>(o)); \ 146 template <typename T> \ 147 void unary_op_##name( \ 148 char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \ 149 EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void *data) { \ 150 unary_op_##name<T, T>(args, dimensions, steps, data); \ 153EIGENPY_REGISTER_UNARY_OPERATOR(negative, -)
154EIGENPY_REGISTER_UNARY_OPERATOR(square, x *)
158#define EIGENPY_REGISTER_BINARY_UFUNC(name, code, T1, T2, R) \ 160 PyUFuncObject *ufunc = \ 161 (PyUFuncObject *)PyObject_GetAttrString(numpy, #name); \ 162 int _types[3] = {Register::getTypeCode<T1>(), Register::getTypeCode<T2>(), \ 163 Register::getTypeCode<R>()}; \ 167 if (sizeof(_types) / sizeof(int) != ufunc->nargs) { \ 168 PyErr_Format(PyExc_AssertionError, \ 169 "ufunc %s takes %d arguments, our loop takes %lu", #name, \ 171 (unsigned long)(sizeof(_types) / sizeof(int))); \ 174 if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, code, \ 175 internal::binary_op_##name<T1, T2, R>, \ 183#define EIGENPY_REGISTER_UNARY_UFUNC(name, code, T, R) \ 185 PyUFuncObject *ufunc = \ 186 (PyUFuncObject *)PyObject_GetAttrString(numpy, #name); \ 187 int _types[2] = {Register::getTypeCode<T>(), Register::getTypeCode<R>()}; \ 191 if (sizeof(_types) / sizeof(int) != ufunc->nargs) { \ 192 PyErr_Format(PyExc_AssertionError, \ 193 "ufunc %s takes %d arguments, our loop takes %lu", #name, \ 195 (unsigned long)(sizeof(_types) / sizeof(int))); \ 198 if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, code, \ 199 internal::unary_op_##name<T, R>, _types, \ 207template <
typename Scalar>
208void registerCommonUfunc() {
209 const int type_code = Register::getTypeCode<Scalar>();
212 numpy_str = PyStr_FromString(
"numpy");
214 numpy = PyImport_Import(numpy_str);
215 Py_DECREF(numpy_str);
221 int types[3] = {type_code, type_code, type_code};
223 std::stringstream ss;
224 ss <<
"return result of multiplying two matrices of ";
225 ss << bp::type_info(
typeid(Scalar)).name();
226 PyUFuncObject *ufunc =
227 (PyUFuncObject *)PyObject_GetAttrString(numpy,
"matmul");
229 std::stringstream ss;
230 ss <<
"Impossible to define matrix_multiply for given type " 231 << bp::type_info(
typeid(Scalar)).name() << std::endl;
232 eigenpy::Exception(ss.str());
234 if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, type_code,
235 &internal::gufunc_matrix_multiply<Scalar>,
237 std::stringstream ss;
238 ss <<
"Impossible to register matrix_multiply for given type " 239 << bp::type_info(
typeid(Scalar)).name() << std::endl;
240 eigenpy::Exception(ss.str());
247 EIGENPY_REGISTER_BINARY_UFUNC(add, type_code, Scalar, Scalar, Scalar);
248 EIGENPY_REGISTER_BINARY_UFUNC(subtract, type_code, Scalar, Scalar, Scalar);
249 EIGENPY_REGISTER_BINARY_UFUNC(multiply, type_code, Scalar, Scalar, Scalar);
250 EIGENPY_REGISTER_BINARY_UFUNC(divide, type_code, Scalar, Scalar, Scalar);
253 EIGENPY_REGISTER_BINARY_UFUNC(equal, type_code, Scalar, Scalar,
bool);
254 EIGENPY_REGISTER_BINARY_UFUNC(not_equal, type_code, Scalar, Scalar,
bool);
255 EIGENPY_REGISTER_BINARY_UFUNC(greater, type_code, Scalar, Scalar,
bool);
256 EIGENPY_REGISTER_BINARY_UFUNC(less, type_code, Scalar, Scalar,
bool);
257 EIGENPY_REGISTER_BINARY_UFUNC(greater_equal, type_code, Scalar, Scalar,
bool);
258 EIGENPY_REGISTER_BINARY_UFUNC(less_equal, type_code, Scalar, Scalar,
bool);
261 EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar);
262 EIGENPY_REGISTER_UNARY_UFUNC(square, type_code, Scalar, Scalar);