Skip to content

Commit f0236e8

Browse files
authored
Merge pull request #148 from jcarpent/devel
Expose Eigen::{LLT,LDLT,QR,EigenSolver,...}
2 parents 95e906b + 593fd54 commit f0236e8

File tree

19 files changed

+787
-49
lines changed

19 files changed

+787
-49
lines changed

CMakeLists.txt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#
22
# Copyright (c) 2014-2019 CNRS
3-
# Copyright (c) 2018-2019 INRIA
3+
# Copyright (c) 2018-2020 INRIA
44
#
55

66
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
@@ -71,6 +71,11 @@ SEARCH_FOR_BOOST()
7171
# ----------------------------------------------------
7272
# --- INCLUDE ----------------------------------------
7373
# ----------------------------------------------------
74+
SET(${PROJECT_NAME}_UTILS_HEADERS
75+
include/eigenpy/utils/scalar-name.hpp
76+
include/eigenpy/utils/is-approx.hpp
77+
)
78+
7479
SET(${PROJECT_NAME}_SOLVERS_HEADERS
7580
include/eigenpy/solvers/solvers.hpp
7681
include/eigenpy/solvers/preconditioners.hpp
@@ -82,8 +87,19 @@ SET(${PROJECT_NAME}_SOLVERS_HEADERS
8287
include/eigenpy/solvers/BFGSPreconditioners.hpp
8388
)
8489

90+
SET(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
91+
include/eigenpy/decompositions/decompositions.hpp
92+
include/eigenpy/decompositions/EigenSolver.hpp
93+
include/eigenpy/decompositions/LDLT.hpp
94+
include/eigenpy/decompositions/LLT.hpp
95+
include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp
96+
)
97+
8598
SET(${PROJECT_NAME}_HEADERS
99+
${${PROJECT_NAME}_UTILS_HEADERS}
86100
${${PROJECT_NAME}_SOLVERS_HEADERS}
101+
${${PROJECT_NAME}_DECOMPOSITIONS_HEADERS}
102+
include/eigenpy/computation-info.hpp
87103
include/eigenpy/eigenpy.hpp
88104
include/eigenpy/exception.hpp
89105
include/eigenpy/expose.hpp
@@ -115,8 +131,13 @@ SET(${PROJECT_NAME}_SOLVERS_SOURCES
115131
src/solvers/solvers.cpp
116132
)
117133

134+
SET(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
135+
src/decompositions/decompositions.cpp
136+
)
137+
118138
SET(${PROJECT_NAME}_SOURCES
119139
${${PROJECT_NAME}_SOLVERS_SOURCES}
140+
${${PROJECT_NAME}_DECOMPOSITIONS_SOURCES}
120141
src/exception.cpp
121142
src/eigenpy.cpp
122143
src/angle-axis.cpp
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decompositions_computation_info_hpp__
6+
#define __eigenpy_decompositions_computation_info_hpp__
7+
8+
#include <Eigen/Core>
9+
#include <boost/python.hpp>
10+
11+
#include "eigenpy/eigenpy_export.h"
12+
13+
namespace eigenpy
14+
{
15+
inline void EIGENPY_EXPORT exposeComputationInfo()
16+
{
17+
boost::python::enum_<Eigen::ComputationInfo>("ComputationInfo")
18+
.value("Success",Eigen::Success)
19+
.value("NumericalIssue",Eigen::NumericalIssue)
20+
.value("NoConvergence",Eigen::NoConvergence)
21+
.value("InvalidInput",Eigen::InvalidInput)
22+
;
23+
}
24+
} // namespace eigenpy
25+
26+
#endif // define __eigenpy_decompositions_computation_info_hpp__
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decomposition_eigen_solver_hpp__
6+
#define __eigenpy_decomposition_eigen_solver_hpp__
7+
8+
#include <boost/python.hpp>
9+
#include <Eigen/Core>
10+
#include <Eigen/Eigenvalues>
11+
12+
#include "eigenpy/utils/scalar-name.hpp"
13+
14+
namespace eigenpy
15+
{
16+
17+
template<typename _MatrixType>
18+
struct EigenSolverVisitor
19+
: public boost::python::def_visitor< EigenSolverVisitor<_MatrixType> >
20+
{
21+
22+
typedef _MatrixType MatrixType;
23+
typedef typename MatrixType::Scalar Scalar;
24+
typedef Eigen::EigenSolver<MatrixType> Solver;
25+
26+
template<class PyClass>
27+
void visit(PyClass& cl) const
28+
{
29+
namespace bp = boost::python;
30+
cl
31+
.def(bp::init<>("Default constructor"))
32+
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
33+
"Default constructor with memory preallocation"))
34+
.def(bp::init<MatrixType,bp::optional<bool> >(bp::args("matrix","compute_eigen_vectors"),
35+
"Computes eigendecomposition of given matrix"))
36+
37+
.def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
38+
"Returns the eigenvalues of given matrix.",
39+
bp::return_value_policy<bp::return_by_value>())
40+
.def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
41+
"Returns the eigenvectors of given matrix.",
42+
bp::return_value_policy<bp::return_by_value>())
43+
44+
.def("compute",&EigenSolverVisitor::compute_proxy<MatrixType>,
45+
bp::args("self","matrix"),
46+
"Computes the eigendecomposition of given matrix.",
47+
bp::return_value_policy<bp::reference_existing_object>())
48+
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, bool))&Solver::compute,
49+
bp::args("self","matrix","compute_eigen_vectors"),
50+
"Computes the eigendecomposition of given matrix.",
51+
bp::return_value_policy<bp::reference_existing_object>())
52+
53+
.def("getMaxIterations",&Solver::getMaxIterations,bp::arg("self"),
54+
"Returns the maximum number of iterations.")
55+
.def("setMaxIterations",&Solver::setMaxIterations,bp::args("self","max_iter"),
56+
"Sets the maximum number of iterations allowed.",
57+
bp::return_value_policy<bp::reference_existing_object>())
58+
59+
.def("pseudoEigenvalueMatrix",&Solver::pseudoEigenvalueMatrix,bp::arg("self"),
60+
"Returns the block-diagonal matrix in the pseudo-eigendecomposition.")
61+
.def("pseudoEigenvectors",&Solver::pseudoEigenvectors ,bp::arg("self"),
62+
"Returns the pseudo-eigenvectors of given matrix.",
63+
bp::return_value_policy<bp::return_by_value>())
64+
65+
.def("info",&Solver::info,bp::arg("self"),
66+
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
67+
;
68+
}
69+
70+
static void expose()
71+
{
72+
static const std::string classname = "EigenSolver" + scalar_name<Scalar>::shortname();
73+
expose(classname);
74+
}
75+
76+
static void expose(const std::string & name)
77+
{
78+
namespace bp = boost::python;
79+
bp::class_<Solver>(name.c_str(),
80+
bp::no_init)
81+
.def(EigenSolverVisitor());
82+
}
83+
84+
private:
85+
86+
template<typename MatrixType>
87+
static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
88+
{
89+
return self.compute(matrix);
90+
}
91+
92+
};
93+
94+
} // namespace eigenpy
95+
96+
#endif // ifndef __eigenpy_decomposition_eigen_solver_hpp__
97+
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decomposition_ldlt_hpp__
6+
#define __eigenpy_decomposition_ldlt_hpp__
7+
8+
#include <boost/python.hpp>
9+
#include <Eigen/Core>
10+
#include <Eigen/Cholesky>
11+
12+
#include "eigenpy/utils/scalar-name.hpp"
13+
14+
namespace eigenpy
15+
{
16+
17+
template<typename _MatrixType>
18+
struct LDLTSolverVisitor
19+
: public boost::python::def_visitor< LDLTSolverVisitor<_MatrixType> >
20+
{
21+
22+
typedef _MatrixType MatrixType;
23+
typedef typename MatrixType::Scalar Scalar;
24+
typedef typename MatrixType::RealScalar RealScalar;
25+
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1,MatrixType::Options> VectorType;
26+
typedef Eigen::LDLT<MatrixType> Solver;
27+
28+
template<class PyClass>
29+
void visit(PyClass& cl) const
30+
{
31+
namespace bp = boost::python;
32+
cl
33+
.def(bp::init<>("Default constructor"))
34+
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
35+
"Default constructor with memory preallocation"))
36+
.def(bp::init<MatrixType>(bp::arg("matrix"),
37+
"Constructs a LDLT factorization from a given matrix."))
38+
39+
.def("isNegative",&Solver::isNegative,bp::arg("self"),
40+
"Returns true if the matrix is negative (semidefinite).")
41+
.def("isPositive",&Solver::isPositive,bp::arg("self"),
42+
"Returns true if the matrix is positive (semidefinite).")
43+
44+
.def("matrixL",&matrixL,bp::arg("self"),
45+
"Returns the lower triangular matrix L.")
46+
.def("matrixU",&matrixU,bp::arg("self"),
47+
"Returns the upper triangular matrix U.")
48+
.def("vectorD",&vectorD,bp::arg("self"),
49+
"Returns the coefficients of the diagonal matrix D.")
50+
.def("transpositionsP",&transpositionsP,bp::arg("self"),
51+
"Returns the permutation matrix P.")
52+
53+
.def("matrixLDLT",&Solver::matrixLDLT,bp::arg("self"),
54+
"Returns the LDLT decomposition matrix.",
55+
bp::return_value_policy<bp::return_by_value>())
56+
57+
.def("rankUpdate",(Solver & (Solver::*)(const Eigen::MatrixBase<VectorType> &, const RealScalar &))&Solver::template rankUpdate<VectorType>,
58+
bp::args("self","vector","sigma"),
59+
bp::return_value_policy<bp::reference_existing_object>() )
60+
61+
#if EIGEN_VERSION_AT_LEAST(3,3,0)
62+
.def("adjoint",&Solver::adjoint,bp::arg("self"),
63+
"Returns the adjoint, that is, a reference to the decomposition itself as if the underlying matrix is self-adjoint.",
64+
bp::return_value_policy<bp::reference_existing_object>())
65+
#endif
66+
67+
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix))&Solver::compute,
68+
bp::args("self","matrix"),
69+
"Computes the LDLT of given matrix.",
70+
bp::return_value_policy<bp::reference_existing_object>())
71+
72+
.def("info",&Solver::info,bp::arg("self"),
73+
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
74+
#if EIGEN_VERSION_AT_LEAST(3,3,0)
75+
.def("rcond",&Solver::rcond,bp::arg("self"),
76+
"Returns an estimate of the reciprocal condition number of the matrix.")
77+
#endif
78+
.def("reconstructedMatrix",&Solver::reconstructedMatrix,bp::arg("self"),
79+
"Returns the matrix represented by the decomposition, i.e., it returns the product: L L^*. This function is provided for debug purpose.")
80+
.def("solve",&solve<VectorType>,bp::args("self","b"),
81+
"Returns the solution x of A x = b using the current decomposition of A.")
82+
83+
.def("setZero",&Solver::setZero,bp::arg("self"),
84+
"Clear any existing decomposition.")
85+
;
86+
}
87+
88+
static void expose()
89+
{
90+
static const std::string classname = "LDLT" + scalar_name<Scalar>::shortname();
91+
expose(classname);
92+
}
93+
94+
static void expose(const std::string & name)
95+
{
96+
namespace bp = boost::python;
97+
bp::class_<Solver>(name.c_str(),
98+
"Robust Cholesky decomposition of a matrix with pivoting.\n\n"
99+
"Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite matrix $ A $ such that $ A = P^TLDL^*P $, where P is a permutation matrix, L is lower triangular with a unit diagonal and D is a diagonal matrix.\n\n"
100+
"The decomposition uses pivoting to ensure stability, so that L will have zeros in the bottom right rank(A) - n submatrix. Avoiding the square root on D also stabilizes the computation.",
101+
bp::no_init)
102+
.def(LDLTSolverVisitor());
103+
}
104+
105+
private:
106+
107+
static MatrixType matrixL(const Solver & self) { return self.matrixL(); }
108+
static MatrixType matrixU(const Solver & self) { return self.matrixU(); }
109+
static VectorType vectorD(const Solver & self) { return self.vectorD(); }
110+
111+
static MatrixType transpositionsP(const Solver & self)
112+
{
113+
return self.transpositionsP() * MatrixType::Identity(self.matrixL().rows(),
114+
self.matrixL().rows());
115+
}
116+
117+
template<typename VectorType>
118+
static VectorType solve(const Solver & self, const VectorType & vec)
119+
{
120+
return self.solve(vec);
121+
}
122+
};
123+
124+
} // namespace eigenpy
125+
126+
#endif // ifndef __eigenpy_decomposition_ldlt_hpp__

0 commit comments

Comments
 (0)