Skip to content

Commit 63ce2fb

Browse files
committed
eigenvalues: RealSchur
1 parent a4b2eb4 commit 63ce2fb

File tree

8 files changed

+134
-10
lines changed

8 files changed

+134
-10
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
240240
include/eigenpy/decompositions/GeneralizedSelfAdjointEigenSolver.hpp
241241
include/eigenpy/decompositions/HessenbergDecomposition.hpp
242242
include/eigenpy/decompositions/RealQZ.hpp
243+
include/eigenpy/decompositions/RealSchur.hpp
243244
include/eigenpy/decompositions/ComplexEigenSolver.hpp
244245
include/eigenpy/decompositions/ComplexSchur.hpp
245246
include/eigenpy/decompositions/PermutationMatrix.hpp
@@ -335,6 +336,7 @@ set(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
335336
src/decompositions/fullpivlu-solver.cpp
336337
src/decompositions/hessenberg-decomposition.cpp
337338
src/decompositions/real-qz.cpp
339+
src/decompositions/real-schur.cpp
338340
src/decompositions/partialpivlu-solver.cpp
339341
src/decompositions/minres-solver.cpp
340342
src/decompositions/sparse-lu-solver.cpp

include/eigenpy/decompositions/ComplexSchur.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct ComplexSchurVisitor
4242
const Eigen::EigenBase<MatrixType>& matrixQ,
4343
bool)) &
4444
Solver::computeFromHessenberg,
45-
bp::args("self", "matrix", "computeU"),
45+
bp::args("self", "matrixH", "matrixQ", "computeU"),
4646
"Compute Schur decomposition from a given Hessenberg matrix. ",
4747
bp::return_self<>())
4848

