Skip to content
Snippets Groups Projects
Unverified Commit 977844fd authored by Justin Carpentier's avatar Justin Carpentier Committed by GitHub
Browse files

Merge pull request #16 from jcarpent/devel

Make EigenPy a library for Python
parents 780ce8f1 a02f5cd8
No related branches found
No related tags found
No related merge requests found
Showing
with 940 additions and 35 deletions
# #
# Copyright (c) 2015-2016 LAAS-CNRS # Copyright (c) 2015-2017 LAAS-CNRS
# #
# This file is part of eigenpy. # This file is part of eigenpy.
# eigenpy is free software: you can redistribute it and/or # eigenpy is free software: you can redistribute it and/or
...@@ -19,6 +19,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) ...@@ -19,6 +19,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
INCLUDE(cmake/base.cmake) INCLUDE(cmake/base.cmake)
INCLUDE(cmake/boost.cmake) INCLUDE(cmake/boost.cmake)
INCLUDE(cmake/python.cmake) INCLUDE(cmake/python.cmake)
INCLUDE(cmake/ide.cmake)
SET(PROJECT_NAME eigenpy) SET(PROJECT_NAME eigenpy)
SET(PROJECT_DESCRIPTION "Wrapping Eigen3 -- numpy") SET(PROJECT_DESCRIPTION "Wrapping Eigen3 -- numpy")
...@@ -45,6 +46,12 @@ IF(APPLE) ...@@ -45,6 +46,12 @@ IF(APPLE)
ENDIF("${isSystemDir}" STREQUAL "-1") ENDIF("${isSystemDir}" STREQUAL "-1")
ENDIF(APPLE) ENDIF(APPLE)
IF(WIN32)
SET(LINK copy_if_different)
ELSE(WIN32)
SET(LINK create_symlink)
ENDIF(WIN32)
# ---------------------------------------------------- # ----------------------------------------------------
# --- OPTIONS --------------------------------------- # --- OPTIONS ---------------------------------------
# ---------------------------------------------------- # ----------------------------------------------------
...@@ -73,61 +80,97 @@ INCLUDE_DIRECTORIES(${NUMPY_INCLUDE_DIRS}) ...@@ -73,61 +80,97 @@ INCLUDE_DIRECTORIES(${NUMPY_INCLUDE_DIRS})
# ---------------------------------------------------- # ----------------------------------------------------
# --- INCLUDE ---------------------------------------- # --- INCLUDE ----------------------------------------
# ---------------------------------------------------- # ----------------------------------------------------
SET(${PROJECT_NAME}_SOLVERS_HEADERS
solvers/solvers.hpp
solvers/preconditioners.hpp
solvers/IterativeSolverBase.hpp
solvers/LeastSquaresConjugateGradient.hpp
solvers/ConjugateGradient.hpp
solvers/SparseSolverBase.hpp
solvers/BasicPreconditioners.hpp
solvers/BFGSPreconditioners.hpp
)
SET(HEADERS SET(HEADERS
src/eigenpy.hpp ${${PROJECT_NAME}_SOLVERS_HEADERS}
src/exception.hpp eigenpy.hpp
src/details.hpp exception.hpp
src/fwd.hpp details.hpp
src/map.hpp fwd.hpp
src/geometry.hpp map.hpp
src/memory.hpp geometry.hpp
src/registration.hpp memory.hpp
src/angle-axis.hpp registration.hpp
src/quaternion.hpp angle-axis.hpp
quaternion.hpp
) )
MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy") MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy")
MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy/solvers")
INCLUDE_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy) INCLUDE_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/include/eigenpy)
#FOREACH(header ${HEADERS})
# GET_FILENAME_COMPONENT(headerName ${header} NAME)
# IF(WIN32)
# execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
# ${${PROJECT_NAME}_SOURCE_DIR}/${header}
# ${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/)
# ELSE(WIN32)
# execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
# ${${PROJECT_NAME}_SOURCE_DIR}/${header}
# ${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/${headerName})
# ENDIF(WIN32)
# INSTALL(FILES ${${PROJECT_NAME}_SOURCE_DIR}/${header}
# DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME}
# PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
#ENDFOREACH(header)
SET(${PROJECT_NAME}_HEADERS)
FOREACH(header ${HEADERS}) FOREACH(header ${HEADERS})
GET_FILENAME_COMPONENT(headerName ${header} NAME) GET_FILENAME_COMPONENT(headerName ${header} NAME)
IF(WIN32) GET_FILENAME_COMPONENT(headerPath ${header} PATH)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E ${LINK}
${${PROJECT_NAME}_SOURCE_DIR}/${header} ${${PROJECT_NAME}_SOURCE_DIR}/src/${header}
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/) ${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/${header})
ELSE(WIN32) INSTALL(FILES ${${PROJECT_NAME}_SOURCE_DIR}/src/${header}
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME}/${headerPath}
${${PROJECT_NAME}_SOURCE_DIR}/${header} PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_WRITE)
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/${headerName}) LIST(APPEND ${PROJECT_NAME}_HEADERS src/${header})
ENDIF(WIN32)
INSTALL(FILES ${${PROJECT_NAME}_SOURCE_DIR}/${header}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME}
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
ENDFOREACH(header) ENDFOREACH(header)
# ---------------------------------------------------- # ----------------------------------------------------
# --- TARGETS ---------------------------------------- # --- TARGETS ----------------------------------------
# ---------------------------------------------------- # ----------------------------------------------------
SET(${PROJECT_NAME}_SOLVERS_SOURCES
src/solvers/preconditioners.cpp
src/solvers/solvers.cpp
)
SET(${PROJECT_NAME}_SOURCES SET(${PROJECT_NAME}_SOURCES
${${PROJECT_NAME}_SOLVERS_SOURCES}
src/exception.cpp src/exception.cpp
src/eigenpy.cpp src/eigenpy.cpp
src/angle-axis.cpp src/angle-axis.cpp
src/quaternion.cpp src/quaternion.cpp
) )
ADD_LIBRARY(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES} ${HEADERS}) ADD_LIBRARY(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS})
TARGET_LINK_BOOST_PYTHON(${PROJECT_NAME}) TARGET_LINK_BOOST_PYTHON(${PROJECT_NAME})
PKG_CONFIG_USE_DEPENDENCY(${PROJECT_NAME} eigen3) PKG_CONFIG_USE_DEPENDENCY(${PROJECT_NAME} eigen3)
INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
ADD_HEADER_GROUP(${PROJECT_NAME}_HEADERS)
ADD_SOURCE_GROUP(${PROJECT_NAME}_SOURCES)
# ---------------------------------------------------- # ----------------------------------------------------
# --- UNIT TEST -------------------------------------- # --- PYTHON LIBRARY ---------------------------------
# ---------------------------------------------------- # ----------------------------------------------------
ADD_SUBDIRECTORY(unittest) ADD_SUBDIRECTORY(python)
# ---------------------------------------------------- # ----------------------------------------------------
# --- EXECUTABLES ------------------------------------ # --- UNIT TEST --------------------------------------
# ---------------------------------------------------- # ----------------------------------------------------
ADD_SUBDIRECTORY(unittest)
IF(EIGEN_NUMPY_ALIGNED) IF(EIGEN_NUMPY_ALIGNED)
PKG_CONFIG_APPEND_CFLAGS("-DEIGENPY_ALIGNED") PKG_CONFIG_APPEND_CFLAGS("-DEIGENPY_ALIGNED")
......
Subproject commit 45ea8074e31604d3e4cc594baaa5abe9fac1921b Subproject commit 687a16b8d42e20294ec3f51759d122db2d212695
#
# Copyright (c) 2017 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
# General Lesser 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/>.
MACRO(SYMLINK_AND_INSTALL_HEADERS HEADERS SUBPATH)
FOREACH(header ${HEADERS})
GET_FILENAME_COMPONENT(headerName ${header} NAME)
GET_FILENAME_COMPONENT(headerPath ${header} PATH)
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E ${LINK}
${CMAKE_CURRENT_SOURCE_DIR}/${header}
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/${SUBPATH}/${header})
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${header}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME}/${SUBPATH}/${headerPath}
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_WRITE)
ENDFOREACH(header)
ENDMACRO(SYMLINK_AND_INSTALL_HEADERS HEADERS SUBPATH)
# --- LIBRARY --- #
SET(PYWRAP ${PROJECT_NAME}_pywrap)
MAKE_DIRECTORY("${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}")
ADD_LIBRARY(${PYWRAP} SHARED main.cpp)
TARGET_LINK_LIBRARIES(${PYWRAP} ${PROJECT_NAME})
TARGET_LINK_BOOST_PYTHON(${PYWRAP})
#IF(BUILD_WITH_COMMIT_VERSION)
# TAG_LIBRARY_VERSION(${PYWRAP})
#ENDIF(BUILD_WITH_COMMIT_VERSION)
SET(${PYWRAP}_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${PYTHON_SITELIB})
SET_PROPERTY(TARGET ${PYWRAP} PROPERTY LINKER_LANGUAGE CXX)
IF(APPLE)
# We need to change the extension for python bindings
SET_TARGET_PROPERTIES(${PYWRAP} PROPERTIES SUFFIX ".so")
ENDIF(APPLE)
SET_TARGET_PROPERTIES(${PYWRAP} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}")
SET_TARGET_PROPERTIES(${PYWRAP} PROPERTIES PREFIX "")
SET_TARGET_PROPERTIES(${PYWRAP} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}")
INSTALL(TARGETS ${PYWRAP} DESTINATION ${${PYWRAP}_INSTALL_DIR})
## --- INSTALL SCRIPTS
#SET(PYTHON_FILES
# __init__.py
# )
#
#FOREACH(python ${PYTHON_FILES})
# GET_FILENAME_COMPONENT(pythonFile ${python} NAME)
# EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E ${LINK}
# ${${PROJECT_NAME}_SOURCE_DIR}/python/scripts/${python}
# ${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}/${pythonFile})
#
# # Generate pyc file
# EXECUTE_PROCESS(COMMAND
# ${PYTHON_EXECUTABLE} -m py_compile
# ${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}/${pythonFile})
# # Tag pyc file as generated.
# SET_SOURCE_FILES_PROPERTIES(
# "${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}/${pythonFile}c"
# PROPERTIES GENERATED TRUE)
#
# # Clean generated files.
# SET_PROPERTY(
# DIRECTORY APPEND PROPERTY
# ADDITIONAL_MAKE_CLEAN_FILES
# "${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}/${pythonFile}c")
#
# INSTALL(FILES
# "${${PROJECT_NAME}_SOURCE_DIR}/python/scripts/${python}"
# "${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}/${pythonFile}c"
# DESTINATION ${${PYWRAP}_INSTALL_DIR})
#ENDFOREACH(python)
//
// Copyright (c) 2017, Justin Carpentier, 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
// General Lesser 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/>.
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/geometry.hpp"
#include "eigenpy/solvers/solvers.hpp"
#include "eigenpy/solvers/preconditioners.hpp"
#include <iostream>
#include <boost/python/scope.hpp>
using namespace eigenpy;
BOOST_PYTHON_MODULE(eigenpy)
{
enableEigenPy();
exposeAngleAxis();
exposeQuaternion();
{
boost::python::scope solvers = boost::python::class_<SolversScope>("solvers");
exposeSolvers();
exposePreconditioners();
}
}
#
# Copyright (c) 2017 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.
# Pinocchio 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
# General Lesser 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/>.
import numpy as np
from eigenpy import *
...@@ -71,16 +71,16 @@ namespace eigenpy ...@@ -71,16 +71,16 @@ namespace eigenpy
"The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!")) "The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!"))
.add_property("x", .add_property("x",
(Scalar (Quaternion::*)()const)&Quaternion::x, &QuaternionVisitor::getCoeff<0>,
&QuaternionVisitor::setCoeff<0>,"The x coefficient.") &QuaternionVisitor::setCoeff<0>,"The x coefficient.")
.add_property("y", .add_property("y",
(Scalar (Quaternion::*)()const)&Quaternion::y, &QuaternionVisitor::getCoeff<1>,
&QuaternionVisitor::setCoeff<1>,"The y coefficient.") &QuaternionVisitor::setCoeff<1>,"The y coefficient.")
.add_property("z", .add_property("z",
(Scalar (Quaternion::*)()const)&Quaternion::z, &QuaternionVisitor::getCoeff<2>,
&QuaternionVisitor::setCoeff<2>,"The z coefficient.") &QuaternionVisitor::setCoeff<2>,"The z coefficient.")
.add_property("w", .add_property("w",
(Scalar (Quaternion::*)()const)&Quaternion::w, &QuaternionVisitor::getCoeff<3>,
&QuaternionVisitor::setCoeff<3>,"The w coefficient.") &QuaternionVisitor::setCoeff<3>,"The w coefficient.")
// .def("isApprox",(bool (Quaternion::*)(const Quaternion &))&Quaternion::template isApprox<Quaternion>, // .def("isApprox",(bool (Quaternion::*)(const Quaternion &))&Quaternion::template isApprox<Quaternion>,
...@@ -151,6 +151,9 @@ namespace eigenpy ...@@ -151,6 +151,9 @@ namespace eigenpy
template<int i> template<int i>
static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; } static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; }
template<int i>
static Scalar getCoeff(Quaternion & self) { return self.coeffs()[i]; }
static Quaternion & setFromTwoVectors(Quaternion & self, const Vector3 & a, const Vector3 & b) static Quaternion & setFromTwoVectors(Quaternion & self, const Vector3 & a, const Vector3 & b)
{ return self.setFromTwoVectors(a,b); } { return self.setFromTwoVectors(a,b); }
......
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_bfgs_preconditioners_hpp__
#define __eigenpy_bfgs_preconditioners_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/solvers/BasicPreconditioners.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename Preconditioner>
struct BFGSPreconditionerBaseVisitor
: public bp::def_visitor< BFGSPreconditionerBaseVisitor<Preconditioner> >
{
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
.def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
.def("dim",&Preconditioner::dim,"Returns the dimension of the BFGS preconditioner")
.def("update",(const Preconditioner& (Preconditioner::*)(const VectorType &, const VectorType &) const)&Preconditioner::update,bp::args("s","y"),"Update the BFGS estimate of the matrix A.",bp::return_value_policy<bp::reference_existing_object>())
.def("reset",&Preconditioner::reset,"Reset the BFGS estimate.")
;
}
static void expose(const std::string & name)
{
bp::class_<Preconditioner>(name,
bp::no_init)
.def(BFGSPreconditionerBaseVisitor<Preconditioner>())
;
}
};
template<typename Preconditioner>
struct LimitedBFGSPreconditionerBaseVisitor
: public bp::def_visitor< LimitedBFGSPreconditionerBaseVisitor<Preconditioner> >
{
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def(BFGSPreconditionerBaseVisitor<Preconditioner>())
.def("resize",&Preconditioner::resize,bp::arg("dim"),"Resizes the preconditionner with size dim.",bp::return_value_policy<bp::reference_existing_object>())
;
}
static void expose(const std::string & name)
{
bp::class_<Preconditioner>(name.c_str(),
bp::no_init)
.def(LimitedBFGSPreconditionerBaseVisitor<Preconditioner>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_bfgs_preconditioners_hpp__
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_basic_preconditioners_hpp__
#define __eigenpy_basic_preconditioners_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
namespace eigenpy
{
namespace bp = boost::python;
template<typename Preconditioner>
struct PreconditionerBaseVisitor
: public bp::def_visitor< PreconditionerBaseVisitor<Preconditioner> >
{
typedef Eigen::MatrixXd MatrixType;
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the preconditioner with matrix A for further Az=b solving."))
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("info",&Preconditioner::info,
"Returns success if the Preconditioner has been well initialized.")
#endif
.def("solve",&solve,bp::arg("b"),
"Returns the solution A * z = b where the preconditioner is an estimate of A^-1.")
.def("compute",&Preconditioner::template compute<MatrixType>,bp::arg("mat"),
"Initialize the preconditioner from the matrix value.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize",&Preconditioner::template factorize<MatrixType>,bp::arg("mat"),
"Initialize the preconditioner from the matrix value, i.e factorize the mat given as input to approximate its inverse.",
bp::return_value_policy<bp::reference_existing_object>())
;
}
private:
static VectorType solve(Preconditioner & self, const VectorType & b)
{
return self.solve(b);
}
};
template<typename Scalar>
struct DiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> >
{
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
.def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
;
}
static void expose()
{
bp::class_<Preconditioner>("DiagonalPreconditioner",
"A preconditioner based on the digonal entrie.\n"
"This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.",
bp::no_init)
;
}
};
#if EIGEN_VERSION_AT_LEAST(3,3,0)
template<typename Scalar>
struct LeastSquareDiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::LeastSquareDiagonalPreconditioner<Scalar> >
{
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;
template<class PyClass>
void visit(PyClass&) const
{
}
static void expose()
{
bp::class_<Preconditioner>("LeastSquareDiagonalPreconditioner",
"Jacobi preconditioner for LeastSquaresConjugateGradient.\n"
"his class allows to approximately solve for A' A x = A' b problems assuming A' A is a diagonal matrix.",
bp::no_init)
.def(DiagonalPreconditionerVisitor<Scalar>())
;
}
};
#endif
struct IdentityPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::IdentityPreconditioner >
{
typedef Eigen::IdentityPreconditioner Preconditioner;
template<class PyClass>
void visit(PyClass&) const
{
}
static void expose()
{
bp::class_<Preconditioner>("IdentityPreconditioner",
bp::no_init)
.def(PreconditionerBaseVisitor<Preconditioner>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_basic_preconditioners_hpp__
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_conjugate_gradient_hpp__
#define __eigenpy_conjugate_gradient_hpp__
#include <boost/python.hpp>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/solvers/IterativeSolverBase.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename ConjugateGradient>
struct ConjugateGradientVisitor
: public boost::python::def_visitor< ConjugateGradientVisitor<ConjugateGradient> >
{
typedef typename ConjugateGradient::MatrixType MatrixType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(IterativeSolverVisitor<ConjugateGradient>())
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the solver with matrix A for further Ax=b solving.\n"
"This constructor is a shortcut for the default constructor followed by a call to compute()."))
;
}
static void expose(const std::string & name = "ConjugateGradient")
{
bp::class_<ConjugateGradient,boost::noncopyable>(name.c_str(),
bp::no_init)
.def(ConjugateGradientVisitor<ConjugateGradient>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_conjugate_gradient_hpp__
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_iterative_solver_base_hpp__
#define __eigenpy_iterative_solver_base_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include "eigenpy/solvers/SparseSolverBase.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename IterativeSolver>
struct IterativeSolverVisitor
: public boost::python::def_visitor< IterativeSolverVisitor<IterativeSolver> >
{
typedef typename IterativeSolver::MatrixType MatrixType;
typedef typename IterativeSolver::Preconditioner Preconditioner;
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
typedef IterativeSolver IS;
cl
.def(SparseSolverVisitor<IS>())
.def("error",&IS::error,"Returns the tolerance error reached during the last solve.\n"
"It is a close approximation of the true relative residual error |Ax-b|/|b|.")
.def("info",&IS::info,"Returns success if the iterations converged, and NoConvergence otherwise.")
.def("iterations",&IS::iterations,"Returns the number of iterations performed during the last solve.")
.def("maxIterations",&IS::maxIterations,"Returns the max number of iterations.\n"
"It is either the value setted by setMaxIterations or, by default, twice the number of columns of the matrix.")
.def("setMaxIterations",&IS::setMaxIterations,"Sets the max number of iterations.\n"
"Default is twice the number of columns of the matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("tolerance",&IS::tolerance,"Returns he tolerance threshold used by the stopping criteria.")
.def("setTolerance",&IS::setTolerance,"Sets the tolerance threshold used by the stopping criteria.\n"
"This value is used as an upper bound to the relative residual error: |Ax-b|/|b|. The default value is the machine precision.",
bp::return_value_policy<bp::reference_existing_object>())
.def("analyzePattern",&analyzePattern,bp::arg("A"),"Initializes the iterative solver for the sparsity pattern of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls analyzePattern on the preconditioner.\n"
"In the future we might, for instance, implement column reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize",&factorize,bp::arg("A"),"Initializes the iterative solver with the numerical values of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the preconditioner.",
bp::return_value_policy<bp::reference_existing_object>())
.def("compute",&compute,bp::arg("A"),"Initializes the iterative solver with the numerical values of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the preconditioner.\n"
"In the future we might, for instance, implement column reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("solveWithGuess",&solveWithGuess,bp::args("b","x0"),
"Returns the solution x of Ax = b using the current decomposition of A and x0 as an initial solution.")
.def("preconditioner",(Preconditioner & (IS::*)(void))&IS::preconditioner,"Returns a read-write reference to the preconditioner for custom configuration.",bp::return_internal_reference<>())
;
}
private:
static IterativeSolver & factorize(IterativeSolver & self, const MatrixType & m)
{
return self.factorize(m);
}
static IterativeSolver & compute(IterativeSolver & self, const MatrixType & m)
{
return self.compute(m);
}
static IterativeSolver & analyzePattern(IterativeSolver & self, const MatrixType & m)
{
return self.analyzePattern(m);
}
static VectorType solveWithGuess(IterativeSolver & self, const Eigen::VectorXd & b, const Eigen::VectorXd & x0)
{
return self.solveWithGuess(b,x0);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_iterative_solver_base_hpp__
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_least_square_conjugate_gradient_hpp__
#define __eigenpy_least_square_conjugate_gradient_hpp__
#include <boost/python.hpp>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/solvers/IterativeSolverBase.hpp"
namespace Eigen
{
template <typename _Scalar>
class LeastSquareDiagonalPreconditionerFix
: public LeastSquareDiagonalPreconditioner<_Scalar>
{
typedef _Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef LeastSquareDiagonalPreconditioner<_Scalar> Base;
using DiagonalPreconditioner<_Scalar>::m_invdiag;
public:
LeastSquareDiagonalPreconditionerFix() : Base() {}
template<typename MatType>
explicit LeastSquareDiagonalPreconditionerFix(const MatType& mat) : Base()
{
compute(mat);
}
template<typename MatType>
LeastSquareDiagonalPreconditionerFix& analyzePattern(const MatType& )
{
return *this;
}
template<typename MatType>
LeastSquareDiagonalPreconditionerFix& factorize(const MatType& mat)
{
// Compute the inverse squared-norm of each column of mat
m_invdiag.resize(mat.cols());
if(MatType::IsRowMajor)
{
m_invdiag.setZero();
for(Index j=0; j<mat.outerSize(); ++j)
{
for(typename MatType::InnerIterator it(mat,j); it; ++it)
m_invdiag(it.index()) += numext::abs2(it.value());
}
for(Index j=0; j<mat.cols(); ++j)
if(numext::real(m_invdiag(j))>RealScalar(0))
m_invdiag(j) = RealScalar(1)/numext::real(m_invdiag(j));
}
else
{
for(Index j=0; j<mat.outerSize(); ++j)
{
RealScalar sum = mat.col(j).squaredNorm();
if(sum>RealScalar(0))
m_invdiag(j) = RealScalar(1)/sum;
else
m_invdiag(j) = RealScalar(1);
}
}
Base::m_isInitialized = true;
return *this;
}
};
}
namespace eigenpy
{
namespace bp = boost::python;
template<typename LeastSquaresConjugateGradient>
struct LeastSquaresConjugateGradientVisitor
: public boost::python::def_visitor< LeastSquaresConjugateGradientVisitor<LeastSquaresConjugateGradient> >
{
typedef Eigen::MatrixXd MatrixType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the solver with matrix A for further || Ax - b || solving.\n"
"This constructor is a shortcut for the default constructor followed by a call to compute()."))
;
}
static void expose()
{
bp::class_<LeastSquaresConjugateGradient,boost::noncopyable>("LeastSquaresConjugateGradient",
bp::no_init)
.def(IterativeSolverVisitor<LeastSquaresConjugateGradient>())
.def(LeastSquaresConjugateGradientVisitor<LeastSquaresConjugateGradient>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_least_square_conjugate_gradient_hpp__
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_sparse_solver_base_hpp__
#define __eigenpy_sparse_solver_base_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
namespace eigenpy
{
namespace bp = boost::python;
template<typename SparseSolver>
struct SparseSolverVisitor
: public bp::def_visitor< SparseSolverVisitor<SparseSolver> >
{
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def("solve",&solve,bp::arg("b"),
"Returns the solution x of Ax = b using the current decomposition of A.")
;
}
private:
static VectorType solve(SparseSolver & self, const VectorType & b)
{
return self.solve(b);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_sparse_solver_base_hpp__
/*
* Copyright 2017, 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/>.
*/
#include "eigenpy/solvers/preconditioners.hpp"
#include "eigenpy/solvers/BasicPreconditioners.hpp"
//#include "eigenpy/solvers/BFGSPreconditioners.hpp"
namespace eigenpy
{
void exposePreconditioners()
{
using namespace Eigen;
DiagonalPreconditionerVisitor<double>::expose();
#if EIGEN_VERSION_AT_LEAST(3,3,0)
LeastSquareDiagonalPreconditionerVisitor<double>::expose();
#endif
IdentityPreconditionerVisitor::expose();
// LimitedBFGSPreconditionerBaseVisitor< LimitedBFGSPreconditioner<double,Eigen::Dynamic,Eigen::Upper|Eigen::Lower> >::expose("LimitedBFGSPreconditioner");
}
} // namespace eigenpy
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_preconditioners_hpp__
#define __eigenpy_preconditioners_hpp__
namespace eigenpy
{
void exposePreconditioners();
} // namespace eigenpy
#endif // define __eigenpy_preconditioners_hpp__
/*
* Copyright 2017, 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/>.
*/
#include "eigenpy/solvers/solvers.hpp"
#include "eigenpy/solvers/ConjugateGradient.hpp"
#if EIGEN_VERSION_AT_LEAST(3,3,0)
#include "eigenpy/solvers/LeastSquaresConjugateGradient.hpp"
#endif
namespace eigenpy
{
void exposeSolvers()
{
using namespace Eigen;
ConjugateGradientVisitor< ConjugateGradient<MatrixXd,Lower|Upper> >::expose();
#if EIGEN_VERSION_AT_LEAST(3,3,0)
LeastSquaresConjugateGradientVisitor< LeastSquaresConjugateGradient<MatrixXd, LeastSquareDiagonalPreconditionerFix<MatrixXd::Scalar> > >::expose();
#endif
// Conjugate gradient with limited BFGS preconditioner
ConjugateGradientVisitor< ConjugateGradient<MatrixXd,Lower|Upper,IdentityPreconditioner > >::expose("IdentityConjugateGradient");
// ConjugateGradientVisitor< ConjugateGradient<MatrixXd,Lower|Upper,LimitedBFGSPreconditioner<double,Dynamic,Lower|Upper> > >::expose("LimitedBFGSConjugateGradient");
boost::python::enum_<Eigen::ComputationInfo>("ComputationInfo")
.value("Success",Eigen::Success)
.value("NumericalIssue",Eigen::NumericalIssue)
.value("NoConvergence",Eigen::NoConvergence)
.value("InvalidInput",Eigen::InvalidInput)
;
}
} // namespace eigenpy
/*
* Copyright 2017, 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/>.
*/
#ifndef __eigenpy_solvers_hpp__
#define __eigenpy_solvers_hpp__
namespace eigenpy
{
struct SolversScope {};
void exposeSolvers();
} // namespace eigenpy
#endif // define __eigenpy_solvers_hpp__
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
# Copyright (c) 2016 CNRS # Copyright (c) 2016 CNRS
# #
# This file is part of eigenpy # This file is part of eigenpy
# Pinocchio is free software: you can redistribute it # eigenpy is free software: you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public # and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation, either version # License as published by the Free Software Foundation, either version
# 3 of the License, or (at your option) any later version. # 3 of the License, or (at your option) any later version.
# Pinocchio is distributed in the hope that it will be # eigenpy is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty # useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Lesser Public License for more details. You should have # General Lesser Public License for more details. You should have
# received a copy of the GNU Lesser General Public License along with # received a copy of the GNU Lesser General Public License along with
# Pinocchio If not, see # eigenpy If not, see
# <http://www.gnu.org/licenses/>. # <http://www.gnu.org/licenses/>.
MACRO(ADD_LIB_UNIT_TEST test PKGS) MACRO(ADD_LIB_UNIT_TEST test PKGS)
......
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment