Skip to content

Linear algebra: Expose the remaining classes listed in Eigen documentation (decompositions and solvers) #571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 40 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9d7a86f
decompositions: Expose classes
Lucas-Haubert Jul 1, 2025
8b90832
readme: added lucas haubert
Lucas-Haubert Jul 2, 2025
c40e851
decompositions: SVDBase, BDCSVD, JacobiSVD
Lucas-Haubert Jul 3, 2025
ed21792
eigenvalues: Expose classes
Lucas-Haubert Jul 3, 2025
16ce327
solvers: BiCGSTAB
Lucas-Haubert Jul 4, 2025
9b9f045
unittest: Comments about permutationP and permutationQ in FullPivLU
Lucas-Haubert Jul 6, 2025
36c7dc7
unittest: PartialPivLU reconstructedMatrix to retrieve the original m…
Lucas-Haubert Jul 6, 2025
e554c92
Added comments and setThreshold default option in SVDBase
Lucas-Haubert Jul 7, 2025
d03cbad
solvers: Completed tests
Lucas-Haubert Jul 7, 2025
6e9e972
decompositions: comments and rewrites
Lucas-Haubert Jul 7, 2025
57773d3
decompositions: Put ordering option AMD in SparseQR
Lucas-Haubert Jul 7, 2025
116f2d8
decompositions: Fixed computation options in BDCSVD
Lucas-Haubert Jul 7, 2025
18ef377
decompositions: Rewrite comments in constructors in BDCSVD and JacobiSVD
Lucas-Haubert Jul 7, 2025
e206461
Set COLAMD Ordering in SParseQR
Lucas-Haubert Jul 20, 2025
e1cb1e9
decompositions: Completed tests
Lucas-Haubert Jul 20, 2025
f105185
Add IncompleteCholesky and IncompleteLUT
Lucas-Haubert Jul 20, 2025
13ebd36
Added all preconditioners in solvers
Lucas-Haubert Jul 20, 2025
04a9ba6
Clean code: Set the same nomenclature of files for exposed classes an…
Lucas-Haubert Jul 20, 2025
8ac770c
Set Eigen::Lower everywhere for UpLo template option
Lucas-Haubert Jul 20, 2025
8646127
Switch MINRES, IncompleteLUT and IncompleteCholesky in eigenpy.solver…
Lucas-Haubert Jul 20, 2025
4be9e81
Optional arguments with bp::optional
Lucas-Haubert Jul 20, 2025
62daa7c
README: Remove the 'SVD and QR to be added', but enounce them
Lucas-Haubert Jul 20, 2025
bede0bf
CI: Fix test_JacobiSVD
Lucas-Haubert Jul 21, 2025
4996734
is_approx: Put is_approx and set the precision
Lucas-Haubert Jul 21, 2025
f401316
Add const in some lambda functions on Solver& to stick to definition
Lucas-Haubert Jul 22, 2025
167045a
Add matrixQ in SparseQR
Lucas-Haubert Jul 23, 2025
de37894
Add actual date in copyrights
Lucas-Haubert Jul 23, 2025
edc5dcb
Add methods matrixU and matrixL in SParseLU
Lucas-Haubert Jul 23, 2025
0098cdb
Capital letters in header names in sparse decompositions
Lucas-Haubert Jul 23, 2025
4c347f8
CMakeLists: Added FullPivLU and PartialPivLU headers
Lucas-Haubert Jul 24, 2025
8fbf5be
Removed outpassed guards regarding eigen version in decompositions an…
Lucas-Haubert Jul 24, 2025
d102a88
Include guards: Set name that corresopnds to directory
Lucas-Haubert Jul 24, 2025
5ddd754
Include guards: Updated date in copyright
Lucas-Haubert Jul 24, 2025
fd712e4
MINRES: Backward compatibility to call from eigenpy and eigenpy.solvers
Lucas-Haubert Jul 24, 2025
029c81f
Split solvers.cpp into separated .cpp as in decompositions
Lucas-Haubert Jul 24, 2025
25ffb23
fwd:hpp: Corrected definition of macro EIGENPY_PRAGMA_DEPRECATED_HEAD…
Lucas-Haubert Jul 24, 2025
681bfc5
Add back compatibility headers due to changes in name and directory o…
Lucas-Haubert Jul 24, 2025
8cca598
unittest: Simplify test_GeneralizedEigenSolver to reduce computation …
Lucas-Haubert Jul 24, 2025
db47b32
Back compatibility accelerate.hpp
Lucas-Haubert Jul 24, 2025
89a07eb
unittest: Reduced computation time of tests
Lucas-Haubert Jul 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,14 @@ set(${PROJECT_NAME}_SOLVERS_HEADERS
include/eigenpy/solvers/preconditioners.hpp
include/eigenpy/solvers/IterativeSolverBase.hpp
include/eigenpy/solvers/LeastSquaresConjugateGradient.hpp
include/eigenpy/solvers/BiCGSTAB.hpp
include/eigenpy/solvers/MINRES.hpp
include/eigenpy/solvers/ConjugateGradient.hpp
include/eigenpy/solvers/SparseSolverBase.hpp
include/eigenpy/solvers/BasicPreconditioners.hpp
include/eigenpy/solvers/BFGSPreconditioners.hpp)
include/eigenpy/solvers/BFGSPreconditioners.hpp
include/eigenpy/solvers/IncompleteCholesky.hpp
include/eigenpy/solvers/IncompleteLUT.hpp)

