2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 06:02:14 +00:00

initial sandbox import for numpy utilities in boost.python

This commit is contained in:
Jim Bosch
2010-03-08 21:50:13 +00:00
parent 189915bc8b
commit eef2eef7dd
14 changed files with 1247 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
#define BOOST_PYTHON_NUMPY_INTERNAL
#include <boost/python/numpy/internal.hpp>
#define NUMPY_DTYPE_TRAITS_BUILTIN(ctype,code) \
template <> struct dtype_traits<ctype> { \
static dtype get() { \
return dtype( \
python::detail::new_reference( \
reinterpret_cast<PyObject*>(PyArray_DescrFromType(code)) \
) \
); \
} \
}; \
template dtype dtype::get_builtin<ctype>()
#define NUMPY_DTYPE_TRAITS_COMPLEX(creal, ctype, code) \
template <> struct dtype_traits< std::complex<creal> > { \
static dtype get() { \
if (sizeof(ctype) != sizeof(std::complex<creal>)) { \
PyErr_SetString(PyExc_TypeError, "Cannot reinterpret std::complex<T> as T[2]"); \
throw_error_already_set(); \
} \
return dtype( \
python::detail::new_reference( \
reinterpret_cast<PyObject*>(PyArray_DescrFromType(code)) \
) \
); \
} \
}; \
template dtype dtype::get_builtin< std::complex<creal> >()
namespace boost { namespace python {
namespace numpy {
template <typename T> struct dtype_traits;
python::detail::new_reference dtype::convert(object const & arg, bool align) {
PyArray_Descr* obj=NULL;
if (align) {
if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0)
throw_error_already_set();
} else {
if (PyArray_DescrConverter(arg.ptr(), &obj) < 0)
throw_error_already_set();
}
return python::detail::new_reference(reinterpret_cast<PyObject*>(obj));
}
int dtype::get_itemsize() const {
return reinterpret_cast<PyArray_Descr*>(ptr())->elsize;
}
template <typename T>
dtype dtype::get_builtin() { return dtype_traits<T>::get(); }
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ubyte, NPY_UBYTE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_byte, NPY_BYTE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ushort, NPY_USHORT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_short, NPY_SHORT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_uint, NPY_UINT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_int, NPY_INT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ulong, NPY_ULONG);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_long, NPY_LONG);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_float, NPY_FLOAT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_double, NPY_DOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_longdouble, NPY_LONGDOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_cfloat, NPY_CFLOAT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_cdouble, NPY_CDOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_clongdouble, NPY_CLONGDOUBLE);
NUMPY_DTYPE_TRAITS_COMPLEX(float, npy_cfloat, NPY_CFLOAT);
NUMPY_DTYPE_TRAITS_COMPLEX(double, npy_cdouble, NPY_CDOUBLE);
NUMPY_DTYPE_TRAITS_COMPLEX(long double, npy_clongdouble, NPY_CLONGDOUBLE);
template <> struct dtype_traits<bool> {
static dtype get() {
if (sizeof(bool) == sizeof(npy_bool)) return dtype_traits<npy_bool>::get();
if (sizeof(bool) == sizeof(npy_ubyte)) return dtype_traits<npy_ubyte>::get();
PyErr_SetString(PyExc_TypeError, "Cannot determine numpy dtype corresponding to C++ bool.");
throw_error_already_set();
}
};
template dtype dtype::get_builtin<bool>();
}}} // namespace boost::python::numpy

View File

@@ -0,0 +1,51 @@
#define BOOST_PYTHON_NUMPY_INTERNAL
#include <boost/python/numpy/internal.hpp>
#include <boost/python/numpy/matrix.hpp>
namespace boost { namespace python {
namespace numpy { namespace detail {
inline object get_matrix_type() {
object module = import("numpy");
return module.attr("matrix");
}
}} // namespace numpy::detail
namespace converter {
PyTypeObject const * object_manager_traits<numpy::matrix>::get_pytype() {
return reinterpret_cast<PyTypeObject*>(numpy::detail::get_matrix_type().ptr());
}
} // namespace boost::python::converter
namespace numpy {
object matrix::construct(object const & obj, dtype const & dt, bool copy) {
return numpy::detail::get_matrix_type()(obj, dt, copy);
}
object matrix::construct(object const & obj, bool copy) {
return numpy::detail::get_matrix_type()(obj, object(), copy);
}
matrix matrix::view(dtype const & dt) const {
return matrix(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr())
)
);
}
matrix matrix::copy() const {
return matrix(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>(""))
)
);
}
matrix matrix::transpose() const {
return matrix(extract<matrix>(ndarray::transpose()));
}
}}} // namespace boost::python::numpy

View File

