NumCpp  2.6.2
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 
33 #include "NumCpp/Core/Types.hpp"
34 #include "NumCpp/Utils/num2str.hpp"
35 
36 #include <cmath>
37 #include <iostream>
38 #include <string>
39 #include <utility>
40 #include <vector>
41 
42 #include "boost/python.hpp"
43 #include "boost/python/numpy.hpp"
44 
45 namespace nc
46 {
47  namespace boostPythonInterface
48  {
49  //================================================================================
51  template<typename dtype>
52  class BoostNdarrayHelper
53  {
54  public:
55  //================================================================================
57  enum class Order { F, C };
58 
59  //============================================================================
64  explicit BoostNdarrayHelper(const boost::python::numpy::ndarray& inArray) :
65  theArray_(inArray.astype(boost::python::numpy::dtype::get_builtin<dtype>())),
66  numDimensions_(static_cast<uint8>(inArray.get_nd())),
67  shape_(numDimensions_),
68  strides_(numDimensions_),
69  order_(Order::C)
70 
71  {
72  Py_intptr_t const * shapePtr = inArray.get_shape();
73  for (uint8 i = 0; i < numDimensions_; ++i)
74  {
75  strides_[i] = static_cast<uint32>(theArray_.strides(i));
76  shape_[i] = shapePtr[i];
77  }
78 
79  if (numDimensions_ > 1 && inArray.strides(0) < inArray.strides(1))
80  {
81  order_ = Order::F;
82  }
83  }
84 
85  //============================================================================
90  explicit BoostNdarrayHelper(boost::python::tuple inShape) :
91  theArray_(boost::python::numpy::zeros(inShape, boost::python::numpy::dtype::get_builtin<dtype>())),
92  numDimensions_(static_cast<uint8>(theArray_.get_nd())),
93  shape_(numDimensions_),
94  strides_(numDimensions_),
95  order_(Order::C)
96  {
97  Py_intptr_t const * shapePtr = theArray_.get_shape();
98  for (uint8 i = 0; i < numDimensions_; ++i)
99  {
100  strides_[i] = static_cast<uint32>(theArray_.strides(i));
101  shape_[i] = shapePtr[i];
102  }
103 
104  if (numDimensions_ > 1 && theArray_.strides(0) < theArray_.strides(1))
105  {
106  order_ = Order::F;
107  }
108 
109  }
110 
111 
112  //============================================================================
117  const boost::python::numpy::ndarray& getArray() noexcept
118  {
119  return theArray_;
120  }
121 
122  //============================================================================
127  boost::python::numpy::matrix getArrayAsMatrix()
128  {
129  return boost::python::numpy::matrix(theArray_);
130  }
131 
132  //============================================================================
137  uint8 numDimensions() noexcept
138  {
139  return numDimensions_;
140  }
141 
142  //============================================================================
147  const std::vector<Py_intptr_t>& shape() noexcept
148  {
149  return shape_;
150  }
151 
152  //============================================================================
157  uint32 size()
158  {
159  uint32 theSize = 1;
160  for (auto dimSize : shape_)
161  {
162  theSize *= static_cast<uint32>(dimSize);
163  }
164  return theSize;
165  }
166 
167 
168  //============================================================================
173  const std::vector<uint32>& strides()
174  {
175  return strides_;
176  }
177 
178  //============================================================================
183  Order order()
184  {
185  return order_;
186  }
187 
188  //============================================================================
195  bool shapeEqual(BoostNdarrayHelper& otherNdarrayHelper)
196  {
197  if (shape_.size() != otherNdarrayHelper.shape_.size())
198  {
199  return false;
200  }
201 
202  return stl_algorithms::equal(shape_.begin(), shape_.end(), otherNdarrayHelper.shape_.begin());
203  }
204 
205  //============================================================================
212  dtype& operator()(uint32 index)
213  {
214  checkIndices1D(index);
215 
216  return *reinterpret_cast<dtype*>(theArray_.get_data() + strides_.front() * index);
217  }
218 
219  //============================================================================
227  dtype& operator()(uint32 index1, uint32 index2)
228  {
229  checkIndices2D(index1, index2);
230 
231  return *reinterpret_cast<dtype*>(theArray_.get_data() + strides_.front() * index1 + strides_[1] * index2);
232  }
233 
234  //============================================================================
237  void printArray1D()
238  {
239  printf("array = \n");
240  if (numDimensions_ != 1)
241  {
242  std::cout << "printArray1D can only be used on a 1D array." << std::endl;
243  return;
244  }
245 
246  for (int32 i = 0; i < shape_.front(); ++i)
247  {
248  printf("\t%f\n", operator()(i));
249  }
250  }
251 
252  //============================================================================
255  void printArray2D()
256  {
257  printf("array = \n");
258  if (numDimensions_ != 2)
259  {
260  std::cout << "printArray2D can only be used on a 2D array." << std::endl;
261  return;
262  }
263 
264  for (int32 index1 = 0; index1 < shape_.front(); ++index1)
265  {
266  for (int32 index2 = 0; index2 < shape_.back(); ++index2)
267  {
268  printf("\t%f", operator()(index1, index2));
269  }
270  printf('\n');
271  }
272  }
273 
274  private:
275  //====================================Attributes==============================
276  boost::python::numpy::ndarray theArray_;
277  uint8 numDimensions_;
278  std::vector<Py_intptr_t> shape_;
279  std::vector<uint32> strides_;
280  Order order_;
281 
282  //============================================================================
287  void checkIndicesGeneric(boost::python::tuple indices)
288  {
289  if (boost::python::len(indices) != numDimensions_)
290  {
291  std::string errStr = "Error: BoostNdarrayHelper::checkIndicesGeneric: Array has " + utils::num2str(numDimensions_);
292  errStr += " dimensions, you asked for " + utils::num2str(static_cast<int>(boost::python::len(indices))) + "!";
293  PyErr_SetString(PyExc_RuntimeError, errStr.c_str());
294  }
295 
296  for (int i = 0; i < numDimensions_; ++i)
297  {
298  int index = boost::python::extract<int>(indices[i]);
299  if (index > shape_[i])
300  {
301  std::string errStr = "Error: BoostNdarrayHelper::checkIndicesGeneric: Input index [" + utils::num2str(index);
302  errStr += "] is larger than the size of the array [" + utils::num2str(shape_[i]) + "].";
303  PyErr_SetString(PyExc_RuntimeError, errStr.c_str());
304  }
305  }
306  }
307 
308  //============================================================================
313  void checkIndices1D(uint32 index)
314  {
315  boost::python::tuple indices = boost::python::make_tuple(index);
316  checkIndicesGeneric(indices);
317  }
318 
319  //============================================================================
325  void checkIndices2D(uint32 index1, uint32 index2)
326  {
327  boost::python::tuple indices = boost::python::make_tuple(index1, index2);
328  checkIndicesGeneric(indices);
329  }
330  };
331  } // namespace boostPythonInterface
332 } // namespace nc
333 
334 #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:135
std::string num2str(dtype inNumber)
Definition: num2str.hpp:46
Definition: Coordinate.hpp:45
NdArray< dtypeOut > astype(const NdArray< dtype > inArray)
Definition: astype.hpp:47
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:45
NdArray< dtype > zeros(uint32 inSquareSize)
Definition: zeros.hpp:50
std::int32_t int32
Definition: Types.hpp:36
std::uint8_t uint8
Definition: Types.hpp:42
Shape shape(const NdArray< dtype > &inArray) noexcept
Definition: Functions/Shape.hpp:44
std::uint32_t uint32
Definition: Types.hpp:40