Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • jcarpent/eigenpy
  • gsaurel/eigenpy
  • stack-of-tasks/eigenpy
3 results
Show changes
Showing
with 458 additions and 577 deletions
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy {
void exposeMatrixMacLong() {
// On Mac, long is a 64 bytes type but it's a different type than int64_t
#ifdef __APPLE__
exposeType<long>();
exposeType<long, Eigen::RowMajor>();
#endif // Mac
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy {
void exposeMatrixMacULong() {
// On Mac, long is a 64 bytes type but it's a different type than int64_t
#ifdef __APPLE__
exposeType<unsigned long>();
exposeType<unsigned long, Eigen::RowMajor>();
#endif // Mac
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixUInt16() {
exposeType<uint16_t>();
exposeType<uint16_t, Eigen::RowMajor>();
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixUInt32() {
exposeType<uint32_t>();
exposeType<uint32_t, Eigen::RowMajor>();
}
} // namespace eigenpy
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixUInt64() {
exposeType<uint64_t>();
exposeType<uint64_t, Eigen::RowMajor>();
}
} // namespace eigenpy
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixUInt8() {
exposeType<std::uint8_t>();
exposeType<std::uint8_t, Eigen::RowMajor>();
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy {
void exposeMatrixWindowsLong() {
// On Windows, long is a 32 bytes type but it's a different type than int
#ifdef WIN32
exposeType<long>();
exposeType<long, Eigen::RowMajor>();
#endif // WIN32
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy {
void exposeMatrixWindowsULong() {
// On Windows, long is a 32 bytes type but it's a different type than int
#ifdef WIN32
exposeType<unsigned long>();
exposeType<unsigned long, Eigen::RowMajor>();
#endif // WIN32
}
} // namespace eigenpy
/*
* Copyright 2018-2020 INRIA
* Copyright 2018-2023 INRIA
*/
#include "eigenpy/numpy-type.hpp"
......@@ -17,70 +17,24 @@ bp::object NumpyType::make(PyArrayObject* pyArray, bool copy) {
return make((PyObject*)pyArray, copy);
}
bp::object NumpyType::make(PyObject* pyObj, bool copy) {
bp::object NumpyType::make(PyObject* pyObj, bool /*copy*/) {
bp::object m;
if (isMatrix())
m = getInstance().NumpyMatrixObject(bp::object(bp::handle<>(pyObj)),
bp::object(), copy);
// m = NumpyAsMatrixObject(bp::object(bp::handle<>(pyObj)));
else if (isArray())
m = bp::object(bp::handle<>(pyObj)); // nothing to do here
m = bp::object(bp::handle<>(pyObj)); // nothing to do here
Py_INCREF(m.ptr());
return m;
}
void NumpyType::setNumpyType(bp::object& obj) {
PyTypeObject* obj_type = PyType_Check(obj.ptr())
? reinterpret_cast<PyTypeObject*>(obj.ptr())
: obj.ptr()->ob_type;
if (PyType_IsSubtype(obj_type, getInstance().NumpyMatrixType))
switchToNumpyMatrix();
else if (PyType_IsSubtype(obj_type, getInstance().NumpyArrayType))
switchToNumpyArray();
}
void NumpyType::sharedMemory(const bool value) {
getInstance().shared_memory = value;
}
bool NumpyType::sharedMemory() { return getInstance().shared_memory; }
void NumpyType::switchToNumpyArray() {
getInstance().CurrentNumpyType = getInstance().NumpyArrayObject;
getInstance().getType() = ARRAY_TYPE;
}
void NumpyType::switchToNumpyMatrix() {
getInstance().CurrentNumpyType = getInstance().NumpyMatrixObject;
getInstance().getType() = MATRIX_TYPE;
}
NP_TYPE& NumpyType::getType() { return getInstance().np_type; }
bp::object NumpyType::getNumpyType() { return getInstance().CurrentNumpyType; }
const PyTypeObject* NumpyType::getNumpyMatrixType() {
return getInstance().NumpyMatrixType;
}
const PyTypeObject* NumpyType::getNumpyArrayType() {
return getInstance().NumpyArrayType;
}
bool NumpyType::isMatrix() {
return PyType_IsSubtype(
reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()),
getInstance().NumpyMatrixType);
}
bool NumpyType::isArray() {
if (getInstance().isMatrix()) return false;
return PyType_IsSubtype(
reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()),
getInstance().NumpyArrayType);
}
NumpyType::NumpyType() {
pyModule = bp::import("numpy");
......@@ -90,16 +44,8 @@ NumpyType::NumpyType() {
Py_INCREF(pyModule.ptr());
#endif
NumpyMatrixObject = pyModule.attr("matrix");
NumpyMatrixType = reinterpret_cast<PyTypeObject*>(NumpyMatrixObject.ptr());
NumpyArrayObject = pyModule.attr("ndarray");
NumpyArrayType = reinterpret_cast<PyTypeObject*>(NumpyArrayObject.ptr());
// NumpyAsMatrixObject = pyModule.attr("asmatrix");
// NumpyAsMatrixType =
// reinterpret_cast<PyTypeObject*>(NumpyAsMatrixObject.ptr());
CurrentNumpyType = NumpyArrayObject; // default conversion
np_type = ARRAY_TYPE;
shared_memory = true;
}
......
/*
* Copyright 2020-2022 INRIA
* Copyright 2020-2024 INRIA
*/
#include "eigenpy/numpy.hpp"
......@@ -14,7 +14,12 @@ void import_numpy() {
}
int PyArray_TypeNum(PyTypeObject* type) {
return PyArray_TypeNumFromName(const_cast<char*>(type->tp_name));
PyArray_Descr* descr =
PyArray_DescrFromTypeObject(reinterpret_cast<PyObject*>(type));
if (descr == NULL) {
return NPY_NOTYPE;
}
return descr->type_num;
}
#if defined _WIN32 || defined __CYGWIN__
......@@ -52,7 +57,7 @@ void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs) {
PyArray_InitArrFuncs(funcs);
}
int call_PyArray_RegisterDataType(PyArray_Descr* dtype) {
int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype) {
return PyArray_RegisterDataType(dtype);
}
......
///
/// Copyright 2023 CNRS, INRIA
///
#include "eigenpy/optional.hpp"
namespace eigenpy {
void exposeNoneType() {
detail::NoneToPython<boost::none_t>::registration();
#ifdef EIGENPY_WITH_CXX17_SUPPORT
detail::NoneToPython<std::nullopt_t>::registration();
#endif
}
} // namespace eigenpy
......@@ -14,6 +14,17 @@ PyArray_Descr* Register::getPyArrayDescr(PyTypeObject* py_type_ptr) {
return NULL;
}
PyArray_Descr* Register::getPyArrayDescrFromTypeNum(const int type_num) {
if (type_num >= NPY_USERDEF) {
for (const auto& elt : instance().py_array_code_bindings) {
if (elt.second == type_num)
return instance().py_array_descr_bindings[elt.first];
}
return nullptr;
} else
return PyArray_DescrFromType(type_num);
}
bool Register::isRegistered(PyTypeObject* py_type_ptr) {
if (getPyArrayDescr(py_type_ptr) != NULL)
return true;
......@@ -52,9 +63,8 @@ int Register::registerNewType(
throw std::invalid_argument("PyType_Ready fails to initialize input type.");
}
PyArray_Descr* descr_ptr =
new PyArray_Descr(*call_PyArray_DescrFromType(NPY_OBJECT));
PyArray_Descr& descr = *descr_ptr;
PyArray_DescrProto* descr_ptr = new PyArray_DescrProto();
PyArray_DescrProto& descr = *descr_ptr;
descr.typeobj = py_type_ptr;
descr.kind = 'V';
descr.byteorder = '=';
......@@ -81,13 +91,14 @@ int Register::registerNewType(
funcs.fill = fill;
funcs.fillwithscalar = fillwithscalar;
// f->cast = cast;
Py_SET_TYPE(descr_ptr, &PyArrayDescr_Type);
const int code = call_PyArray_RegisterDataType(descr_ptr);
assert(code >= 0 && "The return code should be positive");
PyArray_Descr* new_descr = call_PyArray_DescrFromType(code);
if (PyDict_SetItemString(py_type_ptr->tp_dict, "dtype",
(PyObject*)descr_ptr) < 0) {
(PyObject*)new_descr) < 0) {
throw std::invalid_argument("PyDict_SetItemString fails.");
}
......
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/scipy-type.hpp"
#include <patchlevel.h> // For PY_MAJOR_VERSION
namespace eigenpy {
ScipyType& ScipyType::getInstance() {
static ScipyType instance;
return instance;
}
void ScipyType::sharedMemory(const bool value) {
getInstance().shared_memory = value;
}
bool ScipyType::sharedMemory() { return getInstance().shared_memory; }
const PyTypeObject* ScipyType::getScipyCSRMatrixType() {
return getInstance().csr_matrix_type;
}
const PyTypeObject* ScipyType::getScipyCSCMatrixType() {
return getInstance().csc_matrix_type;
}
ScipyType::ScipyType() {
try {
sparse_module = bp::import("scipy.sparse");
} catch (...) {
throw std::runtime_error(
"SciPy is not installed. "
"You can install it using the command \'pip install scipy\'.");
}
#if PY_MAJOR_VERSION >= 3
// TODO I don't know why this Py_INCREF is necessary.
// Without it, the destructor of ScipyType SEGV sometimes.
Py_INCREF(sparse_module.ptr());
#endif
csr_matrix_obj = sparse_module.attr("csr_matrix");
csr_matrix_type = reinterpret_cast<PyTypeObject*>(csr_matrix_obj.ptr());
csc_matrix_obj = sparse_module.attr("csc_matrix");
csc_matrix_type = reinterpret_cast<PyTypeObject*>(csc_matrix_obj.ptr());
shared_memory = true;
}
} // namespace eigenpy
/*
* Copyright 2017-2018, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#include <Eigen/Core>
......
///
/// Copyright 2024 INRIA
///
#include <typeinfo>
#include <typeindex>
#include <boost/python.hpp>
#include <boost/type_index.hpp>
#include "eigenpy/registration.hpp"
namespace bp = boost::python;
namespace eigenpy {
void exposeStdTypeIndex() {
typedef std::type_index Self;
if (register_symbolic_link_to_registered_type<Self>()) return;
bp::class_<Self>(
"std_type_index",
"The class type_index holds implementation-specific information about a "
"type, including the name of the type and means to compare two types for "
"equality or collating order.",
bp::no_init)
.def(bp::self == bp::self)
.def(bp::self >= bp::self)
.def(bp::self > bp::self)
.def(bp::self < bp::self)
.def(bp::self <= bp::self)
.def("hash_code", &Self::hash_code, bp::arg("self"),
"Returns an unspecified value (here denoted by hash code) such that "
"for all std::type_info objects referring to the same type, their "
"hash code is the same.")
.def("name", &Self::name, bp::arg("self"),
"Returns an implementation defined null-terminated character string "
"containing the name of the type. No guarantees are given; in "
"particular, the returned string can be identical for several types "
"and change between invocations of the same program.")
.def(
"pretty_name",
+[](const Self &value) -> std::string {
return boost::core::demangle(value.name());
},
bp::arg("self"), "Human readible name.");
}
void exposeBoostTypeIndex() {
typedef boost::typeindex::type_index Self;
if (register_symbolic_link_to_registered_type<Self>()) return;
bp::class_<Self>(
"boost_type_index",
"The class type_index holds implementation-specific information about a "
"type, including the name of the type and means to compare two types for "
"equality or collating order.",
bp::no_init)
.def(bp::self == bp::self)
.def(bp::self >= bp::self)
.def(bp::self > bp::self)
.def(bp::self < bp::self)
.def(bp::self <= bp::self)
.def("hash_code", &Self::hash_code, bp::arg("self"),
"Returns an unspecified value (here denoted by hash code) such that "
"for all std::type_info objects referring to the same type, their "
"hash code is the same.")
.def("name", &Self::name, bp::arg("self"),
"Returns an implementation defined null-terminated character string "
"containing the name of the type. No guarantees are given; in "
"particular, the returned string can be identical for several types "
"and change between invocations of the same program.")
.def("pretty_name", &Self::pretty_name, bp::arg("self"),
"Human readible name.");
}
void exposeTypeInfo() {
exposeStdTypeIndex();
exposeBoostTypeIndex();
}
} // namespace eigenpy
#
# Copyright (c) 2014-2019 CNRS Copyright (c) 2018-2023 INRIA
# Copyright (c) 2014-2019 CNRS Copyright (c) 2018-2024 INRIA
#
if("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_11")
set(EIGENPY_WITH_TENSOR_SUPPORT TRUE)
endif()
macro(ADD_LIB_UNIT_TEST test)
function(ADD_LIB_UNIT_TEST test)
create_ctest_build_tests_target()
set(test_target ${PROJECT_NAME}-${test})
if(BUILD_TESTING)
add_library(${test} SHARED "${test}.cpp")
else(BUILD_TESTING)
add_library(${test} SHARED EXCLUDE_FROM_ALL "${test}.cpp")
endif(BUILD_TESTING)
target_link_libraries(${test} PUBLIC ${PROJECT_NAME})
set_target_properties(${test} PROPERTIES PREFIX "")
set_target_properties(${test} PROPERTIES SUFFIX ${PYTHON_EXT_SUFFIX})
add_test(NAME ${test} COMMAND ${PYTHON_EXECUTABLE} -c "import ${test}")
add_dependencies(build_tests ${test})
add_library(${test_target} SHARED "${test}.cpp")
else()
add_library(${test_target} SHARED EXCLUDE_FROM_ALL "${test}.cpp")
endif()
set_standard_output_directory(${test_target})
target_link_libraries(${test_target} PUBLIC ${PROJECT_NAME})
set_target_properties(
${test_target}
PROPERTIES PREFIX ""
LIBRARY_OUTPUT_NAME ${test}
RUNTIME_OUTPUT_NAME ${test})
set_target_properties(${test_target} PROPERTIES SUFFIX ${PYTHON_EXT_SUFFIX})
add_test(
NAME ${test_target}
COMMAND ${PYTHON_EXECUTABLE} -c "import ${test}"
WORKING_DIRECTORY $<TARGET_FILE_DIR:${test_target}>)
add_dependencies(build_tests ${test_target})
if(NOT BUILD_TESTING)
set_tests_properties(${test} PROPERTIES DEPENDS ctest_build_tests)
set_tests_properties(${test_target} PROPERTIES DEPENDS ctest_build_tests)
endif(NOT BUILD_TESTING)
endmacro(ADD_LIB_UNIT_TEST)
endfunction()
add_dependencies(build_tests ${PYWRAP})
add_lib_unit_test(matrix)
if(EIGENPY_WITH_TENSOR_SUPPORT)
add_lib_unit_test(tensor)
add_lib_unit_test(type_info)
add_lib_unit_test(multiple_registration)
if(BUILD_TESTING_SCIPY)
find_scipy()
add_lib_unit_test(sparse_matrix)
endif()
add_lib_unit_test(tensor)
add_lib_unit_test(geometry)
add_lib_unit_test(complex)
add_lib_unit_test(deprecation_policy)
add_lib_unit_test(return_by_ref)
add_lib_unit_test(include)
if(NOT ${EIGEN3_VERSION} VERSION_LESS "3.2.0")
......@@ -44,59 +55,154 @@ if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT)
add_lib_unit_test(user_type)
endif()
add_lib_unit_test(std_vector)
add_lib_unit_test(std_array)
add_lib_unit_test(std_pair)
add_lib_unit_test(std_map)
add_lib_unit_test(user_struct)
add_python_unit_test("py-matrix" "unittest/python/test_matrix.py" "unittest")
if(CMAKE_CXX_STANDARD GREATER 14 AND CMAKE_CXX_STANDARD LESS 98)
add_lib_unit_test(std_unique_ptr)
endif()
if(EIGENPY_WITH_TENSOR_SUPPORT)
add_python_unit_test("py-tensor" "unittest/python/test_tensor.py" "unittest")
function(add_python_lib_unit_test name source)
set(test_target ${PROJECT_NAME}-${name})
add_python_unit_test(${test_target} ${source} "lib" "bin")
endfunction()
function(add_python_eigenpy_lib_unit_test name source)
set(test_target ${PROJECT_NAME}-${name})
add_python_unit_test(${test_target} ${source} "lib" "bin" "python")
set_tests_properties(${test_target} PROPERTIES DEPENDS ${PYWRAP})
endfunction()
function(add_python_eigenpy_unit_test name source)
set(test_target ${PROJECT_NAME}-${name})
add_python_unit_test(${test_target} ${source} "python")
set_tests_properties(${test_target} PROPERTIES DEPENDS ${PYWRAP})
endfunction()
function(config_test test tagname opttype)
set(MODNAME ${test}_${tagname})
set(TEST_TYPE ${opttype})
configure_file(${test}.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/${MODNAME}.cpp)
set(py_file test_${test}_${tagname}.py)
configure_file(python/test_${test}.py.in
${CMAKE_CURRENT_BINARY_DIR}/python/${py_file})
add_lib_unit_test(${MODNAME})
set(PYTHON_TEST_NAME "${PROJECT_NAME}-py-${test}-${tagname}")
add_test(NAME ${PYTHON_TEST_NAME}
COMMAND ${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_BINARY_DIR}/python/${py_file}")
compute_pythonpath(ENV_VARIABLES "lib" "bin")
set_tests_properties(${PYTHON_TEST_NAME} PROPERTIES ENVIRONMENT
"${ENV_VARIABLES}")
endfunction()
config_test(variant boost "boost::variant")
if(CMAKE_CXX_STANDARD GREATER 14 AND CMAKE_CXX_STANDARD LESS 98)
config_test(variant std "std::variant")
endif()
add_python_unit_test("py-geometry" "unittest/python/test_geometry.py"
"unittest")
add_python_unit_test("py-complex" "unittest/python/test_complex.py" "unittest")
add_python_unit_test("py-return-by-ref" "unittest/python/test_return_by_ref.py"
"unittest")
add_python_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py"
"unittest")
if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT)
add_python_unit_test("py-user-type" "unittest/python/test_user_type.py"
"unittest")
config_test(bind_optional boost "boost::optional")
if(CMAKE_CXX_STANDARD GREATER 14 AND CMAKE_CXX_STANDARD LESS 98)
config_test(bind_optional std "std::optional")
endif()
add_python_unit_test("py-switch" "unittest/python/test_switch.py"
"python;unittest")
set_tests_properties("py-switch" PROPERTIES DEPENDS ${PYWRAP})
add_lib_unit_test(bind_virtual_factory)
add_python_lib_unit_test("py-matrix" "unittest/python/test_matrix.py")
add_python_lib_unit_test("py-type-info" "unittest/python/test_type_info.py")
add_python_lib_unit_test("py-multiple-registration"
"unittest/python/test_multiple_registration.py")
add_python_unit_test("py-dimensions" "unittest/python/test_dimensions.py"
"python;unittest")
set_tests_properties("py-dimensions" PROPERTIES DEPENDS ${PYWRAP})
add_python_lib_unit_test("py-tensor" "unittest/python/test_tensor.py")
add_python_lib_unit_test("py-geometry" "unittest/python/test_geometry.py")
add_python_lib_unit_test("py-complex" "unittest/python/test_complex.py")
add_python_lib_unit_test("py-deprecation-policy"
"unittest/python/test_deprecation_policy.py")
add_python_lib_unit_test("py-return-by-ref"
"unittest/python/test_return_by_ref.py")
add_python_lib_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py")
if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT)
add_python_lib_unit_test("py-user-type" "unittest/python/test_user_type.py")
endif()
add_python_unit_test("py-version" "unittest/python/test_version.py"
"python;unittest")
set_tests_properties("py-version" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-dimensions"
"unittest/python/test_dimensions.py")
add_python_unit_test("py-eigen-solver" "unittest/python/test_eigen_solver.py"
"python;unittest")
set_tests_properties("py-eigen-solver" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-version" "unittest/python/test_version.py")
add_python_unit_test(
add_python_eigenpy_lib_unit_test("py-eigen-solver"
"unittest/python/test_eigen_solver.py")
add_python_eigenpy_lib_unit_test(
"py-self-adjoint-eigen-solver"
"unittest/python/test_self_adjoint_eigen_solver.py" "python;unittest")
set_tests_properties("py-self-adjoint-eigen-solver" PROPERTIES DEPENDS
${PYWRAP})
"unittest/python/test_self_adjoint_eigen_solver.py")
add_python_eigenpy_lib_unit_test("py-LLT" "unittest/python/test_LLT.py")
add_python_eigenpy_lib_unit_test("py-LDLT" "unittest/python/test_LDLT.py")
add_python_unit_test("py-LLT" "unittest/python/test_LLT.py" "python;unittest")
set_tests_properties("py-LLT" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-id" "unittest/python/test_id.py")
add_python_unit_test("py-LDLT" "unittest/python/test_LDLT.py" "python;unittest")
set_tests_properties("py-LDLT" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-QR" "unittest/python/test_QR.py")
if(NOT WIN32)
add_python_unit_test("py-MINRES" "unittest/python/test_MINRES.py"
"python;unittest")
set_tests_properties("py-MINRES" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-MINRES" "unittest/python/test_MINRES.py")
endif(NOT WIN32)
add_python_unit_test("py-std-vector" "unittest/python/test_std_vector.py"
"python;unittest")
set_tests_properties("py-std-vector" PROPERTIES DEPENDS ${PYWRAP})
add_python_eigenpy_lib_unit_test("py-std-vector"
"unittest/python/test_std_vector.py")
add_python_lib_unit_test("py-std-array" "unittest/python/test_std_array.py")
add_python_lib_unit_test("py-std-map" "unittest/python/test_std_map.py")
add_python_lib_unit_test("py-std-pair" "unittest/python/test_std_pair.py")
add_python_lib_unit_test("py-user-struct" "unittest/python/test_user_struct.py")
if(CMAKE_CXX_STANDARD GREATER 14 AND CMAKE_CXX_STANDARD LESS 98)
add_python_lib_unit_test("py-std-unique-ptr"
"unittest/python/test_std_unique_ptr.py")
endif()
add_python_lib_unit_test("py-bind-virtual"
"unittest/python/test_bind_virtual.py")
if(BUILD_TESTING_SCIPY)
add_python_lib_unit_test("py-sparse-matrix"
"unittest/python/test_sparse_matrix.py")
add_python_eigenpy_unit_test(
"py-SimplicialLLT"
"unittest/python/decompositions/sparse/test_SimplicialLLT.py")
add_python_eigenpy_unit_test(
"py-SimplicialLDLT"
"unittest/python/decompositions/sparse/test_SimplicialLDLT.py")
if(BUILD_WITH_CHOLMOD_SUPPORT)
add_python_eigenpy_unit_test(
"py-CholmodSimplicialLLT"
"unittest/python/decompositions/sparse/cholmod/test_CholmodSimplicialLLT.py"
)
add_python_eigenpy_unit_test(
"py-CholmodSimplicialLDLT"
"unittest/python/decompositions/sparse/cholmod/test_CholmodSimplicialLDLT.py"
)
add_python_eigenpy_unit_test(
"py-CholmodSupernodalLLT"
"unittest/python/decompositions/sparse/cholmod/test_CholmodSupernodalLLT.py"
)
endif(BUILD_WITH_CHOLMOD_SUPPORT)
if(BUILD_WITH_ACCELERATE_SUPPORT)
add_python_eigenpy_unit_test(
"py-Accelerate"
"unittest/python/decompositions/sparse/test_Accelerate.py")
endif(BUILD_WITH_ACCELERATE_SUPPORT)
endif()
/* Simple test using the boost::numpy interface: return an array and a matrix.
*/
#include "boost/numpy.hpp"
#include "eigenpy/fwd.hpp"
namespace bp = boost::python;
namespace bn = boost::numpy;
/* Return an dim-1 array with 5 elements. */
bn::ndarray array() {
std::vector<double> v(5);
v[0] = 56;
Py_intptr_t shape[1] = {v.size()};
bn::ndarray result = bn::zeros(1, shape, bn::dtype::get_builtin<double>());
std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data()));
return result;
}
/* Return a dim-1 matrix with five elements. */
boost::python::object matrix() {
std::vector<double> v(5);
v[0] = 56;
Py_intptr_t shape[1] = {v.size()};
bn::matrix t(bn::zeros(1, shape, bn::dtype::get_builtin<double>()));
std::copy(v.begin(), v.end(), reinterpret_cast<double*>(t.get_data()));
return t;
}
BOOST_PYTHON_MODULE(libbnpy) {
bn::initialize();
bp::def("array", array);
bp::def("matrix", matrix);
}
#include <boost/numpy.hpp>
#include "eigenpy/fwd.hpp"
namespace boopy {
namespace bpn = boost::numpy;
namespace bp = boost::python;
struct Eigenvec_to_python_matrix {
static PyObject* convert(Eigen::VectorXd const& v) {
Py_intptr_t shape[1] = {v.size()};
bpn::matrix result(bpn::zeros(1, shape, bpn::dtype::get_builtin<double>()));
std::copy(v.data(), v.data() + v.size(),
reinterpret_cast<double*>(result.get_data()));
return bp::incref(result.ptr());
}
};
struct Eigenvec_from_python_array {
Eigenvec_from_python_array() {
bp::converter::registry ::push_back(&convertible, &construct,
bp::type_id<Eigen::VectorXd>());
}
// Determine if obj_ptr can be converted in a Eigenvec
static void* convertible(PyObject* obj_ptr) {
try {
bp::object obj(bp::handle<>(bp::borrowed(obj_ptr)));
std::auto_ptr<bpn::ndarray> array(new bpn::ndarray(bpn::from_object(
obj, bpn::dtype::get_builtin<double>(), bpn::ndarray::V_CONTIGUOUS)));
if ((array->get_nd() == 1) ||
((array->get_nd() == 2) && (array->get_shape()[1] == 1)))
return array.release();
else
return 0;
} catch (bp::error_already_set& err) {
bp::handle_exception();
return 0;
}
}
// Convert obj_ptr into a Eigenvec
static void construct(PyObject*,
bp::converter::rvalue_from_python_stage1_data* memory) {
// Recover the pointer created in <convertible>
std::auto_ptr<bpn::ndarray> array(
reinterpret_cast<bpn::ndarray*>(memory->convertible));
const int nrow = array->get_shape()[0];
std::cout << "nrow = " << nrow << std::endl;
// Get the memory where to create the vector
void* storage =
((bp::converter::rvalue_from_python_storage<Eigen::VectorXd>*)memory)
->storage.bytes;
// Create the vector
Eigen::VectorXd& res = *new (storage) Eigen::VectorXd(nrow);
// Copy the data
double* data = (double*)array->get_data();
for (int i = 0; i < nrow; ++i) res[i] = data[i];
// Stash the memory chunk pointer for later use by boost.python
memory->convertible = storage;
}
};
} // namespace boopy
Eigen::VectorXd test() {
Eigen::VectorXd v = Eigen::VectorXd::Random(5);
std::cout << v.transpose() << std::endl;
return v;
}
void test2(Eigen::VectorXd v) {
std::cout << "test2: dim = " << v.size() << " ||| v[0] = " << v[0]
<< std::endl;
}
BOOST_PYTHON_MODULE(libeigen) {
namespace bpn = boost::numpy;
namespace bp = boost::python;
bpn::initialize();
bp::to_python_converter<Eigen::VectorXd, boopy::Eigenvec_to_python_matrix>();
boopy::Eigenvec_from_python_array();
bp::def("test", test);
bp::def("test2", test2);
}
#include <numpy/arrayobject.h>
#include "eigenpy/fwd.hpp"
namespace boopy {
namespace bp = boost::python;
template <typename SCALAR>
struct NumpyEquivalentType {};
template <>
struct NumpyEquivalentType<double> {
enum { type_code = NPY_DOUBLE };
};
template <>
struct NumpyEquivalentType<int> {
enum { type_code = NPY_INT };
};
template <>
struct NumpyEquivalentType<float> {
enum { type_code = NPY_FLOAT };
};
struct EigenMatrix_to_python_matrix {
static PyObject* convert(Eigen::MatrixXd const& mat) {
typedef Eigen::MatrixXd::Scalar T;
npy_intp shape[2] = {mat.rows(), mat.cols()};
PyArrayObject* pyArray = (PyArrayObject*)PyArray_SimpleNew(
2, shape, NumpyEquivalentType<T>::type_code);
T* pyData = (T*)PyArray_DATA(pyArray);
for (int i = 0; i < mat.rows(); ++i)
for (int j = 0; j < mat.cols(); ++j)
pyData[i * mat.cols() + j] = mat(i, j);
return ((PyObject*)pyArray);
}
};
struct EigenMatrix_from_python_array {
EigenMatrix_from_python_array() {
bp::converter::registry ::push_back(&convertible, &construct,
bp::type_id<Eigen::MatrixXd>());
}
// Determine if obj_ptr can be converted in a Eigenvec
static void* convertible(PyObject* obj_ptr) {
typedef Eigen::MatrixXd::Scalar T;
if (!PyArray_Check(obj_ptr)) {
return 0;
}
if (PyArray_NDIM(obj_ptr) > 2) {
return 0;
}
if (PyArray_ObjectType(obj_ptr, 0) != NumpyEquivalentType<T>::type_code) {
return 0;
}
int flags = PyArray_FLAGS(obj_ptr);
if (!(flags & NPY_C_CONTIGUOUS)) {
return 0;
}
if (!(flags & NPY_ALIGNED)) {
return 0;
}
return obj_ptr;
}
// Convert obj_ptr into a Eigenvec
static void construct(PyObject* pyObj,
bp::converter::rvalue_from_python_stage1_data* memory) {
typedef Eigen::MatrixXd::Scalar T;
using namespace Eigen;
PyArrayObject* pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
int ndims = PyArray_NDIM(pyArray);
assert(ndims == 2);
int dtype_size = (PyArray_DESCR(pyArray))->elsize;
int s1 = PyArray_STRIDE(pyArray, 0);
assert(s1 % dtype_size == 0);
int R = MatrixXd::RowsAtCompileTime;
int C = MatrixXd::ColsAtCompileTime;
if (R == Eigen::Dynamic)
R = PyArray_DIMS(pyArray)[0];
else
assert(PyArray_DIMS(pyArray)[0] == R);
if (C == Eigen::Dynamic)
C = PyArray_DIMS(pyArray)[1];
else
assert(PyArray_DIMS(pyArray)[1] == C);
T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray));
void* storage =
((bp::converter::rvalue_from_python_storage<MatrixXd>*)(memory))
->storage.bytes;
MatrixXd& mat = *new (storage) MatrixXd(R, C);
for (int i = 0; i < R; ++i)
for (int j = 0; j < C; ++j) mat(i, j) = pyData[i * C + j];
memory->convertible = storage;
}
};
} // namespace boopy
Eigen::MatrixXd test() {
Eigen::MatrixXd mat = Eigen::MatrixXd::Random(5, 5);
std::cout << "EigenMAt = " << mat << std::endl;
return mat;
}
void test2(Eigen::MatrixXd mat) {
std::cout << "test2: dim = " << mat.rows() << " ||| m[0,0] = " << mat(0, 0)
<< std::endl;
}
BOOST_PYTHON_MODULE(libeigenc) {
import_array();
namespace bp = boost::python;
bp::to_python_converter<Eigen::MatrixXd,
boopy::EigenMatrix_to_python_matrix>();
boopy::EigenMatrix_from_python_array();
bp::def("test", test);
bp::def("test2", test2);
}
#include <numpy/arrayobject.h>
#include "eigenpy/fwd.hpp"
namespace boopy {
namespace bp = boost::python;
template <typename SCALAR>
struct NumpyEquivalentType {};
template <>
struct NumpyEquivalentType<double> {
enum { type_code = NPY_DOUBLE };
};
template <>
struct NumpyEquivalentType<int> {
enum { type_code = NPY_INT };
};
template <>
struct NumpyEquivalentType<float> {
enum { type_code = NPY_FLOAT };
};
/* --- TO PYTHON --------------------------------------------------------------
*/
template <typename MatType>
struct EigenMatrix_to_python_matrix {
static PyObject* convert(MatType const& mat) {
typedef typename MatType::Scalar T;
const int R = mat.rows(), C = mat.cols();
npy_intp shape[2] = {R, C};
PyArrayObject* pyArray = (PyArrayObject*)PyArray_SimpleNew(
2, shape, NumpyEquivalentType<T>::type_code);
T* pyData = (T*)PyArray_DATA(pyArray);
Eigen::Map<
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
pyMatrix(pyData, R, C);
pyMatrix = mat;
return (PyObject*)pyArray;
}
};
/* --- FROM PYTHON ------------------------------------------------------------
*/
template <typename MatType>
struct EigenMatrix_from_python_array {
EigenMatrix_from_python_array() {
bp::converter::registry ::push_back(&convertible, &construct,
bp::type_id<MatType>());
}
// Determine if obj_ptr can be converted in a Eigenvec
static void* convertible(PyObject* obj_ptr) {
typedef typename MatType::Scalar T;
if (!PyArray_Check(obj_ptr)) return 0;
std::cout << "Until here ok. ndim = " << PyArray_NDIM(obj_ptr)
<< " isvec " << MatType::IsVectorAtCompileTime << std::endl;
if (PyArray_NDIM(obj_ptr) != 2)
if ((PyArray_NDIM(obj_ptr) != 1) || (!MatType::IsVectorAtCompileTime))
return 0;
std::cout << "Until here ok." << std::endl;
if (PyArray_ObjectType(obj_ptr, 0) != NumpyEquivalentType<T>::type_code)
return 0;
if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED)) {
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
return 0;
}
return obj_ptr;
}
// Convert obj_ptr into a Eigenvec
static void construct(PyObject* pyObj,
bp::converter::rvalue_from_python_stage1_data* memory) {
typedef typename MatType::Scalar T;
using namespace Eigen;
std::cout << "Until here ok. Constructing..." << std::endl;
PyArrayObject* pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
if (PyArray_NDIM(pyArray) == 2) {
int R = MatType::RowsAtCompileTime;
int C = MatType::ColsAtCompileTime;
if (R == Eigen::Dynamic)
R = PyArray_DIMS(pyArray)[0];
else
assert(PyArray_DIMS(pyArray)[0] == R);
if (C == Eigen::Dynamic)
C = PyArray_DIMS(pyArray)[1];
else
assert(PyArray_DIMS(pyArray)[1] == C);
T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray));
int itemsize = PyArray_ITEMSIZE(pyArray);
int stride1 = PyArray_STRIDE(pyArray, 0) / itemsize;
int stride2 = PyArray_STRIDE(pyArray, 1) / itemsize;
std::cout << "STRIDE = " << stride1 << " x " << stride2 << std::endl;
Eigen::Map<MatType, 0, Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> >
pyMap(
pyData, R, C,
Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>(stride2, stride1));
std::cout << "Map = " << pyMap << std::endl;
void* storage =
((bp::converter::rvalue_from_python_storage<MatType>*)(memory))
->storage.bytes;
MatType& mat = *new (storage) MatType(R, C);
mat = pyMap;
memory->convertible = storage;
} else {
int R = MatType::MaxSizeAtCompileTime, C = 1;
if (R == Eigen::Dynamic)
R = PyArray_DIMS(pyArray)[0];
else
assert(PyArray_DIMS(pyArray)[0] == R);
T* pyData = reinterpret_cast<T*>(PyArray_DATA(pyArray));
int itemsize = PyArray_ITEMSIZE(pyArray);
int stride = PyArray_STRIDE(pyArray, 0) / itemsize;
Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> s(stride, 0);
Eigen::Map<MatType, 0, Eigen::InnerStride<Eigen::Dynamic> > pyMap(
pyData, R, 1, Eigen::InnerStride<Eigen::Dynamic>(stride));
std::cout << "Map = " << pyMap << std::endl;
void* storage =
((bp::converter::rvalue_from_python_storage<MatType>*)(memory))
->storage.bytes;
MatType& mat = *new (storage) MatType(R, C);
mat = pyMap;
memory->convertible = storage;
}
}
};
} // namespace boopy
Eigen::MatrixXd test() {
Eigen::MatrixXd mat = Eigen::MatrixXd::Random(3, 6);
std::cout << "EigenMAt = " << mat << std::endl;
return mat;
}
Eigen::VectorXd testVec() {
Eigen::VectorXd mat = Eigen::VectorXd::Random(6);
std::cout << "EigenVec = " << mat << std::endl;
return mat;
}
void test2(Eigen::MatrixXd mat) {
std::cout << "Test2 mat = " << mat << std::endl;
}
void test2Vec(Eigen::VectorXd v) {
std::cout << "Test2 vec = " << v << std::endl;
}
BOOST_PYTHON_MODULE(libeigentemplate) {
import_array();
namespace bp = boost::python;
bp::to_python_converter<
Eigen::MatrixXd, boopy::EigenMatrix_to_python_matrix<Eigen::MatrixXd> >();
boopy::EigenMatrix_from_python_array<Eigen::MatrixXd>();
bp::to_python_converter<
Eigen::VectorXd, boopy::EigenMatrix_to_python_matrix<Eigen::VectorXd> >();
boopy::EigenMatrix_from_python_array<Eigen::VectorXd>();
bp::def("test", test);
bp::def("testVec", testVec);
bp::def("test2", test2);
bp::def("test2Vec", test2Vec);
}