eigenpy 3.12.0
Bindings between Numpy and Eigen using Boost.Python
Loading...
Searching...
No Matches
numpy.hpp
1/*
2 * Copyright 2020-2024 INRIA
3 */
4
5#ifndef __eigenpy_numpy_hpp__
6#define __eigenpy_numpy_hpp__
7
8#include "eigenpy/config.hpp"
9
10#ifndef PY_ARRAY_UNIQUE_SYMBOL
11#define PY_ARRAY_UNIQUE_SYMBOL EIGENPY_ARRAY_API
12#endif
13
14// For compatibility with Numpy 2.x. See:
15// https://numpy.org/devdocs/reference/c-api/array.html#c.NPY_API_SYMBOL_ATTRIBUTE
16#define NPY_API_SYMBOL_ATTRIBUTE EIGENPY_DLLAPI
17
18// When building with MSVC, Python headers use some pragma operator to link
19// against the Python DLL.
20// Unfortunately, it can link against the wrong build type of the library
21// leading to some linking issue.
22// Boost::Python provides a helper specifically dedicated to selecting the right
23// Python library depending on build type, so let's make use of it.
24// Numpy headers drags Python with them. As a result, it
25// is necessary to include this helper before including Numpy.
26// See: https://github.com/stack-of-tasks/eigenpy/pull/514
27#include <boost/python/detail/wrap_python.hpp>
28
29#include <numpy/numpyconfig.h>
30#ifdef NPY_1_8_API_VERSION
31#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
32#endif
33
34// Allow compiling against NumPy 1.x and 2.x. See:
35// https://github.com/numpy/numpy/blob/afea8fd66f6bdbde855f5aff0b4e73eb0213c646/doc/source/reference/c-api/array.rst#L1224
36#if NPY_ABI_VERSION < 0x02000000
37#define PyArray_DescrProto PyArray_Descr
38#endif
39
40#include <numpy/ndarrayobject.h>
41#include <numpy/ufuncobject.h>
42
43#if NPY_ABI_VERSION < 0x02000000
44static inline PyArray_ArrFuncs* PyDataType_GetArrFuncs(PyArray_Descr* descr) {
45 return descr->f;
46}
47#endif
48
49/* PEP 674 disallow using macros as l-values
50 see : https://peps.python.org/pep-0674/
51*/
52#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
53static inline void _Py_SET_TYPE(PyObject* o, PyTypeObject* type) {
54 Py_TYPE(o) = type;
55}
56#define Py_SET_TYPE(o, type) _Py_SET_TYPE((PyObject*)(o), type)
57#endif
58
59#if defined _WIN32 || defined __CYGWIN__
60#define EIGENPY_GET_PY_ARRAY_TYPE(array) \
61 call_PyArray_MinScalarType(array)->type_num
62#else
63#define EIGENPY_GET_PY_ARRAY_TYPE(array) PyArray_MinScalarType(array)->type_num
64#endif
65
66#include <complex>
67
68namespace eigenpy {
69void EIGENPY_DLLAPI import_numpy();
70int EIGENPY_DLLAPI PyArray_TypeNum(PyTypeObject* type);
71
72// By default, the Scalar is considered as a Python object
73template <typename Scalar, typename Enable = void>
75 enum { type_code = NPY_USERDEF };
76};
77
78template <>
79struct NumpyEquivalentType<bool> {
80 enum { type_code = NPY_BOOL };
81};
82
83template <>
84struct NumpyEquivalentType<char> {
85 enum { type_code = NPY_INT8 };
86};
87template <>
88struct NumpyEquivalentType<unsigned char> {
89 enum { type_code = NPY_UINT8 };
90};
91template <>
92struct NumpyEquivalentType<int8_t> {
93 enum { type_code = NPY_INT8 };
94};
95
96template <>
97struct NumpyEquivalentType<int16_t> {
98 enum { type_code = NPY_INT16 };
99};
100template <>
101struct NumpyEquivalentType<uint16_t> {
102 enum { type_code = NPY_UINT16 };
103};
104
105template <>
106struct NumpyEquivalentType<int32_t> {
107 enum { type_code = NPY_INT32 };
108};
109template <>
110struct NumpyEquivalentType<uint32_t> {
111 enum { type_code = NPY_UINT32 };
112};
113
114// On Windows, long is a 32 bytes type but it's a different type than int
115// See https://github.com/stack-of-tasks/eigenpy/pull/455
116#if defined _WIN32 || defined __CYGWIN__
117
118template <>
119struct NumpyEquivalentType<long> {
120 enum { type_code = NPY_INT32 };
121};
122template <>
123struct NumpyEquivalentType<unsigned long> {
124 enum { type_code = NPY_UINT32 };
125};
126
127#endif // WIN32
128
129template <>
130struct NumpyEquivalentType<int64_t> {
131 enum { type_code = NPY_INT64 };
132};
133template <>
134struct NumpyEquivalentType<uint64_t> {
135 enum { type_code = NPY_UINT64 };
136};
137
138// On Mac, long is a 64 bytes type but it's a different type than int64_t
139// See https://github.com/stack-of-tasks/eigenpy/pull/455
140#if defined __APPLE__
141
142template <>
143struct NumpyEquivalentType<long> {
144 enum { type_code = NPY_INT64 };
145};
146template <>
147struct NumpyEquivalentType<unsigned long> {
148 enum { type_code = NPY_UINT64 };
149};
150
151#endif // MAC
152
153// On Linux, long long is a 64 bytes type but it's a different type than int64_t
154// See https://github.com/stack-of-tasks/eigenpy/pull/455
155#if defined __linux__
156
157#include <type_traits>
158
159template <typename Scalar>
161 Scalar,
162 typename std::enable_if<!std::is_same<int64_t, long long>::value &&
163 std::is_same<Scalar, long long>::value>::type> {
164 enum { type_code = NPY_LONGLONG };
165};
166template <typename Scalar>
168 Scalar, typename std::enable_if<
169 !std::is_same<uint64_t, unsigned long long>::value &&
170 std::is_same<Scalar, unsigned long long>::value>::type> {
171 enum { type_code = NPY_ULONGLONG };
172};
173
174#endif // Linux
175
176template <>
177struct NumpyEquivalentType<float> {
178 enum { type_code = NPY_FLOAT };
179};
180template <>
181struct NumpyEquivalentType<double> {
182 enum { type_code = NPY_DOUBLE };
183};
184template <>
185struct NumpyEquivalentType<long double> {
186 enum { type_code = NPY_LONGDOUBLE };
187};
188
189template <>
190struct NumpyEquivalentType<std::complex<float>> {
191 enum { type_code = NPY_CFLOAT };
192};
193template <>
194struct NumpyEquivalentType<std::complex<double>> {
195 enum { type_code = NPY_CDOUBLE };
196};
197template <>
198struct NumpyEquivalentType<std::complex<long double>> {
199 enum { type_code = NPY_CLONGDOUBLE };
200};
201
202template <typename Scalar>
203bool isNumpyNativeType() {
204 if ((int)NumpyEquivalentType<Scalar>::type_code == NPY_USERDEF) return false;
205 return true;
206}
207
208} // namespace eigenpy
209
210namespace eigenpy {
211#if defined _WIN32 || defined __CYGWIN__
212EIGENPY_DLLAPI bool call_PyArray_Check(PyObject*);
213
214EIGENPY_DLLAPI PyObject* call_PyArray_SimpleNew(int nd, npy_intp* shape,
215 int np_type);
216
217EIGENPY_DLLAPI PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
218 npy_intp* shape, int np_type,
219 void* data_ptr, int options);
220
221EIGENPY_DLLAPI PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
222 npy_intp* shape, int np_type,
223 npy_intp* strides, void* data_ptr,
224 int options);
225
226EIGENPY_DLLAPI int call_PyArray_ObjectType(PyObject*, int);
227
228EIGENPY_DLLAPI PyTypeObject* getPyArrayType();
229
230EIGENPY_DLLAPI PyArray_Descr* call_PyArray_DescrFromType(int typenum);
231
232EIGENPY_DLLAPI void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs);
233
234EIGENPY_DLLAPI int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype);
235
236EIGENPY_DLLAPI int call_PyArray_RegisterCanCast(PyArray_Descr* descr,
237 int totype,
238 NPY_SCALARKIND scalar);
239
240EIGENPY_DLLAPI PyArray_Descr* call_PyArray_MinScalarType(PyArrayObject* arr);
241
242EIGENPY_DLLAPI int call_PyArray_RegisterCastFunc(
243 PyArray_Descr* descr, int totype, PyArray_VectorUnaryFunc* castfunc);
244#else
245inline bool call_PyArray_Check(PyObject* py_obj) {
246 return PyArray_Check(py_obj);
247}
248
249inline PyObject* call_PyArray_SimpleNew(int nd, npy_intp* shape, int np_type) {
250 return PyArray_SimpleNew(nd, shape, np_type);
251}
252
253inline PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
254 npy_intp* shape, int np_type, void* data_ptr,
255 int options) {
256 return PyArray_New(py_type_ptr, nd, shape, np_type, NULL, data_ptr, 0,
257 options, NULL);
258}
259
260inline PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
261 npy_intp* shape, int np_type,
262 npy_intp* strides, void* data_ptr,
263 int options) {
264 return PyArray_New(py_type_ptr, nd, shape, np_type, strides, data_ptr, 0,
265 options, NULL);
266}
267
268inline int call_PyArray_ObjectType(PyObject* obj, int val) {
269 return PyArray_ObjectType(obj, val);
270}
271
272inline PyTypeObject* getPyArrayType() { return &PyArray_Type; }
273
274inline PyArray_Descr* call_PyArray_DescrFromType(int typenum) {
275 return PyArray_DescrFromType(typenum);
276}
277
278inline void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs) {
279 PyArray_InitArrFuncs(funcs);
280}
281
282inline int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype) {
283 return PyArray_RegisterDataType(dtype);
284}
285
286inline PyArray_Descr* call_PyArray_MinScalarType(PyArrayObject* arr) {
287 return PyArray_MinScalarType(arr);
288}
289
290inline int call_PyArray_RegisterCanCast(PyArray_Descr* descr, int totype,
291 NPY_SCALARKIND scalar) {
292 return PyArray_RegisterCanCast(descr, totype, scalar);
293}
294
295inline int call_PyArray_RegisterCastFunc(PyArray_Descr* descr, int totype,
296 PyArray_VectorUnaryFunc* castfunc) {
297 return PyArray_RegisterCastFunc(descr, totype, castfunc);
298}
299#endif
300} // namespace eigenpy
301
302#endif // ifndef __eigenpy_numpy_hpp__