LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
numpy.h
Go to the documentation of this file.
1 // -*- c++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008, 2009, 2010 LSST Corporation.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #ifndef NDARRAY_SWIG_numpy_h_INCLUDED
25 #define NDARRAY_SWIG_numpy_h_INCLUDED
26 
32 #include "ndarray.h"
34 
35 namespace ndarray {
36 namespace detail {
37 
42 template <typename T> struct NumpyTraits {
43  static int getCode();
44 };
45 
47 
48 template <> struct NumpyTraits<bool> {
49  static int getCode() {
50  if (sizeof(bool)==sizeof(npy_bool)) return NPY_BOOL;
51  if (sizeof(bool)==1) return NPY_UBYTE;
52  if (sizeof(bool)==2 && sizeof(short)==2) return NPY_USHORT;
53  if (sizeof(bool)==4 && sizeof(int)==4) return NPY_UINT;
54  assert(false);
55  return 0;
56  }
57 };
58 
59 template <> struct NumpyTraits<npy_ubyte> { static int getCode() { return NPY_UBYTE; } };
60 template <> struct NumpyTraits<npy_byte> { static int getCode() { return NPY_BYTE; } };
61 template <> struct NumpyTraits<npy_ushort> { static int getCode() { return NPY_USHORT; } };
62 template <> struct NumpyTraits<npy_short> { static int getCode() { return NPY_SHORT; } };
63 template <> struct NumpyTraits<npy_uint> { static int getCode() { return NPY_UINT; } };
64 template <> struct NumpyTraits<npy_int> { static int getCode() { return NPY_INT; } };
65 template <> struct NumpyTraits<npy_ulong> { static int getCode() { return NPY_ULONG; } };
66 template <> struct NumpyTraits<npy_long> { static int getCode() { return NPY_LONG; } };
67 template <> struct NumpyTraits<npy_ulonglong> { static int getCode() { return NPY_ULONGLONG; } };
68 template <> struct NumpyTraits<npy_longlong> { static int getCode() { return NPY_LONGLONG; } };
69 template <> struct NumpyTraits<npy_float> { static int getCode() { return NPY_FLOAT; } };
70 template <> struct NumpyTraits<npy_double> { static int getCode() { return NPY_DOUBLE; } };
71 template <> struct NumpyTraits<npy_longdouble> { static int getCode() { return NPY_LONGDOUBLE; } };
72 template <> struct NumpyTraits<npy_cfloat> { static int getCode() { return NPY_CFLOAT; } };
73 template <> struct NumpyTraits<npy_cdouble> { static int getCode() { return NPY_CDOUBLE; } };
74 template <> struct NumpyTraits<npy_clongdouble> { static int getCode() { return NPY_CLONGDOUBLE; } };
75 
76 template <> struct NumpyTraits<std::complex<float> > {
77  static int getCode() { assert(sizeof(std::complex<float>)==sizeof(npy_cfloat)); return NPY_CFLOAT; }
78 };
79 
80 template <> struct NumpyTraits<std::complex<double> > {
81  static int getCode() { assert(sizeof(std::complex<double>)==sizeof(npy_cdouble)); return NPY_CDOUBLE; }
82 };
83 
84 template <> struct NumpyTraits<std::complex<long double> > {
85  static int getCode() {
86  assert(sizeof(std::complex<long double>)==sizeof(npy_clongdouble));
87  return NPY_CLONGDOUBLE;
88  }
89 };
90 
92 
97 inline void destroyCObject(void * p) {
98  ndarray::Manager::Ptr * b = reinterpret_cast<ndarray::Manager::Ptr*>(p);
99  delete b;
100 }
101 
102 } // namespace ndarray::detail
103 
111 template <typename T, int N, int C>
112 struct PyConverter< Array<T,N,C> > : public detail::PyConverterBase< Array<T,N,C> > {
113  typedef typename Array<T,N,C>::Element Element;
114  typedef typename boost::remove_const<Element>::type NonConst;
115 
124  static bool fromPythonStage1(
125  PyPtr & p
129  ) {
130  if (!PyArray_Check(p.get())) {
131  PyErr_SetString(PyExc_TypeError, "numpy.ndarray argument required");
132  return false;
133  }
134  int actualType = PyArray_TYPE(p.get());
135  int requiredType = detail::NumpyTraits<NonConst>::getCode();
136  if (actualType != requiredType) {
137  PyErr_SetString(PyExc_ValueError, "numpy.ndarray argument has incorrect data type");
138  return false;
139  }
140  if (PyArray_NDIM(p.get()) != N) {
141  PyErr_SetString(PyExc_ValueError, "numpy.ndarray argument has incorrect number of dimensions");
142  return false;
143  }
144  bool writeable = !boost::is_const<Element>::value;
145  if (writeable && !(PyArray_FLAGS(p.get()) & NPY_WRITEABLE)) {
146  PyErr_SetString(PyExc_TypeError, "numpy.ndarray argument must be writeable");
147  return false;
148  }
149  if (C > 0) {
150  int requiredStride = sizeof(Element);
151  for (int i = 0; i < C; ++i) {
152  int actualStride = PyArray_STRIDE(p.get(), N-i-1);
153  if (actualStride != requiredStride) {
154  PyErr_SetString(
155  PyExc_ValueError,
156  "numpy.ndarray does not have enough row-major contiguous dimensions"
157  );
158  return false;
159  }
160  requiredStride *= PyArray_DIM(p.get(), N-i-1);
161  }
162  } else if (C < 0) {
163  int requiredStride = sizeof(Element);
164  for (int i = 0; i < -C; ++i) {
165  int actualStride = PyArray_STRIDE(p.get(), i);
166  if (actualStride != requiredStride) {
167  PyErr_SetString(
168  PyExc_ValueError,
169  "numpy.ndarray does not have enough column-major contiguous dimensions"
170  );
171  return false;
172  }
173  requiredStride *= PyArray_DIM(p.get(), i);
174  }
175  }
176  return true;
177  }
178 
191  static bool fromPythonStage2(
192  PyPtr const & input,
193  Array<T,N,C> & output
194  ) {
195  if (!(PyArray_FLAGS(input.get()) & NPY_ALIGNED)) {
196  PyErr_SetString(PyExc_ValueError, "unaligned arrays cannot be converted to C++");
197  return false;
198  }
199  Vector<int,N> shape;
200  Vector<int,N> strides;
201  std::copy(PyArray_DIMS(input.get()), PyArray_DIMS(input.get()) + N, shape.begin());
202  std::copy(PyArray_STRIDES(input.get()), PyArray_STRIDES(input.get()) + N , strides.begin());
203  for (int i = 0; i < N; ++i) strides[i] /= sizeof(Element);
204  output = external(
205  reinterpret_cast<Element*>(PyArray_DATA(input.get())),
206  shape, strides, input
207  );
208  return true;
209  }
210 
221  static PyObject* toPython(
222  Array<T,N,C> const & m,
223  PyObject* owner=NULL
225  ) {
226  int flags = NPY_ALIGNED;
227  if (C==N) flags |= NPY_C_CONTIGUOUS;
228  bool writeable = !boost::is_const<Element>::value;
229  if (writeable) flags |= NPY_WRITEABLE;
230  npy_intp outShape[N];
231  npy_intp outStrides[N];
232  Vector<int,N> inShape = m.getShape();
233  Vector<int,N> inStrides = m.getStrides();
234  std::copy(inShape.begin(), inShape.end(), outShape);
235  for (int i = 0; i < N; ++i) outStrides[i] = inStrides[i] * sizeof(Element);
236  PyPtr array(
237  PyArray_New(
238  &PyArray_Type, N, outShape, detail::NumpyTraits<NonConst>::getCode(),
239  outStrides, const_cast<NonConst*>(m.getData()), sizeof(Element), flags, NULL
240  ),
241  false
242  );
243  if (!array) return NULL;
244  if (!m.getManager() && owner == NULL) {
245  flags = NPY_CARRAY_RO | NPY_ENSURECOPY | NPY_C_CONTIGUOUS;
246  if (writeable) flags |= NPY_WRITEABLE;
247  PyPtr r = PyArray_FROM_OF(array.get(),flags);
248  if (!r) return NULL;
249  array.swap(r);
250  } else {
251  if (owner != NULL) {
252  Py_INCREF(owner);
253  } else {
254  owner = PyCObject_FromVoidPtr(new Manager::Ptr(m.getManager()), detail::destroyCObject);
255  }
256  reinterpret_cast<PyArrayObject*>(array.get())->base = owner;
257  }
258  Py_INCREF(array.get());
259  return PyArray_Return(reinterpret_cast<PyArrayObject*>(array.get()));
260  }
261 
262  static PyTypeObject const * getPyType() { return &PyArray_Type; }
263 };
264 
265 } // namespace ndarray
266 
267 #endif // !NDARRAY_SWIG_numpy_h_INCLUDED
void destroyCObject(void *p)
Definition: numpy.h:97
Index getStrides() const
Return a Vector of the strides of all dimensions.
Definition: ArrayBase.h:139
boost::remove_const< Element >::type NonConst
Definition: numpy.h:114
Array< T, N, C >::Element Element
Definition: numpy.h:113
boost::intrusive_ptr< PyObject > PyPtr
A reference-counting smart pointer for PyObject.
Definition: PyConverter.h:48
detail::ExternalInitializer< T, N, Owner > external(T *data, Vector< int, N > const &shape, Vector< int, N > const &strides, Owner const &owner)
Create an expression that initializes an Array with externally allocated memory.
SelectEigenView< T >::Type copy(Eigen::EigenBase< T > const &other)
Copy an arbitrary Eigen expression into a new EigenView.
Definition: eigen.h:390
static PyObject * toPython(Array< T, N, C > const &m, PyObject *owner=NULL)
Create a numpy.ndarray from an ndarray::Array.
Definition: numpy.h:221
ExpressionTraits< Derived >::Element Element
Data type of expression elements.
static bool fromPythonStage2(PyPtr const &input, Array< T, N, C > &output)
Complete a Python to C++ conversion begun with fromPythonStage1().
Definition: numpy.h:191
A class providing Python conversion functions for T.
Definition: PyConverter.h:50
Index getShape() const
Return a Vector of the sizes of all dimensions.
Definition: ArrayBase.h:136
boost::intrusive_ptr< Manager > Ptr
Definition: Manager.h:42
iterator begin()
Return an iterator to the beginning of the Vector.
Definition: Vector.h:120
iterator end()
Return an iterator to the end of the Vector.
Definition: Vector.h:124
Element * getData() const
Return a raw pointer to the first element of the array.
Definition: ArrayBase.h:117
static bool fromPythonStage1(PyPtr &p)
Check if a Python object is convertible to T and optionally begin the conversion by replacing the inp...
Definition: numpy.h:124
A multidimensional strided array.
Definition: Array.h:47
tuple m
Definition: lsstimport.py:48
Python C-API conversions for standard numeric types.
afw::table::Key< double > b
static PyTypeObject const * getPyType()
Definition: numpy.h:262
Manager::Ptr getManager() const
Return the opaque object responsible for memory management.
Definition: ArrayBase.h:123