Skip to content

Commit e1cb1e9

Browse files
committed
decompositions: Completed tests
1 parent e206461 commit e1cb1e9

23 files changed

+1271
-251
lines changed

include/eigenpy/decompositions/FullPivLU.hpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ struct FullPivLUSolverVisitor
3333
.def(bp::init<Eigen::DenseIndex, Eigen::DenseIndex>(
3434
bp::args("self", "rows", "cols"),
3535
"Default constructor with memory preallocation"))
36-
.def(bp::init<const MatrixType>(bp::args("self", "matrix"),
37-
"Constructor."))
3836
.def(bp::init<MatrixType>(
3937
bp::args("self", "matrix"),
4038
"Constructs a LU factorization from a given matrix."))
@@ -57,7 +55,7 @@ struct FullPivLUSolverVisitor
5755
"is the LU decomposition.")
5856
.def(
5957
"image",
60-
+[](const Solver &self, const MatrixType &mat) -> MatrixType {
58+
+[](Solver &self, const MatrixType &mat) -> MatrixType {
6159
return self.image(mat);
6260
},
6361
bp::args("self", "originalMatrix"),
@@ -66,7 +64,7 @@ struct FullPivLUSolverVisitor
6664
"image (column-space).")
6765
.def(
6866
"inverse",
69-
+[](const Solver &self) -> MatrixType { return self.inverse(); },
67+
+[](Solver &self) -> MatrixType { return self.inverse(); },
7068
bp::arg("self"),
7169
"Returns the inverse of the matrix of which *this is the LU "
7270
"decomposition.")
@@ -76,8 +74,7 @@ struct FullPivLUSolverVisitor
7674
.def("isSurjective", &Solver::isSurjective, bp::arg("self"))
7775

7876
.def(
79-
"kernel",
80-
+[](const Solver &self) -> MatrixType { return self.kernel(); },
77+
"kernel", +[](Solver &self) -> MatrixType { return self.kernel(); },
8178
bp::arg("self"),
8279
"Returns the kernel of the matrix, also called its null-space. "
8380
"The columns of the returned matrix will form a basis of the "
@@ -90,7 +87,6 @@ struct FullPivLUSolverVisitor
9087
.def("maxPivot", &Solver::maxPivot, bp::arg("self"))
9188
.def("nonzeroPivots", &Solver::nonzeroPivots, bp::arg("self"))
9289

93-
// TODO: Expose so that the return type are convertible to np arrays
9490
.def("permutationP", &Solver::permutationP, bp::arg("self"),
9591
"Returns the permutation P.",
9692
bp::return_value_policy<bp::copy_const_reference>())

include/eigenpy/decompositions/GeneralizedEigenSolver.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ struct GeneralizedEigenSolverVisitor
3434

3535
.def("eigenvectors", &Solver::eigenvectors, bp::arg("self"),
3636
"Returns an expression of the computed generalized eigenvectors. ")
37-
// TODO: Expose so that the return type are convertible to np arrays
38-
.def("eigenvalues", &Solver::eigenvalues, bp::arg("self"),
39-
"Returns an expression of the computed generalized eigenvalues. ")
37+
.def(
38+
"eigenvalues",
39+
+[](const Solver& c) { return c.eigenvalues().eval(); },
40+
"Returns the computed generalized eigenvalues.")
4041

4142
.def("alphas", &Solver::alphas, bp::arg("self"),
4243
"Returns the vectors containing the alpha values. ")

include/eigenpy/decompositions/HessenbergDecomposition.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,14 @@ struct HessenbergDecompositionVisitor
4444
bp::arg("self"), "Returns the Householder coefficients. ",
4545
bp::return_value_policy<bp::copy_const_reference>())
4646

47-
// TODO: Expose so that the return type are convertible to np arrays
48-
// matrixH
49-
// matrixQ
47+
.def(
48+
"matrixQ",
49+
+[](const Solver& c) -> MatrixType { return c.matrixQ(); },
50+
"Reconstructs the orthogonal matrix Q in the decomposition.")
51+
.def(
52+
"matrixH",
53+
+[](const Solver& c) -> MatrixType { return c.matrixH(); },
54+
"Constructs the Hessenberg matrix H in the decomposition.")
5055

5156
.def("packedMatrix", &Solver::packedMatrix, bp::arg("self"),
5257
"Returns the internal representation of the decomposition. ",

include/eigenpy/decompositions/JacobiSVD.hpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@
1515

1616
namespace eigenpy {
1717

18-
template <typename _MatrixType>
18+
template <typename JacobiSVD>
1919
struct JacobiSVDVisitor
20-
: public boost::python::def_visitor<JacobiSVDVisitor<_MatrixType>> {
21-
typedef _MatrixType MatrixType;
22-
typedef Eigen::JacobiSVD<MatrixType> Solver;
20+
: public boost::python::def_visitor<JacobiSVDVisitor<JacobiSVD>> {
21+
typedef typename JacobiSVD::MatrixType MatrixType;
2322
typedef typename MatrixType::Scalar Scalar;
2423

2524
template <class PyClass>
@@ -46,28 +45,29 @@ struct JacobiSVDVisitor
4645
"and the constructor. If possible, prefer using the Options "
4746
"template parameter."))
4847

49-
.def("cols", &Solver::cols, bp::arg("self"),
48+
.def("cols", &JacobiSVD::cols, bp::arg("self"),
5049
"Returns the number of columns. ")
5150
.def("compute",
52-
(Solver & (Solver::*)(const MatrixType &matrix)) & Solver::compute,
51+
(JacobiSVD & (JacobiSVD::*)(const MatrixType &matrix)) &
52+
JacobiSVD::compute,
5353
bp::args("self", "matrix"),
5454
"Method performing the decomposition of given matrix. Computes "
5555
"Thin/Full "
5656
"unitaries U/V if specified using the Options template parameter "
5757
"or the class constructor. ",
5858
bp::return_self<>())
5959
.def("compute",
60-
(Solver & (Solver::*)(const MatrixType &matrix,
61-
unsigned int computationOptions)) &
62-
Solver::compute,
60+
(JacobiSVD & (JacobiSVD::*)(const MatrixType &matrix,
61+
unsigned int computationOptions)) &
62+
JacobiSVD::compute,
6363
bp::args("self", "matrix", "computationOptions"),
6464
"Method performing the decomposition of given matrix, as "
6565
"specified by the computationOptions parameter. ",
6666
bp::return_self<>())
67-
.def("rows", &Solver::rows, bp::arg("self"),
67+
.def("rows", &JacobiSVD::rows, bp::arg("self"),
6868
"Returns the number of rows. . ")
6969

70-
.def(SVDBaseVisitor<Solver>());
70+
.def(SVDBaseVisitor<JacobiSVD>());
7171
}
7272

7373
static void expose() {
@@ -77,7 +77,7 @@ struct JacobiSVDVisitor
7777
}
7878

7979
static void expose(const std::string &name) {
80-
bp::class_<Solver, boost::noncopyable>(
80+
bp::class_<JacobiSVD, boost::noncopyable>(
8181
name.c_str(),
8282
"Two-sided Jacobi SVD decomposition of a rectangular matrix. \n\n"
8383
"SVD decomposition consists in decomposing any n-by-p matrix A as a "
@@ -109,7 +109,7 @@ struct JacobiSVDVisitor
109109
"solving.",
110110
bp::no_init)
111111
.def(JacobiSVDVisitor())
112-
.def(IdVisitor<Solver>());
112+
.def(IdVisitor<JacobiSVD>());
113113
}
114114
};
115115

include/eigenpy/decompositions/PartialPivLU.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ struct PartialPivLUSolverVisitor : public boost::python::def_visitor<
3333
.def(bp::init<Eigen::DenseIndex>(
3434
bp::args("self", "size"),
3535
"Default constructor with memory preallocation"))
36-
.def(bp::init<const MatrixType>(bp::args("self", "matrix"),
37-
"Constructor."))
3836
.def(bp::init<MatrixType>(
3937
bp::args("self", "matrix"),
4038
"Constructs a LU factorization from a given matrix."))
@@ -44,6 +42,13 @@ struct PartialPivLUSolverVisitor : public boost::python::def_visitor<
4442
.def("determinant", &Solver::determinant, bp::arg("self"),
4543
"Returns the determinant of the matrix of which *this is the LU "
4644
"decomposition.")
45+
.def(
46+
"compute",
47+
(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> &matrix)) &
48+
Solver::compute,
49+
bp::args("self", "matrix"),
50+
"Computes the LU factorization of given matrix.",
51+
bp::return_self<>())
4752
.def(
4853
"inverse",
4954
+[](const Solver &self) -> MatrixType { return self.inverse(); },
@@ -54,7 +59,6 @@ struct PartialPivLUSolverVisitor : public boost::python::def_visitor<
5459
"Returns the LU decomposition matrix.",
5560
bp::return_internal_reference<>())
5661

57-
// TODO: Expose so that the return type are convertible to np arrays
5862
.def("permutationP", &Solver::permutationP, bp::arg("self"),
5963
"Returns the permutation P.",
6064
bp::return_value_policy<bp::copy_const_reference>())

include/eigenpy/decompositions/Tridiagonalization.hpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ struct TridiagonalizationVisitor : public boost::python::def_visitor<
2020
typedef _MatrixType MatrixType;
2121
typedef typename MatrixType::Scalar Scalar;
2222
typedef Eigen::Tridiagonalization<MatrixType> Solver;
23+
typedef Eigen::VectorXd VectorType;
2324

2425
template <class PyClass>
25-
void visit(PyClass& cl) const {
26+
void visit(PyClass &cl) const {
2627
cl.def(
2728
bp::init<Eigen::DenseIndex>(bp::arg("size"), "Default constructor. "))
2829
.def(bp::init<MatrixType>(bp::arg("matrix"),
@@ -31,7 +32,7 @@ struct TridiagonalizationVisitor : public boost::python::def_visitor<
3132

3233
.def(
3334
"compute",
34-
(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType>& matrix)) &
35+
(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> &matrix)) &
3536
Solver::compute,
3637
bp::args("self", "matrix"),
3738
"Computes tridiagonal decomposition of given matrix. ",
@@ -43,18 +44,28 @@ struct TridiagonalizationVisitor : public boost::python::def_visitor<
4344
"Returns the internal representation of the decomposition. ",
4445
bp::return_value_policy<bp::copy_const_reference>())
4546

46-
// TODO: Expose so that the return type are convertible to np arrays
47-
.def("matrixQ", &Solver::matrixQ, bp::arg("self"),
48-
"Returns the unitary matrix Q in the decomposition. ")
49-
.def("matrixT", &Solver::matrixT, bp::arg("self"),
50-
"Returns the unitary matrix T in the decomposition. ")
47+
.def(
48+
"matrixQ",
49+
+[](const Solver &c) -> MatrixType { return c.matrixQ(); },
50+
"Returns the unitary matrix Q in the decomposition.")
51+
.def(
52+
"matrixT", +[](Solver &c) -> MatrixType { return c.matrixT(); },
53+
"Returns an expression of the tridiagonal matrix T in the "
54+
"decomposition.")
5155

52-
.def("diagonal", &Solver::diagonal, bp::arg("self"),
53-
"Returns the diagonal of the tridiagonal matrix T in the "
54-
"decomposition. ")
55-
.def("subDiagonal", &Solver::subDiagonal, bp::arg("self"),
56-
"Returns the subdiagonal of the tridiagonal matrix T in the "
57-
"decomposition.");
56+
.def(
57+
"diagonal",
58+
+[](const Solver &c) -> VectorType { return c.diagonal(); },
59+
bp::arg("self"),
60+
"Returns the diagonal of the tridiagonal matrix T in the "
61+
"decomposition. ")
62+
63+
.def(
64+
"subDiagonal",
65+
+[](const Solver &c) -> VectorType { return c.subDiagonal(); },
66+
bp::arg("self"),
67+
"Returns the subdiagonal of the tridiagonal matrix T in the "
68+
"decomposition.");
5869
}
5970

6071
static void expose() {
@@ -63,7 +74,7 @@ struct TridiagonalizationVisitor : public boost::python::def_visitor<
6374
expose(classname);
6475
}
6576

66-
static void expose(const std::string& name) {
77+
static void expose(const std::string &name) {
6778
bp::class_<Solver>(name.c_str(), bp::no_init)
6879
.def(TridiagonalizationVisitor())
6980
.def(IdVisitor<Solver>());

include/eigenpy/decompositions/sparse/LU.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ struct SparseLUVisitor : public boost::python::def_visitor<
4949
"Returns the natural log of the absolute value of the determinant "
5050
"of the matrix of which *this is the QR decomposition")
5151

52+
.def("rows", &Solver::rows, bp::arg("self"),
53+
"Returns the number of rows of the matrix.")
54+
.def("cols", &Solver::cols, bp::arg("self"),
55+
"Returns the number of cols of the matrix.")
56+
57+
.def("nnzL", &Solver::nnzL, bp::arg("self"),
58+
"The number of non zero elements in L")
59+
.def("nnzU", &Solver::nnzU, bp::arg("self"),
60+
"The number of non zero elements in L")
61+
5262
.def("colsPermutation", &Solver::colsPermutation, bp::arg("self"),
5363
"Returns a reference to the column matrix permutation PTc such "
5464
"that Pr A PTc = LU.",
@@ -71,12 +81,6 @@ struct SparseLUVisitor : public boost::python::def_visitor<
7181
"The given matrix must has the same sparcity than the matrix on "
7282
"which the symbolic decomposition has been performed.")
7383

74-
// TODO: Expose so that the return type are convertible to np arrays
75-
// transpose()
76-
// adjoint()
77-
// matrixL()
78-
// matrixU()
79-
8084
.def("isSymmetric", &Solver::isSymmetric, bp::args("self", "sym"),
8185
"Indicate that the pattern of the input matrix is symmetric. ")
8286

include/eigenpy/decompositions/sparse/QR.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ struct SparseQRVisitor : public boost::python::def_visitor<
5757
"The given matrix must has the same sparcity than the matrix on "
5858
"which the symbolic decomposition has been performed.")
5959

60-
// TODO: Expose so that the return type are convertible to np arrays
61-
// matrixQ
62-
// matrixR
63-
6460
.def("colsPermutation", &Solver::colsPermutation, bp::arg("self"),
6561
"Returns a reference to the column matrix permutation PTc such "
6662
"that Pr A PTc = LU.",

src/decompositions/jacobisvd-solver.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@
77
namespace eigenpy {
88
void exposeJacobiSVDSolver() {
99
using namespace Eigen;
10-
JacobiSVDVisitor<MatrixXd>::expose("JacobiSVD");
10+
using Eigen::JacobiSVD;
11+
12+
using Eigen::ColPivHouseholderQRPreconditioner;
13+
using Eigen::FullPivHouseholderQRPreconditioner;
14+
using Eigen::HouseholderQRPreconditioner;
15+
using Eigen::NoQRPreconditioner;
16+
17+
using ColPivHhJacobiSVD =
18+
JacobiSVD<MatrixXd, ColPivHouseholderQRPreconditioner>;
19+
using FullPivHhJacobiSVD =
20+
JacobiSVD<MatrixXd, FullPivHouseholderQRPreconditioner>;
21+
using HhJacobiSVD = JacobiSVD<MatrixXd, HouseholderQRPreconditioner>;
22+
using NoPrecondJacobiSVD = JacobiSVD<MatrixXd, NoQRPreconditioner>;
23+
24+
JacobiSVDVisitor<ColPivHhJacobiSVD>::expose("ColPivHhJacobiSVD");
25+
JacobiSVDVisitor<FullPivHhJacobiSVD>::expose("FullPivHhJacobiSVD");
26+
JacobiSVDVisitor<HhJacobiSVD>::expose("HhJacobiSVD");
27+
JacobiSVDVisitor<NoPrecondJacobiSVD>::expose("NoPrecondJacobiSVD");
1128
}
1229
} // namespace eigenpy
Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,38 @@
11
import numpy as np
2-
import scipy
3-
from scipy.sparse import csc_matrix
2+
import scipy.sparse as spa
43

54
import eigenpy
65

76
dim = 100
87
rng = np.random.default_rng()
98

10-
A = rng.random((dim, dim))
11-
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
12-
A = csc_matrix(A)
9+
A_fac = spa.random(dim, dim, density=0.25, random_state=rng)
10+
A = A_fac.T @ A_fac
11+
A += spa.diags(10.0 * rng.standard_normal(dim) ** 2)
12+
A = A.tocsc(True)
13+
A.check_format()
1314

14-
sparselu = eigenpy.SparseLU(A)
15+
splu = eigenpy.SparseLU(A)
1516

16-
assert sparselu.info() == eigenpy.ComputationInfo.Success
17+
assert splu.info() == eigenpy.ComputationInfo.Success
1718

18-
# Solve
1919
X = rng.random((dim, 20))
2020
B = A.dot(X)
21-
X_est = sparselu.solve(B)
21+
X_est = splu.solve(B)
22+
assert isinstance(X_est, np.ndarray)
2223
assert eigenpy.is_approx(X, X_est)
2324
assert eigenpy.is_approx(A.dot(X_est), B)
2425

25-
X_sparse = scipy.sparse.random(dim, 10)
26-
B_sparse = A.dot(X_sparse)
27-
B_sparse = B_sparse.tocsc(True)
26+
splu.analyzePattern(A)
27+
splu.factorize(A)
2828

29+
X_sparse = spa.random(dim, 10, random_state=rng)
30+
B_sparse = A.dot(X_sparse)
31+
B_sparse: spa.csc_matrix = B_sparse.tocsc(True)
2932
if not B_sparse.has_sorted_indices:
3033
B_sparse.sort_indices()
3134

32-
X_est = sparselu.solve(B_sparse)
35+
X_est = splu.solve(B_sparse)
36+
assert isinstance(X_est, spa.csc_matrix)
3337
assert eigenpy.is_approx(X_est.toarray(), X_sparse.toarray())
3438
assert eigenpy.is_approx(A.dot(X_est.toarray()), B_sparse.toarray())
35-
36-
# Others
37-
det = sparselu.determinant()
38-
sign_det = sparselu.signDeterminant()
39-
abs_det = sparselu.absDeterminant()
40-
log_abs_det = sparselu.logAbsDeterminant()
41-
42-
sparselu.analyzePattern(A)
43-
sparselu.factorize(A)
44-
45-
cols_permutation = sparselu.colsPermutation()
46-
rows_permutation = sparselu.rowsPermutation()
47-
48-
sparselu.setPivotThreshold(1e-8)

0 commit comments

Comments
 (0)