Add numpy_eigen as a 3rd party library.
This commit adds a simple version of numpy_eigen, copied from gtborg/numpy_eigen commit 255c09efb82496, and with a fix released in the commit 9a75383733b3dc4bc2bb0649053949ad2bec9326 of Scheizer-Messer/numpy_eigen (https://github.com/ethz-asl/Schweizer-Messer/tree/master/numpy_eigen) Conflicts: CMakeLists.txt gtsam/CMakeLists.txtrelease/4.3a0
parent
6a34fa0a22
commit
2dbe7fa2e9
|
@ -30,7 +30,6 @@ message(STATUS "GTSAM_SOURCE_ROOT_DIR: [${GTSAM_SOURCE_ROOT_DIR}]")
|
|||
|
||||
# Load build type flags and default to Debug mode
|
||||
include(GtsamBuildTypes)
|
||||
include(GtsamPythonWrap)
|
||||
|
||||
# Use macros for creating tests/timing scripts
|
||||
include(GtsamTesting)
|
||||
|
@ -65,6 +64,7 @@ option(GTSAM_WITH_TBB "Use Intel Threaded Building Blocks (TB
|
|||
option(GTSAM_WITH_EIGEN_MKL "Eigen will use Intel MKL if available" ON)
|
||||
option(GTSAM_WITH_EIGEN_MKL_OPENMP "Eigen, when using Intel MKL, will also use OpenMP for multithreading if available" ON)
|
||||
option(GTSAM_THROW_CHEIRALITY_EXCEPTION "Throw exception when a triangulated point is behind a camera" ON)
|
||||
option(GTSAM_BUILD_PYTHON "Build Python wrapper statically (increases build time)" OFF)
|
||||
|
||||
# Options relating to MATLAB wrapper
|
||||
# TODO: Check for matlab mex binary before handling building of binaries
|
||||
|
@ -345,8 +345,10 @@ if (GTSAM_INSTALL_MATLAB_TOOLBOX)
|
|||
add_subdirectory(matlab)
|
||||
endif()
|
||||
|
||||
if(GTSAM_BUILD_PYTHON)
|
||||
add_subdirectory(python)
|
||||
# Python wrap
|
||||
if (GTSAM_BUILD_PYTHON)
|
||||
include(GtsamPythonWrap)
|
||||
wrap_and_install_python(gtsampy.h "${GTSAM_ADDITIONAL_LIBRARIES}" "")
|
||||
endif()
|
||||
|
||||
# Build gtsam_unstable
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#Setup cache options
|
||||
option(GTSAM_BUILD_PYTHON "Build Python wrapper statically (increases build time)" OFF)
|
||||
set(GTSAM_BUILD_PYTHON_FLAGS "" CACHE STRING "Extra flags for running Matlab PYTHON compilation")
|
||||
set(GTSAM_PYTHON_INSTALL_PATH "" CACHE PATH "Python toolbox destination, blank defaults to CMAKE_INSTALL_PREFIX/borg/python")
|
||||
if(NOT GTSAM_PYTHON_INSTALL_PATH)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
numpy_eigen
|
||||
===========
|
||||
|
||||
A boost python converter that handles the copy of matrices from the Eigen linear algebra library in C++ to numpy in Python.
|
||||
|
||||
This is a minimal version based on the original from Paul Furgale (https://github.com/ethz-asl/Schweizer-Messer/tree/master/numpy_eigen)
|
|
@ -0,0 +1,316 @@
|
|||
/**
|
||||
* @file NumpyEigenConverter.hpp
|
||||
* @author Paul Furgale <paul.furgale@utoronto.ca>
|
||||
* @date Fri Feb 4 11:17:25 2011
|
||||
*
|
||||
* @brief Classes to support conversion from numpy arrays in Python
|
||||
* to Eigen3 matrices in c++
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NUMPY_EIGEN_CONVERTER_HPP
|
||||
#define NUMPY_EIGEN_CONVERTER_HPP
|
||||
|
||||
#include "boost_python_headers.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#define PY_ARRAY_UNIQUE_SYMBOL NP_Eigen_AS
|
||||
#include <numpy/arrayobject.h>
|
||||
|
||||
#include "type_traits.hpp"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "copy_routines.hpp"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class NumpyEigenConverter
|
||||
* @tparam the Eigen3 matrix type this class is specialized for
|
||||
*
|
||||
* adapted from http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
|
||||
* General help available http://docs.scipy.org/doc/numpy/reference/c-api.array.html
|
||||
*
|
||||
* To use:
|
||||
*
|
||||
* #include <NumpyEigenConverter.hpp>
|
||||
*
|
||||
*
|
||||
* BOOST_PYTHON_MODULE(libmy_module_python)
|
||||
* {
|
||||
* // The converters will cause a segfault unless import_array() is called before the first one
|
||||
* import_array();
|
||||
* NumpyEigenConverter<Eigen::Matrix< double, 1, 1 > >::register_converter();
|
||||
* NumpyEigenConverter<Eigen::Matrix< double, 2, 1 > >::register_converter();
|
||||
* }
|
||||
*
|
||||
*/
|
||||
template<typename EIGEN_MATRIX_T>
|
||||
struct NumpyEigenConverter
|
||||
{
|
||||
|
||||
typedef EIGEN_MATRIX_T matrix_t;
|
||||
typedef typename matrix_t::Scalar scalar_t;
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = matrix_t::RowsAtCompileTime,
|
||||
ColsAtCompileTime = matrix_t::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = matrix_t::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = matrix_t::MaxColsAtCompileTime,
|
||||
NpyType = TypeToNumPy<scalar_t>::NpyType,
|
||||
//Flags = ei_compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret,
|
||||
//CoeffReadCost = NumTraits<Scalar>::ReadCost,
|
||||
Options = matrix_t::Options
|
||||
//InnerStrideAtCompileTime = 1,
|
||||
//OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime
|
||||
};
|
||||
|
||||
static std::string castSizeOption(int option)
|
||||
{
|
||||
if(option == Eigen::Dynamic)
|
||||
return "Dynamic";
|
||||
else
|
||||
return boost::lexical_cast<std::string>(option);
|
||||
}
|
||||
|
||||
static std::string toString()
|
||||
{
|
||||
return std::string() + "Eigen::Matrix<" + TypeToNumPy<scalar_t>::typeString() + ", " +
|
||||
castSizeOption(RowsAtCompileTime) + ", " +
|
||||
castSizeOption(ColsAtCompileTime) + ", " +
|
||||
boost::lexical_cast<std::string>((int)Options) + ", " +
|
||||
castSizeOption(MaxRowsAtCompileTime) + ", " +
|
||||
castSizeOption(MaxColsAtCompileTime) + ">";
|
||||
}
|
||||
|
||||
// The "Convert from C to Python" API
|
||||
static PyObject * convert(const matrix_t & M)
|
||||
{
|
||||
PyObject * P = NULL;
|
||||
if(RowsAtCompileTime == 1 || ColsAtCompileTime == 1)
|
||||
{
|
||||
// Create a 1D array
|
||||
npy_intp dimensions[1];
|
||||
dimensions[0] = M.size();
|
||||
P = PyArray_SimpleNew(1, dimensions, TypeToNumPy<scalar_t>::NpyType);
|
||||
numpyTypeDemuxer< CopyEigenToNumpyVector<const matrix_t> >(&M,P);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a 2D array.
|
||||
npy_intp dimensions[2];
|
||||
dimensions[0] = M.rows();
|
||||
dimensions[1] = M.cols();
|
||||
P = PyArray_SimpleNew(2, dimensions, TypeToNumPy<scalar_t>::NpyType);
|
||||
numpyTypeDemuxer< CopyEigenToNumpyMatrix<const matrix_t> >(&M,P);
|
||||
}
|
||||
|
||||
// incrementing the reference seems to cause a memory leak.
|
||||
// boost::python::incref(P);
|
||||
// This agrees with the sample code found here:
|
||||
// http://mail.python.org/pipermail/cplusplus-sig/2008-October/013825.html
|
||||
return P;
|
||||
}
|
||||
|
||||
static bool isDimensionValid(int requestedSize, int sizeAtCompileTime, int maxSizeAtCompileTime)
|
||||
{
|
||||
bool valid = true;
|
||||
if(sizeAtCompileTime == Eigen::Dynamic)
|
||||
{
|
||||
// Check for dynamic fixed size
|
||||
// http://eigen.tuxfamily.org/dox-devel/TutorialMatrixClass.html#TutorialMatrixOptTemplParams
|
||||
if(!(maxSizeAtCompileTime == Eigen::Dynamic || requestedSize <= maxSizeAtCompileTime))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
else if(sizeAtCompileTime != requestedSize)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void checkMatrixSizes(PyObject * obj_ptr)
|
||||
{
|
||||
int rows = PyArray_DIM(obj_ptr, 0);
|
||||
int cols = PyArray_DIM(obj_ptr, 1);
|
||||
|
||||
bool rowsValid = isDimensionValid(rows, RowsAtCompileTime, MaxRowsAtCompileTime);
|
||||
bool colsValid = isDimensionValid(cols, ColsAtCompileTime, MaxColsAtCompileTime);
|
||||
if(!rowsValid || !colsValid)
|
||||
{
|
||||
THROW_TYPE_ERROR("Can not convert " << npyArrayTypeString(obj_ptr) << " to " << toString()
|
||||
<< ". Mismatched sizes.");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkRowVectorSizes(PyObject * obj_ptr, int cols)
|
||||
{
|
||||
if(!isDimensionValid(cols, ColsAtCompileTime, MaxColsAtCompileTime))
|
||||
{
|
||||
THROW_TYPE_ERROR("Can not convert " << npyArrayTypeString(obj_ptr) << " to " << toString()
|
||||
<< ". Mismatched sizes.");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkColumnVectorSizes(PyObject * obj_ptr, int rows)
|
||||
{
|
||||
// Check if the type can accomidate one column.
|
||||
if(ColsAtCompileTime == Eigen::Dynamic || ColsAtCompileTime == 1)
|
||||
{
|
||||
if(!isDimensionValid(rows, RowsAtCompileTime, MaxRowsAtCompileTime))
|
||||
{
|
||||
THROW_TYPE_ERROR("Can not convert " << npyArrayTypeString(obj_ptr) << " to " << toString()
|
||||
<< ". Mismatched sizes.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW_TYPE_ERROR("Can not convert " << npyArrayTypeString(obj_ptr) << " to " << toString()
|
||||
<< ". Mismatched sizes.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void checkVectorSizes(PyObject * obj_ptr)
|
||||
{
|
||||
int size = PyArray_DIM(obj_ptr, 0);
|
||||
|
||||
// If the number of rows is fixed at 1, assume that is the sense of the vector.
|
||||
// Otherwise, assume it is a column.
|
||||
if(RowsAtCompileTime == 1)
|
||||
{
|
||||
checkRowVectorSizes(obj_ptr, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkColumnVectorSizes(obj_ptr, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void* convertible(PyObject *obj_ptr)
|
||||
{
|
||||
// Check for a null pointer.
|
||||
if(!obj_ptr)
|
||||
{
|
||||
//THROW_TYPE_ERROR("PyObject pointer was null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make sure this is a numpy array.
|
||||
if (!PyArray_Check(obj_ptr))
|
||||
{
|
||||
//THROW_TYPE_ERROR("Conversion is only defined for numpy array and matrix types");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check the type of the array.
|
||||
int npyType = PyArray_ObjectType(obj_ptr, 0);
|
||||
|
||||
if(!TypeToNumPy<scalar_t>::canConvert(npyType))
|
||||
{
|
||||
//THROW_TYPE_ERROR("Can not convert " << npyArrayTypeString(obj_ptr) << " to " << toString()
|
||||
// << ". Mismatched types.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check the array dimensions.
|
||||
int nd = PyArray_NDIM(obj_ptr);
|
||||
|
||||
if(nd != 1 && nd != 2)
|
||||
{
|
||||
THROW_TYPE_ERROR("Conversion is only valid for arrays with 1 or 2 dimensions. Argument has " << nd << " dimensions");
|
||||
}
|
||||
|
||||
if(nd == 1)
|
||||
{
|
||||
checkVectorSizes(obj_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Two-dimensional matrix type.
|
||||
checkMatrixSizes(obj_ptr);
|
||||
}
|
||||
|
||||
|
||||
return obj_ptr;
|
||||
}
|
||||
|
||||
|
||||
static void construct(PyObject *obj_ptr, boost::python::converter::rvalue_from_python_stage1_data *data)
|
||||
{
|
||||
boost::python::converter::rvalue_from_python_storage<matrix_t> * matData = reinterpret_cast<boost::python::converter::rvalue_from_python_storage<matrix_t> * >(data);
|
||||
void* storage = matData->storage.bytes;
|
||||
|
||||
// Make sure storage is 16byte aligned. With help from code from Memory.h
|
||||
void * aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
|
||||
|
||||
matrix_t * Mp = new (aligned) matrix_t();
|
||||
// Stash the memory chunk pointer for later use by boost.python
|
||||
// This signals boost::python that the new value must be deleted eventually
|
||||
data->convertible = storage;
|
||||
|
||||
|
||||
// std::cout << "Creating aligned pointer " << aligned << " from storage " << storage << std::endl;
|
||||
// std::cout << "matrix size: " << sizeof(matrix_t) << std::endl;
|
||||
// std::cout << "referent size: " << boost::python::detail::referent_size< matrix_t & >::value << std::endl;
|
||||
// std::cout << "sizeof(storage): " << sizeof(matData->storage) << std::endl;
|
||||
// std::cout << "sizeof(bytes): " << sizeof(matData->storage.bytes) << std::endl;
|
||||
|
||||
|
||||
|
||||
matrix_t & M = *Mp;
|
||||
|
||||
int nd = PyArray_NDIM(obj_ptr);
|
||||
if(nd == 1)
|
||||
{
|
||||
int size = PyArray_DIM(obj_ptr, 0);
|
||||
// This is a vector type
|
||||
if(RowsAtCompileTime == 1)
|
||||
{
|
||||
// Row Vector
|
||||
M.resize(1,size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Column Vector
|
||||
M.resize(size,1);
|
||||
}
|
||||
numpyTypeDemuxer< CopyNumpyToEigenVector<matrix_t> >(&M,obj_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
int rows = PyArray_DIM(obj_ptr, 0);
|
||||
int cols = PyArray_DIM(obj_ptr, 1);
|
||||
|
||||
M.resize(rows,cols);
|
||||
numpyTypeDemuxer< CopyNumpyToEigenMatrix<matrix_t> >(&M,obj_ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// The registration function.
|
||||
static void register_converter()
|
||||
{
|
||||
boost::python::to_python_converter<matrix_t,NumpyEigenConverter>();
|
||||
boost::python::converter::registry::push_back(
|
||||
&NumpyEigenConverter::convertible,
|
||||
&NumpyEigenConverter::construct,
|
||||
boost::python::type_id<matrix_t>());
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* NUMPY_EIGEN_CONVERTER_HPP */
|
250
gtsam/3rdparty/numpy_eigen/include/numpy_eigen/boost_python_headers.hpp
vendored
Executable file
250
gtsam/3rdparty/numpy_eigen/include/numpy_eigen/boost_python_headers.hpp
vendored
Executable file
|
@ -0,0 +1,250 @@
|
|||
/**
|
||||
* @file boost_python_headers.hpp
|
||||
* @author Paul Furgale <paul.furgale@gmail.com>
|
||||
* @date Mon Dec 12 10:36:03 2011
|
||||
*
|
||||
* @brief A header that specializes boost-python to work with fixed-sized Eigen types.
|
||||
*
|
||||
* The original version of this library did not include these specializations and this caused
|
||||
* assert failures when running on Ubuntu 10.04 32-bit. More information about fixed-size
|
||||
* vectorizable types in Eigen is available here:
|
||||
* http://eigen.tuxfamily.org/dox-devel/TopicFixedSizeVectorizable.html
|
||||
*
|
||||
* This code has been tested on Ubunutu 10.04 64 and 32 bit, OSX Snow Leopard and OSX Lion.
|
||||
*
|
||||
* This code is derived from boost/python/converter/arg_from_python.hpp
|
||||
* Copyright David Abrahams 2002.
|
||||
* Distributed under the Boost Software License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef NUMPY_EIGEN_CONVERTERS_HPP
|
||||
#define NUMPY_EIGEN_CONVERTERS_HPP
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/detail/referent_storage.hpp>
|
||||
#include <boost/python/converter/arg_from_python.hpp>
|
||||
#include <boost/python/converter/rvalue_from_python_data.hpp>
|
||||
#include <boost/python/tuple.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
template<typename T>
|
||||
struct referent_size;
|
||||
|
||||
// This bit of code makes sure we have 16 extra bytes to do the pointer alignment for fixed-sized Eigen types
|
||||
template<typename T, int A, int B, int C, int D, int E>
|
||||
struct referent_size< Eigen::Matrix<T,A,B,C,D,E>& >
|
||||
{
|
||||
// Add 16 bytes so we can get alignment
|
||||
BOOST_STATIC_CONSTANT( std::size_t, value = sizeof(Eigen::Matrix<T,A,B,C,D,E>) + 16);
|
||||
};
|
||||
|
||||
// This bit of code makes sure we have 16 extra bytes to do the pointer alignment for fixed-sized Eigen types
|
||||
template<typename T, int A, int B, int C, int D, int E>
|
||||
struct referent_size< Eigen::Matrix<T,A,B,C,D,E> const & >
|
||||
{
|
||||
// Add 16 bytes so we can get alignment
|
||||
BOOST_STATIC_CONSTANT( std::size_t, value = sizeof(Eigen::Matrix<T,A,B,C,D,E>) + 16);
|
||||
};
|
||||
|
||||
// This bit of code makes sure we have 16 extra bytes to do the pointer alignment for fixed-sized Eigen types
|
||||
template<typename T, int A, int B, int C, int D, int E>
|
||||
struct referent_size< Eigen::Matrix<T,A,B,C,D,E> >
|
||||
{
|
||||
// Add 16 bytes so we can get alignment
|
||||
BOOST_STATIC_CONSTANT( std::size_t, value = sizeof(Eigen::Matrix<T,A,B,C,D,E>) + 16);
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
|
||||
template<typename S, int A, int B, int C, int D, int E>
|
||||
struct rvalue_from_python_data< Eigen::Matrix<S,A,B,C,D,E> const &> : rvalue_from_python_storage< Eigen::Matrix<S,A,B,C,D,E> const & >
|
||||
{
|
||||
typedef typename Eigen::Matrix<S,A,B,C,D,E> T;
|
||||
# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
|
||||
&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
|
||||
&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
|
||||
&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
|
||||
// This must always be a POD struct with m_data its first member.
|
||||
BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
|
||||
# endif
|
||||
|
||||
// The usual constructor
|
||||
rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
|
||||
{
|
||||
this->stage1 = _stage1;
|
||||
}
|
||||
|
||||
|
||||
// This constructor just sets m_convertible -- used by
|
||||
// implicitly_convertible<> to perform the final step of the
|
||||
// conversion, where the construct() function is already known.
|
||||
rvalue_from_python_data(void* convertible)
|
||||
{
|
||||
this->stage1.convertible = convertible;
|
||||
}
|
||||
|
||||
// Destroys any object constructed in the storage.
|
||||
~rvalue_from_python_data()
|
||||
{
|
||||
// Realign the pointer and destroy
|
||||
if (this->stage1.convertible == this->storage.bytes)
|
||||
{
|
||||
void * storage = reinterpret_cast<void *>(this->storage.bytes);
|
||||
T * aligned = reinterpret_cast<T *>(reinterpret_cast<void *>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16));
|
||||
|
||||
//std::cout << "Destroying " << (void*)aligned << std::endl;
|
||||
aligned->T::~T();
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef typename add_reference<typename add_cv<T>::type>::type ref_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Used when T is a plain value (non-pointer, non-reference) type or
|
||||
// a (non-volatile) const reference to a plain value type.
|
||||
template<typename S, int A, int B, int C, int D, int E>
|
||||
struct arg_rvalue_from_python< Eigen::Matrix<S,A,B,C,D,E> >
|
||||
{
|
||||
typedef Eigen::Matrix<S,A,B,C,D,E> const & T;
|
||||
typedef typename boost::add_reference<
|
||||
T
|
||||
// We can't add_const here, or it would be impossible to pass
|
||||
// auto_ptr<U> args from Python to C++
|
||||
>::type result_type;
|
||||
|
||||
arg_rvalue_from_python(PyObject * obj) : m_data(converter::rvalue_from_python_stage1(obj, registered<T>::converters))
|
||||
, m_source(obj)
|
||||
{
|
||||
|
||||
}
|
||||
bool convertible() const
|
||||
{
|
||||
return m_data.stage1.convertible != 0;
|
||||
}
|
||||
|
||||
|
||||
# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196
|
||||
typename arg_rvalue_from_python<T>::
|
||||
# endif
|
||||
result_type operator()()
|
||||
{
|
||||
if (m_data.stage1.construct != 0)
|
||||
m_data.stage1.construct(m_source, &m_data.stage1);
|
||||
|
||||
// Here is the magic...
|
||||
// Realign the pointer
|
||||
void * storage = reinterpret_cast<void *>(m_data.storage.bytes);
|
||||
void * aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
|
||||
|
||||
return python::detail::void_ptr_to_reference(aligned, (result_type(*)())0);
|
||||
}
|
||||
|
||||
private:
|
||||
rvalue_from_python_data<result_type> m_data;
|
||||
PyObject* m_source;
|
||||
};
|
||||
|
||||
|
||||
// Used when T is a plain value (non-pointer, non-reference) type or
|
||||
// a (non-volatile) const reference to a plain value type.
|
||||
template<typename S, int A, int B, int C, int D, int E>
|
||||
struct arg_rvalue_from_python< Eigen::Matrix<S,A,B,C,D,E> const & >
|
||||
{
|
||||
typedef Eigen::Matrix<S,A,B,C,D,E> const & T;
|
||||
typedef typename boost::add_reference<
|
||||
T
|
||||
// We can't add_const here, or it would be impossible to pass
|
||||
// auto_ptr<U> args from Python to C++
|
||||
>::type result_type;
|
||||
|
||||
arg_rvalue_from_python(PyObject * obj) : m_data(converter::rvalue_from_python_stage1(obj, registered<T>::converters))
|
||||
, m_source(obj)
|
||||
{
|
||||
|
||||
}
|
||||
bool convertible() const
|
||||
{
|
||||
return m_data.stage1.convertible != 0;
|
||||
}
|
||||
|
||||
|
||||
# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196
|
||||
typename arg_rvalue_from_python<T>::
|
||||
# endif
|
||||
result_type operator()()
|
||||
{
|
||||
if (m_data.stage1.construct != 0)
|
||||
m_data.stage1.construct(m_source, &m_data.stage1);
|
||||
|
||||
// Here is the magic...
|
||||
// Realign the pointer
|
||||
void * storage = reinterpret_cast<void *>(m_data.storage.bytes);
|
||||
void * aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
|
||||
|
||||
return python::detail::void_ptr_to_reference(aligned, (result_type(*)())0);
|
||||
}
|
||||
|
||||
private:
|
||||
rvalue_from_python_data<result_type> m_data;
|
||||
PyObject* m_source;
|
||||
};
|
||||
|
||||
// Used when T is a plain value (non-pointer, non-reference) type or
|
||||
// a (non-volatile) const reference to a plain value type.
|
||||
template<typename S, int A, int B, int C, int D, int E>
|
||||
struct arg_rvalue_from_python< Eigen::Matrix<S,A,B,C,D,E> const >
|
||||
{
|
||||
typedef Eigen::Matrix<S,A,B,C,D,E> const & T;
|
||||
typedef typename boost::add_reference<
|
||||
T
|
||||
// We can't add_const here, or it would be impossible to pass
|
||||
// auto_ptr<U> args from Python to C++
|
||||
>::type result_type;
|
||||
|
||||
arg_rvalue_from_python(PyObject * obj) : m_data(converter::rvalue_from_python_stage1(obj, registered<T>::converters))
|
||||
, m_source(obj)
|
||||
{
|
||||
|
||||
}
|
||||
bool convertible() const
|
||||
{
|
||||
return m_data.stage1.convertible != 0;
|
||||
}
|
||||
|
||||
|
||||
# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196
|
||||
typename arg_rvalue_from_python<T>::
|
||||
# endif
|
||||
result_type operator()()
|
||||
{
|
||||
if (m_data.stage1.construct != 0)
|
||||
m_data.stage1.construct(m_source, &m_data.stage1);
|
||||
|
||||
// Here is the magic...
|
||||
// Realign the pointer
|
||||
void * storage = reinterpret_cast<void *>(m_data.storage.bytes);
|
||||
void * aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
|
||||
|
||||
return python::detail::void_ptr_to_reference(aligned, (result_type(*)())0);
|
||||
}
|
||||
|
||||
private:
|
||||
rvalue_from_python_data<result_type> m_data;
|
||||
PyObject* m_source;
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
#endif /* NUMPY_EIGEN_CONVERTERS_HPP */
|
|
@ -0,0 +1,148 @@
|
|||
#ifndef NUMPY_EIGEN_COPY_ROUTINES_HPP
|
||||
#define NUMPY_EIGEN_COPY_ROUTINES_HPP
|
||||
|
||||
|
||||
template<typename EIGEN_T>
|
||||
struct CopyNumpyToEigenMatrix
|
||||
{
|
||||
typedef EIGEN_T matrix_t;
|
||||
typedef typename matrix_t::Scalar scalar_t;
|
||||
|
||||
template<typename T>
|
||||
void exec(EIGEN_T * M_, PyObject * P_)
|
||||
{
|
||||
// Assumes M is already initialized.
|
||||
for(int r = 0; r < M_->rows(); r++)
|
||||
{
|
||||
for(int c = 0; c < M_->cols(); c++)
|
||||
{
|
||||
T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c));
|
||||
(*M_)(r,c) = static_cast<scalar_t>(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename EIGEN_T>
|
||||
struct CopyEigenToNumpyMatrix
|
||||
{
|
||||
typedef EIGEN_T matrix_t;
|
||||
typedef typename matrix_t::Scalar scalar_t;
|
||||
|
||||
template<typename T>
|
||||
void exec(EIGEN_T * M_, PyObject * P_)
|
||||
{
|
||||
// Assumes M is already initialized.
|
||||
for(int r = 0; r < M_->rows(); r++)
|
||||
{
|
||||
for(int c = 0; c < M_->cols(); c++)
|
||||
{
|
||||
T * p = static_cast<T*>(PyArray_GETPTR2(P_, r, c));
|
||||
*p = static_cast<T>((*M_)(r,c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename EIGEN_T>
|
||||
struct CopyEigenToNumpyVector
|
||||
{
|
||||
typedef EIGEN_T matrix_t;
|
||||
typedef typename matrix_t::Scalar scalar_t;
|
||||
|
||||
template<typename T>
|
||||
void exec(EIGEN_T * M_, PyObject * P_)
|
||||
{
|
||||
// Assumes M is already initialized.
|
||||
for(int i = 0; i < M_->size(); i++)
|
||||
{
|
||||
T * p = static_cast<T*>(PyArray_GETPTR1(P_, i));
|
||||
*p = static_cast<T>((*M_)(i));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename EIGEN_T>
|
||||
struct CopyNumpyToEigenVector
|
||||
{
|
||||
typedef EIGEN_T matrix_t;
|
||||
typedef typename matrix_t::Scalar scalar_t;
|
||||
|
||||
template<typename T>
|
||||
void exec(EIGEN_T * M_, PyObject * P_)
|
||||
{
|
||||
// Assumes M is already initialized.
|
||||
for(int i = 0; i < M_->size(); i++)
|
||||
{
|
||||
T * p = static_cast<T*>(PyArray_GETPTR1(P_, i));
|
||||
(*M_)(i) = static_cast<scalar_t>(*p);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Crazy syntax in this function was found here:
|
||||
// http://stackoverflow.com/questions/1840253/c-template-member-function-of-template-class-called-from-template-function/1840318#1840318
|
||||
template< typename FUNCTOR_T>
|
||||
inline void numpyTypeDemuxer(typename FUNCTOR_T::matrix_t * M, PyObject * P)
|
||||
{
|
||||
FUNCTOR_T f;
|
||||
int npyType = PyArray_ObjectType(P, 0);
|
||||
switch(npyType)
|
||||
{
|
||||
case NPY_BOOL:
|
||||
f.template exec<bool>(M,P);
|
||||
break;
|
||||
case NPY_BYTE:
|
||||
f.template exec<char>(M,P);
|
||||
break;
|
||||
case NPY_UBYTE:
|
||||
f.template exec<unsigned char>(M,P);
|
||||
break;
|
||||
case NPY_SHORT:
|
||||
f.template exec<short>(M,P);
|
||||
break;
|
||||
case NPY_USHORT:
|
||||
f.template exec<unsigned short>(M,P);
|
||||
break;
|
||||
case NPY_INT:
|
||||
f.template exec<int>(M,P);
|
||||
break;
|
||||
case NPY_UINT:
|
||||
f.template exec<unsigned int>(M,P);
|
||||
break;
|
||||
case NPY_LONG:
|
||||
f.template exec<long>(M,P);
|
||||
break;
|
||||
case NPY_ULONG:
|
||||
f.template exec<unsigned long>(M,P);
|
||||
break;
|
||||
case NPY_LONGLONG:
|
||||
f.template exec<long long>(M,P);
|
||||
break;
|
||||
case NPY_ULONGLONG:
|
||||
f.template exec<unsigned long long>(M,P);
|
||||
break;
|
||||
case NPY_FLOAT:
|
||||
f.template exec<float>(M,P);
|
||||
break;
|
||||
case NPY_DOUBLE:
|
||||
f.template exec<double>(M,P);
|
||||
break;
|
||||
case NPY_LONGDOUBLE:
|
||||
f.template exec<long double>(M,P);
|
||||
break;
|
||||
default:
|
||||
THROW_TYPE_ERROR("Unsupported type: " << npyTypeToString(npyType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* NUMPY_EIGEN_COPY_ROUTINES_HPP */
|
|
@ -0,0 +1,153 @@
|
|||
#ifndef NUMPY_EIGEN_TYPE_TRAITS_HPP
|
||||
#define NUMPY_EIGEN_TYPE_TRAITS_HPP
|
||||
|
||||
#define THROW_TYPE_ERROR(msg) \
|
||||
{ \
|
||||
std::stringstream type_error_ss; \
|
||||
type_error_ss << msg; \
|
||||
PyErr_SetString(PyExc_TypeError, type_error_ss.str().c_str()); \
|
||||
throw boost::python::error_already_set(); \
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// TypeToNumPy
|
||||
// Defines helper functions based on the Eigen3 matrix type that
|
||||
// decide what conversions can happen Eigen3 --> NumPy
|
||||
// Also, converts a type to a NumPy enum.
|
||||
template<typename Scalar> struct TypeToNumPy;
|
||||
|
||||
template<> struct TypeToNumPy<int>
|
||||
{
|
||||
enum { NpyType = NPY_INT };
|
||||
static const char * npyString() { return "NPY_INT"; }
|
||||
static const char * typeString() { return "int"; }
|
||||
static bool canConvert(int type)
|
||||
{
|
||||
return type == NPY_INT || type == NPY_LONG;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct TypeToNumPy<unsigned char>
|
||||
{
|
||||
enum { NpyType = NPY_UBYTE };
|
||||
static const char * npyString() { return "NPY_UBYTE"; }
|
||||
static const char * typeString() { return "unsigned char"; }
|
||||
static bool canConvert(int type)
|
||||
{
|
||||
return type == NPY_UBYTE || type == NPY_BYTE || type == NPY_CHAR;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct TypeToNumPy<char>
|
||||
{
|
||||
enum { NpyType = NPY_BYTE };
|
||||
static const char * npyString() { return "NPY_BYTE"; }
|
||||
static const char * typeString() { return "char"; }
|
||||
static bool canConvert(int type)
|
||||
{
|
||||
return type == NPY_UBYTE || type == NPY_BYTE || type == NPY_CHAR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<> struct TypeToNumPy<float>
|
||||
{
|
||||
enum { NpyType = NPY_FLOAT };
|
||||
static const char * npyString() { return "NPY_FLOAT"; }
|
||||
static const char * typeString() { return "float"; }
|
||||
static bool canConvert(int type)
|
||||
{
|
||||
return type == NPY_INT || type == NPY_FLOAT || type == NPY_LONG;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct TypeToNumPy<double>
|
||||
{
|
||||
enum { NpyType = NPY_DOUBLE };
|
||||
static const char * npyString() { return "NPY_DOUBLE"; }
|
||||
static const char * typeString() { return "double"; }
|
||||
static bool canConvert(int type)
|
||||
{
|
||||
return type == NPY_INT || type == NPY_FLOAT || type == NPY_DOUBLE || type == NPY_LONG;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline const char * npyTypeToString(int npyType)
|
||||
{
|
||||
switch(npyType)
|
||||
{
|
||||
case NPY_BOOL:
|
||||
return "NPY_BOOL";
|
||||
case NPY_BYTE:
|
||||
return "NPY_BYTE";
|
||||
case NPY_UBYTE:
|
||||
return "NPY_UBYTE";
|
||||
case NPY_SHORT:
|
||||
return "NPY_SHORT";
|
||||
case NPY_USHORT:
|
||||
return "NPY_USHORT";
|
||||
case NPY_INT:
|
||||
return "NPY_INT";
|
||||
case NPY_UINT:
|
||||
return "NPY_UINT";
|
||||
case NPY_LONG:
|
||||
return "NPY_LONG";
|
||||
case NPY_ULONG:
|
||||
return "NPY_ULONG";
|
||||
case NPY_LONGLONG:
|
||||
return "NPY_LONGLONG";
|
||||
case NPY_ULONGLONG:
|
||||
return "NPY_ULONGLONG";
|
||||
case NPY_FLOAT:
|
||||
return "NPY_FLOAT";
|
||||
case NPY_DOUBLE:
|
||||
return "NPY_DOUBLE";
|
||||
case NPY_LONGDOUBLE:
|
||||
return "NPY_LONGDOUBLE";
|
||||
case NPY_CFLOAT:
|
||||
return "NPY_CFLOAT";
|
||||
case NPY_CDOUBLE:
|
||||
return "NPY_CDOUBLE";
|
||||
case NPY_CLONGDOUBLE:
|
||||
return "NPY_CLONGDOUBLE";
|
||||
case NPY_OBJECT:
|
||||
return "NPY_OBJECT";
|
||||
case NPY_STRING:
|
||||
return "NPY_STRING";
|
||||
case NPY_UNICODE:
|
||||
return "NPY_UNICODE";
|
||||
case NPY_VOID:
|
||||
return "NPY_VOID";
|
||||
case NPY_NTYPES:
|
||||
return "NPY_NTYPES";
|
||||
case NPY_NOTYPE:
|
||||
return "NPY_NOTYPE";
|
||||
case NPY_CHAR:
|
||||
return "NPY_CHAR";
|
||||
default:
|
||||
return "Unknown type";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string npyArrayTypeString(PyObject * obj_ptr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
int nd = PyArray_NDIM(obj_ptr);
|
||||
ss << "numpy.array<" << npyTypeToString(PyArray_ObjectType(obj_ptr, 0)) << ">[";
|
||||
if(nd > 0)
|
||||
{
|
||||
ss << PyArray_DIM(obj_ptr, 0);
|
||||
for(int i = 1; i < nd; i++)
|
||||
{
|
||||
ss << ", " << PyArray_DIM(obj_ptr, i);
|
||||
}
|
||||
}
|
||||
ss << "]";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
#endif /* NUMPY_EIGEN_TYPE_TRAITS_HPP */
|
Loading…
Reference in New Issue