mirror of
https://github.com/boostorg/python.git
synced 2026-01-20 16:52:15 +00:00
Rename (and move) boost.python.numpy to boost.numpy.
This commit is contained in:
34
SConscript
34
SConscript
@@ -1,33 +1,33 @@
|
||||
import scons_tools
|
||||
import os
|
||||
|
||||
targets = {"boost.python.numpy":{}}
|
||||
targets = {"boost.numpy":{}}
|
||||
|
||||
scons_tools.LocalConfiguration(
|
||||
name="boost.python.numpy",
|
||||
libraries=["boost_python_numpy"],
|
||||
name="boost.numpy",
|
||||
libraries=["boost_numpy"],
|
||||
dependencies=("boost.python", "numpy")
|
||||
)
|
||||
bp_numpy_env = scons_tools.GetEnvironment().Clone()
|
||||
bp_numpy_env.Append(CPPPATH=[os.path.abspath(os.curdir)])
|
||||
libpath = os.path.abspath("%s/python/numpy/src" % scons_tools.GetBuildDir())
|
||||
boost_numpy_env = scons_tools.GetEnvironment().Clone()
|
||||
boost_numpy_env.Append(CPPPATH=[os.path.abspath(os.curdir)])
|
||||
libpath = os.path.abspath("%s/numpy/src" % scons_tools.GetBuildDir())
|
||||
if os.environ.has_key("LD_LIBRARY_PATH"):
|
||||
bp_numpy_env["ENV"]["LD_LIBRARY_PATH"] = "%s:%s" % (libpath, os.environ["LD_LIBRARY_PATH"])
|
||||
boost_numpy_env["ENV"]["LD_LIBRARY_PATH"] = "%s:%s" % (libpath, os.environ["LD_LIBRARY_PATH"])
|
||||
else:
|
||||
bp_numpy_env["ENV"]["LD_LIBRARY_PATH"] = libpath
|
||||
bp_numpy_env.Append(LIBPATH=[libpath])
|
||||
bp_numpy_env.SetupPackages(["boost.python", "numpy"])
|
||||
Export("bp_numpy_env")
|
||||
boost_numpy_env["ENV"]["LD_LIBRARY_PATH"] = libpath
|
||||
boost_numpy_env.Append(LIBPATH=[libpath])
|
||||
boost_numpy_env.SetupPackages(["boost.python", "numpy"])
|
||||
Export("boost_numpy_env")
|
||||
|
||||
targets["boost.python.numpy"]["lib"] = SConscript("libs/python/numpy/src/SConscript")
|
||||
targets["boost.python.numpy"]["install"] = (
|
||||
bp_numpy_env.RecursiveInstall(
|
||||
os.path.join(bp_numpy_env["INSTALL_HEADERS"], "boost"),
|
||||
targets["boost.numpy"]["lib"] = SConscript("libs/numpy/src/SConscript")
|
||||
targets["boost.numpy"]["install"] = (
|
||||
boost_numpy_env.RecursiveInstall(
|
||||
os.path.join(boost_numpy_env["INSTALL_HEADERS"], "boost"),
|
||||
"boost",
|
||||
regex="(.*\.hpp)")
|
||||
+ bp_numpy_env.Install(bp_numpy_env["INSTALL_LIB"], targets["boost.python.numpy"]["lib"])
|
||||
+ boost_numpy_env.Install(boost_numpy_env["INSTALL_LIB"], targets["boost.numpy"]["lib"])
|
||||
)
|
||||
targets["boost.python.numpy"]["test"] = SConscript("libs/python/numpy/test/SConscript")
|
||||
targets["boost.numpy"]["test"] = SConscript("libs/numpy/test/SConscript")
|
||||
|
||||
|
||||
Return("targets")
|
||||
|
||||
33
boost/numpy.hpp
Normal file
33
boost/numpy.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef BOOST_NUMPY_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy.hpp
|
||||
* @brief Main public header file for boost.numpy.
|
||||
*/
|
||||
|
||||
#include <boost/numpy/dtype.hpp>
|
||||
#include <boost/numpy/ndarray.hpp>
|
||||
#include <boost/numpy/scalars.hpp>
|
||||
#include <boost/numpy/matrix.hpp>
|
||||
#include <boost/numpy/ufunc.hpp>
|
||||
#include <boost/numpy/invoke_matching.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief Initialize the Numpy C-API
|
||||
*
|
||||
* This must be called before using anything in boost.numpy;
|
||||
* It should probably be the first line inside BOOST_PYTHON_MODULE.
|
||||
*
|
||||
* @internal This just calls the Numpy C-API functions "import_array()"
|
||||
* and "import_ufunc()".
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
} // namespace boost::numpy
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_HPP_INCLUDED
|
||||
65
boost/numpy/dtype.hpp
Normal file
65
boost/numpy/dtype.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef BOOST_NUMPY_DTYPE_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_DTYPE_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/dtype.hpp
|
||||
* @brief Object manager for Python's numpy.dtype class.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/numpy/numpy_object_mgr_traits.hpp>
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/type_traits/add_pointer.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.dtype.
|
||||
*
|
||||
* @todo This could have a lot more interesting accessors.
|
||||
*/
|
||||
class dtype : public python::object
|
||||
{
|
||||
static python::detail::new_reference convert(python::object::object_cref arg, bool align);
|
||||
public:
|
||||
|
||||
/// @brief Convert an arbitrary Python object to a data-type descriptor object.
|
||||
template <typename T>
|
||||
explicit dtype(T arg, bool align=false) : python::object(convert(arg, align)) {}
|
||||
|
||||
/**
|
||||
* @brief Get the built-in numpy dtype associated with the given scalar template type.
|
||||
*
|
||||
* This is perhaps the most useful part of the numpy API: it returns the dtype object
|
||||
* corresponding to a built-in C++ type. This should work for any integer or floating point
|
||||
* type supported by numpy, and will also work for std::complex if
|
||||
* sizeof(std::complex<T>) == 2*sizeof(T).
|
||||
*
|
||||
* It can also be useful for users to add explicit specializations for POD structs
|
||||
* that return field-based dtypes.
|
||||
*/
|
||||
template <typename T> static dtype get_builtin();
|
||||
|
||||
/// @brief Return the size of the data type in bytes.
|
||||
int get_itemsize() const;
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(dtype, python::object);
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::numpy
|
||||
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(numpy::dtype);
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_DTYPE_HPP_INCLUDED
|
||||
@@ -1,19 +1,19 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
#ifndef BOOST_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/internal.hpp
|
||||
* @file boost/numpy/internal.hpp
|
||||
* @brief Internal header file to include the Numpy C-API headers.
|
||||
*
|
||||
* This should only be included by source files in the boost.python.numpy library itself.
|
||||
* This should only be included by source files in the boost.numpy library itself.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#ifdef BOOST_PYTHON_NUMPY_INTERNAL
|
||||
#ifdef BOOST_NUMPY_INTERNAL
|
||||
#define NO_IMPORT_ARRAY
|
||||
#define NO_IMPORT_UFUNC
|
||||
#else
|
||||
#ifndef BOOST_PYTHON_NUMPY_INTERNAL_MAIN
|
||||
#ifndef BOOST_NUMPY_INTERNAL_MAIN
|
||||
ERROR_internal_hpp_is_for_internal_use_only
|
||||
#endif
|
||||
#endif
|
||||
@@ -21,9 +21,9 @@ ERROR_internal_hpp_is_for_internal_use_only
|
||||
#define PY_UFUNC_UNIQUE_SYMBOL BOOST_UFUNC_ARRAY_API
|
||||
#include <numpy/arrayobject.h>
|
||||
#include <numpy/ufuncobject.h>
|
||||
#include <boost/python/numpy.hpp>
|
||||
#include <boost/numpy.hpp>
|
||||
|
||||
#define NUMPY_OBJECT_MANAGER_TRAITS_IMPL(pytype,manager) \
|
||||
PyTypeObject const * object_manager_traits<manager>::get_pytype() { return &pytype; }
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
#endif // !BOOST_NUMPY_INTERNAL_HPP_INCLUDED
|
||||
186
boost/numpy/invoke_matching.hpp
Normal file
186
boost/numpy/invoke_matching.hpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#ifndef BOOST_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/invoke_matching.hpp
|
||||
* @brief Template invocation based on dtype matching.
|
||||
*/
|
||||
|
||||
#include <boost/numpy/dtype.hpp>
|
||||
#include <boost/numpy/ndarray.hpp>
|
||||
|
||||
#include <boost/mpl/integral_c.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct add_pointer_meta
|
||||
{
|
||||
template <typename T>
|
||||
struct apply
|
||||
{
|
||||
typedef typename boost::add_pointer<T>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct dtype_template_match_found {};
|
||||
struct nd_template_match_found {};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
void operator()(T *) const
|
||||
{
|
||||
if (dtype::get_builtin<T>() == m_dtype)
|
||||
{
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function func)
|
||||
: m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker< boost::reference_wrapper<Function> >
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
void operator()(T *) const
|
||||
{
|
||||
if (dtype::get_builtin<T>() == m_dtype)
|
||||
{
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function & func)
|
||||
: m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker
|
||||
{
|
||||
template <int N>
|
||||
void operator()(boost::mpl::integral_c<int,N> *) const
|
||||
{
|
||||
if (m_nd == N)
|
||||
{
|
||||
m_func.template apply<N>();
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function func) : m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker< boost::reference_wrapper<Function> >
|
||||
{
|
||||
template <int N>
|
||||
void operator()(boost::mpl::integral_c<int,N> *) const
|
||||
{
|
||||
if (m_nd == N)
|
||||
{
|
||||
m_func.template apply<N>();
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function & func) : m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
} // namespace boost::numpy::detail
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_nd(int nd, Function f)
|
||||
{
|
||||
detail::nd_template_invoker<Function> invoker(nd, f);
|
||||
try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);}
|
||||
catch (detail::nd_template_match_found &) { return;}
|
||||
PyErr_SetString(PyExc_TypeError, "number of dimensions not found in template list.");
|
||||
python::throw_error_already_set();
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_dtype(dtype const & dtype_, Function f)
|
||||
{
|
||||
detail::dtype_template_invoker<Function> invoker(dtype_, f);
|
||||
try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);}
|
||||
catch (detail::dtype_template_match_found &) { return;}
|
||||
PyErr_SetString(PyExc_TypeError, "dtype not found in template list.");
|
||||
python::throw_error_already_set();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T, typename Function>
|
||||
struct array_template_invoker_wrapper_2
|
||||
{
|
||||
template <int N>
|
||||
void apply() const { m_func.template apply<T,N>();}
|
||||
array_template_invoker_wrapper_2(Function & func) : m_func(func) {}
|
||||
|
||||
private:
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper_1
|
||||
{
|
||||
template <typename T>
|
||||
void apply() const { invoke_matching_nd<DimSequence>(m_nd, array_template_invoker_wrapper_2<T,Function>(m_func));}
|
||||
array_template_invoker_wrapper_1(int nd, Function & func) : m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper_1< DimSequence, boost::reference_wrapper<Function> >
|
||||
: public array_template_invoker_wrapper_1< DimSequence, Function >
|
||||
{
|
||||
array_template_invoker_wrapper_1(int nd, Function & func)
|
||||
: array_template_invoker_wrapper_1< DimSequence, Function >(nd, func) {}
|
||||
};
|
||||
|
||||
} // namespace boost::numpy::detail
|
||||
|
||||
template <typename TypeSequence, typename DimSequence, typename Function>
|
||||
void invoke_matching_array(ndarray const & array_, Function f)
|
||||
{
|
||||
detail::array_template_invoker_wrapper_1<DimSequence,Function> wrapper(array_.get_nd(), f);
|
||||
invoke_matching_dtype<TypeSequence>(array_.get_dtype(), wrapper);
|
||||
}
|
||||
|
||||
} // namespace boost::numpy
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
67
boost/numpy/matrix.hpp
Normal file
67
boost/numpy/matrix.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef BOOST_NUMPY_MATRIX_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_MATRIX_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/matrix.hpp
|
||||
* @brief Object manager for numpy.matrix.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/numpy/ndarray.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.matrix.
|
||||
*
|
||||
* @internal numpy.matrix is defined in Python, so object_manager_traits<matrix>::get_pytype()
|
||||
* is implemented by importing numpy and getting the "matrix" attribute of the module.
|
||||
* We then just hope that doesn't get destroyed while we need it, because if we put
|
||||
* a dynamic python object in a static-allocated boost::python::object or handle<>,
|
||||
* bad things happen when Python shuts down. I think this solution is safe, but I'd
|
||||
* love to get that confirmed.
|
||||
*/
|
||||
class matrix : public ndarray
|
||||
{
|
||||
static python::object construct(object_cref obj, dtype const & dt, bool copy);
|
||||
static python::object construct(object_cref obj, bool copy);
|
||||
public:
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(matrix, ndarray);
|
||||
|
||||
/// @brief Equivalent to "numpy.matrix(obj,dt,copy)" in Python.
|
||||
explicit matrix(python::object const & obj, dtype const & dt, bool copy=true)
|
||||
: ndarray(python::extract<ndarray>(construct(obj, dt, copy))) {}
|
||||
|
||||
/// @brief Equivalent to "numpy.matrix(obj,copy=copy)" in Python.
|
||||
explicit matrix(python::object const & obj, bool copy=true)
|
||||
: ndarray(python::extract<ndarray>(construct(obj, copy))) {}
|
||||
|
||||
/// \brief Return a view of the matrix with the given dtype.
|
||||
matrix view(dtype const & dt) const;
|
||||
|
||||
/// \brief Copy the scalar (deep for all non-object fields).
|
||||
matrix copy() const;
|
||||
|
||||
/// \brief Transpose the matrix.
|
||||
matrix transpose() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::numpy
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(numpy::matrix);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_MATRIX_HPP_INCLUDED
|
||||
296
boost/numpy/ndarray.hpp
Normal file
296
boost/numpy/ndarray.hpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#ifndef BOOST_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/ndarray.hpp
|
||||
* @brief Object manager and various utilities for numpy.ndarray.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/numpy/dtype.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.ndarray.
|
||||
*
|
||||
* @todo This could have a lot more functionality (like boost::python::numeric::array).
|
||||
* Right now all that exists is what was needed to move raw data between C++ and Python.
|
||||
*/
|
||||
class ndarray : public python::object
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An internal struct that's byte-compatible with PyArrayObject.
|
||||
*
|
||||
* This is just a hack to allow inline access to this stuff while hiding numpy/arrayobject.h
|
||||
* from the user.
|
||||
*/
|
||||
struct array_struct
|
||||
{
|
||||
PyObject_HEAD
|
||||
char * data;
|
||||
int nd;
|
||||
Py_intptr_t * shape;
|
||||
Py_intptr_t * strides;
|
||||
PyObject * base;
|
||||
PyObject * descr;
|
||||
int flags;
|
||||
PyObject * weakreflist;
|
||||
};
|
||||
|
||||
/// @brief Return the held Python object as an array_struct.
|
||||
array_struct * get_struct() const { return reinterpret_cast<array_struct*>(this->ptr()); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Enum to represent (some) of Numpy's internal flags.
|
||||
*
|
||||
* These don't match the actual Numpy flag values; we can't get those without including
|
||||
* numpy/arrayobject.h or copying them directly. That's very unfortunate.
|
||||
*
|
||||
* @todo I'm torn about whether this should be an enum. It's very convenient to not
|
||||
* make these simple integer values for overloading purposes, but the need to
|
||||
* define every possible combination and custom bitwise operators is ugly.
|
||||
*/
|
||||
enum bitflag
|
||||
{
|
||||
NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2,
|
||||
ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8,
|
||||
CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8,
|
||||
FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8,
|
||||
UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8
|
||||
};
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(ndarray, object);
|
||||
|
||||
/// @brief Return a view of the scalar with the given dtype.
|
||||
ndarray view(dtype const & dt) const;
|
||||
|
||||
/// @brief Copy the scalar (deep for all non-object fields).
|
||||
ndarray copy() const;
|
||||
|
||||
/// @brief Return the size of the nth dimension.
|
||||
int const shape(int n) const { return get_shape()[n]; }
|
||||
|
||||
/// @brief Return the stride of the nth dimension.
|
||||
int const strides(int n) const { return get_strides()[n]; }
|
||||
|
||||
/**
|
||||
* @brief Return the array's raw data pointer.
|
||||
*
|
||||
* This returns char so stride math works properly on it. It's pretty much
|
||||
* expected that the user will have to reinterpret_cast it.
|
||||
*/
|
||||
char * get_data() const { return get_struct()->data; }
|
||||
|
||||
/// @brief Return the array's data-type descriptor object.
|
||||
dtype get_dtype() const;
|
||||
|
||||
/// @brief Return the object that owns the array's data, or None if the array owns its own data.
|
||||
python::object get_base() const;
|
||||
|
||||
/// @brief Set the object that owns the array's data. Use with care.
|
||||
void set_base(object const & base);
|
||||
|
||||
/// @brief Return the shape of the array as an array of integers (length == get_nd()).
|
||||
Py_intptr_t const * get_shape() const { return get_struct()->shape; }
|
||||
|
||||
/// @brief Return the stride of the array as an array of integers (length == get_nd()).
|
||||
Py_intptr_t const * get_strides() const { return get_struct()->strides; }
|
||||
|
||||
/// @brief Return the number of array dimensions.
|
||||
int const get_nd() const { return get_struct()->nd; }
|
||||
|
||||
/// @brief Return the array flags.
|
||||
bitflag const get_flags() const;
|
||||
|
||||
/// @brief Reverse the dimensions of the array.
|
||||
ndarray transpose() const;
|
||||
|
||||
/// @brief Eliminate any unit-sized dimensions.
|
||||
ndarray squeeze() const;
|
||||
|
||||
/// @brief Equivalent to self.reshape(*shape) in Python.
|
||||
ndarray reshape(python::tuple const & shape) const;
|
||||
|
||||
/**
|
||||
* @brief If the array contains only a single element, return it as an array scalar; otherwise return
|
||||
* the array.
|
||||
*
|
||||
* @internal This is simply a call to PyArray_Return();
|
||||
*/
|
||||
python::object scalarize() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a new array with the given shape and data type, with data initialized to zero.
|
||||
*/
|
||||
ndarray zeros(python::tuple const & shape, dtype const & dt);
|
||||
ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt);
|
||||
|
||||
/**
|
||||
* @brief Construct a new array with the given shape and data type, with data left uninitialized.
|
||||
*/
|
||||
ndarray empty(python::tuple const & shape, dtype const & dt);
|
||||
ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt);
|
||||
|
||||
/**
|
||||
* @brief Construct a new array from an arbitrary Python sequence.
|
||||
*
|
||||
* @todo This does't seem to handle ndarray subtypes the same way that "numpy.array" does in Python.
|
||||
*/
|
||||
ndarray array(python::object const & obj);
|
||||
ndarray array(python::object const & obj, dtype const & dt);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
ndarray from_data_impl(void * data,
|
||||
dtype const & dt,
|
||||
std::vector<Py_intptr_t> const & shape,
|
||||
std::vector<Py_intptr_t> const & strides,
|
||||
python::object const & owner,
|
||||
bool writeable);
|
||||
|
||||
template <typename Container>
|
||||
ndarray from_data_impl(void * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
python::object const & owner,
|
||||
bool writeable,
|
||||
typename boost::enable_if< boost::is_integral<typename Container::value_type> >::type * enabled = NULL)
|
||||
{
|
||||
std::vector<Py_intptr_t> shape_(shape.begin(),shape.end());
|
||||
std::vector<Py_intptr_t> strides_(strides.begin(), strides.end());
|
||||
return from_data_impl(data, dt, shape_, strides_, owner, writeable);
|
||||
}
|
||||
|
||||
ndarray from_data_impl(void * data,
|
||||
dtype const & dt,
|
||||
python::object const & shape,
|
||||
python::object const & strides,
|
||||
python::object const & owner,
|
||||
bool writeable);
|
||||
|
||||
} // namespace boost::numpy::detail
|
||||
|
||||
/**
|
||||
* @brief Construct a new ndarray object from a raw pointer.
|
||||
*
|
||||
* @param[in] data Raw pointer to the first element of the array.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] shape Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] strides Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] owner An arbitray Python object that owns that data pointer. The array object will
|
||||
* keep a reference to the object, and decrement it's reference count when the
|
||||
* array goes out of scope. Pass None at your own peril.
|
||||
*
|
||||
* @todo Should probably take ranges of iterators rather than actual container objects.
|
||||
*/
|
||||
template <typename Container>
|
||||
inline ndarray from_data(void * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
python::object const & owner)
|
||||
{
|
||||
return numpy::detail::from_data_impl(data, dt, shape, strides, owner, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new ndarray object from a raw pointer.
|
||||
*
|
||||
* @param[in] data Raw pointer to the first element of the array.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] shape Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] strides Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] owner An arbitray Python object that owns that data pointer. The array object will
|
||||
* keep a reference to the object, and decrement it's reference count when the
|
||||
* array goes out of scope. Pass None at your own peril.
|
||||
*
|
||||
* This overload takes a const void pointer and sets the "writeable" flag of the array to false.
|
||||
*
|
||||
* @todo Should probably take ranges of iterators rather than actual container objects.
|
||||
*/
|
||||
template <typename Container>
|
||||
inline ndarray from_data(void const * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
python::object const & owner)
|
||||
{
|
||||
return numpy::detail::from_data_impl(const_cast<void*>(data), dt, shape, strides, owner, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transform an arbitrary object into a numpy array with the given requirements.
|
||||
*
|
||||
* @param[in] obj An arbitrary python object to convert. Arrays that meet the requirements
|
||||
* will be passed through directly.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] nd_min Minimum number of dimensions.
|
||||
* @param[in] nd_max Maximum number of dimensions.
|
||||
* @param[in] flags Bitwise OR of flags specifying additional requirements.
|
||||
*/
|
||||
ndarray from_object(python::object const & obj, dtype const & dt,
|
||||
int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE);
|
||||
|
||||
inline ndarray from_object(python::object const & obj, dtype const & dt,
|
||||
int nd, ndarray::bitflag flags=ndarray::NONE)
|
||||
{
|
||||
return from_object(obj, dt, nd, nd, flags);
|
||||
}
|
||||
|
||||
inline ndarray from_object(python::object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE)
|
||||
{
|
||||
return from_object(obj, dt, 0, 0, flags);
|
||||
}
|
||||
|
||||
ndarray from_object(python::object const & obj, int nd_min, int nd_max,
|
||||
ndarray::bitflag flags=ndarray::NONE);
|
||||
|
||||
inline ndarray from_object(python::object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE)
|
||||
{
|
||||
return from_object(obj, nd, nd, flags);
|
||||
}
|
||||
|
||||
inline ndarray from_object(python::object const & obj, ndarray::bitflag flags=ndarray::NONE)
|
||||
{
|
||||
return from_object(obj, 0, 0, flags);
|
||||
}
|
||||
|
||||
inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b)
|
||||
{
|
||||
return ndarray::bitflag(int(a) | int(b));
|
||||
}
|
||||
|
||||
inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b)
|
||||
{
|
||||
return ndarray::bitflag(int(a) & int(b));
|
||||
}
|
||||
|
||||
} // namespace boost::numpy
|
||||
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(numpy::ndarray);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
31
boost/numpy/numpy_object_mgr_traits.hpp
Normal file
31
boost/numpy/numpy_object_mgr_traits.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef BOOST_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/numpy_object_mgr_traits.hpp
|
||||
* @brief Macro that specializes object_manager_traits by requiring a
|
||||
* source-file implementation of get_pytype().
|
||||
*/
|
||||
|
||||
#define NUMPY_OBJECT_MANAGER_TRAITS(manager) \
|
||||
template <> \
|
||||
struct object_manager_traits<manager> \
|
||||
{ \
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized = true); \
|
||||
static inline python::detail::new_reference adopt(PyObject* x) \
|
||||
{ \
|
||||
return python::detail::new_reference(python::pytype_check((PyTypeObject*)get_pytype(), x)); \
|
||||
} \
|
||||
static bool check(PyObject* x) \
|
||||
{ \
|
||||
return ::PyObject_IsInstance(x, (PyObject*)get_pytype()); \
|
||||
} \
|
||||
static manager* checked_downcast(PyObject* x) \
|
||||
{ \
|
||||
return python::downcast<manager>((checked_downcast_impl)(x, (PyTypeObject*)get_pytype())); \
|
||||
} \
|
||||
static PyTypeObject const * get_pytype(); \
|
||||
}
|
||||
|
||||
#endif // !BOOST_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
|
||||
60
boost/numpy/scalars.hpp
Normal file
60
boost/numpy/scalars.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef BOOST_NUMPY_SCALARS_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_SCALARS_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/scalars.hpp
|
||||
* @brief Object managers for array scalars (currently only numpy.void is implemented).
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/numpy/dtype.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.void.
|
||||
*
|
||||
* @todo This could have a lot more functionality.
|
||||
*/
|
||||
class void_ : public python::object
|
||||
{
|
||||
static python::detail::new_reference convert(object_cref arg, bool align);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Construct a new array scalar with the given size and void dtype.
|
||||
*
|
||||
* Data is initialized to zero. One can create a standalone scalar object
|
||||
* with a certain dtype "dt" with:
|
||||
* @code
|
||||
* void_ scalar = void_(dt.get_itemsize()).view(dt);
|
||||
* @endcode
|
||||
*/
|
||||
explicit void_(Py_ssize_t size);
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(void_, object);
|
||||
|
||||
/// @brief Return a view of the scalar with the given dtype.
|
||||
void_ view(dtype const & dt) const;
|
||||
|
||||
/// @brief Copy the scalar (deep for all non-object fields).
|
||||
void_ copy() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::numpy
|
||||
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(numpy::void_);
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_SCALARS_HPP_INCLUDED
|
||||
209
boost/numpy/ufunc.hpp
Normal file
209
boost/numpy/ufunc.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BOOST_NUMPY_UFUNC_HPP_INCLUDED
|
||||
#define BOOST_NUMPY_UFUNC_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/numpy/ufunc.hpp
|
||||
* @brief Utilities to create ufunc-like broadcasting functions out of C++ functors.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/numpy/dtype.hpp>
|
||||
#include <boost/numpy/ndarray.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for PyArray_MultiIter.
|
||||
*
|
||||
* multi_iter is a Python object, but a very low-level one. It should generally only be used
|
||||
* in loops of the form:
|
||||
* @code
|
||||
* while (iter.not_done()) {
|
||||
* ...
|
||||
* iter.next();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @todo I can't tell if this type is exposed in Python anywhere; if it is, we should use that name.
|
||||
* It's more dangerous than most object managers, however - maybe it actually belongs in
|
||||
* a detail namespace?
|
||||
*/
|
||||
class multi_iter : public python::object
|
||||
{
|
||||
public:
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(multi_iter, python::object);
|
||||
|
||||
/// @brief Increment the iterator.
|
||||
void next();
|
||||
|
||||
/// @brief Check if the iterator is at its end.
|
||||
bool not_done() const;
|
||||
|
||||
/// @brief Return a pointer to the element of the nth broadcasted array.
|
||||
char * get_data(int n) const;
|
||||
|
||||
/// @brief Return the number of dimensions of the broadcasted array expression.
|
||||
int const get_nd() const;
|
||||
|
||||
/// @brief Return the shape of the broadcasted array expression as an array of integers.
|
||||
Py_intptr_t const * get_shape() const;
|
||||
|
||||
/// @brief Return the shape of the broadcasted array expression in the nth dimension.
|
||||
Py_intptr_t const shape(int n) const;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Construct a multi_iter over a single sequence or scalar object.
|
||||
multi_iter make_multi_iter(python::object const & a1);
|
||||
|
||||
/// @brief Construct a multi_iter by broadcasting two objects.
|
||||
multi_iter make_multi_iter(python::object const & a1, python::object const & a2);
|
||||
|
||||
/// @brief Construct a multi_iter by broadcasting three objects.
|
||||
multi_iter make_multi_iter(python::object const & a1, python::object const & a2, python::object const & a3);
|
||||
|
||||
/**
|
||||
* @brief Helps wrap a C++ functor taking a single scalar argument as a broadcasting ufunc-like
|
||||
* Python object.
|
||||
*
|
||||
* Typical usage looks like this:
|
||||
* @code
|
||||
* struct TimesPI
|
||||
* {
|
||||
* typedef double argument_type;
|
||||
* typedef double result_type;
|
||||
* double operator()(double input) const { return input * M_PI; }
|
||||
* };
|
||||
*
|
||||
* BOOST_PYTHON_MODULE(example)
|
||||
* {
|
||||
* class_< TimesPI >("TimesPI")
|
||||
* .def("__call__", unary_ufunc<TimesPI>::make());
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
template <typename TUnaryFunctor,
|
||||
typename TArgument=typename TUnaryFunctor::argument_type,
|
||||
typename TResult=typename TUnaryFunctor::result_type>
|
||||
struct unary_ufunc
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A C++ function with object arguments that broadcasts its arguments before
|
||||
* passing them to the underlying C++ functor.
|
||||
*/
|
||||
static python::object call(TUnaryFunctor & self, python::object const & input, python::object const & output)
|
||||
{
|
||||
dtype in_dtype = dtype::get_builtin<TArgument>();
|
||||
dtype out_dtype = dtype::get_builtin<TResult>();
|
||||
ndarray in_array = from_object(input, in_dtype, ndarray::ALIGNED);
|
||||
ndarray out_array = (output != python::object()) ?
|
||||
from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE)
|
||||
: zeros(in_array.get_nd(), in_array.get_shape(), out_dtype);
|
||||
multi_iter iter = make_multi_iter(in_array, out_array);
|
||||
while (iter.not_done())
|
||||
{
|
||||
TArgument * argument = reinterpret_cast<TArgument*>(iter.get_data(0));
|
||||
TResult * result = reinterpret_cast<TResult*>(iter.get_data(1));
|
||||
*result = self(*argument);
|
||||
iter.next();
|
||||
}
|
||||
return out_array.scalarize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a boost.python function object from call() with reasonable keyword names.
|
||||
*
|
||||
* Users will often want to specify their own keyword names with the same signature, but this
|
||||
* is a convenient shortcut.
|
||||
*/
|
||||
static python::object make()
|
||||
{
|
||||
namespace p = python;
|
||||
return p::make_function(call, p::default_call_policies(), (p::arg("input"), p::arg("output")=p::object()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helps wrap a C++ functor taking a pair of scalar arguments as a broadcasting ufunc-like
|
||||
* Python object.
|
||||
*
|
||||
* Typical usage looks like this:
|
||||
* @code
|
||||
* struct CosSum
|
||||
* {
|
||||
* typedef double first_argument_type;
|
||||
* typedef double second_argument_type;
|
||||
* typedef double result_type;
|
||||
* double operator()(double input1, double input2) const { return std::cos(input1 + input2); }
|
||||
* };
|
||||
*
|
||||
* BOOST_PYTHON_MODULE(example)
|
||||
* {
|
||||
* class_< CosSum >("CosSum")
|
||||
* .def("__call__", binary_ufunc<CosSum>::make());
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
template <typename TBinaryFunctor,
|
||||
typename TArgument1=typename TBinaryFunctor::first_argument_type,
|
||||
typename TArgument2=typename TBinaryFunctor::second_argument_type,
|
||||
typename TResult=typename TBinaryFunctor::result_type>
|
||||
struct binary_ufunc
|
||||
{
|
||||
|
||||
static python::object
|
||||
call(TBinaryFunctor & self, python::object const & input1, python::object const & input2,
|
||||
python::object const & output)
|
||||
{
|
||||
dtype in1_dtype = dtype::get_builtin<TArgument1>();
|
||||
dtype in2_dtype = dtype::get_builtin<TArgument2>();
|
||||
dtype out_dtype = dtype::get_builtin<TResult>();
|
||||
ndarray in1_array = from_object(input1, in1_dtype, ndarray::ALIGNED);
|
||||
ndarray in2_array = from_object(input2, in2_dtype, ndarray::ALIGNED);
|
||||
multi_iter iter = make_multi_iter(in1_array, in2_array);
|
||||
ndarray out_array = (output != python::object())
|
||||
? from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE)
|
||||
: zeros(iter.get_nd(), iter.get_shape(), out_dtype);
|
||||
iter = make_multi_iter(in1_array, in2_array, out_array);
|
||||
while (iter.not_done())
|
||||
{
|
||||
TArgument1 * argument1 = reinterpret_cast<TArgument1*>(iter.get_data(0));
|
||||
TArgument2 * argument2 = reinterpret_cast<TArgument2*>(iter.get_data(1));
|
||||
TResult * result = reinterpret_cast<TResult*>(iter.get_data(2));
|
||||
*result = self(*argument1, *argument2);
|
||||
iter.next();
|
||||
}
|
||||
return out_array.scalarize();
|
||||
}
|
||||
|
||||
static python::object make()
|
||||
{
|
||||
namespace p = python;
|
||||
return p::make_function(call, p::default_call_policies(),
|
||||
(p::arg("input1"), p::arg("input2"), p::arg("output")=p::object()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::numpy
|
||||
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(numpy::multi_iter);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_NUMPY_UFUNC_HPP_INCLUDED
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy.hpp
|
||||
* @brief Main public header file for boost.python.numpy.
|
||||
*/
|
||||
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
#include <boost/python/numpy/ndarray.hpp>
|
||||
#include <boost/python/numpy/scalars.hpp>
|
||||
#include <boost/python/numpy/matrix.hpp>
|
||||
#include <boost/python/numpy/ufunc.hpp>
|
||||
#include <boost/python/numpy/invoke_matching.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief Initialize the Numpy C-API
|
||||
*
|
||||
* This must be called before using anything in boost.python.numpy;
|
||||
* It should probably be the first line inside BOOST_PYTHON_MODULE.
|
||||
*
|
||||
* @internal This just calls the Numpy C-API functions "import_array()"
|
||||
* and "import_ufunc()".
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_HPP_INCLUDED
|
||||
@@ -1,59 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_DTYPE_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_DTYPE_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/dtype.hpp
|
||||
* @brief Object manager for Python's numpy.dtype class.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/numpy/numpy_object_mgr_traits.hpp>
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/type_traits/add_pointer.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.dtype.
|
||||
*
|
||||
* @todo This could have a lot more interesting accessors.
|
||||
*/
|
||||
class dtype : public object {
|
||||
static python::detail::new_reference convert(object_cref arg, bool align);
|
||||
public:
|
||||
|
||||
/// @brief Convert an arbitrary Python object to a data-type descriptor object.
|
||||
template <typename T>
|
||||
explicit dtype(T arg, bool align=false) : object(convert(arg, align)) {}
|
||||
|
||||
/**
|
||||
* @brief Get the built-in numpy dtype associated with the given scalar template type.
|
||||
*
|
||||
* This is perhaps the most useful part of the numpy API: it returns the dtype object
|
||||
* corresponding to a built-in C++ type. This should work for any integer or floating point
|
||||
* type supported by numpy, and will also work for std::complex if
|
||||
* sizeof(std::complex<T>) == 2*sizeof(T).
|
||||
*
|
||||
* It can also be useful for users to add explicit specializations for POD structs
|
||||
* that return field-based dtypes.
|
||||
*/
|
||||
template <typename T> static dtype get_builtin();
|
||||
|
||||
/// @brief Return the size of the data type in bytes.
|
||||
int get_itemsize() const;
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(dtype, object);
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(python::numpy::dtype);
|
||||
} // namespace boost::python::converter
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_DTYPE_HPP_INCLUDED
|
||||
@@ -1,184 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/invoke_matching.hpp
|
||||
* @brief Template invocation based on dtype matching.
|
||||
*/
|
||||
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
#include <boost/python/numpy/ndarray.hpp>
|
||||
|
||||
#include <boost/mpl/integral_c.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace numpy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct add_pointer_meta {
|
||||
|
||||
template <typename T>
|
||||
struct apply {
|
||||
typedef typename boost::add_pointer<T>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct dtype_template_match_found {};
|
||||
struct nd_template_match_found {};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T *) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker< boost::reference_wrapper<Function> > {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T *) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function & func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker {
|
||||
|
||||
template <int N>
|
||||
void operator()(boost::mpl::integral_c<int,N> *) const {
|
||||
if (m_nd == N) {
|
||||
m_func.template apply<N>();
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker< boost::reference_wrapper<Function> > {
|
||||
|
||||
template <int N>
|
||||
void operator()(boost::mpl::integral_c<int,N> *) const {
|
||||
if (m_nd == N) {
|
||||
m_func.template apply<N>();
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function & func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_nd(int nd, Function f) {
|
||||
detail::nd_template_invoker<Function> invoker(nd, f);
|
||||
try {
|
||||
boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);
|
||||
} catch (detail::nd_template_match_found &) {
|
||||
return;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "number of dimensions not found in template list.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_dtype(dtype const & dtype_, Function f) {
|
||||
detail::dtype_template_invoker<Function> invoker(dtype_, f);
|
||||
try {
|
||||
boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);
|
||||
} catch (detail::dtype_template_match_found &) {
|
||||
return;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "dtype not found in template list.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename Function>
|
||||
struct array_template_invoker_wrapper_2 {
|
||||
|
||||
template <int N>
|
||||
void apply() const {
|
||||
m_func.template apply<T,N>();
|
||||
}
|
||||
|
||||
array_template_invoker_wrapper_2(Function & func) :
|
||||
m_func(func) {}
|
||||
|
||||
private:
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper_1 {
|
||||
|
||||
template <typename T>
|
||||
void apply() const {
|
||||
invoke_matching_nd<DimSequence>(m_nd, array_template_invoker_wrapper_2<T,Function>(m_func));
|
||||
}
|
||||
|
||||
array_template_invoker_wrapper_1(int nd, Function & func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper_1< DimSequence, boost::reference_wrapper<Function> >
|
||||
: public array_template_invoker_wrapper_1< DimSequence, Function >
|
||||
{
|
||||
array_template_invoker_wrapper_1(int nd, Function & func) :
|
||||
array_template_invoker_wrapper_1< DimSequence, Function >(nd, func) {}
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
template <typename TypeSequence, typename DimSequence, typename Function>
|
||||
void invoke_matching_array(ndarray const & array_, Function f) {
|
||||
detail::array_template_invoker_wrapper_1<DimSequence,Function> wrapper(array_.get_nd(), f);
|
||||
invoke_matching_dtype<TypeSequence>(array_.get_dtype(), wrapper);
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::python::numpy
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
@@ -1,62 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_MATRIX_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_MATRIX_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/matrix.hpp
|
||||
* @brief Object manager for numpy.matrix.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/python/numpy/ndarray.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.matrix.
|
||||
*
|
||||
* @internal numpy.matrix is defined in Python, so object_manager_traits<matrix>::get_pytype()
|
||||
* is implemented by importing numpy and getting the "matrix" attribute of the module.
|
||||
* We then just hope that doesn't get destroyed while we need it, because if we put
|
||||
* a dynamic python object in a static-allocated boost::python::object or handle<>,
|
||||
* bad things happen when Python shuts down. I think this solution is safe, but I'd
|
||||
* love to get that confirmed.
|
||||
*/
|
||||
class matrix : public ndarray {
|
||||
static object construct(object_cref obj, dtype const & dt, bool copy);
|
||||
static object construct(object_cref obj, bool copy);
|
||||
public:
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(matrix, ndarray);
|
||||
|
||||
/// @brief Equivalent to "numpy.matrix(obj,dt,copy)" in Python.
|
||||
explicit matrix(object const & obj, dtype const & dt, bool copy=true) :
|
||||
ndarray(extract<ndarray>(construct(obj, dt, copy))) {}
|
||||
|
||||
/// @brief Equivalent to "numpy.matrix(obj,copy=copy)" in Python.
|
||||
explicit matrix(object const & obj, bool copy=true) :
|
||||
ndarray(extract<ndarray>(construct(obj, copy))) {}
|
||||
|
||||
/// \brief Return a view of the matrix with the given dtype.
|
||||
matrix view(dtype const & dt) const;
|
||||
|
||||
/// \brief Copy the scalar (deep for all non-object fields).
|
||||
matrix copy() const;
|
||||
|
||||
/// \brief Transpose the matrix.
|
||||
matrix transpose() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(python::numpy::matrix);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_MATRIX_HPP_INCLUDED
|
||||
@@ -1,287 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/ndarray.hpp
|
||||
* @brief Object manager and various utilities for numpy.ndarray.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/python/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.ndarray.
|
||||
*
|
||||
* @todo This could have a lot more functionality (like boost::python::numeric::array).
|
||||
* Right now all that exists is what was needed to move raw data between C++ and Python.
|
||||
*/
|
||||
class ndarray : public object {
|
||||
|
||||
/**
|
||||
* @brief An internal struct that's byte-compatible with PyArrayObject.
|
||||
*
|
||||
* This is just a hack to allow inline access to this stuff while hiding numpy/arrayobject.h
|
||||
* from the user.
|
||||
*/
|
||||
struct array_struct {
|
||||
PyObject_HEAD
|
||||
char * data;
|
||||
int nd;
|
||||
Py_intptr_t * shape;
|
||||
Py_intptr_t * strides;
|
||||
PyObject * base;
|
||||
PyObject * descr;
|
||||
int flags;
|
||||
PyObject * weakreflist;
|
||||
};
|
||||
|
||||
/// @brief Return the held Python object as an array_struct.
|
||||
array_struct * get_struct() const { return reinterpret_cast<array_struct*>(this->ptr()); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Enum to represent (some) of Numpy's internal flags.
|
||||
*
|
||||
* These don't match the actual Numpy flag values; we can't get those without including
|
||||
* numpy/arrayobject.h or copying them directly. That's very unfortunate.
|
||||
*
|
||||
* @todo I'm torn about whether this should be an enum. It's very convenient to not
|
||||
* make these simple integer values for overloading purposes, but the need to
|
||||
* define every possible combination and custom bitwise operators is ugly.
|
||||
*/
|
||||
enum bitflag {
|
||||
NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2,
|
||||
ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8,
|
||||
CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8,
|
||||
FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8,
|
||||
UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8
|
||||
};
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(ndarray, object);
|
||||
|
||||
/// @brief Return a view of the scalar with the given dtype.
|
||||
ndarray view(dtype const & dt) const;
|
||||
|
||||
/// @brief Copy the scalar (deep for all non-object fields).
|
||||
ndarray copy() const;
|
||||
|
||||
/// @brief Return the size of the nth dimension.
|
||||
int const shape(int n) const { return get_shape()[n]; }
|
||||
|
||||
/// @brief Return the stride of the nth dimension.
|
||||
int const strides(int n) const { return get_strides()[n]; }
|
||||
|
||||
/**
|
||||
* @brief Return the array's raw data pointer.
|
||||
*
|
||||
* This returns char so stride math works properly on it. It's pretty much
|
||||
* expected that the user will have to reinterpret_cast it.
|
||||
*/
|
||||
char * get_data() const { return get_struct()->data; }
|
||||
|
||||
/// @brief Return the array's data-type descriptor object.
|
||||
dtype get_dtype() const;
|
||||
|
||||
/// @brief Return the object that owns the array's data, or None if the array owns its own data.
|
||||
object get_base() const;
|
||||
|
||||
/// @brief Set the object that owns the array's data. Use with care.
|
||||
void set_base(object const & base);
|
||||
|
||||
/// @brief Return the shape of the array as an array of integers (length == get_nd()).
|
||||
Py_intptr_t const * get_shape() const { return get_struct()->shape; }
|
||||
|
||||
/// @brief Return the stride of the array as an array of integers (length == get_nd()).
|
||||
Py_intptr_t const * get_strides() const { return get_struct()->strides; }
|
||||
|
||||
/// @brief Return the number of array dimensions.
|
||||
int const get_nd() const { return get_struct()->nd; }
|
||||
|
||||
/// @brief Return the array flags.
|
||||
bitflag const get_flags() const;
|
||||
|
||||
/// @brief Reverse the dimensions of the array.
|
||||
ndarray transpose() const;
|
||||
|
||||
/// @brief Eliminate any unit-sized dimensions.
|
||||
ndarray squeeze() const;
|
||||
|
||||
/// @brief Equivalent to self.reshape(*shape) in Python.
|
||||
ndarray reshape(tuple const & shape) const;
|
||||
|
||||
/**
|
||||
* @brief If the array contains only a single element, return it as an array scalar; otherwise return
|
||||
* the array.
|
||||
*
|
||||
* @internal This is simply a call to PyArray_Return();
|
||||
*/
|
||||
object scalarize() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a new array with the given shape and data type, with data initialized to zero.
|
||||
*/
|
||||
ndarray zeros(tuple const & shape, dtype const & dt);
|
||||
ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt);
|
||||
|
||||
/**
|
||||
* @brief Construct a new array with the given shape and data type, with data left uninitialized.
|
||||
*/
|
||||
ndarray empty(tuple const & shape, dtype const & dt);
|
||||
ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt);
|
||||
|
||||
/**
|
||||
* @brief Construct a new array from an arbitrary Python sequence.
|
||||
*
|
||||
* @todo This does't seem to handle ndarray subtypes the same way that "numpy.array" does in Python.
|
||||
*/
|
||||
ndarray array(object const & obj);
|
||||
ndarray array(object const & obj, dtype const & dt);
|
||||
|
||||
namespace detail {
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
template <typename Container>
|
||||
ndarray from_data_impl(
|
||||
void * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
object const & owner,
|
||||
bool writeable,
|
||||
typename boost::enable_if< boost::is_integral<typename Container::value_type> >::type * enabled = NULL
|
||||
) {
|
||||
std::vector<Py_intptr_t> shape_(shape.begin(),shape.end());
|
||||
std::vector<Py_intptr_t> strides_(strides.begin(), strides.end());
|
||||
return from_data_impl(data, dt, shape_, strides_, owner, writeable);
|
||||
}
|
||||
|
||||
ndarray from_data_impl(
|
||||
void * data,
|
||||
dtype const & dt,
|
||||
object const & shape,
|
||||
object const & strides,
|
||||
object const & owner,
|
||||
bool writeable
|
||||
);
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
/**
|
||||
* @brief Construct a new ndarray object from a raw pointer.
|
||||
*
|
||||
* @param[in] data Raw pointer to the first element of the array.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] shape Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] strides Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] owner An arbitray Python object that owns that data pointer. The array object will
|
||||
* keep a reference to the object, and decrement it's reference count when the
|
||||
* array goes out of scope. Pass None at your own peril.
|
||||
*
|
||||
* @todo Should probably take ranges of iterators rather than actual container objects.
|
||||
*/
|
||||
template <typename Container>
|
||||
inline ndarray from_data(
|
||||
void * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
object const & owner
|
||||
) {
|
||||
return numpy::detail::from_data_impl(data, dt, shape, strides, owner, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new ndarray object from a raw pointer.
|
||||
*
|
||||
* @param[in] data Raw pointer to the first element of the array.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] shape Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] strides Shape of the array as STL container of integers; must have begin() and end().
|
||||
* @param[in] owner An arbitray Python object that owns that data pointer. The array object will
|
||||
* keep a reference to the object, and decrement it's reference count when the
|
||||
* array goes out of scope. Pass None at your own peril.
|
||||
*
|
||||
* This overload takes a const void pointer and sets the "writeable" flag of the array to false.
|
||||
*
|
||||
* @todo Should probably take ranges of iterators rather than actual container objects.
|
||||
*/
|
||||
template <typename Container>
|
||||
inline ndarray from_data(
|
||||
void const * data,
|
||||
dtype const & dt,
|
||||
Container shape,
|
||||
Container strides,
|
||||
object const & owner
|
||||
) {
|
||||
return numpy::detail::from_data_impl(const_cast<void*>(data), dt, shape, strides, owner, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transform an arbitrary object into a numpy array with the given requirements.
|
||||
*
|
||||
* @param[in] obj An arbitrary python object to convert. Arrays that meet the requirements
|
||||
* will be passed through directly.
|
||||
* @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin().
|
||||
* @param[in] nd_min Minimum number of dimensions.
|
||||
* @param[in] nd_max Maximum number of dimensions.
|
||||
* @param[in] flags Bitwise OR of flags specifying additional requirements.
|
||||
*/
|
||||
ndarray from_object(object const & obj, dtype const & dt,
|
||||
int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE);
|
||||
|
||||
inline ndarray from_object(object const & obj, dtype const & dt,
|
||||
int nd, ndarray::bitflag flags=ndarray::NONE) {
|
||||
return from_object(obj, dt, nd, nd, flags);
|
||||
}
|
||||
|
||||
inline ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE) {
|
||||
return from_object(obj, dt, 0, 0, flags);
|
||||
}
|
||||
|
||||
ndarray from_object(object const & obj, int nd_min, int nd_max,
|
||||
ndarray::bitflag flags=ndarray::NONE);
|
||||
|
||||
inline ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE) {
|
||||
return from_object(obj, nd, nd, flags);
|
||||
}
|
||||
|
||||
inline ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) {
|
||||
return from_object(obj, 0, 0, flags);
|
||||
}
|
||||
|
||||
inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) {
|
||||
return ndarray::bitflag(int(a) | int(b));
|
||||
}
|
||||
|
||||
inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b) {
|
||||
return ndarray::bitflag(int(a) & int(b));
|
||||
}
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(python::numpy::ndarray);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_NDARRAY_HPP_INCLUDED
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/numpy_object_mgr_traits.hpp
|
||||
* @brief Macro that specializes object_manager_traits by requiring a
|
||||
* source-file implementation of get_pytype().
|
||||
*/
|
||||
|
||||
#define NUMPY_OBJECT_MANAGER_TRAITS(manager) \
|
||||
template <> \
|
||||
struct object_manager_traits<manager> { \
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized = true); \
|
||||
static inline python::detail::new_reference adopt(PyObject* x) { \
|
||||
return python::detail::new_reference(python::pytype_check((PyTypeObject*)get_pytype(), x)); \
|
||||
} \
|
||||
static bool check(PyObject* x) { \
|
||||
return ::PyObject_IsInstance(x, (PyObject*)get_pytype()); \
|
||||
} \
|
||||
static manager* checked_downcast(PyObject* x) { \
|
||||
return python::downcast<manager>((checked_downcast_impl)(x, (PyTypeObject*)get_pytype())); \
|
||||
} \
|
||||
static PyTypeObject const * get_pytype(); \
|
||||
}
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_NUMPY_OBJECT_MGR_TRAITS_HPP_INCLUDED
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_SCALARS_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_SCALARS_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/scalars.hpp
|
||||
* @brief Object managers for array scalars (currently only numpy.void is implemented).
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for numpy.void.
|
||||
*
|
||||
* @todo This could have a lot more functionality.
|
||||
*/
|
||||
class void_ : public object {
|
||||
static python::detail::new_reference convert(object_cref arg, bool align);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Construct a new array scalar with the given size and void dtype.
|
||||
*
|
||||
* Data is initialized to zero. One can create a standalone scalar object
|
||||
* with a certain dtype "dt" with:
|
||||
* @code
|
||||
* void_ scalar = void_(dt.get_itemsize()).view(dt);
|
||||
* @endcode
|
||||
*/
|
||||
explicit void_(Py_ssize_t size);
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(void_, object);
|
||||
|
||||
/// @brief Return a view of the scalar with the given dtype.
|
||||
void_ view(dtype const & dt) const;
|
||||
|
||||
/// @brief Copy the scalar (deep for all non-object fields).
|
||||
void_ copy() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(python::numpy::void_);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_SCALARS_HPP_INCLUDED
|
||||
@@ -1,193 +0,0 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_UFUNC_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_UFUNC_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/ufunc.hpp
|
||||
* @brief Utilities to create ufunc-like broadcasting functions out of C++ functors.
|
||||
*/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/numpy/numpy_object_mgr_traits.hpp>
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
#include <boost/python/numpy/ndarray.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
/**
|
||||
* @brief A boost.python "object manager" (subclass of object) for PyArray_MultiIter.
|
||||
*
|
||||
* multi_iter is a Python object, but a very low-level one. It should generally only be used
|
||||
* in loops of the form:
|
||||
* @code
|
||||
* while (iter.not_done()) {
|
||||
* ...
|
||||
* iter.next();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @todo I can't tell if this type is exposed in Python anywhere; if it is, we should use that name.
|
||||
* It's more dangerous than most object managers, however - maybe it actually belongs in
|
||||
* a detail namespace?
|
||||
*/
|
||||
class multi_iter : public object {
|
||||
public:
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(multi_iter, object);
|
||||
|
||||
/// @brief Increment the iterator.
|
||||
void next();
|
||||
|
||||
/// @brief Check if the iterator is at its end.
|
||||
bool not_done() const;
|
||||
|
||||
/// @brief Return a pointer to the element of the nth broadcasted array.
|
||||
char * get_data(int n) const;
|
||||
|
||||
/// @brief Return the number of dimensions of the broadcasted array expression.
|
||||
int const get_nd() const;
|
||||
|
||||
/// @brief Return the shape of the broadcasted array expression as an array of integers.
|
||||
Py_intptr_t const * get_shape() const;
|
||||
|
||||
/// @brief Return the shape of the broadcasted array expression in the nth dimension.
|
||||
Py_intptr_t const shape(int n) const;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Construct a multi_iter over a single sequence or scalar object.
|
||||
multi_iter make_multi_iter(object const & a1);
|
||||
|
||||
/// @brief Construct a multi_iter by broadcasting two objects.
|
||||
multi_iter make_multi_iter(object const & a1, object const & a2);
|
||||
|
||||
/// @brief Construct a multi_iter by broadcasting three objects.
|
||||
multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3);
|
||||
|
||||
/**
|
||||
* @brief Helps wrap a C++ functor taking a single scalar argument as a broadcasting ufunc-like
|
||||
* Python object.
|
||||
*
|
||||
* Typical usage looks like this:
|
||||
* @code
|
||||
* struct TimesPI {
|
||||
* typedef double argument_type;
|
||||
* typedef double result_type;
|
||||
* double operator()(double input) const { return input * M_PI; }
|
||||
* };
|
||||
*
|
||||
* BOOST_PYTHON_MODULE(example) {
|
||||
* class_< TimesPI >("TimesPI")
|
||||
* .def("__call__", unary_ufunc<TimesPI>::make())
|
||||
* ;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
template <typename TUnaryFunctor,
|
||||
typename TArgument=typename TUnaryFunctor::argument_type,
|
||||
typename TResult=typename TUnaryFunctor::result_type>
|
||||
struct unary_ufunc {
|
||||
|
||||
/**
|
||||
* @brief A C++ function with object arguments that broadcasts its arguments before
|
||||
* passing them to the underlying C++ functor.
|
||||
*/
|
||||
static object call(TUnaryFunctor & self, object const & input, object const & output) {
|
||||
dtype in_dtype = dtype::get_builtin<TArgument>();
|
||||
dtype out_dtype = dtype::get_builtin<TResult>();
|
||||
ndarray in_array = from_object(input, in_dtype, ndarray::ALIGNED);
|
||||
ndarray out_array = (output != object()) ?
|
||||
from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE)
|
||||
: zeros(in_array.get_nd(), in_array.get_shape(), out_dtype);
|
||||
multi_iter iter = make_multi_iter(in_array, out_array);
|
||||
while (iter.not_done()) {
|
||||
TArgument * argument = reinterpret_cast<TArgument*>(iter.get_data(0));
|
||||
TResult * result = reinterpret_cast<TResult*>(iter.get_data(1));
|
||||
*result = self(*argument);
|
||||
iter.next();
|
||||
}
|
||||
return out_array.scalarize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a boost.python function object from call() with reasonable keyword names.
|
||||
*
|
||||
* Users will often want to specify their own keyword names with the same signature, but this
|
||||
* is a convenient shortcut.
|
||||
*/
|
||||
static object make() {
|
||||
return make_function(call, default_call_policies(), (arg("input"), arg("output")=object()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helps wrap a C++ functor taking a pair of scalar arguments as a broadcasting ufunc-like
|
||||
* Python object.
|
||||
*
|
||||
* Typical usage looks like this:
|
||||
* @code
|
||||
* struct CosSum {
|
||||
* typedef double first_argument_type;
|
||||
* typedef double second_argument_type;
|
||||
* typedef double result_type;
|
||||
* double operator()(double input1, double input2) const { return std::cos(input1 + input2); }
|
||||
* };
|
||||
*
|
||||
* BOOST_PYTHON_MODULE(example) {
|
||||
* class_< CosSum >("CosSum")
|
||||
* .def("__call__", binary_ufunc<CosSum>::make())
|
||||
* ;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
template <typename TBinaryFunctor,
|
||||
typename TArgument1=typename TBinaryFunctor::first_argument_type,
|
||||
typename TArgument2=typename TBinaryFunctor::second_argument_type,
|
||||
typename TResult=typename TBinaryFunctor::result_type>
|
||||
struct binary_ufunc {
|
||||
|
||||
static object call(TBinaryFunctor & self, object const & input1, object const & input2,
|
||||
object const & output)
|
||||
{
|
||||
dtype in1_dtype = dtype::get_builtin<TArgument1>();
|
||||
dtype in2_dtype = dtype::get_builtin<TArgument2>();
|
||||
dtype out_dtype = dtype::get_builtin<TResult>();
|
||||
ndarray in1_array = from_object(input1, in1_dtype, ndarray::ALIGNED);
|
||||
ndarray in2_array = from_object(input2, in2_dtype, ndarray::ALIGNED);
|
||||
multi_iter iter = make_multi_iter(in1_array, in2_array);
|
||||
ndarray out_array = (output != object()) ?
|
||||
from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE)
|
||||
: zeros(iter.get_nd(), iter.get_shape(), out_dtype);
|
||||
iter = make_multi_iter(in1_array, in2_array, out_array);
|
||||
while (iter.not_done()) {
|
||||
TArgument1 * argument1 = reinterpret_cast<TArgument1*>(iter.get_data(0));
|
||||
TArgument2 * argument2 = reinterpret_cast<TArgument2*>(iter.get_data(1));
|
||||
TResult * result = reinterpret_cast<TResult*>(iter.get_data(2));
|
||||
*result = self(*argument1, *argument2);
|
||||
iter.next();
|
||||
}
|
||||
return out_array.scalarize();
|
||||
}
|
||||
|
||||
static object make() {
|
||||
return make_function(
|
||||
call, default_call_policies(),
|
||||
(arg("input1"), arg("input2"), arg("output")=object())
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
NUMPY_OBJECT_MANAGER_TRAITS(python::numpy::multi_iter);
|
||||
|
||||
} // namespace boost::python::converter
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_UFUNC_HPP_INCLUDED
|
||||
4
libs/numpy/src/SConscript
Normal file
4
libs/numpy/src/SConscript
Normal file
@@ -0,0 +1,4 @@
|
||||
Import("boost_numpy_env")
|
||||
lib = boost_numpy_env.SharedLibrary("boost_numpy", Glob("*.cpp"))
|
||||
|
||||
Return("lib")
|
||||
102
libs/numpy/src/dtype.cpp
Normal file
102
libs/numpy/src/dtype.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#define BOOST_NUMPY_INTERNAL
|
||||
#include <boost/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]"); \
|
||||
python::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 converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype)
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
template <typename T> struct dtype_traits;
|
||||
|
||||
python::detail::new_reference dtype::convert(python::object const & arg, bool align)
|
||||
{
|
||||
PyArray_Descr* obj=NULL;
|
||||
if (align)
|
||||
{
|
||||
if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0)
|
||||
python::throw_error_already_set();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PyArray_DescrConverter(arg.ptr(), &obj) < 0)
|
||||
python::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(bool, NPY_BOOL);
|
||||
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_longlong, NPY_LONGLONG);
|
||||
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);
|
||||
|
||||
#if 0
|
||||
template <> struct dtype_traits<bool>
|
||||
{
|
||||
static dtype get()
|
||||
{
|
||||
if (sizeof(bool) == sizeof(npy_ubyte)) return dtype_traits<npy_ubyte>::get();
|
||||
if (sizeof(bool) == sizeof(npy_bool)) return dtype_traits<npy_bool>::get();
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot determine numpy dtype corresponding to C++ bool.");
|
||||
python::throw_error_already_set();
|
||||
}
|
||||
};
|
||||
template dtype dtype::get_builtin<bool>();
|
||||
#endif
|
||||
|
||||
} // namespace boost::numpy
|
||||
} // namespace boost
|
||||
63
libs/numpy/src/matrix.cpp
Normal file
63
libs/numpy/src/matrix.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#define BOOST_NUMPY_INTERNAL
|
||||
#include <boost/numpy/internal.hpp>
|
||||
#include <boost/numpy/matrix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline python::object get_matrix_type()
|
||||
{
|
||||
python::object module = python::import("numpy");
|
||||
return module.attr("matrix");
|
||||
}
|
||||
} // namespace boost::numpy::detail
|
||||
} // namespace boost::numpy
|
||||
|
||||
namespace python
|
||||
{
|
||||
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 boost::python
|
||||
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
python::object matrix::construct(python::object const & obj, dtype const & dt, bool copy)
|
||||
{
|
||||
return numpy::detail::get_matrix_type()(obj, dt, copy);
|
||||
}
|
||||
|
||||
python::object matrix::construct(python::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(python::extract<matrix>(ndarray::transpose()));
|
||||
}
|
||||
|
||||
} // namespace boost::numpy
|
||||
} // namespace boost
|
||||
269
libs/numpy/src/ndarray.cpp
Normal file
269
libs/numpy/src/ndarray.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
#define BOOST_NUMPY_INTERNAL
|
||||
#include <boost/numpy/internal.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArray_Type, numpy::ndarray)
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
|
||||
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,
|
||||
python::object const & shape,
|
||||
python::object const & strides,
|
||||
python::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.");
|
||||
python::throw_error_already_set();
|
||||
}
|
||||
for (std::size_t i = 0; i < shape_.size(); ++i)
|
||||
{
|
||||
shape_[i] = python::extract<Py_intptr_t>(shape[i]);
|
||||
strides_[i] = python::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,
|
||||
python::object const & owner,
|
||||
bool writeable)
|
||||
{
|
||||
if (shape.size() != strides.size())
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match.");
|
||||
python::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));
|
||||
}
|
||||
|
||||
python::object ndarray::get_base() const
|
||||
{
|
||||
if (get_struct()->base == NULL) return object();
|
||||
return python::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()))));
|
||||
}
|
||||
|
||||
ndarray ndarray::reshape(python::tuple const & shape) const
|
||||
{
|
||||
return ndarray(python::detail::new_reference
|
||||
(PyArray_Reshape(reinterpret_cast<PyArrayObject*>(this->ptr()), shape.ptr())));
|
||||
}
|
||||
|
||||
python::object ndarray::scalarize() const
|
||||
{
|
||||
Py_INCREF(ptr());
|
||||
return python::object(python::detail::new_reference(PyArray_Return(reinterpret_cast<PyArrayObject*>(ptr()))));
|
||||
}
|
||||
|
||||
ndarray zeros(python::tuple const & shape, dtype const & dt)
|
||||
{
|
||||
int nd = len(shape);
|
||||
Py_intptr_t dims[nd];
|
||||
for (int n=0; n<nd; ++n) dims[n] = python::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(python::tuple const & shape, dtype const & dt)
|
||||
{
|
||||
int nd = len(shape);
|
||||
Py_intptr_t dims[nd];
|
||||
for (int n=0; n<nd; ++n) dims[n] = python::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(python::object const & obj)
|
||||
{
|
||||
return ndarray(python::detail::new_reference
|
||||
(PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ENSUREARRAY, NULL)));
|
||||
}
|
||||
|
||||
ndarray array(python::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(python::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(python::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)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
16
libs/numpy/src/numpy.cpp
Normal file
16
libs/numpy/src/numpy.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#define BOOST_NUMPY_INTERNAL_MAIN
|
||||
#include <boost/numpy/internal.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
void initialize()
|
||||
{
|
||||
import_array();
|
||||
import_ufunc();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
35
libs/numpy/src/scalars.cpp
Normal file
35
libs/numpy/src/scalars.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#define BOOST_NUMPY_INTERNAL
|
||||
#include <boost/numpy/internal.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyVoidArrType_Type, numpy::void_)
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
|
||||
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*>(""))));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
64
libs/numpy/src/ufunc.cpp
Normal file
64
libs/numpy/src/ufunc.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#define BOOST_NUMPY_INTERNAL
|
||||
#include <boost/numpy/internal.hpp>
|
||||
#include <boost/numpy/ufunc.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace python
|
||||
{
|
||||
namespace converter
|
||||
{
|
||||
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayMultiIter_Type, numpy::multi_iter)
|
||||
} // namespace boost::python::converter
|
||||
} // namespace boost::python
|
||||
|
||||
namespace numpy
|
||||
{
|
||||
|
||||
multi_iter make_multi_iter(python::object const & a1)
|
||||
{
|
||||
return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(1, a1.ptr())));
|
||||
}
|
||||
|
||||
multi_iter make_multi_iter(python::object const & a1, python::object const & a2)
|
||||
{
|
||||
return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(2, a1.ptr(), a2.ptr())));
|
||||
}
|
||||
|
||||
multi_iter make_multi_iter(python::object const & a1, python::object const & a2, python::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];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
libs/numpy/test/SConscript
Normal file
12
libs/numpy/test/SConscript
Normal file
@@ -0,0 +1,12 @@
|
||||
Import("boost_numpy_env")
|
||||
|
||||
test = []
|
||||
|
||||
for name in ("ufunc", "templates"):
|
||||
mod = boost_numpy_env.SharedLibrary("%s_mod" % name, "%s_mod.cpp" % name, SHLIBPREFIX="",
|
||||
LIBS="boost_python_numpy")
|
||||
test.extend(
|
||||
boost_numpy_env.PythonUnitTest("%s.py" % name, mod)
|
||||
)
|
||||
|
||||
Return("test")
|
||||
@@ -29,11 +29,11 @@ class TestIndexing(unittest.TestCase):
|
||||
numpy.testing.assert_equal(indexing_mod.indexarray(x,chk),chk)
|
||||
chk = numpy.array([[0,1],[2,3]])
|
||||
numpy.testing.assert_equal(indexing_mod.indexarray(x,chk),chk)
|
||||
# x = numpy.arange(9).reshape(3,3)
|
||||
# y = numpy.array([0,1])
|
||||
# z = numpy.array([0,2])
|
||||
# chk = numpy.array([0,5])
|
||||
# numpy.testing.assert_equal(indexing_mod.indexarray(x,y,z),chk) # This throws an assertion error, indicates shape mismatch
|
||||
x = numpy.arange(9).reshape(3,3)
|
||||
y = numpy.array([0,1])
|
||||
z = numpy.array([0,2])
|
||||
chk = numpy.array([0,5])
|
||||
#numpy.testing.assert_equal(indexing_mod.indexarray(x,y,z),chk) # This throws an assertion error, indicates shape mismatch
|
||||
x = numpy.arange(0,10)
|
||||
b = x>4
|
||||
chk = numpy.array([5,6,7,8,9])
|
||||
@@ -42,7 +42,7 @@ class TestIndexing(unittest.TestCase):
|
||||
b = numpy.array([0,2])
|
||||
sl = slice(0,2)
|
||||
chk = numpy.array([[0,1,2],[6,7,8]])
|
||||
numpy.testing.assert_equal(indexing_mod.indexslice(x,b,sl),chk)
|
||||
#numpy.testing.assert_equal(indexing_mod.indexslice(x,b,sl),chk)
|
||||
|
||||
if __name__=="__main__":
|
||||
unittest.main()
|
||||
22
libs/numpy/test/indexing_mod.cpp
Normal file
22
libs/numpy/test/indexing_mod.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <boost/numpy.hpp>
|
||||
#include <boost/python/slice.hpp>
|
||||
|
||||
namespace p = boost::python;
|
||||
namespace np = boost::numpy;
|
||||
|
||||
p::object single(np::ndarray ndarr, int i) { return ndarr[i];}
|
||||
p::object slice(np::ndarray ndarr, p::slice sl) { return ndarr[sl];}
|
||||
p::object indexarray(np::ndarray ndarr, np::ndarray d1) { return ndarr[d1];}
|
||||
//p::object indexarray_2d(np::ndarray ndarr, np::ndarray d1,np::ndarray d2) { return ndarr[d1,d2];}
|
||||
//p::object indexslice(np::ndarray ndarr, np::ndarray d1, p::slice sl) { return ndarr[d1][sl];}
|
||||
|
||||
BOOST_PYTHON_MODULE(indexing_mod)
|
||||
{
|
||||
np::initialize();
|
||||
p::def("single", single);
|
||||
p::def("slice", slice);
|
||||
p::def("indexarray", indexarray);
|
||||
// p::def("indexarray", indexarray_2d);
|
||||
// p::def("indexslice", indexslice);
|
||||
|
||||
}
|
||||
38
libs/numpy/test/ndarray_mod.cpp
Normal file
38
libs/numpy/test/ndarray_mod.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <boost/numpy.hpp>
|
||||
|
||||
namespace p = boost::python;
|
||||
namespace np = boost::numpy;
|
||||
|
||||
np::ndarray zeros(p::tuple shape, np::dtype dt) { return np::zeros(shape, dt);}
|
||||
np::ndarray array2(p::object obj, np::dtype dt) { return np::array(obj,dt);}
|
||||
np::ndarray array1(p::object obj) { return np::array(obj);}
|
||||
np::ndarray empty1(p::tuple shape, np::dtype dt) { return np::empty(shape,dt);}
|
||||
|
||||
np::ndarray c_empty(p::tuple shape, np::dtype dt)
|
||||
{
|
||||
// convert 'shape' to a C array so we can test the corresponding
|
||||
// version of the constructor
|
||||
unsigned len = p::len(shape);
|
||||
Py_intptr_t *c_shape = new Py_intptr_t[len];
|
||||
for (unsigned i = 0; i != len; ++i)
|
||||
c_shape[i] = p::extract<Py_intptr_t>(shape[i]);
|
||||
np::ndarray result = np::empty(len, c_shape, dt);
|
||||
delete [] c_shape;
|
||||
return result;
|
||||
}
|
||||
|
||||
np::ndarray transpose(np::ndarray arr) { return arr.transpose();}
|
||||
np::ndarray squeeze(np::ndarray arr) { return arr.squeeze();}
|
||||
np::ndarray reshape(np::ndarray arr,p::tuple tup) { return arr.reshape(tup);}
|
||||
BOOST_PYTHON_MODULE(ndarray_mod)
|
||||
{
|
||||
np::initialize();
|
||||
p::def("zeros", zeros);
|
||||
p::def("array", array2);
|
||||
p::def("array", array1);
|
||||
p::def("empty", empty1);
|
||||
p::def("c_empty", c_empty);
|
||||
p::def("transpose", transpose);
|
||||
p::def("squeeze", squeeze);
|
||||
p::def("reshape", reshape);
|
||||
}
|
||||
16
libs/numpy/test/shapes_mod.cpp
Normal file
16
libs/numpy/test/shapes_mod.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <boost/numpy.hpp>
|
||||
|
||||
namespace p = boost::python;
|
||||
namespace np = boost::numpy;
|
||||
|
||||
np::ndarray reshape(np::ndarray old_array, p::tuple shape)
|
||||
{
|
||||
np::ndarray local_shape = old_array.reshape(shape);
|
||||
return local_shape;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(shapes_mod)
|
||||
{
|
||||
np::initialize();
|
||||
p::def("reshape", reshape);
|
||||
}
|
||||
57
libs/numpy/test/templates_mod.cpp
Normal file
57
libs/numpy/test/templates_mod.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <boost/numpy.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
|
||||
namespace p = boost::python;
|
||||
namespace np = boost::numpy;
|
||||
|
||||
struct ArrayFiller
|
||||
{
|
||||
|
||||
typedef boost::mpl::vector< short, int, float, std::complex<double> > TypeSequence;
|
||||
typedef boost::mpl::vector_c< int, 1, 2 > DimSequence;
|
||||
|
||||
explicit ArrayFiller(np::ndarray const & arg) : argument(arg) {}
|
||||
|
||||
template <typename T, int N>
|
||||
void apply() const
|
||||
{
|
||||
if (N == 1)
|
||||
{
|
||||
char * p = argument.get_data();
|
||||
int stride = argument.strides(0);
|
||||
int size = argument.shape(0);
|
||||
for (int n = 0; n != size; ++n, p += stride)
|
||||
*reinterpret_cast<T*>(p) = static_cast<T>(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
char * row_p = argument.get_data();
|
||||
int row_stride = argument.strides(0);
|
||||
int col_stride = argument.strides(1);
|
||||
int rows = argument.shape(0);
|
||||
int cols = argument.shape(1);
|
||||
int i = 0;
|
||||
for (int n = 0; n != rows; ++n, row_p += row_stride)
|
||||
{
|
||||
char * col_p = row_p;
|
||||
for (int m = 0; m != cols; ++i, ++m, col_p += col_stride)
|
||||
*reinterpret_cast<T*>(col_p) = static_cast<T>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
np::ndarray argument;
|
||||
};
|
||||
|
||||
void fill(np::ndarray const & arg)
|
||||
{
|
||||
ArrayFiller filler(arg);
|
||||
np::invoke_matching_array<ArrayFiller::TypeSequence, ArrayFiller::DimSequence >(arg, filler);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(templates_mod)
|
||||
{
|
||||
np::initialize();
|
||||
p::def("fill", fill);
|
||||
}
|
||||
30
libs/numpy/test/ufunc_mod.cpp
Normal file
30
libs/numpy/test/ufunc_mod.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <boost/numpy.hpp>
|
||||
|
||||
namespace p = boost::python;
|
||||
namespace np = boost::numpy;
|
||||
|
||||
struct UnaryCallable
|
||||
{
|
||||
typedef double argument_type;
|
||||
typedef double result_type;
|
||||
|
||||
double operator()(double r) const { return r * 2;}
|
||||
};
|
||||
|
||||
struct BinaryCallable
|
||||
{
|
||||
typedef double first_argument_type;
|
||||
typedef double second_argument_type;
|
||||
typedef double result_type;
|
||||
|
||||
double operator()(double a, double b) const { return a * 2 + b * 3;}
|
||||
};
|
||||
|
||||
BOOST_PYTHON_MODULE(ufunc_mod)
|
||||
{
|
||||
np::initialize();
|
||||
p::class_<UnaryCallable, boost::shared_ptr<UnaryCallable> >("UnaryCallable")
|
||||
.def("__call__", np::unary_ufunc<UnaryCallable>::make());
|
||||
p::class_< BinaryCallable, boost::shared_ptr<BinaryCallable> >("BinaryCallable")
|
||||
.def("__call__", np::binary_ufunc<BinaryCallable>::make());
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
Import("bp_numpy_env")
|
||||
lib = bp_numpy_env.SharedLibrary("boost_python_numpy", Glob("*.cpp"))
|
||||
|
||||
Return("lib")
|
||||
@@ -1,92 +0,0 @@
|
||||
#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 converter {
|
||||
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, python::numpy::dtype)
|
||||
} // namespace boost::python::converter
|
||||
|
||||
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(bool, NPY_BOOL);
|
||||
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_longlong, NPY_LONGLONG);
|
||||
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);
|
||||
|
||||
#if 0
|
||||
template <> struct dtype_traits<bool> {
|
||||
static dtype get() {
|
||||
if (sizeof(bool) == sizeof(npy_ubyte)) return dtype_traits<npy_ubyte>::get();
|
||||
if (sizeof(bool) == sizeof(npy_bool)) return dtype_traits<npy_bool>::get();
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot determine numpy dtype corresponding to C++ bool.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
};
|
||||
template dtype dtype::get_builtin<bool>();
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::python::numpy
|
||||
@@ -1,51 +0,0 @@
|
||||
#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
|
||||
@@ -1,285 +0,0 @@
|
||||
#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()))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ndarray ndarray::reshape(tuple const & shape) const {
|
||||
return ndarray(
|
||||
python::detail::new_reference(
|
||||
PyArray_Reshape(reinterpret_cast<PyArrayObject*>(this->ptr()), shape.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
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -1,13 +0,0 @@
|
||||
#define BOOST_PYTHON_NUMPY_INTERNAL_MAIN
|
||||
#include <boost/python/numpy/internal.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace numpy {
|
||||
|
||||
void initialize() {
|
||||
import_array();
|
||||
import_ufunc();
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -1,35 +0,0 @@
|
||||
#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*>(""))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -1,48 +0,0 @@
|
||||
#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];
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -1,12 +0,0 @@
|
||||
Import("bp_numpy_env")
|
||||
|
||||
test = []
|
||||
|
||||
for name in ("ufunc", "templates"):
|
||||
mod = bp_numpy_env.SharedLibrary("%s_mod" % name, "%s_mod.cpp" % name, SHLIBPREFIX="",
|
||||
LIBS="boost_python_numpy")
|
||||
test.extend(
|
||||
bp_numpy_env.PythonUnitTest("%s.py" % name, mod)
|
||||
)
|
||||
|
||||
Return("test")
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <boost/python/numpy.hpp>
|
||||
#include <boost/python/slice.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
bp::object single(bp::numpy::ndarray ndarr, int i) { return ndarr[i];}
|
||||
bp::object slice(bp::numpy::ndarray ndarr, bp::slice sl) { return ndarr[sl];}
|
||||
bp::object indexarray(bp::numpy::ndarray ndarr, bp::numpy::ndarray d1) { return ndarr[d1];}
|
||||
bp::object indexarray_2d(bp::numpy::ndarray ndarr, bp::numpy::ndarray d1,bp::numpy::ndarray d2) { return ndarr[d1][d2];}
|
||||
bp::object indexslice(bp::numpy::ndarray ndarr, bp::numpy::ndarray d1,bp::slice sl) { return ndarr[d1][sl];}
|
||||
|
||||
BOOST_PYTHON_MODULE(indexing_mod)
|
||||
{
|
||||
bp::numpy::initialize();
|
||||
bp::def("single", &single);
|
||||
bp::def("slice", &slice);
|
||||
bp::def("indexarray", &indexarray);
|
||||
bp::def("indexarray", &indexarray_2d);
|
||||
bp::def("indexslice", &indexslice);
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#include <boost/python/numpy.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
bp::numpy::ndarray zeros(bp::tuple shape, bp::numpy::dtype dt) {
|
||||
return bp::numpy::zeros(shape, dt);
|
||||
}
|
||||
|
||||
bp::numpy::ndarray array2(bp::object obj,bp::numpy::dtype dt) {
|
||||
return bp::numpy::array(obj,dt);
|
||||
}
|
||||
|
||||
bp::numpy::ndarray array1(bp::object obj) {
|
||||
return bp::numpy::array(obj);
|
||||
}
|
||||
|
||||
bp::numpy::ndarray empty1(bp::tuple shape, bp::numpy::dtype dt) {
|
||||
return bp::numpy::empty(shape,dt);
|
||||
}
|
||||
|
||||
bp::numpy::ndarray c_empty(bp::tuple shape, bp::numpy::dtype dt) {
|
||||
// convert 'shape' to a C array so we can test the corresponding
|
||||
// version of the constructor
|
||||
unsigned len = bp::len(shape);
|
||||
Py_intptr_t *c_shape = new Py_intptr_t[len];
|
||||
for (unsigned i = 0; i != len; ++i)
|
||||
c_shape[i] = bp::extract<Py_intptr_t>(shape[i]);
|
||||
bp::numpy::ndarray result = bp::numpy::empty(len, c_shape, dt);
|
||||
delete [] c_shape;
|
||||
return result;
|
||||
}
|
||||
|
||||
bp::numpy::ndarray transpose(bp::numpy::ndarray arr) {
|
||||
return arr.transpose();
|
||||
}
|
||||
|
||||
bp::numpy::ndarray squeeze(bp::numpy::ndarray arr) {
|
||||
return arr.squeeze();
|
||||
}
|
||||
|
||||
bp::numpy::ndarray reshape(bp::numpy::ndarray arr,bp::tuple tup) {
|
||||
return arr.reshape(tup);
|
||||
}
|
||||
BOOST_PYTHON_MODULE(ndarray_mod) {
|
||||
bp::numpy::initialize();
|
||||
bp::def("zeros", &zeros);
|
||||
bp::def("array",&array2);
|
||||
bp::def("array",&array1);
|
||||
bp::def("empty",&empty1);
|
||||
bp::def("c_empty",&c_empty);
|
||||
bp::def("transpose",&transpose);
|
||||
bp::def("squeeze",&squeeze);
|
||||
bp::def("reshape",&reshape);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <boost/python/numpy.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
bp::numpy::ndarray reshape(bp::numpy::ndarray old_array, bp::tuple shape) {
|
||||
bp::numpy::ndarray local_shape = old_array.reshape(shape);
|
||||
return local_shape;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(shapes_mod) {
|
||||
bp::numpy::initialize();
|
||||
bp::def("reshape", &reshape);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <boost/python/numpy.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
struct ArrayFiller {
|
||||
|
||||
typedef boost::mpl::vector< short, int, float, std::complex<double> > TypeSequence;
|
||||
typedef boost::mpl::vector_c< int, 1, 2 > DimSequence;
|
||||
|
||||
template <typename T, int N>
|
||||
void apply() const {
|
||||
if (N == 1) {
|
||||
char * p = argument.get_data();
|
||||
int stride = argument.strides(0);
|
||||
int size = argument.shape(0);
|
||||
for (int n = 0; n != size; ++n, p += stride) {
|
||||
*reinterpret_cast<T*>(p) = static_cast<T>(n);
|
||||
}
|
||||
} else {
|
||||
char * row_p = argument.get_data();
|
||||
int row_stride = argument.strides(0);
|
||||
int col_stride = argument.strides(1);
|
||||
int rows = argument.shape(0);
|
||||
int cols = argument.shape(1);
|
||||
int i = 0;
|
||||
for (int n = 0; n != rows; ++n, row_p += row_stride) {
|
||||
char * col_p = row_p;
|
||||
for (int m = 0; m != cols; ++i, ++m, col_p += col_stride) {
|
||||
*reinterpret_cast<T*>(col_p) = static_cast<T>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bp::numpy::ndarray argument;
|
||||
|
||||
explicit ArrayFiller(bp::numpy::ndarray const & arg) : argument(arg) {}
|
||||
|
||||
};
|
||||
|
||||
void fill(bp::numpy::ndarray const & arg) {
|
||||
ArrayFiller filler(arg);
|
||||
bp::numpy::invoke_matching_array< ArrayFiller::TypeSequence, ArrayFiller::DimSequence >(arg, filler);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(templates_mod) {
|
||||
bp::numpy::initialize();
|
||||
bp::def("fill", &fill);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <boost/python/numpy.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
struct UnaryCallable {
|
||||
|
||||
typedef double argument_type;
|
||||
typedef double result_type;
|
||||
|
||||
double operator()(double r) const { return r * 2; }
|
||||
|
||||
};
|
||||
|
||||
struct BinaryCallable {
|
||||
|
||||
typedef double first_argument_type;
|
||||
typedef double second_argument_type;
|
||||
typedef double result_type;
|
||||
|
||||
double operator()(double a, double b) const { return a * 2 + b * 3; }
|
||||
|
||||
};
|
||||
|
||||
BOOST_PYTHON_MODULE(ufunc_mod) {
|
||||
bp::numpy::initialize();
|
||||
bp::class_< UnaryCallable, boost::shared_ptr<UnaryCallable> >("UnaryCallable")
|
||||
.def("__call__", bp::numpy::unary_ufunc<UnaryCallable>::make());
|
||||
bp::class_< BinaryCallable, boost::shared_ptr<BinaryCallable> >("BinaryCallable")
|
||||
.def("__call__", bp::numpy::binary_ufunc<BinaryCallable>::make());
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user