@@ -0,0 +1,277 @@
#define BOOST_PYTHON_NUMPY_INTERNAL
#include <boost/python/numpy/internal.hpp>
namespace boost { namespace python {
namespace converter {
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArray_Type, python::numpy::ndarray)
} // namespace boost::python::converter
namespace numpy {
namespace detail {
ndarray::bitflag numpy_to_bitflag(int const f) {
ndarray::bitflag r = ndarray::NONE;
if (f & NPY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS);
if (f & NPY_F_CONTIGUOUS) r = (r | ndarray::F_CONTIGUOUS);
if (f & NPY_ALIGNED) r = (r | ndarray::ALIGNED);
if (f & NPY_WRITEABLE) r = (r | ndarray::WRITEABLE);
return r;
}
int const bitflag_to_numpy(ndarray::bitflag f) {
int r = 0;
if (f & ndarray::C_CONTIGUOUS) r |= NPY_C_CONTIGUOUS;
if (f & ndarray::F_CONTIGUOUS) r |= NPY_F_CONTIGUOUS;
if (f & ndarray::ALIGNED) r |= NPY_ALIGNED;
if (f & ndarray::WRITEABLE) r |= NPY_WRITEABLE;
return r;
}
bool is_c_contiguous(
std::vector<Py_intptr_t> const & shape,
std::vector<Py_intptr_t> const & strides,
int itemsize
) {
std::vector<Py_intptr_t>::const_reverse_iterator j = strides.rbegin();
int total = itemsize;
for (std::vector<Py_intptr_t>::const_reverse_iterator i = shape.rbegin(); i != shape.rend(); ++i, ++j) {
if (total != *j) return false;
total *= (*i);
}
return true;
}
bool is_f_contiguous(
std::vector<Py_intptr_t> const & shape,
std::vector<Py_intptr_t> const & strides,
int itemsize
) {
std::vector<Py_intptr_t>::const_iterator j = strides.begin();
int total = itemsize;
for (std::vector<Py_intptr_t>::const_iterator i = shape.begin(); i != shape.end(); ++i, ++j) {
if (total != *j) return false;
total *= (*i);
}
return true;
}
bool is_aligned(
std::vector<Py_intptr_t> const & strides,
int itemsize
) {
for (std::vector<Py_intptr_t>::const_iterator i = strides.begin(); i != strides.end(); ++i) {
if (*i % itemsize) return false;
}
return true;
}
inline PyArray_Descr * incref_dtype(dtype const & dt) {
Py_INCREF(dt.ptr());
return reinterpret_cast<PyArray_Descr*>(dt.ptr());
}
ndarray from_data_impl(
void * data,
dtype const & dt,
object const & shape,
object const & strides,
object const & owner,
bool writeable
) {
std::vector<Py_intptr_t> shape_(len(shape));
std::vector<Py_intptr_t> strides_(len(strides));
if (shape_.size() != strides_.size()) {
PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match.");
throw_error_already_set();
}
for (std::size_t i = 0; i < shape_.size(); ++i) {
shape_[i] = extract<Py_intptr_t>(shape[i]);
strides_[i] = extract<Py_intptr_t>(strides[i]);
}
return from_data_impl(data, dt, shape_, strides_, owner, writeable);
}
ndarray from_data_impl(
void * data,
dtype const & dt,
std::vector<Py_intptr_t> const & shape,
std::vector<Py_intptr_t> const & strides,
object const & owner,
bool writeable
) {
if (shape.size() != strides.size()) {
PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match.");
throw_error_already_set();
}
int itemsize = dt.get_itemsize();
int flags = 0;
if (writeable) flags |= NPY_WRITEABLE;
if (is_c_contiguous(shape, strides, itemsize)) flags |= NPY_C_CONTIGUOUS;
if (is_f_contiguous(shape, strides, itemsize)) flags |= NPY_F_CONTIGUOUS;
if (is_aligned(strides, itemsize)) flags |= NPY_ALIGNED;
ndarray r(
python::detail::new_reference(
PyArray_NewFromDescr(
&PyArray_Type,
incref_dtype(dt),
shape.size(),
const_cast<Py_intptr_t*>(&shape.front()),
const_cast<Py_intptr_t*>(&strides.front()),
data,
flags,
NULL
)
)
);
r.set_base(owner);
return r;
}
} // namespace detail
ndarray ndarray::view(dtype const & dt) const {
return ndarray(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr())
)
);
}
ndarray ndarray::copy() const {
return ndarray(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>(""))
)
);
}
dtype ndarray::get_dtype() const {
return dtype(python::detail::borrowed_reference(get_struct()->descr));
}
object ndarray::get_base() const {
if (get_struct()->base == NULL) return object();
return object(python::detail::borrowed_reference(get_struct()->base));
}
void ndarray::set_base(object const & base) {
Py_XDECREF(get_struct()->base);
if (base != object()) {
Py_INCREF(base.ptr());
get_struct()->base = base.ptr();
} else {
get_struct()->base = NULL;
}
}
ndarray::bitflag const ndarray::get_flags() const {
return numpy::detail::numpy_to_bitflag(get_struct()->flags);
}
ndarray ndarray::transpose() const {
return ndarray(
python::detail::new_reference(
PyArray_Transpose(reinterpret_cast<PyArrayObject*>(this->ptr()), NULL)
)
);
}
ndarray ndarray::squeeze() const {
return ndarray(
python::detail::new_reference(
PyArray_Squeeze(reinterpret_cast<PyArrayObject*>(this->ptr()))
)
);
}
object ndarray::scalarize() const {
Py_INCREF(ptr());
return object(python::detail::new_reference(PyArray_Return(reinterpret_cast<PyArrayObject*>(ptr()))));
}
ndarray zeros(tuple const & shape, dtype const & dt) {
int nd = len(shape);
Py_intptr_t dims[nd];
for (int n=0; n<nd; ++n) dims[n] = extract<Py_intptr_t>(shape[n]);
return ndarray(
python::detail::new_reference(
PyArray_Zeros(nd, dims, detail::incref_dtype(dt), 0)
)
);
}
ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt) {
return ndarray(
python::detail::new_reference(
PyArray_Zeros(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0)
)
);
}
ndarray empty(tuple const & shape, dtype const & dt) {
int nd = len(shape);
Py_intptr_t dims[nd];
for (int n=0; n<nd; ++n) dims[n] = extract<Py_intptr_t>(shape[n]);
return ndarray(
python::detail::new_reference(
PyArray_Empty(nd, dims, detail::incref_dtype(dt), 0)
)
);
}
ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt) {
return ndarray(
python::detail::new_reference(
PyArray_Empty(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0)
)
);
}
ndarray array(object const & obj) {
return ndarray(
python::detail::new_reference(
PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ENSUREARRAY, NULL)
)
);
}
ndarray array(object const & obj, dtype const & dt) {
return ndarray(
python::detail::new_reference(
PyArray_FromAny(obj.ptr(), detail::incref_dtype(dt), 0, 0, NPY_ENSUREARRAY, NULL)
)
);
}
ndarray from_object(object const & obj, dtype const & dt, int nd_min, int nd_max, ndarray::bitflag flags) {
int requirements = detail::bitflag_to_numpy(flags);
return ndarray(
python::detail::new_reference(
PyArray_FromAny(
obj.ptr(),
detail::incref_dtype(dt),
nd_min, nd_max,
requirements,
NULL
)
)
);
}
ndarray from_object(object const & obj, int nd_min, int nd_max, ndarray::bitflag flags) {
int requirements = detail::bitflag_to_numpy(flags);
return ndarray(
python::detail::new_reference(
PyArray_FromAny(
obj.ptr(),
NULL,
nd_min, nd_max,
requirements,
NULL
)
)
);
}
}}}

