Skip to content

Commit 9c69e0f

Browse files
committed
eigenvalues: GeneralizedSelfAdjointSolver
1 parent 6aec3f5 commit 9c69e0f

File tree

8 files changed

+137
-20
lines changed

8 files changed

+137
-20
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
237237
include/eigenpy/decompositions/decompositions.hpp
238238
include/eigenpy/decompositions/EigenSolver.hpp
239239
include/eigenpy/decompositions/GeneralizedEigenSolver.hpp
240+
include/eigenpy/decompositions/GeneralizedSelfAdjointEigenSolver.hpp
240241
include/eigenpy/decompositions/ComplexEigenSolver.hpp
241242
include/eigenpy/decompositions/ComplexSchur.hpp
242243
include/eigenpy/decompositions/PermutationMatrix.hpp
@@ -322,6 +323,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
322323
src/decompositions/decompositions.cpp
323324
src/decompositions/eigen-solver.cpp
324325
src/decompositions/generalized-eigen-solver.cpp
326+
src/decompositions/generalized-self-adjoint-eigen-solver.cpp
325327
src/decompositions/complex-eigen-solver.cpp
326328
src/decompositions/complex-schur.cpp
327329
src/decompositions/llt-solver.cpp

include/eigenpy/decompositions/GeneralizedEigenSolver.hpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,42 @@ namespace eigenpy {
1616

1717
template <typename _MatrixType>
1818
struct GeneralizedEigenSolverVisitor
19-
: public boost::python::def_visitor<GeneralizedEigenSolverVisitor<_MatrixType>> {
19+
: public boost::python::def_visitor<
20+
GeneralizedEigenSolverVisitor<_MatrixType>> {
2021
typedef _MatrixType MatrixType;
2122
typedef typename MatrixType::Scalar Scalar;
2223
typedef Eigen::GeneralizedEigenSolver<MatrixType> Solver;
2324

2425
template <class PyClass>
2526
void visit(PyClass& cl) const {
2627
cl.def(bp::init<>("Default constructor"))
27-
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
28-
"Default constructor with memory preallocation. "))
28+
.def(bp::init<Eigen::DenseIndex>(
29+
bp::arg("size"), "Default constructor with memory preallocation. "))
2930
.def(bp::init<MatrixType, MatrixType, bp::optional<bool>>(
30-
bp::args("A", "B", "computeEigenVectors"),
31-
"Computes Schur of given matrix"))
31+
bp::args("A", "B", "computeEigenVectors"),
32+
"Computes the generalized eigendecomposition of given matrix "
33+
"pair. "))
3234

3335
.def("alphas", &Solver::alphas, bp::arg("self"),
3436
"Returns the vectors containing the alpha values ")
3537
.def("betas", &Solver::betas, bp::arg("self"),
3638
"Returns the vectors containing the beta values ")
3739

38-
.def("compute", &GeneralizedEigenSolverVisitor::compute_proxy<MatrixType>,
39-
bp::args("self", "A", "B"), "Computes the Schur of given matrix.",
40+
.def("compute",
41+
&GeneralizedEigenSolverVisitor::compute_proxy<MatrixType>,
42+
bp::args("self", "A", "B"),
43+
"Computes generalized eigendecomposition of given matrix. ",
4044
bp::return_self<>())
4145
.def("compute",
4246
(Solver &
4347
(Solver::*)(const MatrixType& A, const MatrixType& B, bool)) &
4448
Solver::compute,
4549
bp::args("self", "A", "B", "computeEigenvectors"),
46-
"Computes generalized eigendecomposition of given matrix. .", bp::return_self<>())
50+
"Computes generalized eigendecomposition of given matrix. .",
51+
bp::return_self<>())
4752

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. ")
53+
.def("eigenvectors", &Solver::eigenvectors, bp::arg("self"),
54+
"Returns an expression of the computed generalized eigenvectors. ")
5255

5356
.def("info", &Solver::info, bp::arg("self"),
5457
"NumericalIssue if the input contains INF or NaN values or "
@@ -57,8 +60,7 @@ struct GeneralizedEigenSolverVisitor
5760
.def("setMaxIterations", &Solver::setMaxIterations,
5861
bp::args("self", "max_iter"),
5962
"Sets the maximum number of iterations allowed.",
60-
bp::return_self<>())
61-
;
63+
bp::return_self<>());
6264
}
6365

