numpycpp
 All Classes Namespaces Files Functions Typedefs Pages
numpy.hpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2016 Michael Welter
3 
4  This file is part of numpycpp.
5 
6  numpycpp is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  numpycpp is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with numpycpp. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef __CXX_NUMPY_H__
20 #define __CXX_NUMPY_H__
21 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
22 
23 #include <boost/python.hpp>
24 #include <boost/python/object.hpp>
25 #include "assert.h"
26 
110 //
111 
112 namespace boost { namespace python {
113 
123 namespace numpy {
124 
128 namespace mw_py_impl
129 {
130  // see here http://stackoverflow.com/questions/16454987/c-generate-a-compile-error-if-user-tries-to-instantiate-a-class-template-wiho
131  template<class T>
132  class incomplete;
133 };
134 
135 
138 enum {
139  MAX_DIM = 32
140 };
141 
142 
145 typedef Py_ssize_t ssize_t;
146 
147 
158 
159 
168 template<class T>
170 {
171 // see here http://stackoverflow.com/questions/16454987/c-generate-a-compile-error-if-user-tries-to-instantiate-a-class-template-wiho
172  enum { S = sizeof(mw_py_impl::incomplete<T>) }; // will generate an error for types for which getItemtype was not implemented!
173  return -1;
174 }
175 
183 int getItemtype(const object &arr);
184 
185 
187 #define NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(T)\
188  template<> int getItemtype<T>();
189 
190 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(PyObject*)
191 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(float)
192 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(double)
193 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(int)
194 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(long)
195 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(long long)
196 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(short)
197 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(char)
198 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(bool)
199 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(unsigned int)
200 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(unsigned long)
201 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(unsigned short)
202 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(unsigned char)
203 NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE(unsigned long long)
204 #undef NUMPY_HPP_FWD_DECLARE_GET_ITEMTYPE
205 
213 object zeros(int rank, const Py_ssize_t *dims, int type);
214 
220 object empty(int rank, const Py_ssize_t *dims, int type);
221 
230 template<class T>
231 bool isCompatibleType(int id);
232 
249 {
250 protected:
251  object obj; // for reference counting
252  PyObject* objptr;
253 
254  arraytbase(object const &a, int typesize);
255  void construct(object const &a, int typesize);
256 
257 public:
258  /*
259  */
260  arraytbase(object const &a = object());
261  typedef Py_ssize_t ssize_t;
262 
263  const ssize_t* shape() const;
264  const ssize_t* dims() const { return shape(); }
265  const ssize_t* strides() const;
266  int itemtype() const;
267  int itemsize() const;
268  int rank() const;
269  int ndim() const { return rank(); }
270  bool isWriteable() const;
271  bool isCContiguous() const;
272  bool isFContiguous() const;
273  const object& getObject() const { return obj; }
274 
275 #define NUMPY_HPP_OFFSET1 \
276  x*m[0]
277 #define NUMPY_HPP_OFFSET2 \
278  NUMPY_HPP_OFFSET1 + y*m[1]
279 #define NUMPY_HPP_OFFSET3 \
280  NUMPY_HPP_OFFSET2 + z*m[2]
281 #define NUMPY_HPP_OFFSET4 \
282  NUMPY_HPP_OFFSET3 + w*m[3]
283 
285 
292  inline ssize_t offset(int x) const
293  {
294  const Py_ssize_t* m = strides();
295  assert((unsigned int)x<shape()[0]);
296  return NUMPY_HPP_OFFSET1;
297  }
298 
299  inline ssize_t offset(int x, int y) const
300  {
301  const Py_ssize_t* m = strides();
302  assert((Py_ssize_t)x<shape()[0]);
303  assert((Py_ssize_t)y<shape()[1]);
304  return NUMPY_HPP_OFFSET2;
305  }
306 
307  inline ssize_t offset(int x, int y, int z) const
308  {
309  const Py_ssize_t* m = strides();
310  assert((Py_ssize_t)x<shape()[0]);
311  assert((Py_ssize_t)y<shape()[1]);
312  assert((Py_ssize_t)z<shape()[2]);
313  return NUMPY_HPP_OFFSET3;
314  }
315 
316  inline ssize_t offset(int x,int y, int z, int w) const
317  {
318  const Py_ssize_t* m = strides();
319  assert((Py_ssize_t)x<shape()[0]);
320  assert((Py_ssize_t)y<shape()[1]);
321  assert((Py_ssize_t)z<shape()[2]);
322  assert((Py_ssize_t)w<shape()[3]);
323  return NUMPY_HPP_OFFSET4;
324  }
325 
326  inline ssize_t offset(const int *c) const
327  {
328  const Py_ssize_t* m = strides();
329  int r = rank();
330  Py_ssize_t q = 0;
331  for(int i=0; i<r; ++i)
332  {
333  assert((Py_ssize_t)(c[i])<shape()[i]);
334  q += c[i]*m[i];
335  }
336  return q;
337  }
338 
339 #undef NUMPY_HPP_OFFSET1
340 #undef NUMPY_HPP_OFFSET2
341 #undef NUMPY_HPP_OFFSET3
342 #undef NUMPY_HPP_OFFSET4
343 
345  char* bytes();
346  const char* bytes() const { return const_cast<arraytbase*>(this)->bytes(); }
347 };
348 
353 template<class T>
354 class arrayt : public arraytbase
355 {
356 public:
357  arrayt() : arraytbase() {}
369  arrayt(arraytbase const &a) : arraytbase(a.getObject(), sizeof(T))
370  {
371  }
372 
374  arrayt(object const &a) : arraytbase(a, sizeof(T))
375  {
376  }
377 
379  void init(object const &a_)
380  {
381  this->~arrayt<T>();
382  new (this) arrayt<T>(a_);
383  }
384 
389  T& operator()(int x)
390  {
391  return *((T*)(arraytbase::bytes()+offset(x)));
392  }
393 
394  T& operator()(int x, int y)
395  {
396  return *((T*)(arraytbase::bytes()+offset(x,y)));
397  }
398 
399  T& operator()(int x, int y, int z)
400  {
401  return *((T*)(arraytbase::bytes()+offset(x,y,z)));
402  }
403 
404  T& operator()(int x, int y, int z, int w)
405  {
406  return *((T*)(arraytbase::bytes()+offset(x,y,z,w)));
407  }
408 
409  T& operator()(int *c)
410  {
411  return *((T*)(arraytbase::bytes()+offset(c)));
412  }
413 
414  T& operator[](int i)
415  {
416  return *((T*)(arraytbase::bytes()+offset(i)));
417  }
418 
419  T* data() { return reinterpret_cast<T*>(bytes()); }
420 
421 
422  T operator()(int x) const
423  {
424  return *((T*)(arraytbase::bytes()+offset(x)));
425  }
426 
427  T operator()(int x, int y) const
428  {
429  return *((T*)(arraytbase::bytes()+offset(x,y)));
430  }
431 
432  T operator()(int x, int y, int z) const
433  {
434  return *((T*)(arraytbase::bytes()+offset(x,y,z)));
435  }
436 
437  T operator()(int x, int y, int z, int w) const
438  {
439  return *((T*)(arraytbase::bytes()+offset(x,y,z,w)));
440  }
441 
442  T operator()(int *c) const
443  {
444  return *((T*)(arraytbase::bytes()+offset(c)));
445  }
446 
447  T operator[](int i) const
448  {
449  return *((T*)(arraytbase::bytes()+offset(i)));
450  }
451 
452  const T* data() const { return reinterpret_cast<T*>(bytes()); }
453 };
454 
455 
456 namespace mw_py_impl
457 {
458  template<class T, class Idx1, class Idx2, class Idx3>
459  inline void gridded_data_ccons(T* dst, const T* src,
460  const Idx1 *dims,
461  const Idx2 *dst_strides,
462  const Idx3 *src_strides,
463  boost::mpl::int_<0>)
464  {
465  for (int i=0; i<dims[0]; ++i)
466  {
467  new (dst) T(*src);
468  dst += dst_strides[0];
469  src += src_strides[0];
470  }
471  }
472 
473  template<class T, class Idx1, class Idx2, class Idx3, int dim>
474  inline void gridded_data_ccons(T* dst, const T* src,
475  const Idx1* dims,
476  const Idx2 *dst_strides,
477  const Idx3 *src_strides,
478  boost::mpl::int_<dim>)
479  {
480  for (int i=0; i<dims[dim]; ++i)
481  {
482  gridded_data_ccons(dst, src, dims, dst_strides, src_strides, boost::mpl::int_<dim-1>());
483  dst += dst_strides[dim];
484  src += src_strides[dim];
485  }
486  }
487 }
488 
489 
498 template<class T, int rank>
499 static object copy(const int* dims, const T* src, const int *strides)
500 {
501  int item_type = getItemtype<T>();
502  typename arrayt<T>::ssize_t arr_dims[MAX_DIM];
503  for (int i=0; i<rank; ++i) arr_dims[i] = dims[i];
504  arrayt<T> arr(empty(rank, arr_dims, item_type));
505 
506  typename arrayt<T>::ssize_t arr_strides[MAX_DIM];
507  for (int i=0; i<rank; ++i) arr_strides[i] = arr.strides()[i]/arr.itemsize();
508 
509  T* dst = arr.data();
510  mw_py_impl::gridded_data_ccons<T>(dst, src, dims, arr_strides, strides, boost::mpl::int_<rank-1>());
511 
512  return arr.getObject();
513 }
514 
523 template<class T, int rank>
524 static void copy(T* dst, const int *dims, const int* strides, const object &pyarr)
525 {
526  arrayt<T> arr(pyarr);
527 
528  typename arrayt<T>::ssize_t arr_strides[MAX_DIM];
529  for (int i=0; i<rank; ++i) {
530  assert(arr.shape()[i] == dims[i]);
531  arr_strides[i] = arr.strides()[i]/arr.itemsize();
532  }
533 
534  const T* src = arr.data();
535  mw_py_impl::gridded_data_ccons<T>(dst, src, arr.shape(), strides, arr_strides, boost::mpl::int_<rank-1>());
536 }
537 
538 
539 } } }
540 
541 #endif
arrayt(object const &a)
Construct a new instance from a boost::python object.
Definition: numpy.hpp:374
ssize_t offset(int x) const
Returned in number of bytes.
Definition: numpy.hpp:292
arrayt(arraytbase const &a)
Construct a new instance from the base class.
Definition: numpy.hpp:369
int getItemtype(const object &a)
Obtain numpy's data type number from an boost-python object which should hold a ndarray.
Definition: numpy.cpp:241
This is the base class from which type specific variants are derived.
Definition: numpy.hpp:248
Py_ssize_t ssize_t
Synonymous for Py_ssize_t.
Definition: numpy.hpp:145
object empty(int rank, const Py_ssize_t *dims, int type)
Create a new ndarray with uninitialized memory.
Definition: numpy.cpp:232
char * bytes()
Access to the array's memory block.
Definition: numpy.cpp:333
void importNumpyAndRegisterTypes()
Initializes things.
Definition: numpy.cpp:196
This class defines operators () and [] to allow for direct memory access to array elements of type T...
Definition: numpy.hpp:354
bool isCompatibleType(int id)
Determines if a numpy data type identified by the type number id is binary compatible with the c-type...
Definition: numpy.cpp:340
const ssize_t * strides() const
Returned in number of bytes.
Definition: numpy.cpp:309
object zeros(int rank, const Py_ssize_t *dims, int type)
Creates a new ndarray filled with zeros.
Definition: numpy.cpp:224
ssize_t offset(const int *c) const
c must point to an array of at least rank() items.
Definition: numpy.hpp:326
static object copy(const int *dims, const T *src, const int *strides)
Copy contents of n-dimensional non-contiguous arrays.
Definition: numpy.hpp:499
void init(object const &a_)
Take hold of another array. Same rules as for the constructors apply.
Definition: numpy.hpp:379