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:
84
libs/python/numpy/src/dtype.cpp
Normal file
84
libs/python/numpy/src/dtype.cpp
Normal 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
|
||||
51
libs/python/numpy/src/matrix.cpp
Normal file
51
libs/python/numpy/src/matrix.cpp
Normal 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
|
||||
277
libs/python/numpy/src/ndarray.cpp
Normal file
277
libs/python/numpy/src/ndarray.cpp
Normal 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
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
13
libs/python/numpy/src/numpy.cpp
Normal file
13
libs/python/numpy/src/numpy.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}}}
|
||||
35
libs/python/numpy/src/scalars.cpp
Normal file
35
libs/python/numpy/src/scalars.cpp
Normal 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*>(""))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
48
libs/python/numpy/src/ufunc.cpp
Normal file
48
libs/python/numpy/src/ufunc.cpp
Normal 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];
|
||||
}
|
||||
|
||||
}}}
|
||||
Reference in New Issue
Block a user