NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
BoostNumpyNdarrayHelper.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#if defined(NUMCPP_INCLUDE_BOOST_PYTHON_INTERFACE) && !defined(NUMCPP_NO_USE_BOOST)
31
32#include <cmath>
33#include <iostream>
34#include <string>
35#include <utility>
36#include <vector>
37
38#include "boost/python.hpp"
39#include "boost/python/numpy.hpp"
40
42#include "NumCpp/Core/Types.hpp"
44
45namespace nc
46{
47 namespace boostPythonInterface
48 {
49 //================================================================================
51 template<typename dtype>
52 class BoostNdarrayHelper
53 {
54 public:
55 //================================================================================
57 enum class Order
58 {
59 F,
60 C
61 };
62
63 //============================================================================
68 explicit BoostNdarrayHelper(const boost::python::numpy::ndarray& inArray) :
69 theArray_(inArray.astype(boost::python::numpy::dtype::get_builtin<dtype>())),
70 numDimensions_(static_cast<uint8>(inArray.get_nd())),
71 shape_(numDimensions_),
72 strides_(numDimensions_),
73 order_(Order::C)
74
75 {
76 Py_intptr_t const* shapePtr = inArray.get_shape();
77 for (uint8 i = 0; i < numDimensions_; ++i)
78 {
79 strides_[i] = static_cast<uint32>(theArray_.strides(i));
80 shape_[i] = shapePtr[i];
81 }
82
83 if (numDimensions_ > 1 && inArray.strides(0) < inArray.strides(1))
84 {
85 order_ = Order::F;
86 }
87 }
88
89 //============================================================================
94 explicit BoostNdarrayHelper(boost::python::tuple inShape) :
95 theArray_(boost::python::numpy::zeros(inShape, boost::python::numpy::dtype::get_builtin<dtype>())),
96 numDimensions_(static_cast<uint8>(theArray_.get_nd())),
97 shape_(numDimensions_),
98 strides_(numDimensions_),
99 order_(Order::C)
100 {
101 Py_intptr_t const* shapePtr = theArray_.get_shape();
102 for (uint8 i = 0; i < numDimensions_; ++i)
103 {
104 strides_[i] = static_cast<uint32>(theArray_.strides(i));
105 shape_[i] = shapePtr[i];
106 }
107
108 if (numDimensions_ > 1 && theArray_.strides(0) < theArray_.strides(1))
109 {
110 order_ = Order::F;
111 }
112 }
113
114 //============================================================================
119 const boost::python::numpy::ndarray& getArray() noexcept
120 {
121 return theArray_;
122 }
123
124 //============================================================================
129 boost::python::numpy::matrix getArrayAsMatrix()
130 {
131 return boost::python::numpy::matrix(theArray_);
132 }
133
134 //============================================================================
139 uint8 numDimensions() noexcept
140 {
141 return numDimensions_;
142 }
143
144 //============================================================================
149 const std::vector<Py_intptr_t>& shape() noexcept
150 {
151 return shape_;
152 }
153
154 //============================================================================
159 uint32 size()
160 {
161 uint32 theSize = 1;
162 for (auto dimSize : shape_)
163 {
164 theSize *= static_cast<uint32>(dimSize);
165 }
166 return theSize;
167 }
168
169 //============================================================================
174 const std::vector<uint32>& strides()
175 {
176 return strides_;
177 }
178
179 //============================================================================
184 Order order()
185 {
186 return order_;
187 }
188
189 //============================================================================
196 bool shapeEqual(BoostNdarrayHelper& otherNdarrayHelper)
197 {
198 if (shape_.size() != otherNdarrayHelper.shape_.size())
199 {
200 return false;
201 }
202
203 return stl_algorithms::equal(shape_.begin(), shape_.end(), otherNdarrayHelper.shape_.begin());
204 }
205
206 //============================================================================
213 dtype& operator()(uint32 index)
214 {
215 checkIndices1D(index);
216
217 return *reinterpret_cast<dtype*>(theArray_.get_data() + strides_.front() * index);
218 }
219
220 //============================================================================
228 dtype& operator()(uint32 index1, uint32 index2)
229 {
230 checkIndices2D(index1, index2);
231
232 return *reinterpret_cast<dtype*>(theArray_.get_data() + strides_.front() * index1 +
233 strides_[1] * index2);
234 }
235
236 //============================================================================
239 void printArray1D()
240 {
241 printf("array = \n");
242 if (numDimensions_ != 1)
243 {
244 std::cout << "printArray1D can only be used on a 1D array." << std::endl;
245 return;
246 }
247
248 for (int32 i = 0; i < shape_.front(); ++i)
249 {
250 printf("\t%f\n", operator()(i));
251 }
252 }
253
254 //============================================================================
257 void printArray2D()
258 {
259 printf("array = \n");
260 if (numDimensions_ != 2)
261 {
262 std::cout << "printArray2D can only be used on a 2D array." << std::endl;
263 return;
264 }
265
266 for (int32 index1 = 0; index1 < shape_.front(); ++index1)
267 {
268 for (int32 index2 = 0; index2 < shape_.back(); ++index2)
269 {
270 printf("\t%f", operator()(index1, index2));
271 }
272 printf('\n');
273 }
274 }
275
276 private:
277 //====================================Attributes==============================
278 boost::python::numpy::ndarray theArray_;
279 uint8 numDimensions_;
280 std::vector<Py_intptr_t> shape_;
281 std::vector<uint32> strides_;
282 Order order_;
283
284 //============================================================================
289 void checkIndicesGeneric(boost::python::tuple indices)
290 {
291 if (boost::python::len(indices) != numDimensions_)
292 {
293 std::string errStr =
294 "Error: BoostNdarrayHelper::checkIndicesGeneric: Array has " + utils::num2str(numDimensions_);
295 errStr += " dimensions, you asked for " +
296 utils::num2str(static_cast<int>(boost::python::len(indices))) + "!";
297 PyErr_SetString(PyExc_RuntimeError, errStr.c_str());
298 }
299
300 for (int i = 0; i < numDimensions_; ++i)
301 {
302 int index = boost::python::extract<int>(indices[i]);
303 if (index > shape_[i])
304 {
305 std::string errStr =
306 "Error: BoostNdarrayHelper::checkIndicesGeneric: Input index [" + utils::num2str(index);
307 errStr += "] is larger than the size of the array [" + utils::num2str(shape_[i]) + "].";
308 PyErr_SetString(PyExc_RuntimeError, errStr.c_str());
309 }
310 }
311 }
312
313 //============================================================================
318 void checkIndices1D(uint32 index)
319 {
320 boost::python::tuple indices = boost::python::make_tuple(index);
321 checkIndicesGeneric(indices);
322 }
323
324 //============================================================================
330 void checkIndices2D(uint32 index1, uint32 index2)
331 {
332 boost::python::tuple indices = boost::python::make_tuple(index1, index2);
333 checkIndicesGeneric(indices);
334 }
335 };
336 } // namespace boostPythonInterface
337} // namespace nc
338
339#endif // #if defined(NUMCPP_INCLUDE_BOOST_PYTHON_INTERFACE) && !defined(NUMCPP_NO_USE_BOOST)
bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) noexcept
Definition: StlAlgorithms.hpp:140
std::string num2str(dtype inNumber)
Definition: num2str.hpp:44
Definition: Cartesian.hpp:40
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:43
std::int32_t int32
Definition: Types.hpp:36
std::uint8_t uint8
Definition: Types.hpp:42
NdArray< dtype > zeros(uint32 inSquareSize)
Definition: zeros.hpp:48
Shape shape(const NdArray< dtype > &inArray) noexcept
Definition: Functions/Shape.hpp:42
NdArray< dtypeOut > astype(const NdArray< dtype > inArray)
Definition: astype.hpp:45
std::uint32_t uint32
Definition: Types.hpp:40