proxsuite-nlp  0.10.0
A primal-dual augmented Lagrangian-type solver for nonlinear programming on manifolds.
Loading...
Searching...
No Matches
block-ldlt.hpp
Go to the documentation of this file.
1
6#pragma once
7
10
12
13#include <numeric>
14
15namespace proxsuite {
16namespace nlp {
17namespace linalg {
18
19namespace backend {
20
22template <typename Scalar> struct block_impl {
24 MatrixRef mat;
27 bool ldlt_in_place_impl(SignMatrix &sign) {
29 assert(false && "Block structure was not analyzed yet.");
30 return false;
31 }
32 const isize nblocks = sym_structure.nsegments();
33 const isize n = mat.rows();
34 if ((nblocks == 0) || (n <= 1)) {
35 return true;
36 }
37
38 const isize bs = sym_structure.segment_lens[0];
39 const isize rem = n - bs;
40 MatrixRef l00 = mat.block(0, 0, bs, bs);
41 MatrixRef l11 = mat.block(bs, bs, rem, rem);
42 const auto d0 = l00.diagonal();
43 const auto d0_inv = d0.asDiagonal().inverse();
44
45 MatrixRef work_tr = mat.block(0, bs, bs, rem);
46 Eigen::Transpose<MatrixRef> work = work_tr.transpose();
47
48 switch (sym_structure(0, 0)) {
49 case Zero:
50 case TriU:
51 case Dense:
52 return false;
53
54 case TriL: {
55 // compute l00
57
58 isize offset = bs;
59
60 for (isize i = 1; i < nblocks; ++i) {
61 const isize bsi = sym_structure.segment_lens[i];
62 MatrixRef li0 = mat.block(offset, 0, bsi, bs);
63 Eigen::Block<decltype(work)> li0_copy =
64 work.block(offset - bs, 0, bsi, bs);
65
66 switch (sym_structure(i, 0)) {
67 case TriL:
68 return false;
69 case TriU: {
70 auto li0_u = li0.template triangularView<Eigen::Upper>();
71 // PERF: replace li0.T by li0_tl
72 // auto li0_tl = li0.transpose().template
73 // triangularView<Eigen::Lower>();
74 l00.template triangularView<Eigen::UnitLower>().solveInPlace(
75 li0.transpose());
76 li0_copy.template triangularView<Eigen::Upper>() = li0_u;
77 li0_u = li0 * d0_inv;
78 break;
79 }
81 case Diag:
82 case Dense: {
83 l00.template triangularView<Eigen::UnitLower>().solveInPlace(
84 li0.transpose());
85 li0_copy = li0;
86 li0 = li0 * d0_inv;
87 break;
88 }
89 case Zero:
90 break;
91 }
92 offset += bsi;
93 }
94
95 break;
96 }
97 case Diag: {
98 // l00 is unchanged
99 for (isize k = 0; k < bs; k++) {
100 update_sign_matrix(sign, l00(k, k));
101 }
102 isize offset = bs;
103
104 for (isize i = 1; i < nblocks; ++i) {
105 const isize bsi = sym_structure.segment_lens[i];
106 MatrixRef li0 = mat.block(offset, 0, bsi, bs);
107 Eigen::Block<decltype(work)> li0_copy =
108 work.block(offset - bs, 0, bsi, bs);
109
110 switch (sym_structure(i, 0)) {
111 case TriL:
112 return false;
113 case Diag: {
114 auto li0_d = li0.diagonal();
115 li0_copy.diagonal() = li0_d;
116 li0_d = li0_d.cwiseQuotient(d0);
117 break;
118 }
119 case TriU: {
120 auto li0_u = li0.template triangularView<Eigen::Upper>();
121 li0_copy.template triangularView<Eigen::Upper>() = li0_u;
122 li0_u = li0 * d0_inv;
123 break;
124 }
125 case Dense: {
126 li0_copy = li0;
127 li0 = li0 * d0_inv;
128 break;
129 }
130 case Zero:
131 break;
132 }
133 offset += bsi;
134 }
135
136 break;
137 }
138 }
139
140 isize offset_i = bs;
141 for (isize i = 1; i < nblocks; ++i) {
142 const isize bsi = sym_structure.segment_lens[i];
143 Eigen::Block<MatrixRef> li0 = mat.block(offset_i, 0, bsi, bs);
144 Eigen::Block<decltype(work)> li0_prev =
145 work.block(offset_i - bs, 0, bsi, bs);
146
148 Eigen::Block<MatrixRef> target_ii =
149 mat.block(offset_i, offset_i, bsi, bsi);
150
151 // target_ii -= li0 * li0_prev.T;
153 backend::gemmt(target_ii, li0, li0_prev, sym_structure(i, 0),
154 sym_structure(i, 0), Scalar(-1));
155
156 isize offset_j = offset_i + bsi;
157 for (isize j = i + 1; j < nblocks; ++j) {
158 // target_ji -= lj0 * li0_prev.T;
159
160 const isize bsj = sym_structure.segment_lens[j];
161 Eigen::Block<MatrixRef> lj0 = mat.block(offset_j, 0, bsj, bs);
162 Eigen::Block<MatrixRef> target_ji =
163 mat.block(offset_j, offset_i, bsj, bsi);
164
165 backend::gemmt(target_ji, lj0, li0_prev, sym_structure(j, 0),
166 sym_structure(i, 0), Scalar(-1));
167
168 offset_j += bsj;
169 }
170
171 offset_i += bsi;
172 }
173
174 return block_impl{
175 l11,
176 sym_structure.submatrix(1, nblocks - 1),
177 }
178 .ldlt_in_place_impl(sign);
179 }
180};
181
182} // namespace backend
183
197template <typename _Scalar> struct BlockLDLT : ldlt_base<_Scalar> {
198 using Scalar = _Scalar;
201 using DView = typename Base::DView;
202 using Traits = LDLT_Traits<MatrixXs, Eigen::Lower>;
204 Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, isize>;
205 using PermIdxType = Eigen::Matrix<isize, Eigen::Dynamic, 1>;
207 using BlockTriU =
208 TriangularBlockMatrix<const typename MatrixXs::AdjointReturnType,
209 Eigen::UnitUpper>;
210
211protected:
212 MatrixXs m_matrix;
216 using Base::m_info;
217 using Base::m_sign;
218 std::vector<isize> m_perm;
219 std::vector<isize> m_perm_inv;
220 std::vector<isize> m_iwork;
221 std::vector<isize> m_start_idx;
222
224
225public:
229 : Base(), m_matrix(size, size), m_structure(structure.copy()),
232 std::iota(m_perm.begin(), m_perm.end(), isize(0));
233 m_permutation.setIdentity();
235 }
236
237 BlockLDLT(BlockLDLT const &other)
238 : BlockLDLT(other.m_matrix.rows(), other.m_structure) {
239 m_matrix = other.m_matrix;
241 m_info = other.m_info;
242 m_perm = other.m_perm;
243 m_perm_inv = other.m_perm_inv;
244 m_iwork = other.m_iwork;
245 m_start_idx = other.m_start_idx;
246 }
247
250 m_start_idx[0] = 0;
251 for (usize i = 0; i < nblocks() - 1; ++i) {
252 m_start_idx[i + 1] = m_start_idx[i] + in.segment_lens[i];
253 }
254 }
255
257 delete[] m_structure.m_data;
258 delete[] m_structure.segment_lens;
259 delete[] m_struct_tr.m_data;
260 delete[] m_struct_tr.segment_lens;
261 m_structure.m_data = nullptr;
262 m_structure.segment_lens = nullptr;
263 }
264
266 inline const SymbolicBlockMatrix &structure() const { return m_structure; }
268
270 inline bool analyzePattern();
271
273
275 void setBlockPermutation(isize const *new_perm = nullptr);
276
277 auto blockPermIndices() -> std::vector<isize> & { return m_perm; }
278
282
283 inline const PermutationType &permutationP() const { return m_permutation; }
284
285 MatrixXs reconstructedMatrix() const override;
286
287 inline typename Traits::MatrixL matrixL() const {
288 return Traits::getL(m_matrix);
289 }
290
291 inline typename Traits::MatrixU matrixU() const {
292 return Traits::getU(m_matrix);
293 }
294
295 inline DView vectorD() const override {
297 }
298
300 template <typename Derived>
301 bool solveInPlace(Eigen::MatrixBase<Derived> &b) const;
302
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
310 const MatrixXs &matrixLDLT() const override { return m_matrix; }
311
312 inline void compute() {
313 m_info =
315 m_sign)
316 ? Eigen::Success
317 : Eigen::NumericalIssue;
318 }
319
322 BlockLDLT &compute(const ConstMatrixRef &mat) override {
323 assert(mat.rows() == mat.cols());
324 m_matrix.conservativeResizeLike(mat);
325 auto mat_coeff = [&](isize i, isize j) {
326 return i >= j ? mat(i, j) : mat(j, i);
327 };
328 auto n = mat.rows();
329 auto indices = permutationP().indices();
330 // by column
331 for (isize j = 0; j < n; ++j) {
332 auto pj = indices[j];
333 // by line starting at j
334 for (isize i = j; i < n; ++i) {
335 m_matrix(i, j) = mat_coeff(indices[i], pj);
336 }
337 }
338 // m_matrix.noalias() = permutationP() * m_matrix;
339 // m_matrix.noalias() = m_matrix * permutationP().transpose();
340 // do not re-run analysis
341 compute();
342
343 return *this;
344 }
345};
346
347} // namespace linalg
348} // namespace nlp
349} // namespace proxsuite
350
351#include "./block-ldlt.hxx"
352
353#ifdef PROXSUITE_NLP_ENABLE_TEMPLATE_INSTANTIATION
354#include "./block-ldlt.txx"
355#endif
Routines for Cholesky factorization.
#define PROXSUITE_NLP_DYNAMIC_TYPEDEFS(Scalar)
Definition math.hpp:26
void gemmt(Eigen::MatrixBase< DstDerived > &dst, Eigen::MatrixBase< LhsDerived > const &lhs, Eigen::MatrixBase< RhsDerived > const &rhs, BlockKind lhs_kind, BlockKind rhs_kind, Scalar alpha)
Definition gemmt.hpp:211
bool dense_ldlt_in_place(Eigen::MatrixBase< Derived > &a, SignMatrix &sign)
Definition dense.hpp:94
void update_sign_matrix(SignMatrix &sign, const Scalar &akk)
Definition dense.hpp:19
std::make_unsigned< isize >::type usize
PROXSUITE_NLP_DLLAPI void print_sparsity_pattern(const SymbolicBlockMatrix &smat) noexcept
@ Dense
There is no known prior structure; assume a dense block.
@ Diag
The block is diagonal.
@ Zero
All entries in the block are zero.
@ TriL
The block is lower-triangular.
@ TriU
The block is upper-triangular.
Main package namespace.
Definition bcl-params.hpp:5
Block sparsity-aware LDLT factorization algorithm.
Eigen::ComputationInfo m_info
Definition ldlt-base.hpp:48
BlockLDLT & compute(const ConstMatrixRef &mat) override
Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic, isize > PermutationType
Eigen::Matrix< isize, Eigen::Dynamic, 1 > PermIdxType
std::vector< isize > m_start_idx
BlockLDLT(BlockLDLT const &other)
Traits::MatrixL matrixL() const
void setBlockPermutation(isize const *new_perm=nullptr)
Calls updateBlockPermutationMatrix.
const PermutationType & permutationP() const
bool solveInPlace(Eigen::MatrixBase< Derived > &b) const
Solve for the right-hand side in-place.
BlockLDLT(isize size, SymbolicBlockMatrix const &structure)
The constructor copies the input matrix.
const SymbolicBlockMatrix & structure() const
BlockLDLT & findSparsifyingPermutation()
Find a sparsity-maximizing permutation of the blocks. This will also compute the symbolic factorizati...
Traits::MatrixU matrixU() const
BlockLDLT & updateBlockPermutationMatrix(SymbolicBlockMatrix const &in)
DView vectorD() const override
std::vector< isize > m_perm_inv
void computeStartIndices(const SymbolicBlockMatrix &in)
Compute indices indicating where blocks start.
auto blockPermIndices() -> std::vector< isize > &
bool analyzePattern()
Analyze and factorize the block structure, if not done already.
Rhs::PlainObject solve(const Eigen::MatrixBase< Rhs > &rhs) const
MatrixXs reconstructedMatrix() const override
LDLT_Traits< MatrixXs, Eigen::Lower > Traits
const MatrixXs & matrixLDLT() const override
Symbolic representation of the sparsity structure of a (square) block matrix.
SymbolicBlockMatrix transpose() const
SymbolicBlockMatrix submatrix(isize i, isize n) noexcept
Representation for triangular block matrices.
Implementation struct for the recursive block LDLT algorithm.
Base interface for LDLT solvers.
Definition ldlt-base.hpp:24
Eigen::ComputationInfo m_info
Definition ldlt-base.hpp:48
Eigen::Map< const VectorXs, Eigen::Unaligned, Eigen::InnerStride< Eigen::Dynamic > > DView
Definition ldlt-base.hpp:26
static DView diag_view_impl(Mat &&mat)
Definition ldlt-base.hpp:29