diff --git a/examples/custom_numeric_type/CMakeLists.txt b/examples/custom_numeric_type/CMakeLists.txt index 6fade50b0..fe4300a74 100644 --- a/examples/custom_numeric_type/CMakeLists.txt +++ b/examples/custom_numeric_type/CMakeLists.txt @@ -3,15 +3,16 @@ cmake_minimum_required(VERSION 3.1) set(PROJECT_NAME eigenpy_example_custom_numeric_type) -set(PROJECT_DESCRIPTION "An example of using eigenpy with a custom numeric type: Boost.Multiprecision complex numbers") -set(PROJECT_URL "http://github.com/stack-of-tasks/eigenpy/examples/custom_numeric_type") +set(PROJECT_DESCRIPTION + "An example of using eigenpy with a custom numeric type: Boost.Multiprecision complex numbers" +) +set(PROJECT_URL + "http://github.com/stack-of-tasks/eigenpy/examples/custom_numeric_type") set(PROJECT_USE_CMAKE_EXPORT TRUE) set(PROJECT_USE_KEYWORD_LINK_LIBRARIES TRUE) set(PROJECT_CUSTOM_HEADER_EXTENSION "hpp") set(PROJECT_COMPATIBILITY_VERSION AnyNewerVersion) - - # Check if the submodule cmake have been initialized set(JRL_CMAKE_MODULES "${CMAKE_CURRENT_LIST_DIR}/cmake") if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/base.cmake") @@ -31,7 +32,6 @@ if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/base.cmake") endif() endif() - # Disable -Werror on Unix for now. set(CXX_DISABLE_WERROR True) set(CMAKE_VERBOSE_MAKEFILE True) @@ -41,29 +41,24 @@ option(SUFFIX_SO_VERSION "Suffix library name with its version" OFF) if(DEFINED BUILD_UNIT_TESTS) message( - AUTHOR_WARNING - "BUILD_UNIT_TESTS is deprecated. Use BUILD_TESTING instead.") + AUTHOR_WARNING "BUILD_UNIT_TESTS is deprecated. Use BUILD_TESTING instead.") set(BUILD_TESTING ${BUILD_UNIT_TESTS}) endif(DEFINED BUILD_UNIT_TESTS) - include("${JRL_CMAKE_MODULES}/base.cmake") compute_project_args(PROJECT_ARGS LANGUAGES CXX) project(${PROJECT_NAME} ${PROJECT_ARGS}) - include("${JRL_CMAKE_MODULES}/boost.cmake") include("${JRL_CMAKE_MODULES}/python.cmake") include("${JRL_CMAKE_MODULES}/ide.cmake") include("${JRL_CMAKE_MODULES}/apple.cmake") - option(GENERATE_PYTHON_STUBS "Generate the Python stubs associated to the Python library" OFF) string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - # If needed, fix CMake policy for APPLE systems apply_default_apple_configuration() check_minimal_cxx_standard(11 ENFORCE) @@ -82,12 +77,10 @@ endif() set(PYTHON_EXPORT_DEPENDENCY ON) findpython(REQUIRED) - if(${NUMPY_VERSION} VERSION_LESS "1.16.0") set(NUMPY_WITH_BROKEN_UFUNC_SUPPORT TRUE) endif() - if(WIN32) link_directories(${PYTHON_LIBRARY_DIRS}) # # Set default Windows build paths SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY @@ -97,8 +90,6 @@ if(WIN32) # ${PROJECT_BINARY_DIR}/Bin CACHE PATH "Sing$le directory for all archives") endif(WIN32) - - # ---------------------------------------------------- # --- DEPENDENCIES ----------------------------------- # ---------------------------------------------------- @@ -110,28 +101,21 @@ export_boost_default_options() find_package(Boost REQUIRED) search_for_boost_python(REQUIRED) - # ---------------------------------------------------- # --- INCLUDE ---------------------------------------- # ---------------------------------------------------- -set(${PROJECT_NAME}_HEADERS - include/header.hpp) - +set(${PROJECT_NAME}_HEADERS include/header.hpp) set(${PROJECT_NAME}_SOURCES src/src.cpp) - - add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS}) - target_include_directories( ${PROJECT_NAME} SYSTEM PUBLIC $ $) - modernize_target_link_libraries( ${PROJECT_NAME} SCOPE @@ -141,7 +125,6 @@ modernize_target_link_libraries( INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR}) - modernize_target_link_libraries( ${PROJECT_NAME} SCOPE @@ -152,15 +135,10 @@ modernize_target_link_libraries( ${NUMPY_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIR}) - - if(SUFFIX_SO_VERSION) set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION}) endif(SUFFIX_SO_VERSION) - - - if(NOT WIN32) target_compile_options( ${PROJECT_NAME} PRIVATE $<$:-bigobj> @@ -214,13 +192,9 @@ install( # ---------------------------------------------------- # --- PYTHON LIBRARY --------------------------------- # ---------------------------------------------------- -#add_subdirectory(python) +# add_subdirectory(python) pkg_config_append_libs(${PROJECT_NAME}) pkg_config_append_cflags("-I${PYTHON_INCLUDE_DIRS}") pkg_config_append_cflags("-I${NUMPY_INCLUDE_DIRS}") pkg_config_append_boost_libs(${BOOST_COMPONENTS}) - - - - diff --git a/examples/custom_numeric_type/examplescript.py b/examples/custom_numeric_type/examplescript.py index d3c947d63..e566d36be 100644 --- a/examples/custom_numeric_type/examplescript.py +++ b/examples/custom_numeric_type/examplescript.py @@ -1,3 +1,3 @@ import eigenpy_example_custom_numeric_type as example -example.MpfrComplex(2) # the number 2, in variable precision as a complex number \ No newline at end of file +example.MpfrComplex(2) # the number 2, in variable precision as a complex number diff --git a/examples/custom_numeric_type/include/header.hpp b/examples/custom_numeric_type/include/header.hpp index 97536d972..659cfdae6 100644 --- a/examples/custom_numeric_type/include/header.hpp +++ b/examples/custom_numeric_type/include/header.hpp @@ -11,41 +11,33 @@ #include - namespace bmp = boost::multiprecision; using bmp::backends::mpc_complex_backend; -using mpfr_complex = bmp::number, bmp::et_on >; // T is a variable-precision complex number with expression templates turned on. - - +using mpfr_complex = + bmp::number, + bmp::et_on>; // T is a variable-precision complex number with + // expression templates turned on. void Expose(); - - - - - -// this code derived from +// this code derived from // https://github.com/stack-of-tasks/eigenpy/issues/365 -// where I asked about using custom types, and @jcarpent responded with a discussion -// of an application of this in Pinnochio, a library for rigid body dynamics. -namespace eigenpy -{ - namespace internal - { - - +// where I asked about using custom types, and @jcarpent responded with a +// discussion of an application of this in Pinnochio, a library for rigid body +// dynamics. +namespace eigenpy { +namespace internal { // a template specialization for complex numbers - // derived directly from the example for Pinnochio +// derived directly from the example for Pinnochio template <> -struct getitem -{ - static PyObject* run(void* data, void* /* arr */) { - mpfr_complex & mpfr_scalar = *static_cast(data); - auto & backend = mpfr_scalar.backend(); - - if(backend.data()[0].re->_mpfr_d == 0) // If the mpfr_scalar is not initialized, we have to init it. +struct getitem { + static PyObject *run(void *data, void * /* arr */) { + mpfr_complex &mpfr_scalar = *static_cast(data); + auto &backend = mpfr_scalar.backend(); + + if (backend.data()[0].re->_mpfr_d == + 0) // If the mpfr_scalar is not initialized, we have to init it. { mpfr_scalar = mpfr_complex(0); } @@ -55,175 +47,159 @@ struct getitem } }; +} // namespace internal -} // namespace internal - - - - - - -// i lifted this from EigenPy and adapted it, basically removing the calls for the comparitors. +// i lifted this from EigenPy and adapted it, basically removing the calls for +// the comparitors. template -void registerUfunct_without_comparitors(){ - const int type_code = Register::getTypeCode(); - - PyObject *numpy_str; - #if PY_MAJOR_VERSION >= 3 - numpy_str = PyUnicode_FromString("numpy"); - #else - numpy_str = PyString_FromString("numpy"); - #endif - PyObject *numpy; - numpy = PyImport_Import(numpy_str); - Py_DECREF(numpy_str); - - import_ufunc(); - - // Matrix multiply - { - int types[3] = {type_code, type_code, type_code}; +void registerUfunct_without_comparitors() { + const int type_code = Register::getTypeCode(); + + PyObject *numpy_str; +#if PY_MAJOR_VERSION >= 3 + numpy_str = PyUnicode_FromString("numpy"); +#else + numpy_str = PyString_FromString("numpy"); +#endif + PyObject *numpy; + numpy = PyImport_Import(numpy_str); + Py_DECREF(numpy_str); + import_ufunc(); + + // Matrix multiply + { + int types[3] = {type_code, type_code, type_code}; + + std::stringstream ss; + ss << "return result of multiplying two matrices of "; + ss << bp::type_info(typeid(Scalar)).name(); + PyUFuncObject *ufunc = + (PyUFuncObject *)PyObject_GetAttrString(numpy, "matmul"); + if (!ufunc) { std::stringstream ss; - ss << "return result of multiplying two matrices of "; - ss << bp::type_info(typeid(Scalar)).name(); - PyUFuncObject *ufunc = - (PyUFuncObject *)PyObject_GetAttrString(numpy, "matmul"); - if (!ufunc) { - std::stringstream ss; - ss << "Impossible to define matrix_multiply for given type " - << bp::type_info(typeid(Scalar)).name() << std::endl; - eigenpy::Exception(ss.str()); - } - if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, type_code, - &internal::gufunc_matrix_multiply, - types, 0) < 0) { - std::stringstream ss; - ss << "Impossible to register matrix_multiply for given type " - << bp::type_info(typeid(Scalar)).name() << std::endl; - eigenpy::Exception(ss.str()); - } - - Py_DECREF(ufunc); + ss << "Impossible to define matrix_multiply for given type " + << bp::type_info(typeid(Scalar)).name() << std::endl; + eigenpy::Exception(ss.str()); + } + if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, type_code, + &internal::gufunc_matrix_multiply, + types, 0) < 0) { + std::stringstream ss; + ss << "Impossible to register matrix_multiply for given type " + << bp::type_info(typeid(Scalar)).name() << std::endl; + eigenpy::Exception(ss.str()); } - // Binary operators - EIGENPY_REGISTER_BINARY_UFUNC(add, type_code, Scalar, Scalar, Scalar); - EIGENPY_REGISTER_BINARY_UFUNC(subtract, type_code, Scalar, Scalar, Scalar); - EIGENPY_REGISTER_BINARY_UFUNC(multiply, type_code, Scalar, Scalar, Scalar); - EIGENPY_REGISTER_BINARY_UFUNC(divide, type_code, Scalar, Scalar, Scalar); - - // Comparison operators - EIGENPY_REGISTER_BINARY_UFUNC(equal, type_code, Scalar, Scalar, bool); - EIGENPY_REGISTER_BINARY_UFUNC(not_equal, type_code, Scalar, Scalar, bool); + Py_DECREF(ufunc); + } - //these are commented out because the comparisons are NOT defined for complex types!! - // EIGENPY_REGISTER_BINARY_UFUNC(greater, type_code, Scalar, Scalar, bool); - // EIGENPY_REGISTER_BINARY_UFUNC(less, type_code, Scalar, Scalar, bool); - // EIGENPY_REGISTER_BINARY_UFUNC(greater_equal, type_code, Scalar, Scalar, bool); - // EIGENPY_REGISTER_BINARY_UFUNC(less_equal, type_code, Scalar, Scalar, bool); + // Binary operators + EIGENPY_REGISTER_BINARY_UFUNC(add, type_code, Scalar, Scalar, Scalar); + EIGENPY_REGISTER_BINARY_UFUNC(subtract, type_code, Scalar, Scalar, Scalar); + EIGENPY_REGISTER_BINARY_UFUNC(multiply, type_code, Scalar, Scalar, Scalar); + EIGENPY_REGISTER_BINARY_UFUNC(divide, type_code, Scalar, Scalar, Scalar); - // Unary operators - EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar); + // Comparison operators + EIGENPY_REGISTER_BINARY_UFUNC(equal, type_code, Scalar, Scalar, bool); + EIGENPY_REGISTER_BINARY_UFUNC(not_equal, type_code, Scalar, Scalar, bool); - Py_DECREF(numpy); -} + // these are commented out because the comparisons are NOT defined for complex + // types!! + // EIGENPY_REGISTER_BINARY_UFUNC(greater, type_code, Scalar, Scalar, bool); + // EIGENPY_REGISTER_BINARY_UFUNC(less, type_code, Scalar, Scalar, bool); + // EIGENPY_REGISTER_BINARY_UFUNC(greater_equal, type_code, Scalar, Scalar, + // bool); EIGENPY_REGISTER_BINARY_UFUNC(less_equal, type_code, Scalar, + // Scalar, bool); -} // namespace eigenpy + // Unary operators + EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar); + Py_DECREF(numpy); +} +} // namespace eigenpy namespace bp = boost::python; -// this derived directly from the code at https://github.com/stack-of-tasks/eigenpy/issues/365, in which this example was requested -template -struct BoostNumberPythonVisitor -: public boost::python::def_visitor< BoostNumberPythonVisitor > -{ - -public: - - template - void visit(PyClass& cl) const - { - cl - .def(bp::init<>("Default constructor.",bp::arg("self"))) - .def(bp::init("Copy constructor.",bp::args("self","value"))) - .def(bp::init("Constructor from a string.",bp::args("self","str_value"))) - .def(bp::init("Constructor from a pair of strings.",bp::args("self","real","imag"))) - - - .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(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(bp::self_ns::pow(bp::self_ns::self,long())) - - - - .def("str",&BoostNumber::str,bp::args("self","precision","scientific")) - - .def("default_precision", - static_cast(BoostNumber::default_precision), - "Get the default precision of the class.") - .def("default_precision", - static_cast(BoostNumber::default_precision),bp::arg("digits10"), - "Set the default precision of the class.") - .staticmethod("default_precision") - - .def("precision", - static_cast(&BoostNumber::precision), - bp::arg("self"), - "Get the precision of this.") - .def("precision", - static_cast(&BoostNumber::precision), - bp::args("self","digits10"), - "Set the precision of this.") - - - .def("__str__",&print,bp::arg("self")) - .def("__repr__",&print,bp::arg("self")) - - .def("set_display_precision",&set_display_precision,bp::arg("digit"), - "Set the precision when printing values.") - .staticmethod("set_display_precision") - - .def("get_display_precision",&get_display_precision, - "Get the precision when printing values.", - bp::return_value_policy()) - .staticmethod("get_display_precision") - - ; - +// this derived directly from the code at +// https://github.com/stack-of-tasks/eigenpy/issues/365, in which this example +// was requested +template +struct BoostNumberPythonVisitor : public boost::python::def_visitor< + BoostNumberPythonVisitor > { + public: + template + void visit(PyClass &cl) const { + cl.def(bp::init<>("Default constructor.", bp::arg("self"))) + .def(bp::init("Copy constructor.", + bp::args("self", "value"))) + .def(bp::init("Constructor from a string.", + bp::args("self", "str_value"))) + .def(bp::init( + "Constructor from a pair of strings.", + bp::args("self", "real", "imag"))) + + .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(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(bp::self_ns::pow(bp::self_ns::self, long())) + + .def("str", &BoostNumber::str, + bp::args("self", "precision", "scientific")) + + .def("default_precision", + static_cast(BoostNumber::default_precision), + "Get the default precision of the class.") + .def("default_precision", + static_cast(BoostNumber::default_precision), + bp::arg("digits10"), "Set the default precision of the class.") + .staticmethod("default_precision") + + .def("precision", + static_cast( + &BoostNumber::precision), + bp::arg("self"), "Get the precision of this.") + .def("precision", + static_cast( + &BoostNumber::precision), + bp::args("self", "digits10"), "Set the precision of this.") + + .def("__str__", &print, bp::arg("self")) + .def("__repr__", &print, bp::arg("self")) + + .def("set_display_precision", &set_display_precision, bp::arg("digit"), + "Set the precision when printing values.") + .staticmethod("set_display_precision") + + .def("get_display_precision", &get_display_precision, + "Get the precision when printing values.", + bp::return_value_policy()) + .staticmethod("get_display_precision") + + ; } - static std::string print(const BoostNumber & self) - { + static std::string print(const BoostNumber &self) { return self.str(get_display_precision(), std::ios_base::dec); } - static void set_display_precision(const int digit) - { + static void set_display_precision(const int digit) { get_display_precision() = digit; } - - static int & get_display_precision() - { + + static int &get_display_precision() { static int precision = BoostNumber::default_precision(); return precision; } }; - - - #endif - - diff --git a/examples/custom_numeric_type/src/src.cpp b/examples/custom_numeric_type/src/src.cpp index a47aaf810..79b88b85c 100644 --- a/examples/custom_numeric_type/src/src.cpp +++ b/examples/custom_numeric_type/src/src.cpp @@ -1,62 +1,47 @@ #include "header.hpp" - - -BOOST_PYTHON_MODULE(eigenpy_example_custom_numeric_type) // this name must match the name of the generated .so file. -{ - // see https://stackoverflow.com/questions/6114462/how-to-override-the-automatically-created-docstring-data-for-boostpython - // docstring_options d(true, true, false); // local_ - boost::python::docstring_options docopt; - docopt.enable_all(); - docopt.disable_cpp_signatures(); - - boost::python::object package = boost::python::scope(); - package.attr("__path__") = "eigenpy_example_custom_numeric_type"; - - - Expose(); +BOOST_PYTHON_MODULE( + eigenpy_example_custom_numeric_type) // this name must match the name of + // the generated .so file. +{ + // see + // https://stackoverflow.com/questions/6114462/how-to-override-the-automatically-created-docstring-data-for-boostpython + // docstring_options d(true, true, false); // local_ + boost::python::docstring_options docopt; + docopt.enable_all(); + docopt.disable_cpp_signatures(); + + boost::python::object package = boost::python::scope(); + package.attr("__path__") = "eigenpy_example_custom_numeric_type"; + + Expose(); } +#define IMPLICITLY_CONVERTIBLE(T1, T2) \ + boost::python::implicitly_convertible(); +void Expose() { + eigenpy::enableEigenPy(); -#define IMPLICITLY_CONVERTIBLE(T1,T2) \ - boost::python::implicitly_convertible(); - -void Expose(){ - - eigenpy::enableEigenPy(); - - boost::python::class_("MpfrComplex", - "",bp::no_init) - .def(BoostNumberPythonVisitor()) - ; - + boost::python::class_("MpfrComplex", "", bp::no_init) + .def(BoostNumberPythonVisitor()); + eigenpy::registerNewType(); + eigenpy::registerUfunct_without_comparitors(); - eigenpy::registerNewType(); - eigenpy::registerUfunct_without_comparitors(); + eigenpy::registerCast(true); + eigenpy::registerCast(true); + eigenpy::registerCast(true); + IMPLICITLY_CONVERTIBLE(int, mpfr_complex); + IMPLICITLY_CONVERTIBLE(long, mpfr_complex); + IMPLICITLY_CONVERTIBLE(int64_t, mpfr_complex); - eigenpy::registerCast(true); - eigenpy::registerCast(true); - eigenpy::registerCast(true); + using VecX = Eigen::Matrix; + using MatXX = Eigen::Matrix; - - - IMPLICITLY_CONVERTIBLE(int,mpfr_complex); - IMPLICITLY_CONVERTIBLE(long,mpfr_complex); - IMPLICITLY_CONVERTIBLE(int64_t,mpfr_complex); - - using VecX = Eigen::Matrix; - using MatXX = Eigen::Matrix; - - - - - eigenpy::enableEigenPySpecific(); - eigenpy::enableEigenPySpecific(); + eigenpy::enableEigenPySpecific(); + eigenpy::enableEigenPySpecific(); } - - #undef IMPLICITLY_CONVERTIBLE