Skip to content
This repository was archived by the owner on Sep 26, 2025. It is now read-only.

Commit a0cc581

Browse files
authored
Merge pull request #62 from Simple-Robotics/wjallet/topic/bk-fix-1d
[linalg] fix corner case for Bunch-Kaufman solver
2 parents 701c42c + 416a6f4 commit a0cc581

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
1012
* Add missing dependencies in `package.xml`: pinocchio, eigen.
1113
* Fix `ConstraintObjectTpl::operator==` constness (mandatory for eigenpy 3.3)
14+
* Corner case in `BunchKaufman<>` decomposition class when number of lhs rows is 1
15+
16+
### Added
17+
18+
* Typedef for `Scalar` in the matrix decomposition classes
19+
* `.solve(rhs)` (allocating version of `.solveInPlace()`) to their C++ class and Python bindings
1220

1321
## [0.3.4] - 2024-01-19
1422

bindings/python/expose-ldlt.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ namespace python {
99

1010
template <class LDLTtype>
1111
struct LDLTVisitor : bp::def_visitor<LDLTVisitor<LDLTtype>> {
12+
using Scalar = typename LDLTtype::Scalar;
13+
using VectorXs = Eigen::Matrix<Scalar, -1, 1, Eigen::ColMajor>;
14+
using MatrixXs = Eigen::Matrix<Scalar, -1, -1, Eigen::ColMajor>;
1215

1316
static LDLTtype &compute_proxy(LDLTtype &fac,
1417
const context::ConstMatrixRef &mat) {
@@ -20,10 +23,17 @@ struct LDLTVisitor : bp::def_visitor<LDLTVisitor<LDLTtype>> {
2023
return fac.solveInPlace(rhsAndX);
2124
}
2225

26+
template <typename RhsType>
27+
static auto solve(const LDLTtype &fac, RhsType &rhs) {
28+
return fac.solve(rhs);
29+
}
30+
2331
template <typename... Args> void visit(bp::class_<Args...> &cl) const {
2432
cl.def("compute", compute_proxy, policies::return_internal_reference,
2533
("self"_a, "mat"))
2634
.def("solveInPlace", solveInPlace_proxy, ("self"_a, "rhsAndX"))
35+
.def("solve", solve<Eigen::Ref<const VectorXs>>, ("self"_a, "rhs"))
36+
.def("solve", solve<Eigen::Ref<const MatrixXs>>, ("self"_a, "rhs"))
2737
.def("matrixLDLT", &LDLTtype::matrixLDLT, policies::return_by_value,
2838
"self"_a,
2939
"Get the current value of the decomposition matrix. This makes a "

include/proxsuite-nlp/linalg/block-ldlt.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ template <typename Scalar> struct block_impl {
194194
/// over the lifetime of this object when calling compute(). A change
195195
/// of structure should lead to recalculating the expected sparsity pattern of
196196
/// the factorization, and even recomputing the sparsity-optimal permutation.
197-
template <typename Scalar> struct BlockLDLT : ldlt_base<Scalar> {
197+
template <typename _Scalar> struct BlockLDLT : ldlt_base<_Scalar> {
198+
using Scalar = _Scalar;
198199
PROXSUITE_NLP_DYNAMIC_TYPEDEFS(Scalar);
199200
using Base = ldlt_base<Scalar>;
200201
using DView = typename Base::DView;
@@ -299,6 +300,13 @@ template <typename Scalar> struct BlockLDLT : ldlt_base<Scalar> {
299300
template <typename Derived>
300301
bool solveInPlace(Eigen::MatrixBase<Derived> &b) const;
301302

303+
template <typename Rhs>
304+
typename Rhs::PlainObject solve(const Eigen::MatrixBase<Rhs> &rhs) const {
305+
typename Rhs::PlainObject out = rhs;
306+
solveInPlace(out);
307+
return out;
308+
}
309+
302310
const MatrixXs &matrixLDLT() const override { return m_matrix; }
303311

304312
inline void compute() {

include/proxsuite-nlp/linalg/bunchkaufman.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,21 @@ ComputationInfo bunch_kaufman_in_place_unblocked(MatrixType &a,
2323
Index &pivot_count) {
2424
using Scalar = typename MatrixType::Scalar;
2525
using Real = typename Eigen::NumTraits<Scalar>::Real;
26-
Real alpha = (Real(1) + numext::sqrt(Real(17))) / Real(8);
26+
const Real alpha = (Real(1) + numext::sqrt(Real(17))) / Real(8);
2727
using std::swap;
2828

2929
pivot_count = 0;
3030

31-
Index n = a.rows();
31+
const Index n = a.rows();
3232
if (n == 0) {
3333
return Success;
34+
} else if (n == 1) {
35+
if (numext::abs(numext::real(a(0, 0))) == Real(0)) {
36+
return NumericalIssue;
37+
} else {
38+
a(0, 0) = Real(1) / numext::real(a(0, 0));
39+
return Success;
40+
}
3441
}
3542

3643
Index k = 0;

include/proxsuite-nlp/linalg/dense.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ dense_ldlt_reconstruct(typename math_types<Scalar>::ConstMatrixRef const &mat,
161161
} // namespace backend
162162

163163
/// @brief A fast, recursive divide-and-conquer LDLT algorithm.
164-
template <typename Scalar> struct DenseLDLT : ldlt_base<Scalar> {
164+
template <typename _Scalar> struct DenseLDLT : ldlt_base<_Scalar> {
165+
using Scalar = _Scalar;
165166
PROXSUITE_NLP_DYNAMIC_TYPEDEFS(Scalar);
166167
using Base = ldlt_base<Scalar>;
167168
using DView = typename Base::DView;
@@ -193,6 +194,13 @@ template <typename Scalar> struct DenseLDLT : ldlt_base<Scalar> {
193194
return backend::dense_ldlt_solve_in_place(m_matrix, b);
194195
}
195196

197+
template <typename Rhs>
198+
typename Rhs::PlainObject solve(const Eigen::MatrixBase<Rhs> &rhs) const {
199+
typename Rhs::PlainObject out = rhs;
200+
solveInPlace(out);
201+
return out;
202+
}
203+
196204
MatrixXs reconstructedMatrix() const {
197205
MatrixXs res(m_matrix.rows(), m_matrix.cols());
198206
res.setIdentity();

include/proxsuite-nlp/linalg/proxsuite-ldlt-wrap.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ namespace nlp {
4444
namespace linalg {
4545

4646
/// @brief Use the LDLT from proxsuite.
47-
template <typename Scalar> struct ProxSuiteLDLTWrapper : ldlt_base<Scalar> {
47+
template <typename _Scalar> struct ProxSuiteLDLTWrapper : ldlt_base<_Scalar> {
48+
using Scalar = _Scalar;
4849
PROXSUITE_NLP_DYNAMIC_TYPEDEFS(Scalar);
4950
using Base = ldlt_base<Scalar>;
5051
using psldlt_t = dense_linalg::Ldlt<Scalar>;
@@ -97,6 +98,13 @@ template <typename Scalar> struct ProxSuiteLDLTWrapper : ldlt_base<Scalar> {
9798
return true;
9899
}
99100

101+
template <typename Rhs>
102+
typename Rhs::PlainObject solve(const Eigen::MatrixBase<Rhs> &rhs) const {
103+
typename Rhs::PlainObject out = rhs;
104+
solveInPlace(out);
105+
return out;
106+
}
107+
100108
inline DView vectorD() const {
101109
return dense_linalg::util::diagonal(m_ldlt.ld_col());
102110
}

0 commit comments

Comments
 (0)