diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3ad7e784d46f4e150935828711a90623b6af1..5385030ee66eba843654cec2173a00dcb3ea83d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,13 @@ option(GENERATE_PYTHON_STUBS option(BUILD_WITH_CHOLMOD_SUPPORT "Build EigenPy with the Cholmod support" OFF) +if(APPLE) + option(BUILD_WITH_ACCELERATE_SUPPORT + "Build EigenPy with the Accelerate support" OFF) +else(APPLE) + set(BUILD_WITH_ACCELERATE_SUPPORT FALSE) +endif(APPLE) + string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # If needed, fix CMake policy for APPLE systems @@ -112,6 +119,24 @@ if(BUILD_WITH_CHOLMOD_SUPPORT) add_definitions(-DEIGENPY_WITH_CHOLMOD_SUPPORT) endif(BUILD_WITH_CHOLMOD_SUPPORT) +if(BUILD_WITH_ACCELERATE_SUPPORT) + if(NOT ${Eigen3_VERSION} VERSION_GREATER_EQUAL "3.4.90") + message( + FATAL_ERROR + "Your version of Eigen is too low. Should be at least 3.4.90. Current version is ${Eigen3_VERSION}." + ) + endif() + + set(CMAKE_MODULE_PATH ${JRL_CMAKE_MODULES}/find-external/Accelerate + ${CMAKE_MODULE_PATH}) + add_project_dependency( + Accelerate REQUIRED # FIND_EXTERNAL "Accelerate" # We don't export yet as + # there might be an issue on AMR64 platforms + ) + message(STATUS "Build with Accelerate support framework.") + add_definitions(-DEIGENPY_WITH_ACCELERATE_SUPPORT) +endif(BUILD_WITH_ACCELERATE_SUPPORT) + # ---------------------------------------------------- # --- INCLUDE ---------------------------------------- # ---------------------------------------------------- @@ -139,6 +164,9 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_CHOLMOD_HEADERS include/eigenpy/decompositions/sparse/cholmod/CholmodSimplicialLLT.hpp include/eigenpy/decompositions/sparse/cholmod/CholmodSupernodalLLT.hpp) +set(${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_ACCELERATE_HEADERS + include/eigenpy/decompositions/sparse/accelerate/accelerate.hpp) + set(${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS include/eigenpy/decompositions/sparse/LLT.hpp include/eigenpy/decompositions/sparse/LDLT.hpp @@ -150,6 +178,11 @@ if(BUILD_WITH_CHOLMOD_SUPPORT) ${${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_CHOLMOD_HEADERS}) endif(BUILD_WITH_CHOLMOD_SUPPORT) +if(BUILD_WITH_ACCELERATE_SUPPORT) + list(APPEND ${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS + ${${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_ACCELERATE_HEADERS}) +endif(BUILD_WITH_ACCELERATE_SUPPORT) + set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS ${${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS} include/eigenpy/decompositions/decompositions.hpp @@ -229,6 +262,11 @@ if(BUILD_WITH_CHOLMOD_SUPPORT) src/decompositions/cholmod.cpp) endif(BUILD_WITH_CHOLMOD_SUPPORT) +if(BUILD_WITH_ACCELERATE_SUPPORT) + list(APPEND ${PROJECT_NAME}_DECOMPOSITIONS_SOURCES + src/decompositions/accelerate.cpp) +endif(BUILD_WITH_ACCELERATE_SUPPORT) + set(${PROJECT_NAME}_SOURCES ${${PROJECT_NAME}_SOLVERS_SOURCES} ${${PROJECT_NAME}_DECOMPOSITIONS_SOURCES} @@ -280,10 +318,19 @@ modernize_target_link_libraries( ${NUMPY_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIR}) +# Links against CholMod if(BUILD_WITH_CHOLMOD_SUPPORT) modernize_target_link_libraries(${PROJECT_NAME} SCOPE PUBLIC TARGETS CHOLMOD::CHOLMOD) endif(BUILD_WITH_CHOLMOD_SUPPORT) + +# Links against accelerate +if(BUILD_WITH_ACCELERATE_SUPPORT) + # modernize_target_link_libraries(${PROJECT_NAME} SCOPE PUBLIC TARGETS + # Accelerate) + target_link_libraries(${PROJECT_NAME} PRIVATE "-framework accelerate") +endif(BUILD_WITH_ACCELERATE_SUPPORT) + if(SUFFIX_SO_VERSION) set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION}) endif(SUFFIX_SO_VERSION) diff --git a/include/eigenpy/decompositions/decompositions.hpp b/include/eigenpy/decompositions/decompositions.hpp index 58f9fbde397156a92d5d49949f74b7b91eb2c629..fd55626a4c753149a87a21f0a7540914939735d8 100644 --- a/include/eigenpy/decompositions/decompositions.hpp +++ b/include/eigenpy/decompositions/decompositions.hpp @@ -14,6 +14,10 @@ void EIGENPY_DLLAPI exposeDecompositions(); void EIGENPY_DLLAPI exposeCholmod(); #endif +#ifdef EIGENPY_WITH_ACCELERATE_SUPPORT +void EIGENPY_DLLAPI exposeAccelerate(); +#endif + } // namespace eigenpy #endif // define __eigenpy_decompositions_decompositions_hpp__ diff --git a/include/eigenpy/decompositions/sparse/accelerate/accelerate.hpp b/include/eigenpy/decompositions/sparse/accelerate/accelerate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..903c086fb1233c3aef1d20f431df3a24d32b5baa --- /dev/null +++ b/include/eigenpy/decompositions/sparse/accelerate/accelerate.hpp @@ -0,0 +1,73 @@ +/* + * Copyright 2024 INRIA + */ + +#ifndef __eigenpy_decomposition_sparse_accelerate_accelerate_hpp__ +#define __eigenpy_decomposition_sparse_accelerate_accelerate_hpp__ + +#include "eigenpy/eigenpy.hpp" +#include "eigenpy/eigen/EigenBase.hpp" +#include "eigenpy/decompositions/sparse/SparseSolverBase.hpp" + +#include <Eigen/AccelerateSupport> + +namespace eigenpy { + +template <typename AccelerateDerived> +struct AccelerateImplVisitor : public boost::python::def_visitor< + AccelerateImplVisitor<AccelerateDerived> > { + typedef AccelerateDerived Solver; + + typedef typename AccelerateDerived::MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef MatrixType CholMatrixType; + typedef typename MatrixType::StorageIndex StorageIndex; + + template <class PyClass> + void visit(PyClass &cl) const { + cl + + .def("analyzePattern", &Solver::analyzePattern, + bp::args("self", "matrix"), + "Performs a symbolic decomposition on the sparcity of matrix.\n" + "This function is particularly useful when solving for several " + "problems having the same structure.") + + .def(EigenBaseVisitor<Solver>()) + .def(SparseSolverBaseVisitor<Solver>()) + + .def("compute", + (Solver & (Solver::*)(const MatrixType &matrix)) & Solver::compute, + bp::args("self", "matrix"), + "Computes the sparse Cholesky decomposition of a given matrix.", + bp::return_self<>()) + + .def("factorize", &Solver::factorize, bp::args("self", "matrix"), + "Performs a numeric decomposition of a given matrix.\n" + "The given matrix must has the same sparcity than the matrix on " + "which the symbolic decomposition has been performed.\n" + "See also analyzePattern().") + + .def("info", &Solver::info, bp::arg("self"), + "NumericalIssue if the input contains INF or NaN values or " + "overflow occured. Returns Success otherwise.") + + .def("setOrder", &Solver::setOrder, bp::arg("self"), "Set order"); + } + + static void expose(const std::string &name, const std::string &doc = "") { + bp::class_<Solver, boost::noncopyable>(name.c_str(), doc.c_str(), + bp::no_init) + .def(AccelerateImplVisitor()) + + .def(bp::init<>(bp::arg("self"), "Default constructor")) + .def(bp::init<MatrixType>(bp::args("self", "matrix"), + "Constructs and performs the " + "factorization from a given matrix.")); + } +}; + +} // namespace eigenpy + +#endif // ifndef __eigenpy_decomposition_sparse_accelerate_accelerate_hpp__ diff --git a/src/decompositions/accelerate.cpp b/src/decompositions/accelerate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d7b1d1686ddbf2be48f8f95a65134d73a0f24ef --- /dev/null +++ b/src/decompositions/accelerate.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2024 INRIA + */ + +#include "eigenpy/fwd.hpp" +#include "eigenpy/decompositions/decompositions.hpp" + +#include "eigenpy/decompositions/sparse/accelerate/accelerate.hpp" + +namespace eigenpy { + +void exposeAccelerate() { + using namespace Eigen; + + typedef Eigen::SparseMatrix<double, Eigen::ColMajor> ColMajorSparseMatrix; + // typedef Eigen::SparseMatrix<double,Eigen::RowMajor> RowMajorSparseMatrix; + + bp::enum_<SparseOrder_t>("SparseOrder") + .value("SparseOrderUser", SparseOrderUser) + .value("SparseOrderAMD", SparseOrderAMD) + .value("SparseOrderMetis", SparseOrderMetis) + .value("SparseOrderCOLAMD", SparseOrderCOLAMD); + +#define EXPOSE_ACCELERATE_DECOMPOSITION(name) \ + AccelerateImplVisitor<name<ColMajorSparseMatrix> >::expose( \ + EIGENPY_STRINGIZE(name)) + + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLLT); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLDLT); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLDLTUnpivoted); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLDLTSBK); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLDLTTPP); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateQR); + EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateCholeskyAtA); +} +} // namespace eigenpy diff --git a/src/decompositions/decompositions.cpp b/src/decompositions/decompositions.cpp index 4a611074abf14cff50c60036a764d99b197f745c..2b58c03d0c1cf8cb87ff54b1c81ff016144f7b86 100644 --- a/src/decompositions/decompositions.cpp +++ b/src/decompositions/decompositions.cpp @@ -52,5 +52,9 @@ void exposeDecompositions() { #ifdef EIGENPY_WITH_CHOLMOD_SUPPORT exposeCholmod(); #endif + +#ifdef EIGENPY_WITH_ACCELERATE_SUPPORT + exposeAccelerate(); +#endif } } // namespace eigenpy