ufunc.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 INRIA
3 //
4 
5 #ifndef __eigenpy_ufunc_hpp__
6 #define __eigenpy_ufunc_hpp__
7 
8 #include "eigenpy/register.hpp"
9 
10 namespace eigenpy
11 {
12  namespace internal
13  {
14 
15 #ifdef NPY_1_19_API_VERSION
16  #define EIGENPY_NPY_CONST_UFUNC_ARG const
17 #else
18  #define EIGENPY_NPY_CONST_UFUNC_ARG
19 #endif
20 
21 #define EIGENPY_REGISTER_BINARY_OPERATOR(name,op) \
22  template<typename T1, typename T2, typename R> \
23  void binary_op_##name(char** args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * dimensions, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * steps, void * /*data*/) \
24  { \
25  npy_intp is0 = steps[0], is1 = steps[1], \
26  os = steps[2], n = *dimensions; \
27  char * i0 = args[0], *i1 = args[1], *o = args[2]; \
28  int k; \
29  for (k = 0; k < n; k++) \
30  { \
31  T1 & x = *static_cast<T1*>(static_cast<void*>(i0)); \
32  T2 & y = *static_cast<T2*>(static_cast<void*>(i1)); \
33  R & res = *static_cast<R*>(static_cast<void*>(o)); \
34  res = x op y; \
35  i0 += is0; i1 += is1; o += os; \
36  } \
37  } \
38  \
39  template<typename T> \
40  void binary_op_##name(char** args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * dimensions, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * steps, void * data) \
41  { \
42  binary_op_##name<T,T,T>(args,dimensions,steps,data); \
43  }
44 
54  EIGENPY_REGISTER_BINARY_OPERATOR(greater_equal,>=)
55 
56  #define EIGENPY_REGISTER_UNARY_OPERATOR(name,op) \
57  template<typename T, typename R> \
58  void unary_op_##name(char** args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * dimensions, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * steps, void * /*data*/) \
59  { \
60  npy_intp is = steps[0], \
61  os = steps[1], n = *dimensions; \
62  char * i = args[0], *o = args[1]; \
63  int k; \
64  for (k = 0; k < n; k++) \
65  { \
66  T & x = *static_cast<T*>(static_cast<void*>(i)); \
67  R & res = *static_cast<R*>(static_cast<void*>(o)); \
68  res = op x; \
69  i += is; o += os; \
70  } \
71  } \
72  \
73  template<typename T> \
74  void unary_op_##name(char** args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * dimensions, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp * steps, void * data) \
75  { \
76  unary_op_##name<T,T>(args,dimensions,steps,data); \
77  }
78 
80 
81  } // namespace internal
82 
83 #define EIGENPY_REGISTER_BINARY_UFUNC(name,code,T1,T2,R) { \
84  PyUFuncObject* ufunc = \
85  (PyUFuncObject*)PyObject_GetAttrString(numpy, #name); \
86  int _types[3] = { Register::getTypeCode<T1>(), Register::getTypeCode<T2>(), Register::getTypeCode<R>()}; \
87  if (!ufunc) { \
88  /*goto fail; \*/ \
89  } \
90  if (sizeof(_types)/sizeof(int)!=ufunc->nargs) { \
91  PyErr_Format(PyExc_AssertionError, \
92  "ufunc %s takes %d arguments, our loop takes %lu", \
93  #name, ufunc->nargs, (unsigned long) \
94  (sizeof(_types)/sizeof(int))); \
95  Py_DECREF(ufunc); \
96  } \
97  if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, code, \
98  internal::binary_op_##name<T1,T2,R>, _types, 0) < 0) { \
99  /*Py_DECREF(ufunc);*/ \
100  /*goto fail; \*/ \
101  } \
102  Py_DECREF(ufunc); \
103 }
104 
105 #define EIGENPY_REGISTER_UNARY_UFUNC(name,code,T,R) { \
106  PyUFuncObject* ufunc = \
107  (PyUFuncObject*)PyObject_GetAttrString(numpy, #name); \
108  int _types[2] = { Register::getTypeCode<T>(), Register::getTypeCode<R>()}; \
109  if (!ufunc) { \
110  /*goto fail; \*/ \
111  } \
112  if (sizeof(_types)/sizeof(int)!=ufunc->nargs) { \
113  PyErr_Format(PyExc_AssertionError, \
114  "ufunc %s takes %d arguments, our loop takes %lu", \
115  #name, ufunc->nargs, (unsigned long) \
116  (sizeof(_types)/sizeof(int))); \
117  Py_DECREF(ufunc); \
118  } \
119  if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, code, \
120  internal::unary_op_##name<T,R>, _types, 0) < 0) { \
121  /*Py_DECREF(ufunc);*/ \
122  /*goto fail; \*/ \
123  } \
124  Py_DECREF(ufunc); \
125 }
126 
127  template<typename Scalar>
129  {
130  const int code = Register::getTypeCode<Scalar>();
131 
132  PyObject* numpy_str;
133 #if PY_MAJOR_VERSION >= 3
134  numpy_str = PyUnicode_FromString("numpy");
135 #else
136  numpy_str = PyString_FromString("numpy");
137 #endif
138  PyObject* numpy;
139  numpy = PyImport_Import(numpy_str);
140  Py_DECREF(numpy_str);
141 
142  import_ufunc();
143 
144  // Binary operators
145  EIGENPY_REGISTER_BINARY_UFUNC(add,code,Scalar,Scalar,Scalar);
146  EIGENPY_REGISTER_BINARY_UFUNC(subtract,code,Scalar,Scalar,Scalar);
147  EIGENPY_REGISTER_BINARY_UFUNC(multiply,code,Scalar,Scalar,Scalar);
148  EIGENPY_REGISTER_BINARY_UFUNC(divide,code,Scalar,Scalar,Scalar);
149 
150  // Comparison operators
151  EIGENPY_REGISTER_BINARY_UFUNC(equal,code,Scalar,Scalar,bool);
152  EIGENPY_REGISTER_BINARY_UFUNC(not_equal,code,Scalar,Scalar,bool);
153  EIGENPY_REGISTER_BINARY_UFUNC(greater,code,Scalar,Scalar,bool);
154  EIGENPY_REGISTER_BINARY_UFUNC(less,code,Scalar,Scalar,bool);
155  EIGENPY_REGISTER_BINARY_UFUNC(greater_equal,code,Scalar,Scalar,bool);
156  EIGENPY_REGISTER_BINARY_UFUNC(less_equal,code,Scalar,Scalar,bool);
157 
158  // Unary operators
159  EIGENPY_REGISTER_UNARY_UFUNC(negative,code,Scalar,Scalar);
160 
161  Py_DECREF(numpy);
162  }
163 
164 } // namespace eigenpy
165 
166 #endif // __eigenpy_ufunc_hpp__
#define EIGENPY_REGISTER_UNARY_UFUNC(name, code, T, R)
Definition: ufunc.hpp:105
#define EIGENPY_REGISTER_BINARY_UFUNC(name, code, T1, T2, R)
Definition: ufunc.hpp:83
void registerCommonUfunc()
Definition: ufunc.hpp:128
#define EIGENPY_REGISTER_BINARY_OPERATOR(name, op)
Definition: ufunc.hpp:21
#define EIGENPY_REGISTER_UNARY_OPERATOR(name, op)
Definition: ufunc.hpp:56


eigenpy
Author(s): Justin Carpentier, Nicolas Mansard
autogenerated on Sat Apr 17 2021 02:37:59