Skip to content

Commit fe5f3ce

Browse files
committed
eigenvalues: HenssenbergDecomposition
1 parent 9c69e0f commit fe5f3ce

10 files changed

+138
-20
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
238238
include/eigenpy/decompositions/EigenSolver.hpp
239239
include/eigenpy/decompositions/GeneralizedEigenSolver.hpp
240240
include/eigenpy/decompositions/GeneralizedSelfAdjointEigenSolver.hpp
241+
include/eigenpy/decompositions/HessenbergDecomposition.hpp
241242
include/eigenpy/decompositions/ComplexEigenSolver.hpp
242243
include/eigenpy/decompositions/ComplexSchur.hpp
243244
include/eigenpy/decompositions/PermutationMatrix.hpp
@@ -331,6 +332,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
331332
src/decompositions/bdcsvd-solver.cpp
332333
src/decompositions/jacobisvd-solver.cpp
333334
src/decompositions/fullpivlu-solver.cpp
335+
src/decompositions/hessenberg-decomposition.cpp
334336
src/decompositions/partialpivlu-solver.cpp
335337
src/decompositions/minres-solver.cpp
336338
src/decompositions/sparse-lu-solver.cpp

include/eigenpy/decompositions/GeneralizedSelfAdjointEigenSolver.hpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,35 @@ namespace eigenpy {
1717

1818
template <typename _MatrixType>
1919
struct GeneralizedSelfAdjointEigenSolverVisitor
20-
: public boost::python::def_visitor<GeneralizedSelfAdjointEigenSolverVisitor<_MatrixType>> {
20+
: public boost::python::def_visitor<
21+
GeneralizedSelfAdjointEigenSolverVisitor<_MatrixType>> {
2122
typedef _MatrixType MatrixType;
2223
typedef typename MatrixType::Scalar Scalar;
2324
typedef Eigen::GeneralizedSelfAdjointEigenSolver<MatrixType> Solver;
2425

2526
template <class PyClass>
2627
void visit(PyClass& cl) const {
2728
cl.def(bp::init<>("Default constructor"))
28-
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
29-
"Default constructor with memory preallocation. "))
29+
.def(bp::init<Eigen::DenseIndex>(
30+
bp::arg("size"), "Default constructor with memory preallocation. "))
3031
.def(bp::init<MatrixType, MatrixType, bp::optional<int>>(
31-
bp::args("matA", "matB", "options"),
32-
"Constructor: Computes generalized eigendecomposition of given matrix pencil. "))
32+
bp::args("matA", "matB", "options"),
33+
"Constructor: Computes generalized eigendecomposition of given "
34+
"matrix pencil. "))
3335

34-
.def("compute", &GeneralizedSelfAdjointEigenSolverVisitor::compute_proxy<MatrixType>,
35-
bp::args("self", "A", "B"),
36+
.def("compute",
37+
&GeneralizedSelfAdjointEigenSolverVisitor::compute_proxy<
38+
MatrixType>,
39+
bp::args("self", "A", "B"),
3640
"Computes generalized eigendecomposition of given matrix pencil. ",
3741
bp::return_self<>())
3842
.def("compute",
3943
(Solver &
4044
(Solver::*)(const MatrixType& A, const MatrixType& B, int)) &
4145
Solver::compute,
4246
bp::args("self", "A", "B", "options"),
43-
"Computes generalized eigendecomposition of given matrix pencil.", bp::return_self<>());
47+
"Computes generalized eigendecomposition of given matrix pencil.",
48+
bp::return_self<>());
4449
}
4550

4651
static void expose() {
@@ -50,18 +55,21 @@ struct GeneralizedSelfAdjointEigenSolverVisitor
5055
}
5156

5257
static void expose(const std::string& name) {
53-
bp::class_<Solver, bp::bases<Eigen::SelfAdjointEigenSolver<MatrixType>>>(name.c_str(), bp::no_init)
58+
bp::class_<Solver, bp::bases<Eigen::SelfAdjointEigenSolver<MatrixType>>>(
59+
name.c_str(), bp::no_init)
5460
.def(GeneralizedSelfAdjointEigenSolverVisitor())
5561
.def(IdVisitor<Solver>());
5662
}
5763

5864
private:
5965
template <typename MatrixType>
60-
static Solver& compute_proxy(Solver& self, const MatrixType& A, const MatrixType& B) {
66+
static Solver& compute_proxy(Solver& self, const MatrixType& A,
67+
const MatrixType& B) {
6168
return self.compute(A, B);
6269
}
6370
};
6471

6572
} // namespace eigenpy
6673