set(${PROJECT_NAME}_EIGEN_HEADERS include/eigenpy/eigen/EigenBase.hpp)

Expand All @@ -205,13 +209,18 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_CHOLMOD_HEADERS
include/eigenpy/decompositions/sparse/cholmod/CholmodSupernodalLLT.hpp)

set(${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_ACCELERATE_HEADERS
include/eigenpy/decompositions/sparse/accelerate/Accelerate.hpp
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
include/eigenpy/decompositions/sparse/SimplicialLLT.hpp
include/eigenpy/decompositions/sparse/SimplicialLDLT.hpp
include/eigenpy/decompositions/sparse/SparseLU.hpp
include/eigenpy/decompositions/sparse/SparseQR.hpp
include/eigenpy/decompositions/sparse/SimplicialCholesky.hpp
include/eigenpy/decompositions/sparse/SparseSolverBase.hpp)
include/eigenpy/decompositions/sparse/SparseSolverBase.hpp
include/eigenpy/decompositions/sparse/LDLT.hpp
include/eigenpy/decompositions/sparse/LLT.hpp)

if(BUILD_WITH_CHOLMOD_SUPPORT)
list(APPEND ${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS
Expand All @@ -227,6 +236,16 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
${${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS}
include/eigenpy/decompositions/decompositions.hpp
include/eigenpy/decompositions/EigenSolver.hpp
include/eigenpy/decompositions/GeneralizedEigenSolver.hpp
include/eigenpy/decompositions/GeneralizedSelfAdjointEigenSolver.hpp
include/eigenpy/decompositions/HessenbergDecomposition.hpp
include/eigenpy/decompositions/RealQZ.hpp
include/eigenpy/decompositions/Tridiagonalization.hpp
include/eigenpy/decompositions/RealSchur.hpp
include/eigenpy/decompositions/ComplexEigenSolver.hpp
include/eigenpy/decompositions/ComplexSchur.hpp
include/eigenpy/decompositions/FullPivLU.hpp
include/eigenpy/decompositions/PartialPivLU.hpp
include/eigenpy/decompositions/PermutationMatrix.hpp
include/eigenpy/decompositions/LDLT.hpp
include/eigenpy/decompositions/LLT.hpp
Expand All @@ -236,6 +255,9 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
include/eigenpy/decompositions/CompleteOrthogonalDecomposition.hpp
include/eigenpy/decompositions/FullPivHouseholderQR.hpp
include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp
include/eigenpy/decompositions/SVDBase.hpp
include/eigenpy/decompositions/BDCSVD.hpp
include/eigenpy/decompositions/JacobiSVD.hpp
include/eigenpy/decompositions/minres.hpp)

set(${PROJECT_NAME}_HEADERS
Expand Down Expand Up @@ -300,17 +322,36 @@ list(
# ----------------------------------------------------
# --- TARGETS ----------------------------------------
# ----------------------------------------------------
set(${PROJECT_NAME}_SOLVERS_SOURCES src/solvers/preconditioners.cpp
src/solvers/solvers.cpp)
set(${PROJECT_NAME}_SOLVERS_SOURCES
src/solvers/preconditioners.cpp
src/solvers/solvers.cpp
src/solvers/minres.cpp
src/solvers/bicgstab.cpp
src/solvers/conjugate-gradient.cpp
src/solvers/least-squares-conjugate-gradient.cpp
src/solvers/incomplete-cholesky.cpp
src/solvers/incomplete-lut.cpp)

set(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
src/decompositions/decompositions.cpp
src/decompositions/eigen-solver.cpp
src/decompositions/generalized-eigen-solver.cpp
src/decompositions/generalized-self-adjoint-eigen-solver.cpp
src/decompositions/complex-eigen-solver.cpp
src/decompositions/complex-schur.cpp
src/decompositions/llt-solver.cpp
src/decompositions/ldlt-solver.cpp
src/decompositions/minres-solver.cpp
src/decompositions/bdcsvd-solver.cpp
src/decompositions/jacobisvd-solver.cpp
src/decompositions/fullpivlu-solver.cpp
src/decompositions/hessenberg-decomposition.cpp
src/decompositions/real-qz.cpp
src/decompositions/tridiagonalization.cpp
src/decompositions/real-schur.cpp
src/decompositions/partialpivlu-solver.cpp
src/decompositions/sparse-lu-solver.cpp
src/decompositions/sparse-qr-solver.cpp
src/decompositions/qr-solvers.cpp
src/decompositions/eigen-solver.cpp
src/decompositions/self-adjoint-eigen-solver.cpp
src/decompositions/permutation-matrix.cpp
src/decompositions/simplicial-llt-solver.cpp
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ EigenPy — Versatile and efficient Python bindings between Numpy and Eigen
- full support Eigen::Ref avoiding memory allocation
- full support of the Eigen::Tensor module
- exposition of the Geometry module of Eigen for easy code prototyping
- standard matrix decomposion routines of Eigen such as the Cholesky decomposition (SVD and QR decompositions [can be added](#contributing))
- standard matrix decomposion routines of Eigen such as the Cholesky, SVD and QR decompositions
- full support of SWIG objects
- full support of runtime declaration of Numpy scalar types
- extended API to expose several STL types and some of their Boost equivalents: `optional` types, `std::pair`, maps, variants...
Expand Down Expand Up @@ -94,6 +94,7 @@ The following people have been involved in the development of **EigenPy**:
- [Loïc Estève](https://github.com/lesteve) (Inria): Conda integration
- [Wilson Jallet](https://manifoldfr.github.io/) (Inria/LAAS-CNRS): core developer
- [Joris Vaillant](https://github.com/jorisv) (Inria): core developer and manager of the project
- [Lucas Haubert](https://www.linkedin.com/in/lucas-haubert-b668a421a/) (Inria): core developer

If you have taken part in the development of **EigenPy**, feel free to add your name and contribution here.

Expand Down
2 changes: 1 addition & 1 deletion cmake
99 changes: 99 additions & 0 deletions include/eigenpy/decompositions/BDCSVD.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2025 INRIA
*/

#ifndef __eigenpy_decompositions_bdcsvd_hpp__
#define __eigenpy_decompositions_bdcsvd_hpp__

#include <Eigen/SVD>
#include <Eigen/Core>

#include "eigenpy/eigenpy.hpp"
#include "eigenpy/utils/scalar-name.hpp"
#include "eigenpy/eigen/EigenBase.hpp"
#include "eigenpy/decompositions/SVDBase.hpp"

namespace eigenpy {

template <typename _MatrixType>
struct BDCSVDVisitor
: public boost::python::def_visitor<BDCSVDVisitor<_MatrixType>> {
typedef _MatrixType MatrixType;
typedef Eigen::BDCSVD<MatrixType> Solver;
typedef typename MatrixType::Scalar Scalar;

template <class PyClass>
void visit(PyClass &cl) const {
cl.def(bp::init<>(bp::arg("self"), "Default constructor"))
.def(bp::init<Eigen::DenseIndex, Eigen::DenseIndex,
bp::optional<unsigned int>>(
bp::args("self", "rows", "cols", "computationOptions "),
"Default Constructor with memory preallocation. "))
.def(bp::init<MatrixType, bp::optional<unsigned int>>(
bp::args("self", "matrix", "computationOptions "),
"Constructor performing the decomposition of given matrix."))

.def("cols", &Solver::cols, bp::arg("self"),
"Returns the number of columns. ")
.def("compute",
(Solver & (Solver::*)(const MatrixType &matrix)) & Solver::compute,
bp::args("self", "matrix"),
"Method performing the decomposition of given matrix. Computes "
"Thin/Full "
"unitaries U/V if specified using the Options template parameter "
"or the class constructor. ",
bp::return_self<>())
.def("compute",
(Solver & (Solver::*)(const MatrixType &matrix,
unsigned int computationOptions)) &
Solver::compute,
bp::args("self", "matrix", "computationOptions"),
"Method performing the decomposition of given matrix, as "
"specified by the computationOptions parameter. ",
bp::return_self<>())
.def("rows", &Solver::rows, bp::arg("self"),
"Returns the number of rows. ")
.def("setSwitchSize", &Solver::setSwitchSize, bp::args("self", "s"))

.def(SVDBaseVisitor<Solver>());
}

static void expose() {
static const std::string classname =
"BDCSVD_" + scalar_name<Scalar>::shortname();
expose(classname);
}

static void expose(const std::string &name) {
bp::class_<Solver, boost::noncopyable>(
name.c_str(),
"Class Bidiagonal Divide and Conquer SVD.\n\n"
"This class first reduces the input matrix to bi-diagonal form using "
"class "
"UpperBidiagonalization, and then performs a divide-and-conquer "
"diagonalization. "
"Small blocks are diagonalized using class JacobiSVD. You can control "
"the "
"switching size with the setSwitchSize() method, default is 16. For "
"small matrice "
"(<16), it is thus preferable to directly use JacobiSVD. For larger "
"ones, BDCSVD "
"is highly recommended and can several order of magnitude faster.\n\n"
"Warming: this algorithm is unlikely to provide accurate result when "
"compiled with "
"unsafe math optimizations. For instance, this concerns Intel's "
"compiler (ICC), which "
"performs such optimization by default unless you compile with the "
"-fp-model precise "
"option. Likewise, the -ffast-math option of GCC or clang will "
"significantly degrade the "
"accuracy.",
bp::no_init)
.def(BDCSVDVisitor())
.def(IdVisitor<Solver>());
}
};

} // namespace eigenpy

#endif // ifndef __eigenpy_decompositions_bdcsvd_hpp__
86 changes: 86 additions & 0 deletions include/eigenpy/decompositions/ComplexEigenSolver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2025 INRIA
*/

#ifndef __eigenpy_decompositions_complex_eigen_solver_hpp__
#define __eigenpy_decompositions_complex_eigen_solver_hpp__

#include <Eigen/Core>
#include <Eigen/Eigenvalues>

#include "eigenpy/eigen-to-python.hpp"
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/utils/scalar-name.hpp"

namespace eigenpy {

template <typename _MatrixType>
struct ComplexEigenSolverVisitor : public boost::python::def_visitor<
ComplexEigenSolverVisitor<_MatrixType>> {
typedef _MatrixType MatrixType;
typedef typename MatrixType::Scalar Scalar;
typedef Eigen::ComplexEigenSolver<MatrixType> Solver;

template <class PyClass>
void visit(PyClass& cl) const {
cl.def(bp::init<>("Default constructor"))
.def(bp::init<Eigen::DenseIndex>(
bp::arg("size"), "Default constructor with memory preallocation"))
.def(bp::init<MatrixType, bp::optional<bool>>(
bp::args("matrix", "compute_eigen_vectors"),
"Computes eigendecomposition of given matrix"))

.def("eigenvalues", &Solver::eigenvalues, bp::arg("self"),
"Returns the eigenvalues of given matrix.",
bp::return_internal_reference<>())
.def("eigenvectors", &Solver::eigenvectors, bp::arg("self"),
"Returns the eigenvectors of given matrix.",
bp::return_internal_reference<>())

.def("compute", &ComplexEigenSolverVisitor::compute_proxy<MatrixType>,
bp::args("self", "matrix"),
"Computes the eigendecomposition of given matrix.",
bp::return_self<>())
.def("compute",
(Solver &
(Solver::*)(const Eigen::EigenBase<MatrixType>& matrix, bool)) &
Solver::compute,
bp::args("self", "matrix", "compute_eigen_vectors"),
"Computes the eigendecomposition of given matrix.",
bp::return_self<>())

.def("info", &Solver::info, bp::arg("self"),
"NumericalIssue if the input contains INF or NaN values or "
"overflow occured. Returns Success otherwise.")

.def("getMaxIterations", &Solver::getMaxIterations, bp::arg("self"),
"Returns the maximum number of iterations.")
.def("setMaxIterations", &Solver::setMaxIterations,
bp::args("self", "max_iter"),
"Sets the maximum number of iterations allowed.",
bp::return_self<>());
}

static void expose() {
static const std::string classname =
"ComplexEigenSolver" + scalar_name<Scalar>::shortname();
expose(classname);
}

static void expose(const std::string& name) {
bp::class_<Solver>(name.c_str(), bp::no_init)
.def(ComplexEigenSolverVisitor())
.def(IdVisitor<Solver>());
}

private:
template <typename MatrixType>
static Solver& compute_proxy(Solver& self,
const Eigen::EigenBase<MatrixType>& matrix) {
return self.compute(matrix);
}
};

} // namespace eigenpy

#endif // ifndef __eigenpy_decompositions_complex_eigen_solver_hpp__
Loading