6466
static void expose() {
@@ -75,7 +77,8 @@ struct GeneralizedEigenSolverVisitor
7577

7678
private:
7779
template <typename MatrixType>
78-
static Solver& compute_proxy(Solver& self, const MatrixType& A, const MatrixType& B) {
80+
static Solver& compute_proxy(Solver& self, const MatrixType& A,
81+
const MatrixType& B) {
7982
return self.compute(A, B);
8083
}
8184
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decompositions_generalized_self_adjoint_eigen_solver_hpp__
6+
#define __eigenpy_decompositions_generalized_self_adjoint_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+
#include "eigenpy/decompositions/SelfAdjointEigenSolver.hpp"
15+
16+
namespace eigenpy {
17+
18+
template <typename _MatrixType>
19+
struct GeneralizedSelfAdjointEigenSolverVisitor
20+
: public boost::python::def_visitor<GeneralizedSelfAdjointEigenSolverVisitor<_MatrixType>> {
21+
typedef _MatrixType MatrixType;
22+
typedef typename MatrixType::Scalar Scalar;
23+
typedef Eigen::GeneralizedSelfAdjointEigenSolver<MatrixType> Solver;
24+
25+
template <class PyClass>
26+
void visit(PyClass& cl) const {
27+
cl.def(bp::init<>("Default constructor"))
28+
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
29+
"Default constructor with memory preallocation. "))
30+
.def(bp::init<MatrixType, MatrixType, bp::optional<int>>(
31+
bp::args("matA", "matB", "options"),
32+
"Constructor: Computes generalized eigendecomposition of given matrix pencil. "))
33+
34+
.def("compute", &GeneralizedSelfAdjointEigenSolverVisitor::compute_proxy<MatrixType>,
35+
bp::args("self", "A", "B"),
36+
"Computes generalized eigendecomposition of given matrix pencil. ",
37+
bp::return_self<>())
38+
.def("compute",
39+
(Solver &
40+
(Solver::*)(const MatrixType& A, const MatrixType& B, int)) &
41+
Solver::compute,
42+
bp::args("self", "A", "B", "options"),
43+
"Computes generalized eigendecomposition of given matrix pencil.", bp::return_self<>());
44+
}
45+
46+
static void expose() {
47+
static const std::string classname =
48+
"GeneralizedSelfAdjointEigenSolver" + scalar_name<Scalar>::shortname();
49+
expose(classname);
50+
}
51+
52+
static void expose(const std::string& name) {
53+
bp::class_<Solver, bp::bases<Eigen::SelfAdjointEigenSolver<MatrixType>>>(name.c_str(), bp::no_init)
54+
.def(GeneralizedSelfAdjointEigenSolverVisitor())
55+
.def(IdVisitor<Solver>());
56+
}
57+
58+
private:
59+
template <typename MatrixType>
60+
static Solver& compute_proxy(Solver& self, const MatrixType& A, const MatrixType& B) {
61+
return self.compute(A, B);
62+
}
63+
};
64+
65+
} // namespace eigenpy
66+
67+
#endif // ifndef __eigenpy_decompositions_generalized_self_adjoint_eigen_solver_hpp__

src/decompositions/decompositions.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ namespace eigenpy {
1010

1111
void exposeEigenSolver();
1212
void exposeGeneralizedEigenSolver();
13+
void exposeSelfAdjointEigenSolver();
14+
void exposeGeneralizedSelfAdjointEigenSolver();
1315
void exposeComplexEigenSolver();
1416
void exposeComplexSchur();
15-
void exposeSelfAdjointEigenSolver();
1617
void exposeLLTSolver();
1718
void exposeLDLTSolver();
1819
void exposeFullPivLUSolver();
@@ -32,9 +33,10 @@ void exposeDecompositions() {
3233

3334
exposeEigenSolver();
3435
exposeGeneralizedEigenSolver();
36+
exposeSelfAdjointEigenSolver();
37+
exposeGeneralizedSelfAdjointEigenSolver();
3538
exposeComplexEigenSolver();
3639
exposeComplexSchur();
37-
exposeSelfAdjointEigenSolver();
3840
exposeLLTSolver();
3941
exposeLDLTSolver();
4042
exposeFullPivLUSolver();
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/GeneralizedSelfAdjointEigenSolver.hpp"
7+
8+
namespace eigenpy {
9+
void exposeGeneralizedSelfAdjointEigenSolver() {
10+
using namespace Eigen;
11+
GeneralizedSelfAdjointEigenSolverVisitor<MatrixXd>::expose("GeneralizedSelfAdjointEigenSolver");
12+
}
13+
} // namespace eigenpy

unittest/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ add_python_eigenpy_lib_unit_test("py-eigen-solver"
139139

140140
add_python_eigenpy_lib_unit_test(
141141
"py-generalized-eigen-solver"
142-
"unittest/python/test_generalized-eigen_solver.py")
142+
"unittest/python/test_generalized_eigen_solver.py")
143+
144+
add_python_eigenpy_lib_unit_test(
145+
"py-generalized-self-adjoint-eigen-solver"
146+
"unittest/python/test_generalized_self_adjoint_eigen_solver.py")
143147

144148
add_python_eigenpy_lib_unit_test("py-complex-eigen-solver"
145149
"unittest/python/test_complex_eigen_solver.py")

unittest/python/test_generalized_eigen_solver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
for i in range(dim):
1818
v = V[:, i]
1919
lam = eigenvalues[i]
20-
20+
2121
Av = A @ v
2222
lam_Bv = lam * (B @ v)
23-
23+
2424
assert eigenpy.is_approx(Av.real, lam_Bv.real)
2525
assert eigenpy.is_approx(Av.imag, lam_Bv.imag)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import numpy as np
2+
3+
import eigenpy
4+
5+
dim = 5
6+
rng = np.random.default_rng()
7+
8+
A = rng.random((dim, dim))
9+
A = (A + A.T) * 0.5
10+
11+
B = rng.random((dim, dim))
12+
B = B @ B.T + 0.1 * np.eye(dim)
13+
14+
gsaes = eigenpy.GeneralizedSelfAdjointEigenSolver(A, B)
15+
16+
V = gsaes.eigenvectors()
17+
D = gsaes.eigenvalues()
18+
19+
for i in range(dim):
20+
v = V[:, i]
21+
lam = D[i]
22+
23+
Av = A @ v
24+
lam_Bv = lam * (B @ v)
25+
26+
assert np.allclose(Av, lam_Bv, atol=1e-6)

0 commit comments

Comments
 (0)