View File

@@ -0,0 +1,13 @@
#define BOOST_PYTHON_NUMPY_INTERNAL_MAIN
#include <boost/python/numpy/internal.hpp>
namespace boost { namespace python {
namespace numpy {
void initialize() {
import_array();
import_ufunc();
}
}}}

View File

@@ -0,0 +1,35 @@
#define BOOST_PYTHON_NUMPY_INTERNAL
#include <boost/python/numpy/internal.hpp>
namespace boost { namespace python {
namespace converter {
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyVoidArrType_Type, python::numpy::void_)
} // namespace boost::python::converter
namespace numpy {
void_::void_(Py_ssize_t size) :
object(
python::detail::new_reference(
PyObject_CallFunction((PyObject*)&PyVoidArrType_Type, const_cast<char*>("i"), size)
)
)
{}
void_ void_::view(dtype const & dt) const {
return void_(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr())
)
);
}
void_ void_::copy() const {
return void_(
python::detail::new_reference(
PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>(""))
)
);
}
}}}

View File

@@ -0,0 +1,48 @@
#define BOOST_PYTHON_NUMPY_INTERNAL
#include <boost/python/numpy/internal.hpp>
#include <boost/python/numpy/ufunc.hpp>
namespace boost { namespace python {
namespace converter {
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayMultiIter_Type, python::numpy::multi_iter)
} // namespace boost::python::converter
namespace numpy {
multi_iter make_multi_iter(object const & a1) {
return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(1, a1.ptr())));
}
multi_iter make_multi_iter(object const & a1, object const & a2) {
return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(2, a1.ptr(), a2.ptr())));
}
multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3) {
return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(3, a1.ptr(), a2.ptr(), a3.ptr())));
}
void multi_iter::next() {
PyArray_MultiIter_NEXT(ptr());
}
bool multi_iter::not_done() const {
return PyArray_MultiIter_NOTDONE(ptr());
}
char * multi_iter::get_data(int i) const {
return reinterpret_cast<char*>(PyArray_MultiIter_DATA(ptr(), i));
}
int const multi_iter::get_nd() const {
return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->nd;
}
Py_intptr_t const * multi_iter::get_shape() const {
return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->dimensions;
}
Py_intptr_t const multi_iter::shape(int n) const {
return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->dimensions[n];
}
}}}