Michele De Stefano's C++ Utilities
numpy_array.hpp
Go to the documentation of this file.
1 // mds_utils/python/ublas/numpy_array.hpp
2 //
3 // Copyright (c) 2014 - Michele De Stefano (micdestefano@users.sourceforge.net)
4 //
5 // Distributed under the MIT License (See accompanying file COPYING)
6 
7 #ifndef MDS_UTILS_PYTHON_UBLAS_NUMPY_ARRAY_HPP_INCLUDED
8 #define MDS_UTILS_PYTHON_UBLAS_NUMPY_ARRAY_HPP_INCLUDED
9 
30 #include <numpy/arrayobject.h>
31 #include <mds_utils/python/obj.hpp>
33 #include <boost/numeric/ublas/traits.hpp>
34 #include <boost/numeric/ublas/detail/vector_assign.hpp>
35 
36 
37 namespace boost { namespace numeric { namespace ublas {
38 
54 template<class T>
55 class NumPy1DArray : public mds_utils::python::Obj, public vector_container< NumPy1DArray<T> > {
56 
57  typedef NumPy1DArray self_type;
58 
59 public:
60 
61  typedef npy_intp size_type;
62  typedef npy_intp difference_type;
63  typedef T value_type;
64  typedef const T& const_reference;
65  typedef T& reference;
66  typedef T* pointer;
67  typedef const T* const_pointer;
68  typedef pointer array_type;
69  typedef const vector_reference<const self_type> const_closure_type;
70  typedef vector_reference<self_type> closure_type;
71  typedef self_type vector_temporary_type;
72  typedef dense_tag storage_category;
73 
74 
75 
77  PyArrayObject* getPyArrayObject() const {
78  return reinterpret_cast<PyArrayObject*>(getPyObject());
79  }
80 
82  operator PyArrayObject*() const {
83  return getPyArrayObject();
84  }
85 
86 
93  void incref() {
94  PyArray_INCREF(reinterpret_cast<PyArrayObject*>(getPyObject()));
96  }
97 
99  void decref() {
100  if (decref_on_destroy > 0) {
101  PyArray_XDECREF(reinterpret_cast<PyArrayObject*>(getPyObject()));
103  }
104  }
105 
114  PyObject* transfer() {
115  PyObject *pret(getPyObject());
116  PyArray_INCREF(reinterpret_cast<PyArrayObject*>(pret));
117  reset();
118  return pret;
119  }
120 
121 
122  // Construction and destruction
123 
130  BOOST_UBLAS_INLINE
132 
133 
144  explicit BOOST_UBLAS_INLINE
145  NumPy1DArray(size_type n) :
146  mds_utils::python::Obj(PyArray_SimpleNew(1,&n,
147  mds_utils::python::numpy::numpy_dtype_traits<T>::typenum)) {
148 
149  get_ownership();
150  }
151 
152 
162  template<class FwIt>
163  BOOST_UBLAS_INLINE
164  NumPy1DArray(FwIt b,FwIt e) : NumPy1DArray(std::distance(b,e)) {
165 
166  using namespace mds_utils::python::numpy;
167 
168  if (b != e) std::copy(b,e,NDArrayIterator<T,c_storage,
169  NPY_ITER_WRITEONLY>(getPyArrayObject()));
170  }
171 
172 
182  explicit BOOST_UBLAS_INLINE
183  NumPy1DArray(size_type n,const_reference init) : NumPy1DArray(n) {
184 
185  using namespace mds_utils::python::numpy;
186 
188  b(getPyArrayObject()),
189  e(b,true);
190 
191  if (b != e) std::fill(b,e,init);
192  }
193 
194 
201  BOOST_UBLAS_INLINE
202  size_type size() const {
203  PyArrayObject *po(getPyArrayObject());
204  if (po == NULL) return 0;
205  return PyArray_SIZE(po);
206  }
207 
219  BOOST_UBLAS_INLINE
221 
222  if (PyArray_CopyInto(getPyArrayObject(),rhs.getPyArrayObject())) {
223  throw std::runtime_error("Cannot copy the NumPy array.");
224  }
225  }
226 
237  BOOST_UBLAS_INLINE
238  NumPy1DArray(NumPy1DArray&& rhs) : mds_utils::python::Obj(std::move(rhs)) {}
239 
252  template<class AE>
253  BOOST_UBLAS_INLINE
254  NumPy1DArray(const vector_expression<AE> &ae) : NumPy1DArray(ae().size()) {
255 
256  vector_assign<scalar_assign>(*this,ae);
257  }
258 
259 
271  explicit NumPy1DArray(PyObject *rhs) : mds_utils::python::Obj(rhs) {
272 
273  if (!PyArray_Check(rhs)) {
274  throw std::invalid_argument("Cannot convert to "
275  "boost::numeric::ublas::NumPy1DArrayr: rhs is not a NumPy array.");
276  }
277 
278  incref();
279  }
280 
281 
282 private:
283 
284  void check_index(size_type i) const {
285  assert(getPyObject() != NULL && i >= 0 && i < size());
286  }
287 
288 public:
289 
290  // -----------------
291  // Storage accessors
292  // -----------------
293 
294 
305  BOOST_UBLAS_INLINE
306  pointer find_element(size_type i) {
307  return const_cast<pointer>(const_cast<const self_type&>(*this).find_element(i));
308  }
309 
310 
319  BOOST_UBLAS_INLINE
320  const_pointer find_element(size_type i) const {
321  check_index(i);
322  return const_cast<const pointer>(reinterpret_cast<pointer>(PyArray_GETPTR1(getPyArrayObject(),i)));
323  }
324 
325 
326  // --------------
327  // Element access
328  // --------------
329 
338  BOOST_UBLAS_INLINE
339  const_reference operator () (size_type i) const {
340  check_index(i);
341  return *reinterpret_cast<pointer>(PyArray_GETPTR1(getPyArrayObject(),i));
342  }
343 
344 
353  BOOST_UBLAS_INLINE
354  reference operator () (size_type i) {
355  check_index(i);
356  return *reinterpret_cast<pointer>(PyArray_GETPTR1(getPyArrayObject(),i));
357  }
358 
359 
368  BOOST_UBLAS_INLINE
369  const_reference operator [] (size_type i) const {
370  return (*this)(i);
371  }
372 
373 
382  BOOST_UBLAS_INLINE
383  reference operator [] (size_type i) {
384  return (*this) (i);
385  }
386 
387  // -------
388  // Zeroing
389  // -------
390 
397  BOOST_UBLAS_INLINE
398  void clear() {
399 
400  using namespace mds_utils::python::numpy;
401 
403  b(getPyArrayObject()),
404  e(b,true);
405 
406  if (b != e) std::fill(b,e,static_cast<T>(0));
407  }
408 
409  // Assignment
410 
425  template<class AE>
426  BOOST_UBLAS_INLINE
427  NumPy1DArray& assign(const vector_expression<AE> &ae) {
428  vector_assign<scalar_assign>(*this, ae);
429  return *this;
430  }
431 
442  BOOST_UBLAS_INLINE
444  *this = rhs.getPyObject();
445  incref();
446  return *this;
447  }
448 
449 
462  BOOST_UBLAS_INLINE
464 
465  size_type n(rhs.size());
466 
467  if (size() != n) {
468  reset();
469 
470  m_po = PyArray_SimpleNew(1,&n,
472 
473  get_ownership();
474  }
475 
476  if (PyArray_CopyInto(getPyArrayObject(),rhs.getPyArrayObject())) {
477  throw std::runtime_error("Cannot copy the NumPy array.");
478  }
479 
480  return *this;
481  }
482 
483 
494  BOOST_UBLAS_INLINE
496 
497  mds_utils::python::Obj::operator =(std::move(rhs));
498 
499  return *this;
500  }
501 
502 
515  NumPy1DArray& operator =(PyObject *rhs) {
516 
517  if (!PyArray_Check(rhs) && getPyObject() != rhs) {
518  throw std::invalid_argument("Cannot assign: rhs is not a NumPy array.");
519  }
520 
522 
523  return *this;
524  }
525 
526 
539  template<class val_T>
540  NumPy1DArray& operator =(const val_T& val) {
541 
542  using namespace std;
543 
544  if (size() == 0) return *this;
545 
546  for_each(begin(),end(),[&val](T& x){ x = val; });
547 
548  return *this;
549  }
550 
551 
564  template<class C>
565  BOOST_UBLAS_INLINE
566  NumPy1DArray& operator =(const vector_container<C>& rhs) {
567  assert(size() == rhs.size());
568 
569  assign(rhs);
570  return *this;
571  }
572 
573 
588  template<class AE>
589  BOOST_UBLAS_INLINE
590  NumPy1DArray& operator =(const vector_expression<AE> &ae) {
591  self_type temporary(ae);
592  return assign_temporary(temporary);
593  }
594 
595 
596  // -------------------
597  // Computed assignment
598  // -------------------
599 
614  template<class AE>
615  BOOST_UBLAS_INLINE
616  NumPy1DArray& operator += (const vector_expression<AE> &ae) {
617  self_type temporary(*this + ae);
618  return assign_temporary (temporary);
619  }
620 
635  template<class C> // Container assignment without temporary
636  BOOST_UBLAS_INLINE
637  NumPy1DArray& operator += (const vector_container<C>& v) {
638  plus_assign (v);
639  return *this;
640  }
641 
642 
657  template<class AE>
658  BOOST_UBLAS_INLINE
659  NumPy1DArray& plus_assign(const vector_expression<AE>& ae) {
660  vector_assign<scalar_plus_assign> (*this, ae);
661  return *this;
662  }
663 
664 
677  template<class AE>
678  BOOST_UBLAS_INLINE
679  NumPy1DArray& operator -= (const vector_expression<AE>& ae) {
680  self_type temporary (*this - ae);
681  return assign_temporary (temporary);
682  }
683 
684 
699  template<class C> // Container assignment without temporary
700  BOOST_UBLAS_INLINE
701  NumPy1DArray& operator -= (const vector_container<C>& v) {
702  minus_assign (v);
703  return *this;
704  }
705 
706 
721  template<class AE>
722  BOOST_UBLAS_INLINE
723  NumPy1DArray& minus_assign (const vector_expression<AE>& ae) {
724  vector_assign<scalar_minus_assign> (*this, ae);
725  return *this;
726  }
727 
728 
743  template<class AT>
744  BOOST_UBLAS_INLINE
745  NumPy1DArray& operator *= (const AT &at) {
746  vector_assign_scalar<scalar_multiplies_assign> (*this, at);
747  return *this;
748  }
749 
750 
765  template<class AT>
766  BOOST_UBLAS_INLINE
767  NumPy1DArray& operator /= (const AT &at) {
768  vector_assign_scalar<scalar_divides_assign> (*this, at);
769  return *this;
770  }
771 
772 
773  // --------
774  // Swapping
775  // --------
776 
785  BOOST_UBLAS_INLINE
786  void swap(NumPy1DArray& rhs) {
787  using namespace mds_utils::python::numpy;
788 
789  if (this != &rhs) {
791  it(getPyArrayObject()),
792  e(it,true),
793  it_rhs(rhs.getPyArrayObject());
794 
795  T aux;
796 
797  for (;it != e;++it,++it_rhs) {
798  aux = *it;
799  *it = *it_rhs;
800  *it_rhs = aux;
801  }
802  }
803  }
804 
814  BOOST_UBLAS_INLINE
815  friend void swap(NumPy1DArray& v1,NumPy1DArray& v2) {
816  v1.swap(v2);
817  }
818 
819 private:
820  // Use the storage array iterator
822  mds_utils::python::numpy::c_storage,NPY_ITER_READONLY>
824 
826  mds_utils::python::numpy::c_storage,NPY_ITER_READWRITE>
828 
829 public:
830 
831 
832  typedef indexed_iterator<self_type,dense_random_access_iterator_tag> iterator;
833  typedef indexed_const_iterator<self_type, dense_random_access_iterator_tag> const_iterator;
834 
835  // --------------
836  // Element lookup
837  // --------------
838 
847  BOOST_UBLAS_INLINE
848  const_iterator find(size_type i) const {
849  return const_iterator(*this,i);
850  }
851 
860  BOOST_UBLAS_INLINE
861  iterator find(size_type i) {
862  return iterator(*this,i);
863  }
864 
866  BOOST_UBLAS_INLINE
867  const_iterator begin() const {
868  return find(0);
869  }
870 
872  BOOST_UBLAS_INLINE
873  const_iterator end() const {
874  return find(size());
875  }
876 
878  BOOST_UBLAS_INLINE
879  iterator begin () {
880  return find (0);
881  }
882 
884  BOOST_UBLAS_INLINE
885  iterator end () {
886  return find (size());
887  }
888 
889  // Reverse iterator
890  typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
891  typedef reverse_iterator_base<iterator> reverse_iterator;
892 
894  BOOST_UBLAS_INLINE
895  const_reverse_iterator rbegin () const {
896  return const_reverse_iterator (end ());
897  }
898 
900  BOOST_UBLAS_INLINE
901  const_reverse_iterator rend () const {
902  return const_reverse_iterator (begin ());
903  }
904 
906  BOOST_UBLAS_INLINE
907  reverse_iterator rbegin () {
908  return reverse_iterator (end ());
909  }
910 
912  BOOST_UBLAS_INLINE
913  reverse_iterator rend () {
914  return reverse_iterator (begin ());
915  }
916 
917 };
918 
919 
920 }}}
921 
922 #endif /* MDS_UTILS_PYTHON_UBLAS_NUMPY_ARRAY_HPP_INCLUDED */
void reset()
Resets the object to the state given by the default constructor.
Definition: obj.hpp:377
BOOST_UBLAS_INLINE NumPy1DArray & operator*=(const AT &at)
Assign the product of the vector and a scalar to the vector.
Tag for the C storage ordering.
BOOST_UBLAS_INLINE NumPy1DArray & operator-=(const vector_expression< AE > &ae)
Assign the difference of the vector and a vector_expression to the vector.
Contains the wrapper for the NumPy iterator for ndarray objects.
BOOST_UBLAS_INLINE const_pointer find_element(size_type i) const
Return a const pointer to the element .
BOOST_UBLAS_INLINE NumPy1DArray(const vector_expression< AE > &ae)
Copy-constructor of a NumPy1DArray from a vector_expression.
BOOST_UBLAS_INLINE NumPy1DArray(FwIt b, FwIt e)
Constructor of a vector by copying from another container.
size_t decref_on_destroy
Definition: obj.hpp:84
BOOST_UBLAS_INLINE NumPy1DArray(const NumPy1DArray &rhs)
Copy-constructor.
BOOST_UBLAS_INLINE NumPy1DArray(NumPy1DArray &&rhs)
Move constructor.
BOOST_UBLAS_INLINE NumPy1DArray(size_type n)
Constructor of a vector with a predefined size.
Main namespace of all Michele De Stefano&#39;s C++ utilities.
Definition: endian.hpp:30
Obj()
Default constructor.
Definition: obj.hpp:198
BOOST_UBLAS_INLINE NumPy1DArray & operator=(const NumPy1DArray &rhs)
Assign a full vector (RHS-vector) to the current vector (LHS-vector).
BOOST_UBLAS_INLINE const_iterator find(size_type i) const
Return a const iterator to the element i.
BOOST_UBLAS_INLINE const_iterator end() const
return an iterator after the last element of the vector
PyObject * transfer()
Returns the Python object with transferred ownership.
NumPy1DArray(PyObject *rhs)
Constructor from PyObject.
PyObject * m_po
Underlying pointer to the wrapped Python object.
Definition: obj.hpp:165
BOOST_UBLAS_INLINE NumPy1DArray(size_type n, const_reference init)
Constructor of a vector with a unique initial value.
PyArrayObject * getPyArrayObject() const
Returns the underlying PyArrayObject.
Definition: numpy_array.hpp:77
Contains a wrapper class for the PyObject* datatype.
BOOST_UBLAS_INLINE NumPy1DArray & plus_assign(const vector_expression< AE > &ae)
Assign the sum of the vector and a vector_expression to the vector.
void get_ownership()
Used in place of incref, when the wrapped PyObject* was increfed already.
Definition: obj.hpp:380
Contains utilities for the creation of NumPy extensions.
BOOST_UBLAS_INLINE NumPy1DArray()
Default constructor.
Obj operator()()
Calling operator.
Definition: obj.hpp:435
Wrapper class for NumPy 1D arrays.
Definition: numpy_array.hpp:55
BOOST_UBLAS_INLINE NumPy1DArray & operator+=(const vector_expression< AE > &ae)
Assign the sum of the vector and a vector_expression to the vector.
BOOST_UBLAS_INLINE NumPy1DArray & assign(const vector_expression< AE > &ae)
Assign the result of a vector_expression to the vector.
Obj & operator=(const Obj &rhs)
Standard assignment.
Definition: obj.hpp:257
BOOST_UBLAS_INLINE size_type size() const
Return the size of the vector.
BOOST_UBLAS_INLINE void clear()
Clear the vector, i.e. set all values to the zero value.
BOOST_UBLAS_INLINE friend void swap(NumPy1DArray &v1, NumPy1DArray &v2)
Swap the content of two vectors.
void incref()
Increments the reference count using Py_XINCREF.
Definition: numpy_array.hpp:93
BOOST_UBLAS_INLINE void swap(NumPy1DArray &rhs)
Swap the content of the vector with another vector.
BOOST_UBLAS_INLINE iterator find(size_type i)
Return an iterator to the element i.
BOOST_UBLAS_INLINE const_reference operator[](size_type i) const
Return a const reference to the element .
BOOST_UBLAS_INLINE pointer find_element(size_type i)
Return a pointer to the element .
BOOST_UBLAS_INLINE NumPy1DArray & assign_temporary(NumPy1DArray &rhs)
Assign a full vector (RHS-vector) to the current vector (LHS-vector).
PyObject * getPyObject() const
Returns the underlying PyObject.
Definition: obj.hpp:326
BOOST_UBLAS_INLINE NumPy1DArray & operator/=(const AT &at)
Assign the division of the vector by a scalar to the vector.
BOOST_UBLAS_INLINE iterator end()
Return an iterator at the end of the vector.
BOOST_UBLAS_INLINE NumPy1DArray & minus_assign(const vector_expression< AE > &ae)
Assign the difference of the vector and a vector_expression to the vector.
BOOST_UBLAS_INLINE reverse_iterator rend()
Return a const reverse iterator on the end of the reverse vector (i.e. first element of the normal ve...
BOOST_UBLAS_INLINE iterator begin()
Return an iterator on the first element of the vector.
BOOST_UBLAS_INLINE const_reverse_iterator rbegin() const
Return a const reverse iterator before the first element of the reversed vector (i.e. end() of normal vector)
BOOST_UBLAS_INLINE const_reverse_iterator rend() const
Return a const reverse iterator on the end of the reverse vector (i.e. first element of the normal ve...
void decref()
Decrements the reference count using Py_XDECREF.
Definition: numpy_array.hpp:99
BOOST_UBLAS_INLINE reverse_iterator rbegin()
Return a const reverse iterator before the first element of the reversed vector (i.e. end() of normal vector)
BOOST_UBLAS_INLINE const_iterator begin() const
return an iterator on the first element of the vector
Provides traits for a specific C/C++ datatype.
Definition: traits.hpp:48
This is a simple wrapper around the PyObject* datatype.
Definition: obj.hpp:68