NumCpp  2.9.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
PybindInterface.hpp
Go to the documentation of this file.
1 #pragma once
29 
30 #ifdef NUMCPP_INCLUDE_PYBIND_PYTHON_INTERFACE
31 
32 #include "pybind11/numpy.h"
33 #include "pybind11/pybind11.h"
34 
35 #include <map>
36 #include <utility>
37 
39 #include "NumCpp/Core/Shape.hpp"
40 #include "NumCpp/NdArray.hpp"
41 
42 namespace nc
43 {
44  namespace pybindInterface
45  {
47  enum class ReturnPolicy
48  {
49  COPY,
50  REFERENCE,
51  TAKE_OWNERSHIP
52  };
53 
54  static const std::map<ReturnPolicy, std::string> returnPolicyStringMap = {
55  { ReturnPolicy::COPY, "COPY" },
56  { ReturnPolicy::REFERENCE, "REFERENCE" },
57  { ReturnPolicy::TAKE_OWNERSHIP, "TAKE_OWNERSHIP" }
58  };
59 
60  template<typename dtype>
61  using pbArray = pybind11::array_t<dtype, pybind11::array::c_style>;
62  using pbArrayGeneric = pybind11::array;
63 
64  //============================================================================
72  template<typename dtype>
73  NdArray<dtype> pybind2nc(pbArray<dtype>& numpyArray)
74  {
75  const auto dataPtr = numpyArray.mutable_data();
76  switch (numpyArray.ndim())
77  {
78  case 0:
79  {
80  return NdArray<dtype>(dataPtr, 0, 0, false);
81  }
82  case 1:
83  {
84  const uint32 size = static_cast<uint32>(numpyArray.size());
85  return NdArray<dtype>(dataPtr, 1, size, false);
86  }
87  case 2:
88  {
89  const uint32 numRows = static_cast<uint32>(numpyArray.shape(0));
90  const uint32 numCols = static_cast<uint32>(numpyArray.shape(1));
91  return NdArray<dtype>(dataPtr, numRows, numCols, false);
92  }
93  default:
94  {
95  THROW_INVALID_ARGUMENT_ERROR("input array must be no more than 2 dimensional.");
96  return {};
97  }
98  }
99  }
100 
101  //============================================================================
109  template<typename dtype>
110  NdArray<dtype> pybind2nc_copy(const pbArray<dtype>& numpyArray)
111  {
112  const auto dataPtr = numpyArray.data();
113  switch (numpyArray.ndim())
114  {
115  case 0:
116  {
117  return NdArray<dtype>(dataPtr, 0, 0);
118  }
119  case 1:
120  {
121  const uint32 size = static_cast<uint32>(numpyArray.size());
122  return NdArray<dtype>(dataPtr, 1, size);
123  }
124  case 2:
125  {
126  const uint32 numRows = static_cast<uint32>(numpyArray.shape(0));
127  const uint32 numCols = static_cast<uint32>(numpyArray.shape(1));
128  return NdArray<dtype>(dataPtr, numRows, numCols);
129  }
130  default:
131  {
132  THROW_INVALID_ARGUMENT_ERROR("input array must be no more than 2 dimensional.");
133  return {};
134  }
135  }
136  }
137 
138  //============================================================================
145  template<typename dtype>
146  pbArrayGeneric nc2pybind(const NdArray<dtype>& inArray)
147  {
148  const Shape inShape = inArray.shape();
149  const std::vector<pybind11::ssize_t> shape{ static_cast<pybind11::ssize_t>(inShape.rows),
150  static_cast<pybind11::ssize_t>(inShape.cols) };
151  const std::vector<pybind11::ssize_t> strides{ static_cast<pybind11::ssize_t>(inShape.cols * sizeof(dtype)),
152  static_cast<pybind11::ssize_t>(sizeof(dtype)) };
153  return pbArrayGeneric(shape, strides, inArray.data());
154  }
155 
156  //============================================================================
164  template<typename dtype>
165  pbArrayGeneric nc2pybind(NdArray<dtype>& inArray, ReturnPolicy returnPolicy)
166  {
167  const Shape inShape = inArray.shape();
168  const std::vector<pybind11::ssize_t> shape{ static_cast<pybind11::ssize_t>(inShape.rows),
169  static_cast<pybind11::ssize_t>(inShape.cols) };
170  const std::vector<pybind11::ssize_t> strides{ static_cast<pybind11::ssize_t>(inShape.cols * sizeof(dtype)),
171  static_cast<pybind11::ssize_t>(sizeof(dtype)) };
172 
173  switch (returnPolicy)
174  {
175  case ReturnPolicy::COPY:
176  {
177  return nc2pybind(inArray);
178  }
179  case ReturnPolicy::REFERENCE:
180  {
181  typename pybind11::capsule reference(inArray.data(), [](void* /*ptr*/) {});
182  return pbArrayGeneric(shape, strides, inArray.data(), reference);
183  }
184  case ReturnPolicy::TAKE_OWNERSHIP:
185  {
186  typename pybind11::capsule garbageCollect(inArray.dataRelease(),
187  [](void* ptr)
188  {
189  dtype* dataPtr = reinterpret_cast<dtype*>(ptr);
190  delete[] dataPtr;
191  });
192  return pbArrayGeneric(shape, strides, inArray.data(), garbageCollect);
193  }
194  default:
195  {
196  std::stringstream sstream;
197  sstream << "ReturnPolicy " << returnPolicyStringMap.at(returnPolicy)
198  << " has not been implemented yet" << std::endl;
199  THROW_INVALID_ARGUMENT_ERROR(sstream.str());
200  }
201  }
202  }
203  } // namespace pybindInterface
204 } // namespace nc
205 #endif
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:36
Definition: Coordinate.hpp:45
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:43
Shape shape(const NdArray< dtype > &inArray) noexcept
Definition: Functions/Shape.hpp:42
std::uint32_t uint32
Definition: Types.hpp:40