~yade-dev/yade/0.80

« back to all changes in this revision

Viewing changes to lib/pyutil/numpy_boost.hpp

  • Committer: Anton Gladky
  • Date: 2012-05-02 21:50:42 UTC
  • Revision ID: gladky.anton@gmail.com-20120502215042-v1fa9r65usqe7kfk
0.80.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2008, Michael Droettboom
 
3
All rights reserved.
 
4
 
 
5
Licensed under the BSD license.
 
6
 
 
7
Redistribution and use in source and binary forms, with or without
 
8
modification, are permitted provided that the following conditions are
 
9
met:
 
10
 
 
11
    * Redistributions of source code must retain the above copyright
 
12
      notice, this list of conditions and the following disclaimer.
 
13
 
 
14
    * Redistributions in binary form must reproduce the above
 
15
      copyright notice, this list of conditions and the following
 
16
      disclaimer in the documentation and/or other materials provided
 
17
      with the distribution.
 
18
 
 
19
    * The names of its contributors may not be used to endorse or
 
20
      promote products derived from this software without specific
 
21
      prior written permission.
 
22
 
 
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
24
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
25
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
26
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
27
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
28
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
29
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
30
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
31
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
32
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
33
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
34
*/
 
35
 
 
36
/*
 
37
  Documentation to come
 
38
*/
 
39
 
 
40
#ifndef __NUMPY_BOOST_HPP__
 
41
#define __NUMPY_BOOST_HPP__
 
42
 
 
43
#include <Python.h>
 
44
#include <numpy/arrayobject.h>
 
45
#include <boost/multi_array.hpp>
 
46
#include <boost/cstdint.hpp>
 
47
#include <complex>
 
48
#include <algorithm>
 
49
 
 
50
namespace numpy_boost_detail {
 
51
  template<class T>
 
52
  class numpy_type_map {
 
53
  public:
 
54
    static const int typenum;
 
55
  };
 
56
 
 
57
  template<>
 
58
  const int numpy_type_map<float>::typenum = NPY_FLOAT;
 
59
 
 
60
  template<>
 
61
  const int numpy_type_map<std::complex<float> >::typenum = NPY_CFLOAT;
 
62
 
 
63
  template<>
 
64
  const int numpy_type_map<double>::typenum = NPY_DOUBLE;
 
65
 
 
66
  template<>
 
67
  const int numpy_type_map<std::complex<double> >::typenum = NPY_CDOUBLE;
 
68
 
 
69
  template<>
 
70
  const int numpy_type_map<long double>::typenum = NPY_LONGDOUBLE;
 
71
 
 
72
  template<>
 
73
  const int numpy_type_map<std::complex<long double> >::typenum = NPY_CLONGDOUBLE;
 
74
 
 
75
  template<>
 
76
  const int numpy_type_map<boost::int8_t>::typenum = NPY_INT8;
 
77
 
 
78
  template<>
 
79
  const int numpy_type_map<boost::uint8_t>::typenum = NPY_UINT8;
 
80
 
 
81
  template<>
 
82
  const int numpy_type_map<boost::int16_t>::typenum = NPY_INT16;
 
83
 
 
84
  template<>
 
85
  const int numpy_type_map<boost::uint16_t>::typenum = NPY_UINT16;
 
86
 
 
87
  template<>
 
88
  const int numpy_type_map<boost::int32_t>::typenum = NPY_INT32;
 
89
 
 
90
  template<>
 
91
  const int numpy_type_map<boost::uint32_t>::typenum = NPY_UINT32;
 
92
 
 
93
  template<>
 
94
  const int numpy_type_map<boost::int64_t>::typenum = NPY_INT64;
 
95
 
 
96
  template<>
 
97
  const int numpy_type_map<boost::uint64_t>::typenum = NPY_INT64;
 
98
}
 
99
 
 
100
class numpy_boost_exception : public std::exception {
 
101
 
 
102
};
 
103
 
 
104
template<class T, int NDims>
 
105
class numpy_boost : public boost::multi_array_ref<T, NDims>
 
106
{
 
107
public:
 
108
  typedef numpy_boost<T, NDims> self_type;
 
109
  typedef boost::multi_array_ref<T, NDims> super;
 
110
  typedef typename super::size_type size_type;
 
111
  typedef T* TPtr;
 
112
 
 
113
private:
 
114
  PyArrayObject* array;
 
115
 
 
116
  void init_from_array(PyArrayObject* a) {
 
117
    array = a;
 
118
    super::base_ = (TPtr)PyArray_DATA(a);
 
119
 
 
120
    // It would seem like we would want to choose C or Fortran
 
121
    // ordering here based on the flags in the Numpy array.  However,
 
122
    // those flags are purely informational, the actually information
 
123
    // about storage order is recorded in the strides.
 
124
    super::storage_ = boost::c_storage_order();
 
125
 
 
126
    boost::detail::multi_array::copy_n(PyArray_DIMS(a), NDims, super::extent_list_.begin());
 
127
    for (size_t i = 0; i < NDims; ++i) {
 
128
      super::stride_list_[i] = PyArray_STRIDE(a, i) / sizeof(T);
 
129
    }
 
130
    std::fill_n(super::index_base_list_.begin(), NDims, 0);
 
131
    super::origin_offset_ = 0;
 
132
    super::directional_offset_ = 0;
 
133
    super::num_elements_ = std::accumulate(super::extent_list_.begin(),
 
134
                                           super::extent_list_.end(),
 
135
                                           size_type(1),
 
136
                                           std::multiplies<size_type>());
 
137
  }
 
138
 
 
139
public:
 
140
  numpy_boost(PyObject* obj) :
 
141
    super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
 
142
    array(NULL)
 
143
  {
 
144
    PyArrayObject* a;
 
145
 
 
146
    a = (PyArrayObject*)PyArray_FromObject(obj, numpy_boost_detail::numpy_type_map<T>::typenum, NDims, NDims);
 
147
    if (a == NULL) {
 
148
      // TODO: Extract Python exception
 
149
      throw numpy_boost_exception();
 
150
    }
 
151
 
 
152
    init_from_array(a);
 
153
  }
 
154
 
 
155
  numpy_boost(const self_type &other) :
 
156
    super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
 
157
    array(NULL)
 
158
  {
 
159
    Py_INCREF(other.array);
 
160
    init_from_array(other.array);
 
161
  }
 
162
 
 
163
  template<class ExtentsList>
 
164
  explicit numpy_boost(const ExtentsList& extents) :
 
165
    super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
 
166
    array(NULL)
 
167
  {
 
168
    npy_intp shape[NDims];
 
169
    PyArrayObject* a;
 
170
 
 
171
    boost::detail::multi_array::copy_n(extents, NDims, shape);
 
172
 
 
173
    a = (PyArrayObject*)PyArray_SimpleNew(NDims, shape, numpy_boost_detail::numpy_type_map<T>::typenum);
 
174
    if (a == NULL) {
 
175
      // TODO: Extract Python exception
 
176
      throw numpy_boost_exception();
 
177
    }
 
178
 
 
179
    init_from_array(a);
 
180
  }
 
181
 
 
182
  ~numpy_boost() {
 
183
    Py_DECREF(array);
 
184
  }
 
185
 
 
186
  void operator=(const self_type &other) {
 
187
    Py_DECREF(array);
 
188
    Py_INCREF(other.array);
 
189
    init_from_array(other.array);
 
190
  }
 
191
 
 
192
  PyObject*
 
193
  py_ptr() {
 
194
    Py_INCREF(array);
 
195
    return (PyObject*)array;
 
196
  }
 
197
};
 
198
 
 
199
#endif