Skip to content

Commit 6aec3f5

Browse files
committed
eigenvalues: GeneralizedEigenSolver
1 parent b621dc3 commit 6aec3f5

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
236236
${${PROJECT_NAME}_DECOMPOSITIONS_SPARSE_HEADERS}
237237
include/eigenpy/decompositions/decompositions.hpp
238238
include/eigenpy/decompositions/EigenSolver.hpp
239+
include/eigenpy/decompositions/GeneralizedEigenSolver.hpp
239240
include/eigenpy/decompositions/ComplexEigenSolver.hpp
240241
include/eigenpy/decompositions/ComplexSchur.hpp
241242
include/eigenpy/decompositions/PermutationMatrix.hpp
@@ -320,6 +321,7 @@ set(${PROJECT_NAME}_SOLVERS_SOURCES src/solvers/preconditioners.cpp
320321
set(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
321322
src/decompositions/decompositions.cpp
322323
src/decompositions/eigen-solver.cpp
324+
src/decompositions/generalized-eigen-solver.cpp
323325
src/decompositions/complex-eigen-solver.cpp
324326
src/decompositions/complex-schur.cpp
325327
src/decompositions/llt-solver.cpp
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decompositions_generalized_eigen_solver_hpp__
6+
#define __eigenpy_decompositions_generalized_eigen_solver_hpp__
7+
8+
#include <Eigen/Core>
9+
#include <Eigen/Eigenvalues>
10+
11+
#include "eigenpy/eigen-to-python.hpp"
12+
#include "eigenpy/eigenpy.hpp"
13+
#include "eigenpy/utils/scalar-name.hpp"
14+
15+
namespace eigenpy {
16+
17+
template <typename _MatrixType>
18+
struct GeneralizedEigenSolverVisitor
19+
: public boost::python::def_visitor<GeneralizedEigenSolverVisitor<_MatrixType>> {
20+
typedef _MatrixType MatrixType;
21+
typedef typename MatrixType::Scalar Scalar;
22+
typedef Eigen::GeneralizedEigenSolver<MatrixType> Solver;
23+
24+
template <class PyClass>
25+
void visit(PyClass& cl) const {
26+
cl.def(bp::init<>("Default constructor"))
27+
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
28+
"Default constructor with memory preallocation. "))
29+
.def(bp::init<MatrixType, MatrixType, bp::optional<bool>>(
30+
bp::args("A", "B", "computeEigenVectors"),
31+
"Computes Schur of given matrix"))
32+
33+
.def("alphas", &Solver::alphas, bp::arg("self"),
34+
"Returns the vectors containing the alpha values ")
35+
.def("betas", &Solver::betas, bp::arg("self"),
36+
"Returns the vectors containing the beta values ")
37+
38+
.def("compute", &GeneralizedEigenSolverVisitor::compute_proxy<MatrixType>,
39+
bp::args("self", "A", "B"), "Computes the Schur of given matrix.",
40+
bp::return_self<>())
41+
.def("compute",
42+
(Solver &
43+
(Solver::*)(const MatrixType& A, const MatrixType& B, bool)) &
44+
Solver::compute,
45+
bp::args("self", "A", "B", "computeEigenvectors"),
46+
"Computes generalized eigendecomposition of given matrix. .", bp::return_self<>())
47+
48+
// .def("eigenvalues", &Solver::eigenvalues, bp::arg("self"),
49+
// "Returns an expression of the computed generalized eigenvalues. ")
50+
// .def("eigenvectors", &Solver::eigenvectors, bp::arg("self"),
51+
// "Returns an expression of the computed generalized eigenvectors. ")
52+
53+
.def("info", &Solver::info, bp::arg("self"),
54+
"NumericalIssue if the input contains INF or NaN values or "
55+
"overflow occured. Returns Success otherwise.")
56+
57+
.def("setMaxIterations", &Solver::setMaxIterations,
58+
bp::args("self", "max_iter"),
59+
"Sets the maximum number of iterations allowed.",
60+
bp::return_self<>())
61+
;
62+
}
63+
64+
static void expose() {
65+
static const std::string classname =
66+
"GeneralizedEigenSolver" + scalar_name<Scalar>::shortname();
67+
expose(classname);
68+
}
69+
70+
static void expose(const std::string& name) {
71+
bp::class_<Solver>(name.c_str(), bp::no_init)
72+
.def(GeneralizedEigenSolverVisitor())
73+
.def(IdVisitor<Solver>());
74+
}
75+
76+
private:
77+
template <typename MatrixType>
78+
static Solver& compute_proxy(Solver& self, const MatrixType& A, const MatrixType& B) {
79+
return self.compute(A, B);
80+
}
81+
};
82+
83+
} // namespace eigenpy
84+
85+
#endif // ifndef __eigenpy_decompositions_generalized_eigen_solver_hpp__

src/decompositions/decompositions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace eigenpy {
1010

1111
void exposeEigenSolver();
12+
void exposeGeneralizedEigenSolver();
1213
void exposeComplexEigenSolver();
1314
void exposeComplexSchur();
1415
void exposeSelfAdjointEigenSolver();
@@ -30,6 +31,7 @@ void exposeDecompositions() {
3031
using namespace Eigen;
3132

3233
exposeEigenSolver();
34+
exposeGeneralizedEigenSolver();
3335
exposeComplexEigenSolver();
3436
exposeComplexSchur();
3537
exposeSelfAdjointEigenSolver();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
/*
3+
* Copyright 2024 INRIA
4+
*/
5+
6+
#include "eigenpy/decompositions/GeneralizedEigenSolver.hpp"
7+
8+
namespace eigenpy {
9+
void exposeGeneralizedEigenSolver() {
10+
using namespace Eigen;
11+
GeneralizedEigenSolverVisitor<MatrixXd>::expose("GeneralizedEigenSolver");
12+
}
13+
} // namespace eigenpy

unittest/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ add_python_eigenpy_lib_unit_test("py-version" "unittest/python/test_version.py")
137137
add_python_eigenpy_lib_unit_test("py-eigen-solver"
138138
"unittest/python/test_eigen_solver.py")
139139

140+
add_python_eigenpy_lib_unit_test(
141+
"py-generalized-eigen-solver"
142+
"unittest/python/test_generalized-eigen_solver.py")
143+
140144
add_python_eigenpy_lib_unit_test("py-complex-eigen-solver"
141145
"unittest/python/test_complex_eigen_solver.py")
142146

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import numpy as np
2+
3+
import eigenpy
4+
5+
dim = 100
6+
rng = np.random.default_rng()
7+
A = rng.random((dim, dim))
8+
B = rng.random((dim, dim))
9+
10+
ges = eigenpy.GeneralizedEigenSolver(A, B)
11+
12+
alphas = ges.alphas()
13+
betas = ges.betas()
14+
V = ges.eigenvectors()
15+
16+
eigenvalues = alphas / betas
17+
for i in range(dim):
18+
v = V[:, i]
19+
lam = eigenvalues[i]
20+
21+
Av = A @ v
22+
lam_Bv = lam * (B @ v)
23+
24+
assert eigenpy.is_approx(Av.real, lam_Bv.real)
25+
assert eigenpy.is_approx(Av.imag, lam_Bv.imag)

0 commit comments

Comments
 (0)