7 #ifndef __eigenpy_ufunc_hpp__
8 #define __eigenpy_ufunc_hpp__
17 #ifdef NPY_1_19_API_VERSION
18 #define EIGENPY_NPY_CONST_UFUNC_ARG const
20 #define EIGENPY_NPY_CONST_UFUNC_ARG
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++) {
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); \
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); \
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, \
207 template <
typename Scalar>
209 const int type_code = Register::getTypeCode<Scalar>();
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 ";
226 PyUFuncObject *ufunc =
227 (PyUFuncObject *)PyObject_GetAttrString(numpy,
"matmul");
229 std::stringstream ss;
230 ss <<
"Impossible to define matrix_multiply for given type "
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 "
269 #endif // __eigenpy_ufunc_hpp__