include/eigenpy/decompositions/RealQZ.hpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,20 @@ namespace eigenpy {
1616

1717
template <typename _MatrixType>
1818
struct RealQZVisitor
19-
: public boost::python::def_visitor<
20-
RealQZVisitor<_MatrixType>> {
19+
: public boost::python::def_visitor<RealQZVisitor<_MatrixType>> {
2120
typedef _MatrixType MatrixType;
2221
typedef typename MatrixType::Scalar Scalar;
2322
typedef Eigen::RealQZ<MatrixType> Solver;
2423

2524
template <class PyClass>
2625
void visit(PyClass& cl) const {
27-
cl.def(bp::init<Eigen::DenseIndex>(
28-
bp::arg("size"), "Default constructor. "))
26+
cl.def(
27+
bp::init<Eigen::DenseIndex>(bp::arg("size"), "Default constructor. "))
2928
.def(bp::init<MatrixType, MatrixType, bp::optional<bool>>(
3029
bp::args("A", "B", "computeQZ"),
3130
"Constructor; computes real QZ decomposition of given matrices. "))
3231

33-
.def("compute",
34-
&RealQZVisitor::compute_proxy<MatrixType>,
32+
.def("compute", &RealQZVisitor::compute_proxy<MatrixType>,
3533
bp::args("self", "A", "B"),
3634
"Computes QZ decomposition of given matrix. ",
3735
bp::return_self<>())
@@ -40,8 +38,7 @@ struct RealQZVisitor
4038
(Solver::*)(const MatrixType& A, const MatrixType& B, bool)) &
4139
Solver::compute,
4240
bp::args("self", "A", "B", "computeEigenvectors"),
43-
"Computes QZ decomposition of given matrix. ",
44-
bp::return_self<>())
41+
"Computes QZ decomposition of given matrix. ", bp::return_self<>())
4542

4643
.def("info", &Solver::info, bp::arg("self"),
4744
"NumericalIssue if the input contains INF or NaN values or "
@@ -70,7 +67,7 @@ struct RealQZVisitor
7067

7168
static void expose() {
7269
static const std::string classname =
73-
"RealQZVisitorSolver" + scalar_name<Scalar>::shortname();
70+
"RealQZVisitor" + scalar_name<Scalar>::shortname();
7471
expose(classname);
7572
}
7673

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2020 INRIA
3+
*/
4+
5+
#ifndef __eigenpy_decompositions_generalized_real_schur_hpp__
6+
#define __eigenpy_decompositions_generalized_real_schur_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 RealSchurVisitor
19+
: public boost::python::def_visitor<
20+
RealSchurVisitor<_MatrixType>> {
21+
typedef _MatrixType MatrixType;
22+
typedef typename MatrixType::Scalar Scalar;
23+
typedef Eigen::RealSchur<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. "))
29+
.def(bp::init<MatrixType, bp::optional<bool>>(
30+
bp::args("matrix", "computeU"),
31+
"Constructor; computes real Schur decomposition of given matrix. "))
32+
33+
.def("compute",
34+
&RealSchurVisitor::compute_proxy<MatrixType>,
35+
bp::args("self", "matrix"),
36+
"Computes Schur decomposition of given matrix. ",
37+
bp::return_self<>())
38+
.def("compute",
39+
(Solver &
40+
(Solver::*)(const Eigen::EigenBase<MatrixType>& matrix, bool)) &
41+
Solver::compute,
42+
bp::args("self", "matrix", "computeEigenvectors"),
43+
"Computes Schur decomposition of given matrix. ",
44+
bp::return_self<>())
45+
46+
.def("computeFromHessenberg",
47+
(Solver & (Solver::*)(const MatrixType& matrixH,
48+
const MatrixType& matrixQ,
49+
bool)) &
50+
Solver::computeFromHessenberg,
51+
bp::args("self", "matrixH", "matrixQ", "computeU"),
52+
"Compute Schur decomposition from a given Hessenberg matrix. ",
53+
bp::return_self<>())
54+
55+
.def("info", &Solver::info, bp::arg("self"),
56+
"NumericalIssue if the input contains INF or NaN values or "
57+
"overflow occured. Returns Success otherwise.")
58+
59+
.def("matrixT", &Solver::matrixT, bp::arg("self"),
60+
"Returns the quasi-triangular matrix in the Schur decomposition.",
61+
bp::return_value_policy<bp::copy_const_reference>())
62+
.def("matrixU", &Solver::matrixU, bp::arg("self"),
63+
"Returns the orthogonal matrix in the Schur decomposition. ",
64+
bp::return_value_policy<bp::copy_const_reference>())
65+
66+
.def("setMaxIterations", &Solver::setMaxIterations,
67+
bp::args("self", "max_iter"),
68+
"Sets the maximum number of iterations allowed.",
69+
bp::return_self<>());
70+
}
71+
72+
static void expose() {
73+
static const std::string classname =
74+
"RealSchurVisitor" + scalar_name<Scalar>::shortname();
75+
expose(classname);
76+
}
77+
78+
static void expose(const std::string& name) {
79+
bp::class_<Solver>(name.c_str(), bp::no_init)
80+
.def(RealSchurVisitor())
81+
.def(IdVisitor<Solver>());
82+
}
83+
84+
private:
85+
template <typename MatrixType>
86+
static Solver& compute_proxy(Solver& self, const MatrixType& A) {
87+
return self.compute(A);
88+
}
89+
};
90+
91+
} // namespace eigenpy
92+
93+
#endif // ifndef __eigenpy_decompositions_generalized_real_schur_hpp__

src/decompositions/decompositions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void exposeSelfAdjointEigenSolver();
1414
void exposeGeneralizedSelfAdjointEigenSolver();
1515
void exposeHessenbergDecomposition();
1616
void exposeRealQZ();
17+
void exposeRealSchur();
1718
void exposeComplexEigenSolver();
1819
void exposeComplexSchur();
1920
void exposeLLTSolver();
@@ -39,6 +40,7 @@ void exposeDecompositions() {
3940
exposeGeneralizedSelfAdjointEigenSolver();
4041
exposeHessenbergDecomposition();
4142
exposeRealQZ();
43+
exposeRealSchur();
4244
exposeComplexEigenSolver();
4345
exposeComplexSchur();
4446
exposeLLTSolver();

src/decompositions/real-schur.cpp

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/RealSchur.hpp"
7+
8+
namespace eigenpy {
9+
void exposeRealSchur() {
10+
using namespace Eigen;
11+
RealSchurVisitor<MatrixXd>::expose("RealSchur");
12+
}
13+
} // namespace eigenpy

unittest/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ add_python_eigenpy_lib_unit_test(
161161

162162
add_python_eigenpy_lib_unit_test("py-real-qz" "unittest/python/test_real_qz.py")
163163

164+
add_python_eigenpy_lib_unit_test("py-real-schur"
165+
"unittest/python/test_real_schur.py")
166+
164167
add_python_eigenpy_lib_unit_test("py-LLT" "unittest/python/test_LLT.py")
165168

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

unittest/python/test_real_schur.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
cs = eigenpy.RealSchur(A)
10+
11+
U = cs.matrixU()
12+
T = cs.matrixT()
13+
14+
assert eigenpy.is_approx(A.real, (U @ T @ U.T).real)

0 commit comments

Comments
 (0)