eigenpy 3.12.0
Bindings between Numpy and Eigen using Boost.Python
Loading...
Searching...
No Matches
numpy-map.hpp
1/*
2 * Copyright 2014-2019, CNRS
3 * Copyright 2018-2023, INRIA
4 */
5
6#ifndef __eigenpy_numpy_map_hpp__
7#define __eigenpy_numpy_map_hpp__
8
9#include "eigenpy/exception.hpp"
10#include "eigenpy/fwd.hpp"
11#include "eigenpy/stride.hpp"
12
13namespace eigenpy {
14
15template <typename MatType, typename InputScalar, int AlignmentValue,
16 typename Stride, bool IsVector = MatType::IsVectorAtCompileTime>
18
19template <typename EigenType, typename InputScalar, int AlignmentValue,
20 typename Stride,
21 typename BaseType = typename get_eigen_base_type<EigenType>::type>
23
24template <typename MatType, typename InputScalar, int AlignmentValue,
25 typename Stride>
26struct numpy_map_impl<MatType, InputScalar, AlignmentValue, Stride,
27 Eigen::MatrixBase<MatType>>
28 : numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride> {};
29
30template <typename MatType, typename InputScalar, int AlignmentValue,
31 typename Stride>
32struct numpy_map_impl<const MatType, InputScalar, AlignmentValue, Stride,
33 const Eigen::MatrixBase<MatType>>
34 : numpy_map_impl_matrix<const MatType, InputScalar, AlignmentValue,
35 Stride> {};
36
37template <typename MatType, typename InputScalar, int AlignmentValue,
38 typename Stride>
39struct numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride,
40 false> {
41 typedef Eigen::Matrix<InputScalar, MatType::RowsAtCompileTime,
42 MatType::ColsAtCompileTime, MatType::Options>
43 EquivalentInputMatrixType;
44 typedef Eigen::Map<EquivalentInputMatrixType, AlignmentValue, Stride>
45 EigenMap;
46
47 static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
48 enum {
49 OuterStrideAtCompileTime = Stride::OuterStrideAtCompileTime,
50 InnerStrideAtCompileTime = Stride::InnerStrideAtCompileTime,
51 };
52
53 assert(PyArray_NDIM(pyArray) == 2 || PyArray_NDIM(pyArray) == 1);
54
55 const long int itemsize = PyArray_ITEMSIZE(pyArray);
56 int inner_stride = -1, outer_stride = -1;
57 int rows = -1, cols = -1;
58 if (PyArray_NDIM(pyArray) == 2) {
59 assert((PyArray_DIMS(pyArray)[0] < INT_MAX) &&
60 (PyArray_DIMS(pyArray)[1] < INT_MAX) &&
61 (PyArray_STRIDE(pyArray, 0) < INT_MAX) &&
62 (PyArray_STRIDE(pyArray, 1) < INT_MAX));
63
64 rows = (int)PyArray_DIMS(pyArray)[0];
65 cols = (int)PyArray_DIMS(pyArray)[1];
66
67 if (EquivalentInputMatrixType::IsRowMajor) {
68 inner_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
69 outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
70 } else {
71 inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
72 outer_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
73 }
74 } else if (PyArray_NDIM(pyArray) == 1) {
75 assert((PyArray_DIMS(pyArray)[0] < INT_MAX) &&
76 (PyArray_STRIDE(pyArray, 0) < INT_MAX));
77
78 if (!swap_dimensions) {
79 rows = (int)PyArray_DIMS(pyArray)[0];
80 cols = 1;
81
82 if (EquivalentInputMatrixType::IsRowMajor) {
83 outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
84 inner_stride = 0;
85 } else {
86 inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
87 outer_stride = 0;
88 }
89 } else {
90 rows = 1;
91 cols = (int)PyArray_DIMS(pyArray)[0];
92
93 if (EquivalentInputMatrixType::IsRowMajor) {
94 inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
95 outer_stride = 0;
96 } else {
97 inner_stride = 0;
98 outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
99 }
100 }
101 }
102
103 // Specific care for Eigen::Stride<-1,0>
104 if (InnerStrideAtCompileTime == 0 &&
105 OuterStrideAtCompileTime == Eigen::Dynamic) {
106 outer_stride = std::max(inner_stride, outer_stride);
107 inner_stride = 0;
108 }
109
110 Stride stride(
111 OuterStrideAtCompileTime == Eigen::Dynamic ? outer_stride
112 : OuterStrideAtCompileTime,
113 InnerStrideAtCompileTime == Eigen::Dynamic ? inner_stride
114 : InnerStrideAtCompileTime);
115
116 if ((MatType::RowsAtCompileTime != rows) &&
117 (MatType::RowsAtCompileTime != Eigen::Dynamic)) {
119 "The number of rows does not fit with the matrix type.");
120 }
121
122 if ((MatType::ColsAtCompileTime != cols) &&
123 (MatType::ColsAtCompileTime != Eigen::Dynamic)) {
125 "The number of columns does not fit with the matrix type.");
126 }
127
128 InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
129
130 return EigenMap(pyData, rows, cols, stride);
131 }
132};
133
134template <typename MatType, typename InputScalar, int AlignmentValue,
135 typename Stride>
136struct numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride,
137 true> {
138 typedef Eigen::Matrix<InputScalar, MatType::RowsAtCompileTime,
139 MatType::ColsAtCompileTime, MatType::Options>
140 EquivalentInputMatrixType;
141 typedef Eigen::Map<EquivalentInputMatrixType, AlignmentValue, Stride>
142 EigenMap;
143
144 static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
145 EIGENPY_UNUSED_VARIABLE(swap_dimensions);
146 assert(PyArray_NDIM(pyArray) <= 2);
147
148 int rowMajor;
149 if (PyArray_NDIM(pyArray) == 1)
150 rowMajor = 0;
151 else if (PyArray_DIMS(pyArray)[0] == 0)
152 rowMajor = 0; // handle zero-size vector
153 else if (PyArray_DIMS(pyArray)[1] == 0)
154 rowMajor = 1; // handle zero-size vector
155 else
156 rowMajor = (PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1]) ? 0 : 1;
157
158 assert(PyArray_DIMS(pyArray)[rowMajor] < INT_MAX);
159 const int R = (int)PyArray_DIMS(pyArray)[rowMajor];
160 const long int itemsize = PyArray_ITEMSIZE(pyArray);
161 const int stride = (int)PyArray_STRIDE(pyArray, rowMajor) / (int)itemsize;
162
163 if ((MatType::MaxSizeAtCompileTime != R) &&
164 (MatType::MaxSizeAtCompileTime != Eigen::Dynamic)) {
166 "The number of elements does not fit with the vector type.");
167 }
168
169 InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
170
171 assert(Stride(stride).inner() == stride &&
172 "Stride should be a dynamic stride");
173 return EigenMap(pyData, R, Stride(stride));
174 }
175};
176
177#ifdef EIGENPY_WITH_TENSOR_SUPPORT
178
179template <typename TensorType, typename InputScalar, int AlignmentValue,
180 typename Stride>
181struct numpy_map_impl_tensor;
182
183template <typename TensorType, typename InputScalar, int AlignmentValue,
184 typename Stride>
185struct numpy_map_impl<TensorType, InputScalar, AlignmentValue, Stride,
186 Eigen::TensorBase<TensorType>>
187 : numpy_map_impl_tensor<TensorType, InputScalar, AlignmentValue, Stride> {};
188
189template <typename TensorType, typename InputScalar, int AlignmentValue,
190 typename Stride>
191struct numpy_map_impl<const TensorType, InputScalar, AlignmentValue, Stride,
192 const Eigen::TensorBase<TensorType>>
193 : numpy_map_impl_tensor<const TensorType, InputScalar, AlignmentValue,
194 Stride> {};
195
196template <typename TensorType, typename InputScalar, int AlignmentValue,
197 typename Stride>
198struct numpy_map_impl_tensor {
199 typedef TensorType Tensor;
200 typedef typename Eigen::internal::traits<TensorType>::Index Index;
201 static const int Options = Eigen::internal::traits<TensorType>::Options;
202 static const int NumIndices = TensorType::NumIndices;
203
204 typedef Eigen::Tensor<InputScalar, NumIndices, Options, Index>
205 EquivalentInputTensorType;
206 typedef typename EquivalentInputTensorType::Dimensions Dimensions;
207 typedef Eigen::TensorMap<EquivalentInputTensorType, Options> EigenMap;
208
209 static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
210 EIGENPY_UNUSED_VARIABLE(swap_dimensions);
211 assert(PyArray_NDIM(pyArray) == NumIndices || NumIndices == Eigen::Dynamic);
212
213 Eigen::DSizes<Index, NumIndices> dimensions;
214 for (int k = 0; k < PyArray_NDIM(pyArray); ++k)
215 dimensions[k] = PyArray_DIMS(pyArray)[k];
216
217 InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
218 return EigenMap(pyData, dimensions);
219 }
220};
221#endif
222
223/* Wrap a numpy::array with an Eigen::Map. No memory copy. */
224template <typename EigenType, typename InputScalar,
225 int AlignmentValue = EIGENPY_NO_ALIGNMENT_VALUE,
226 typename Stride = typename StrideType<EigenType>::type>
228 : numpy_map_impl<EigenType, InputScalar, AlignmentValue, Stride> {};
229
230} // namespace eigenpy
231
232#endif // define __eigenpy_numpy_map_hpp__