I'm experiencing difficulties working with boost::python and boost::python::numpy, with python 2.7, boost 1.67.0, and Eigen3.3. My compiler is g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0.
I'm trying to convert Eigen::Matrix types to python ndarray and back (vector_list.hpp):
#ifndef VECTOR_PYLIST_HH
#define VECTOR_PYLIST_HH
#include<iostream>
#include<vector>
#include<boost/python.hpp>
#include<Eigen/Dense>
#include<typeinfo>
#include<boost/python/numpy.hpp>
namespace myutil {
template<class T>
boost::python::list to_py_list(Eigen::Matrix<T, Eigen::Dynamic,Eigen::Dynamic> matrix)
{
boost::python::list list;
boost::python::list helplist;
if (matrix.cols() > 1) {
for (int j = 0; j < matrix.cols(); j++) {
helplist = to_py_list<T>(matrix.col(j));
list.append(helplist);
}
} else {
for (int i = 0; i < matrix.rows(); i++) {
list.append(matrix(i,0));
}
}
return list;
}
template<class T>
boost::python::numpy::ndarray to_py_array(Eigen::Matrix<T, Eigen::Dynamic,Eigen::Dynamic> matrix)
{
int cols = matrix.cols();
int rows = matrix.rows();
boost::python::tuple tu = boost::python::make_tuple(rows,cols);
boost::python::numpy::dtype dtype = boost::python::numpy::dtype::get_builtin<T>();
boost::python::numpy::ndarray arr = boost::python::numpy::empty(tu, dtype);
for (int i; i < rows; i++) {
for (int j = 0; j < cols; j++) {
arr[i][j] = matrix(i,j);
}
}
return arr;
}
#endif
My test programme (eigen_ndarray_eigen.cpp) looks as follows:
#include<vector_list.hpp>
#include<iostream>
#include<typeinfo>
int main()
{
Py_Initialize();
np::initialize();
Eigen::Matrix<double,3,2> m;
m << 1,2,3,4,5,6;
std::cout<<m<<std::endl;
boost::python::numpy::ndarray l = myutil::to_py_array<double>(m);
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> n = myutil::to_eigen<double>(l);
std::cout<<n<<std::endl;
return 0;
}
And my CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(myutil)
set(CMAKE_BUILD_TYPE "Debug")
set(BOOST_ROOT "$ENV{BOOST_ROOT}")
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
find_package(Boost 1.61.0 COMPONENTS python REQUIRED)
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
include_directories(${Boost_INCLUDE_DIR} include)
add_executable(test_eigen_ndarray_eigen test/eigen_ndarray_eigen.cpp)
target_link_libraries(test_eigen_ndarray_eigen Eigen3::Eigen ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
I get an error when compiling:
[ 50%] Building CXX object CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o
[100%] Linking CXX executable test_eigen_ndarray_eigen
CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o:In function `boost::python::numpy::ndarray myutil::to_py_array<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1>)':
/home/usr/devel/myutil/include/vector_list.hpp:70: undefined reference to `boost::python::numpy::empty(boost::python::tuple const&, boost::python::numpy::dtype const&)'
CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o: In function `boost::python::numpy::detail::builtin_dtype<double, false>::get()':
/usr/include/boost/python/numpy/dtype.hpp:98: undefined reference to `boost::python::numpy::dtype boost::python::numpy::detail::get_float_dtype<64>()'
collect2: error: ld returned 1 exit status
CMakeFiles/test_eigen_ndarray_eigen.dir/build.make:96: recipe for target 'test_eigen_ndarray_eigen' failed
make[2]: *** [test_eigen_ndarray_eigen] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/test_eigen_ndarray_eigen.dir/all' failed
make[1]: *** [CMakeFiles/test_eigen_ndarray_eigen.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
It's clearly a linking problem but I am already linking my executable against all boost libraries, and I can't figure out what might be wrong. Has anyone experienced something similar? Any tips?
Thanks for your input.
Edit: I was asked for the full error message when compiled with VERBOSE=1:
/usr/bin/cmake -H/home/usr/devel/myutil -B/home/usr/devel/myutil/build --check-build-system CMakeFiles/Makefile.cmake 1
/usr/bin/cmake -E cmake_progress_start /home/usr/devel/myutil/build/CMakeFiles /home/usr/devel/myutil/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/usr/devel/myutil/build'
make -f CMakeFiles/test_eigen_ndarray_eigen.dir/build.make CMakeFiles/test_eigen_ndarray_eigen.dir/depend
make[2]: Entering directory '/home/usr/devel/myutil/build'
cd /home/usr/devel/myutil/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/usr/devel/myutil /home/usr/devel/myutil /home/usr/devel/myutil/build /home/usr/devel/myutil/build /home/usr/devel/myutil/build/CMakeFiles/test_eigen_ndarray_eigen.dir/DependInfo.cmake --color=
Dependee "../include/vector_list.hpp" is newer than depender "CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o".
Clearing dependencies in "/home/usr/devel/myutil/build/CMakeFiles/test_eigen_ndarray_eigen.dir/depend.make".
Scanning dependencies of target test_eigen_ndarray_eigen
make[2]: Leaving directory '/home/usr/devel/myutil/build'
make -f CMakeFiles/test_eigen_ndarray_eigen.dir/build.make CMakeFiles/test_eigen_ndarray_eigen.dir/build
make[2]: Entering directory '/home/usr/devel/myutil/build'
[ 50%] Building CXX object CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o
/usr/bin/c++ -I/usr/include/python2.7 -I/home/usr/devel/myutil/include -isystem /home/usr/devel/src/eigen-git-mirror -g -o CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o -c /home/usr/devel/myutil/test/eigen_ndarray_eigen.cpp
[100%] Linking CXX executable test_eigen_ndarray_eigen
/usr/bin/cmake -E cmake_link_script CMakeFiles/test_eigen_ndarray_eigen.dir/link.txt --verbose=1
/usr/bin/c++ -g CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o -o test_eigen_ndarray_eigen -rdynamic -lboost_python -lpython2.7
CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o: In function `boost::python::numpy::ndarray myutil::to_py_array<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1>)':
/home/usr/devel/myutil/include/vector_list.hpp:70: undefined reference to `boost::python::numpy::empty(boost::python::tuple const&, boost::python::numpy::dtype const&)'
CMakeFiles/test_eigen_ndarray_eigen.dir/test/eigen_ndarray_eigen.cpp.o: In function `boost::python::numpy::detail::builtin_dtype<double, false>::get()':
/usr/include/boost/python/numpy/dtype.hpp:98: undefined reference to `boost::python::numpy::dtype boost::python::numpy::detail::get_float_dtype<64>()'
collect2: error: ld returned 1 exit status
CMakeFiles/test_eigen_ndarray_eigen.dir/build.make:96: recipe for target 'test_eigen_ndarray_eigen' failed
make[2]: *** [test_eigen_ndarray_eigen] Error 1
make[2]: Leaving directory '/home/usr/devel/myutil/build'
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/test_eigen_ndarray_eigen.dir/all' failed
make[1]: *** [CMakeFiles/test_eigen_ndarray_eigen.dir/all] Error 2
make[1]: Leaving directory '/home/usr/devel/myutil/build'
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
`'
I checked some answers regarding similar problems (here). Apparently boost_numpy doesn't call the right libraries automatically and sometimes you have to include them manually:
#define BOOST_LIB_NAME "boost_numpy"
#include <boost/config/auto_link.hpp>
I tried this but it didn't work for me...