67-
#endif // ifndef __eigenpy_decompositions_generalized_self_adjoint_eigen_solver_hpp__
74+
#endif // ifndef
75+
// __eigenpy_decompositions_generalized_self_adjoint_eigen_solver_hpp__
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decompositions_hessenberg_decomposition_hpp__
6+
#define __eigenpy_decompositions_hessenberg_decomposition_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 HessenbergDecompositionVisitor
19+
: public boost::python::def_visitor<
20+
HessenbergDecompositionVisitor<_MatrixType>> {
21+
typedef _MatrixType MatrixType;
22+
typedef typename MatrixType::Scalar Scalar;
23+
typedef Eigen::HessenbergDecomposition<MatrixType> Solver;
24+
25+
template <class PyClass>
26+
void visit(PyClass& cl) const {
27+
cl.def(bp::init<Eigen::DenseIndex>(
28+
bp::arg("size"), "Default constructor; the decomposition will be computed later. "))
29+
.def(bp::init<MatrixType>(bp::arg("matrix"),
30+
"Constructor; computes Hessenberg decomposition of given matrix. "))
31+
32+
.def("compute",
33+
&HessenbergDecompositionVisitor::compute_proxy<MatrixType>,
34+
bp::args("self", "A"),
35+
"Computes Hessenberg decomposition of given matrix. ",
36+
bp::return_self<>())
37+
.def("compute",
38+
(Solver &
39+
(Solver::*)(const Eigen::EigenBase<MatrixType>& matrix)) &
40+
Solver::compute,
41+
bp::args("self", "A"),
42+
"Computes Hessenberg decomposition of given matrix. ",
43+
bp::return_self<>())
44+
45+
.def("householderCoefficients", &Solver::householderCoefficients, bp::arg("self"),
46+
"Returns the Householder coefficients. ",
47+
bp::return_value_policy<bp::copy_const_reference>())
48+
49+
// matrixH
50+
// matrixQ
51+
52+
.def("packedMatrix", &Solver::packedMatrix, bp::arg("self"),
53+
"Returns the internal representation of the decomposition. ",
54+
bp::return_value_policy<bp::copy_const_reference>());
55+
}
56+
57+
static void expose() {
58+
static const std::string classname =
59+
"HessenbergDecomposition" + scalar_name<Scalar>::shortname();
60+
expose(classname);
61+
}
62+
63+
static void expose(const std::string& name) {
64+
bp::class_<Solver>(name.c_str(), bp::no_init)
65+
.def(HessenbergDecompositionVisitor())
66+
.def(IdVisitor<Solver>());
67+
}
68+
69+
private:
70+
template <typename MatrixType>
71+
static Solver& compute_proxy(Solver& self, const Eigen::EigenBase<MatrixType>& matrix) {
72+
return self.compute(matrix);
73+
}
74+
};
75+
76+
} // namespace eigenpy
77+
78+
#endif // ifndef __eigenpy_decompositions_hessenberg_decomposition_hpp__

src/decompositions/decompositions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ void exposeEigenSolver();
1212
void exposeGeneralizedEigenSolver();
1313
void exposeSelfAdjointEigenSolver();
1414
void exposeGeneralizedSelfAdjointEigenSolver();
15+
void exposeHessenbergDecomposition();
1516
void exposeComplexEigenSolver();
1617
void exposeComplexSchur();
1718
void exposeLLTSolver();
@@ -35,6 +36,7 @@ void exposeDecompositions() {
3536
exposeGeneralizedEigenSolver();
3637
exposeSelfAdjointEigenSolver();
3738
exposeGeneralizedSelfAdjointEigenSolver();
39+
exposeHessenbergDecomposition();
3840
exposeComplexEigenSolver();
3941
exposeComplexSchur();
4042
exposeLLTSolver();

src/decompositions/generalized-self-adjoint-eigen-solver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace eigenpy {
99
void exposeGeneralizedSelfAdjointEigenSolver() {
1010
using namespace Eigen;
11-
GeneralizedSelfAdjointEigenSolverVisitor<MatrixXd>::expose("GeneralizedSelfAdjointEigenSolver");
11+
GeneralizedSelfAdjointEigenSolverVisitor<MatrixXd>::expose(
12+
"GeneralizedSelfAdjointEigenSolver");
1213
}
1314
} // namespace eigenpy
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/HessenbergDecomposition.hpp"
7+
8+
namespace eigenpy {
9+
void exposeHessenbergDecomposition() {
10+
using namespace Eigen;
11+
HessenbergDecompositionVisitor<MatrixXd>::expose("HessenbergDecomposition");
12+
}
13+
} // namespace eigenpy

unittest/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ add_python_eigenpy_lib_unit_test(
155155
"py-self-adjoint-eigen-solver"
156156
"unittest/python/test_self_adjoint_eigen_solver.py")
157157

158+
add_python_eigenpy_lib_unit_test(
159+
"py-hessenberg-decomposition"
160+
"unittest/python/test_hessenberg_decomposition.py")
161+
158162
add_python_eigenpy_lib_unit_test("py-LLT" "unittest/python/test_LLT.py")
159163

160164
add_python_eigenpy_lib_unit_test("py-LDLT" "unittest/python/test_LDLT.py")

unittest/python/test_generalized_eigen_solver.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
V = ges.eigenvectors()
1515

1616
eigenvalues = alphas / betas
17-
for i in range(dim):
18-
v = V[:, i]
19-
lam = eigenvalues[i]
17+
if np.all(np.abs(betas) >= 1e-15):
18+
for i in range(dim):
19+
v = V[:, i]
20+
lam = eigenvalues[i]
2021

21-
Av = A @ v
22-
lam_Bv = lam * (B @ v)
22+
Av = A @ v
23+
lam_Bv = lam * (B @ v)
2324

24-
assert eigenpy.is_approx(Av.real, lam_Bv.real)
25-
assert eigenpy.is_approx(Av.imag, lam_Bv.imag)
25+
assert eigenpy.is_approx(Av.real, lam_Bv.real)
26+
assert eigenpy.is_approx(Av.imag, lam_Bv.imag)

unittest/python/test_generalized_self_adjoint_eigen_solver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
for i in range(dim):
2020
v = V[:, i]
2121
lam = D[i]
22-
22+
2323
Av = A @ v
2424
lam_Bv = lam * (B @ v)
2525

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
9+
ges = eigenpy.HessenbergDecomposition(A)

0 commit comments

Comments
 (0)