]>
Commit | Line | Data |
---|---|---|
1 | // Copyright Jim Bosch 2010-2012. | |
2 | // Copyright Stefan Seefeld 2016. | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #define BOOST_PYTHON_NUMPY_INTERNAL | |
8 | #include <boost/python/numpy/internal.hpp> | |
9 | #include <boost/scoped_array.hpp> | |
10 | ||
11 | namespace boost { namespace python { | |
12 | namespace converter | |
13 | { | |
14 | NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArray_Type, numpy::ndarray) | |
15 | } // namespace boost::python::converter | |
16 | ||
17 | namespace numpy | |
18 | { | |
19 | namespace detail | |
20 | { | |
21 | ||
22 | ndarray::bitflag numpy_to_bitflag(int const f) | |
23 | { | |
24 | ndarray::bitflag r = ndarray::NONE; | |
25 | if (f & NPY_ARRAY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS); | |
26 | if (f & NPY_ARRAY_F_CONTIGUOUS) r = (r | ndarray::F_CONTIGUOUS); | |
27 | if (f & NPY_ARRAY_ALIGNED) r = (r | ndarray::ALIGNED); | |
28 | if (f & NPY_ARRAY_WRITEABLE) r = (r | ndarray::WRITEABLE); | |
29 | return r; | |
30 | } | |
31 | ||
32 | int bitflag_to_numpy(ndarray::bitflag f) | |
33 | { | |
34 | int r = 0; | |
35 | if (f & ndarray::C_CONTIGUOUS) r |= NPY_ARRAY_C_CONTIGUOUS; | |
36 | if (f & ndarray::F_CONTIGUOUS) r |= NPY_ARRAY_F_CONTIGUOUS; | |
37 | if (f & ndarray::ALIGNED) r |= NPY_ARRAY_ALIGNED; | |
38 | if (f & ndarray::WRITEABLE) r |= NPY_ARRAY_WRITEABLE; | |
39 | return r; | |
40 | } | |
41 | ||
42 | bool is_c_contiguous(std::vector<Py_intptr_t> const & shape, | |
43 | std::vector<Py_intptr_t> const & strides, | |
44 | int itemsize) | |
45 | { | |
46 | std::vector<Py_intptr_t>::const_reverse_iterator j = strides.rbegin(); | |
47 | int total = itemsize; | |
48 | for (std::vector<Py_intptr_t>::const_reverse_iterator i = shape.rbegin(); i != shape.rend(); ++i, ++j) | |
49 | { | |
50 | if (total != *j) return false; | |
51 | total *= (*i); | |
52 | } | |
53 | return true; | |
54 | } | |
55 | ||
56 | bool is_f_contiguous(std::vector<Py_intptr_t> const & shape, | |
57 | std::vector<Py_intptr_t> const & strides, | |
58 | int itemsize) | |
59 | { | |
60 | std::vector<Py_intptr_t>::const_iterator j = strides.begin(); | |
61 | int total = itemsize; | |
62 | for (std::vector<Py_intptr_t>::const_iterator i = shape.begin(); i != shape.end(); ++i, ++j) | |
63 | { | |
64 | if (total != *j) return false; | |
65 | total *= (*i); | |
66 | } | |
67 | return true; | |
68 | } | |
69 | ||
70 | bool is_aligned(std::vector<Py_intptr_t> const & strides, | |
71 | int itemsize) | |
72 | { | |
73 | for (std::vector<Py_intptr_t>::const_iterator i = strides.begin(); i != strides.end(); ++i) | |
74 | { | |
75 | if (*i % itemsize) return false; | |
76 | } | |
77 | return true; | |
78 | } | |
79 | ||
80 | inline PyArray_Descr * incref_dtype(dtype const & dt) | |
81 | { | |
82 | Py_INCREF(dt.ptr()); | |
83 | return reinterpret_cast<PyArray_Descr*>(dt.ptr()); | |
84 | } | |
85 | ||
86 | ndarray from_data_impl(void * data, | |
87 | dtype const & dt, | |
88 | python::object const & shape, | |
89 | python::object const & strides, | |
90 | python::object const & owner, | |
91 | bool writeable) | |
92 | { | |
93 | std::vector<Py_intptr_t> shape_(len(shape)); | |
94 | std::vector<Py_intptr_t> strides_(len(strides)); | |
95 | if (shape_.size() != strides_.size()) | |
96 | { | |
97 | PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); | |
98 | python::throw_error_already_set(); | |
99 | } | |
100 | for (std::size_t i = 0; i < shape_.size(); ++i) | |
101 | { | |
102 | shape_[i] = python::extract<Py_intptr_t>(shape[i]); | |
103 | strides_[i] = python::extract<Py_intptr_t>(strides[i]); | |
104 | } | |
105 | return from_data_impl(data, dt, shape_, strides_, owner, writeable); | |
106 | } | |
107 | ||
108 | ndarray from_data_impl(void * data, | |
109 | dtype const & dt, | |
110 | std::vector<Py_intptr_t> const & shape, | |
111 | std::vector<Py_intptr_t> const & strides, | |
112 | python::object const & owner, | |
113 | bool writeable) | |
114 | { | |
115 | if (shape.size() != strides.size()) | |
116 | { | |
117 | PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); | |
118 | python::throw_error_already_set(); | |
119 | } | |
120 | int itemsize = dt.get_itemsize(); | |
121 | int flags = 0; | |
122 | if (writeable) flags |= NPY_ARRAY_WRITEABLE; | |
123 | if (is_c_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_C_CONTIGUOUS; | |
124 | if (is_f_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_F_CONTIGUOUS; | |
125 | if (is_aligned(strides, itemsize)) flags |= NPY_ARRAY_ALIGNED; | |
126 | ndarray r(python::detail::new_reference | |
127 | (PyArray_NewFromDescr(&PyArray_Type, | |
128 | incref_dtype(dt), | |
129 | shape.size(), | |
130 | const_cast<Py_intptr_t*>(&shape.front()), | |
131 | const_cast<Py_intptr_t*>(&strides.front()), | |
132 | data, | |
133 | flags, | |
134 | NULL))); | |
135 | r.set_base(owner); | |
136 | return r; | |
137 | } | |
138 | ||
139 | } // namespace detail | |
140 | ||
141 | namespace { | |
142 | int normalize_index(int n,int nlim) // wraps [-nlim:nlim) into [0:nlim), throw IndexError otherwise | |
143 | { | |
144 | if (n<0) | |
145 | n += nlim; // negative indices work backwards from end | |
146 | if (n < 0 || n >= nlim) | |
147 | { | |
148 | PyErr_SetObject(PyExc_IndexError, Py_None); | |
149 | throw_error_already_set(); | |
150 | } | |
151 | return n; | |
152 | } | |
153 | } | |
154 | ||
155 | Py_intptr_t ndarray::shape(int n) const | |
156 | { | |
157 | return get_shape()[normalize_index(n,get_nd())]; | |
158 | } | |
159 | ||
160 | Py_intptr_t ndarray::strides(int n) const | |
161 | { | |
162 | return get_strides()[normalize_index(n,get_nd())]; | |
163 | } | |
164 | ||
165 | ndarray ndarray::view(dtype const & dt) const | |
166 | { | |
167 | return ndarray(python::detail::new_reference | |
168 | (PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr()))); | |
169 | } | |
170 | ||
171 | ndarray ndarray::astype(dtype const & dt) const | |
172 | { | |
173 | return ndarray(python::detail::new_reference | |
174 | (PyObject_CallMethod(this->ptr(), const_cast<char*>("astype"), const_cast<char*>("O"), dt.ptr()))); | |
175 | } | |
176 | ||
177 | ndarray ndarray::copy() const | |
178 | { | |
179 | return ndarray(python::detail::new_reference | |
180 | (PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>("")))); | |
181 | } | |
182 | ||
183 | dtype ndarray::get_dtype() const | |
184 | { | |
185 | return dtype(python::detail::borrowed_reference(get_struct()->descr)); | |
186 | } | |
187 | ||
188 | python::object ndarray::get_base() const | |
189 | { | |
190 | if (get_struct()->base == NULL) return object(); | |
191 | return python::object(python::detail::borrowed_reference(get_struct()->base)); | |
192 | } | |
193 | ||
194 | void ndarray::set_base(object const & base) | |
195 | { | |
196 | Py_XDECREF(get_struct()->base); | |
197 | if (base.ptr()) | |
198 | { | |
199 | Py_INCREF(base.ptr()); | |
200 | get_struct()->base = base.ptr(); | |
201 | } | |
202 | else | |
203 | { | |
204 | get_struct()->base = NULL; | |
205 | } | |
206 | } | |
207 | ||
208 | ndarray::bitflag ndarray::get_flags() const | |
209 | { | |
210 | return numpy::detail::numpy_to_bitflag(get_struct()->flags); | |
211 | } | |
212 | ||
213 | ndarray ndarray::transpose() const | |
214 | { | |
215 | return ndarray(python::detail::new_reference | |
216 | (PyArray_Transpose(reinterpret_cast<PyArrayObject*>(this->ptr()), NULL))); | |
217 | } | |
218 | ||
219 | ndarray ndarray::squeeze() const | |
220 | { | |
221 | return ndarray(python::detail::new_reference | |
222 | (PyArray_Squeeze(reinterpret_cast<PyArrayObject*>(this->ptr())))); | |
223 | } | |
224 | ||
225 | ndarray ndarray::reshape(python::tuple const & shape) const | |
226 | { | |
227 | return ndarray(python::detail::new_reference | |
228 | (PyArray_Reshape(reinterpret_cast<PyArrayObject*>(this->ptr()), shape.ptr()))); | |
229 | } | |
230 | ||
231 | python::object ndarray::scalarize() const | |
232 | { | |
233 | Py_INCREF(ptr()); | |
234 | return python::object(python::detail::new_reference(PyArray_Return(reinterpret_cast<PyArrayObject*>(ptr())))); | |
235 | } | |
236 | ||
237 | ndarray zeros(python::tuple const & shape, dtype const & dt) | |
238 | { | |
239 | int nd = len(shape); | |
240 | boost::scoped_array<Py_intptr_t> dims(new Py_intptr_t[nd]); | |
241 | for (int n=0; n<nd; ++n) dims[n] = python::extract<Py_intptr_t>(shape[n]); | |
242 | return ndarray(python::detail::new_reference | |
243 | (PyArray_Zeros(nd, dims.get(), detail::incref_dtype(dt), 0))); | |
244 | } | |
245 | ||
246 | ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt) | |
247 | { | |
248 | return ndarray(python::detail::new_reference | |
249 | (PyArray_Zeros(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0))); | |
250 | } | |
251 | ||
252 | ndarray empty(python::tuple const & shape, dtype const & dt) | |
253 | { | |
254 | int nd = len(shape); | |
255 | boost::scoped_array<Py_intptr_t> dims(new Py_intptr_t[nd]); | |
256 | for (int n=0; n<nd; ++n) dims[n] = python::extract<Py_intptr_t>(shape[n]); | |
257 | return ndarray(python::detail::new_reference | |
258 | (PyArray_Empty(nd, dims.get(), detail::incref_dtype(dt), 0))); | |
259 | } | |
260 | ||
261 | ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt) | |
262 | { | |
263 | return ndarray(python::detail::new_reference | |
264 | (PyArray_Empty(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0))); | |
265 | } | |
266 | ||
267 | ndarray array(python::object const & obj) | |
268 | { | |
269 | return ndarray(python::detail::new_reference | |
270 | (PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); | |
271 | } | |
272 | ||
273 | ndarray array(python::object const & obj, dtype const & dt) | |
274 | { | |
275 | return ndarray(python::detail::new_reference | |
276 | (PyArray_FromAny(obj.ptr(), detail::incref_dtype(dt), 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); | |
277 | } | |
278 | ||
279 | ndarray from_object(python::object const & obj, dtype const & dt, int nd_min, int nd_max, ndarray::bitflag flags) | |
280 | { | |
281 | int requirements = detail::bitflag_to_numpy(flags); | |
282 | return ndarray(python::detail::new_reference | |
283 | (PyArray_FromAny(obj.ptr(), | |
284 | detail::incref_dtype(dt), | |
285 | nd_min, nd_max, | |
286 | requirements, | |
287 | NULL))); | |
288 | } | |
289 | ||
290 | ndarray from_object(python::object const & obj, int nd_min, int nd_max, ndarray::bitflag flags) | |
291 | { | |
292 | int requirements = detail::bitflag_to_numpy(flags); | |
293 | return ndarray(python::detail::new_reference | |
294 | (PyArray_FromAny(obj.ptr(), | |
295 | NULL, | |
296 | nd_min, nd_max, | |
297 | requirements, | |
298 | NULL))); | |
299 | } | |
300 | ||
301 | }}} // namespace boost::python::numpy |