Skip to content

Commit 54b6ee9

Browse files
committed
Add matrixU and matrixL in SparseLU
1 parent 3e38169 commit 54b6ee9

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

include/nanoeigenpy/decompositions/sparse/sparse-lu.hpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,74 @@ namespace nanoeigenpy {
1010
namespace nb = nanobind;
1111
using namespace nb::literals;
1212

13+
template <typename LTypeOrUType, typename MatrixOrVector>
14+
static void solveInPlace(const LTypeOrUType &self,
15+
Eigen::Ref<MatrixOrVector> mat_vec) {
16+
self.solveInPlace(mat_vec);
17+
}
18+
19+
template <typename MappedSupernodalType>
20+
void exposeMatrixL(nb::module_ m) {
21+
using LType = Eigen::SparseLUMatrixLReturnType<MappedSupernodalType>;
22+
using Scalar = typename MappedSupernodalType::Scalar;
23+
using VectorXs = Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Eigen::ColMajor>;
24+
using MatrixXs =
25+
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
26+
27+
if (check_registration_alias<LType>(m)) {
28+
return;
29+
}
30+
31+
nb::class_<LType>(m, "SparseLUMatrixLReturnType")
32+
.def("rows", &LType::rows)
33+
.def("cols", &LType::cols)
34+
.def("solveInPlace", &solveInPlace<LType, MatrixXs>, "X"_a)
35+
.def("solveInPlace", &solveInPlace<LType, VectorXs>, "x"_a);
36+
}
37+
38+
template <typename MatrixLType, typename MatrixUType>
39+
void exposeMatrixU(nb::module_ m) {
40+
using UType = Eigen::SparseLUMatrixUReturnType<MatrixLType, MatrixUType>;
41+
using Scalar = typename MatrixLType::Scalar;
42+
using VectorXs = Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Eigen::ColMajor>;
43+
using MatrixXs =
44+
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
45+
46+
if (check_registration_alias<UType>(m)) {
47+
return;
48+
}
49+
50+
nb::class_<UType>(m, "SparseLUMatrixUReturnType")
51+
.def("rows", &UType::rows)
52+
.def("cols", &UType::cols)
53+
.def("solveInPlace", &solveInPlace<UType, MatrixXs>, "X"_a)
54+
.def("solveInPlace", &solveInPlace<UType, VectorXs>, "x"_a);
55+
}
56+
1357
template <typename _MatrixType, typename _Ordering = Eigen::COLAMDOrdering<
1458
typename _MatrixType::StorageIndex>>
1559
void exposeSparseLU(nb::module_ m, const char *name) {
1660
using MatrixType = _MatrixType;
1761
using Solver = Eigen::SparseLU<MatrixType>;
62+
using Scalar = typename MatrixType::Scalar;
1863
using RealScalar = typename MatrixType::RealScalar;
64+
using StorageIndex = typename MatrixType::StorageIndex;
1965
using SparseLUTransposeViewTrue = Eigen::SparseLUTransposeView<true, Solver>;
2066
using SparseLUTransposeViewFalse =
2167
Eigen::SparseLUTransposeView<false, Solver>;
68+
using SCMatrix = typename Solver::SCMatrix;
69+
using MappedSparseMatrix =
70+
typename Eigen::MappedSparseMatrix<Scalar, Eigen::ColMajor, StorageIndex>;
71+
using LType = Eigen::SparseLUMatrixLReturnType<SCMatrix>;
72+
using UType = Eigen::SparseLUMatrixUReturnType<SCMatrix, MappedSparseMatrix>;
2273

2374
if (check_registration_alias<Solver>(m)) {
2475
return;
2576
}
2677

78+
exposeMatrixL<SCMatrix>(m);
79+
exposeMatrixU<SCMatrix, MappedSparseMatrix>(m);
80+
2781
nb::class_<SparseLUTransposeViewFalse>(m, "SparseLUTransposeView")
2882
.def(SparseSolverBaseVisitor())
2983
.def("setIsInitialized", &SparseLUTransposeViewFalse::setIsInitialized)
@@ -104,6 +158,13 @@ void exposeSparseLU(nb::module_ m, const char *name) {
104158
},
105159
"Returns an expression of the adjoint of the factored matrix.")
106160

161+
.def(
162+
"matrixL", [](const Solver &self) -> LType { return self.matrixL(); },
163+
"Returns an expression of the matrix L.")
164+
.def(
165+
"matrixU", [](const Solver &self) -> UType { return self.matrixU(); },
166+
"Returns an expression of the matrix U.")
167+
107168
.def("rows", &Solver::rows, "Returns the number of rows of the matrix.")
108169
.def("cols", &Solver::cols, "Returns the number of cols of the matrix.")
109170

src/module.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,22 @@ using FullPivHhJacobiSVD =
2727
using HhJacobiSVD = JacobiSVD<Matrix, HouseholderQRPreconditioner>;
2828
using NoPrecondJacobiSVD = JacobiSVD<Matrix, NoQRPreconditioner>;
2929

30+
using SparseQR = Eigen::SparseQR<SparseMatrix, Eigen::COLAMDOrdering<int>>;
31+
using SparseLU = Eigen::SparseLU<SparseMatrix>;
32+
using SCMatrix = typename SparseLU::SCMatrix;
33+
using StorageIndex = typename Matrix::StorageIndex;
34+
using MappedSparseMatrix =
35+
typename Eigen::MappedSparseMatrix<Scalar, Options, StorageIndex>;
36+
3037
NB_MAKE_OPAQUE(ColPivHhJacobiSVD)
3138
NB_MAKE_OPAQUE(FullPivHhJacobiSVD)
3239
NB_MAKE_OPAQUE(HhJacobiSVD)
3340
NB_MAKE_OPAQUE(NoPrecondJacobiSVD)
3441

35-
using SparseQR = Eigen::SparseQR<SparseMatrix, Eigen::COLAMDOrdering<int>>;
3642
NB_MAKE_OPAQUE(Eigen::SparseQRMatrixQReturnType<SparseQR>)
3743
NB_MAKE_OPAQUE(Eigen::SparseQRMatrixQTransposeReturnType<SparseQR>)
44+
NB_MAKE_OPAQUE(Eigen::SparseLUMatrixLReturnType<SCMatrix>)
45+
NB_MAKE_OPAQUE(Eigen::SparseLUMatrixUReturnType<SCMatrix, MappedSparseMatrix>)
3846

3947
NB_MAKE_OPAQUE(Eigen::LLT<Eigen::MatrixXd>)
4048
NB_MAKE_OPAQUE(Eigen::LDLT<Eigen::MatrixXd>)

tests/test_sparse_lu.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,29 @@
3535
assert isinstance(X_est, spa.csc_matrix)
3636
assert nanoeigenpy.is_approx(X_est.toarray(), X_sparse.toarray())
3737
assert nanoeigenpy.is_approx(A.dot(X_est.toarray()), B_sparse.toarray())
38+
39+
assert splu.nnzL() > 0
40+
assert splu.nnzU() > 0
41+
42+
L = splu.matrixL()
43+
U = splu.matrixU()
44+
45+
assert L.rows() == dim
46+
assert L.cols() == dim
47+
assert U.rows() == dim
48+
assert U.cols() == dim
49+
50+
x_true = rng.random(dim)
51+
b_true = A.dot(x_true)
52+
P_rows_indices = splu.rowsPermutation().indices()
53+
P_cols_indices = splu.colsPermutation().indices()
54+
55+
b_permuted = b_true[P_rows_indices]
56+
z = b_permuted.copy()
57+
L.solveInPlace(z)
58+
y = z.copy()
59+
U.solveInPlace(y)
60+
x_reconstructed = np.zeros(dim)
61+
x_reconstructed[P_cols_indices] = y
62+
63+
assert nanoeigenpy.is_approx(x_reconstructed, x_true, 1e-6)

0 commit comments

Comments
 (0)