proxsuite-nlp  0.10.0
A primal-dual augmented Lagrangian-type solver for nonlinear programming on manifolds.
Loading...
Searching...
No Matches
ldlt-allocator.hpp
Go to the documentation of this file.
1
5#pragma once
6
9#ifdef PROXSUITE_NLP_USE_PROXSUITE_LDLT
11#endif
12#include <boost/variant.hpp>
13#include <array>
14
15namespace proxsuite {
16namespace nlp {
17
18namespace {
19using linalg::isize;
20} // namespace
21
22enum class LDLTChoice {
24 DENSE,
30 EIGEN,
33};
34
35template <typename Scalar,
36 class MatrixType = typename math_types<Scalar>::MatrixXs>
38 boost::variant<linalg::DenseLDLT<Scalar>, linalg::BlockLDLT<Scalar>,
39 Eigen::LDLT<MatrixType>, Eigen::BunchKaufman<MatrixType>
40#ifdef PROXSUITE_NLP_USE_PROXSUITE_LDLT
41 ,
43#endif
44 >;
45
47create_default_block_structure(const std::vector<isize> &dims_primal,
48 const std::vector<isize> &dims_dual) {
49
51
52 isize nprim_blocks = (isize)dims_primal.size();
53 isize ndual_blocks = (isize)dims_dual.size();
54 isize nblocks = nprim_blocks + ndual_blocks;
55
56 linalg::SymbolicBlockMatrix structure(nblocks, nblocks);
57 isize *segment_lens = structure.segment_lens;
58
59 for (unsigned int i = 0; i < nprim_blocks; ++i) {
60 segment_lens[i] = dims_primal[i];
61 }
62 for (unsigned int i = 0; i < ndual_blocks; ++i) {
63 segment_lens[i + nprim_blocks] = dims_dual[i];
64 }
65
66 // default structure: primal blocks are dense, others are sparse
67
68 for (isize i = 0; i < nprim_blocks; ++i) {
69 for (isize j = 0; j < nprim_blocks; ++j) {
70 structure(i, j) = linalg::Dense;
71 }
72 }
73
74 // jacobian blocks: assumed dense
75 for (isize i = 0; i < nprim_blocks; ++i) {
76 for (isize j = nprim_blocks; j < nblocks; ++j) {
77 structure(i, j) = linalg::Dense;
78 structure(j, i) = linalg::Dense;
79 }
80 }
81
82 for (isize i = nprim_blocks; i < nblocks; ++i) {
83 // diagonal blocks are diagonal
84 structure(i, i) = linalg::Diag;
85
86 // off-diagonal blocks are zero
87 for (isize j = nprim_blocks; j < nblocks; ++j) {
88 if (i != j)
89 structure(i, j) = linalg::Zero;
90 }
91 }
92 return structure;
93}
94
95inline isize get_total_dim_helper(const std::vector<isize> &nprims,
96 const std::vector<isize> &nduals) {
97 return std::accumulate(nprims.begin(), nprims.end(), 0) +
98 std::accumulate(nduals.begin(), nduals.end(), 0);
99}
100
101template <typename Scalar>
102LDLTVariant<Scalar> allocate_ldlt_from_sizes(const std::vector<isize> &nprims,
103 const std::vector<isize> &nduals,
104 LDLTChoice choice) {
105 const isize size = get_total_dim_helper(nprims, nduals);
106 using MatrixXs = typename math_types<Scalar>::MatrixXs;
107
108 switch (choice) {
110 return linalg::DenseLDLT<Scalar>(size);
114 auto structure = create_default_block_structure(nprims, nduals);
115
116 linalg::BlockLDLT<Scalar> block_ldlt(size, structure);
117 block_ldlt.findSparsifyingPermutation();
118 return block_ldlt;
119 }
121 return Eigen::LDLT<MatrixXs>(size);
123#ifdef PROXSUITE_NLP_USE_PROXSUITE_LDLT
124 return linalg::ProxSuiteLDLTWrapper<Scalar>(size, size);
125#else
126 default:
128 "ProxSuite support is not enabled. You should recompile ProxNLP with "
129 "the BUILD_WITH_PROXSUITE_SUPPORT flag.");
130#endif
131 }
132}
133
134namespace internal {
135
137template <typename MatrixType, typename Signature, int UpLo>
138void bunch_kaufman_compute_signature(
139 Eigen::BunchKaufman<MatrixType, UpLo> const &factor, Signature &signature) {
140 using Eigen::Index;
141 using Scalar = typename MatrixType::Scalar;
142 using Real = typename Eigen::NumTraits<Scalar>::Real;
143
144 Index n = factor.rows();
145 signature.conservativeResize(n);
146
147 Index k = 0;
148 const MatrixType &a = factor.matrixLDLT();
149
150 while (k < n) {
151 Index p = factor.pivots()[k];
152 if (p < 0) {
153 // 2x2 block
154 Real ak = Eigen::numext::real(a(k, k));
155 Real akp1 = Eigen::numext::real(a(k + 1, k + 1));
156 Scalar akp1k = factor.subdiag()[k];
157 Real tr = ak + akp1;
158 Real det = ak * akp1 - Eigen::numext::abs2(akp1k);
159
160 if (std::abs(det) <= std::numeric_limits<Scalar>::epsilon()) {
161 signature[k] = 0;
162 signature[k + 1] = int(math::sign(tr));
163 } else if (det > Scalar(0)) {
164 signature[k] = int(math::sign(tr));
165 signature[k + 1] = signature[k];
166 } else {
167 // det < 0
168 signature[k] = -1;
169 signature[k + 1] = +1;
170 }
171
172 k += 2;
173 } else {
174 Real ak = Eigen::numext::real(a(k, k));
175 signature[k] = int(math::sign(ak));
176 k += 1;
177 }
178 }
179}
180
181} // namespace internal
182
184 template <typename Fac> void operator()(const Fac &facto) const {
185 auto sign = facto.vectorD().cwiseSign();
186 signature = sign.template cast<int>();
187 }
188
189 template <typename MatType>
190 void operator()(const Eigen::BunchKaufman<MatType> &facto) const {
191 internal::bunch_kaufman_compute_signature(facto, signature);
192 }
193 Eigen::VectorXi &signature;
194};
195
196inline std::array<int, 3>
197computeInertiaTuple(const Eigen::Ref<Eigen::VectorXi const> &signature) {
198 using Eigen::Index;
199 Index n = signature.size();
200 int np = 0;
201 int n0 = 0;
202 int nn = 0;
203 for (Index i = 0; i < n; i++) {
204 switch (signature(i)) {
205 case 1:
206 np++;
207 break;
208 case 0:
209 n0++;
210 break;
211 case -1:
212 nn++;
213 break;
214 default:
216 "Signature vector should only contain values O, 1, -1.");
217 break;
218 }
219 }
220 return {np, nn, n0};
221}
222
223} // namespace nlp
224} // namespace proxsuite
Routines for block-sparse matrix LDLT factorisation.
#define PROXSUITE_NLP_RUNTIME_ERROR(msg)
Definition exceptions.hpp:8
BlockKind
Kind of matrix block: zeros, diagonal, lower/upper triangular or dense.
@ Dense
There is no known prior structure; assume a dense block.
@ Diag
The block is diagonal.
@ Zero
All entries in the block are zero.
T sign(const T &x)
Definition math.hpp:95
LDLTVariant< Scalar > allocate_ldlt_from_sizes(const std::vector< isize > &nprims, const std::vector< isize > &nduals, LDLTChoice choice)
boost::variant< linalg::DenseLDLT< Scalar >, linalg::BlockLDLT< Scalar >, Eigen::LDLT< MatrixType >, Eigen::BunchKaufman< MatrixType > > LDLTVariant
isize get_total_dim_helper(const std::vector< isize > &nprims, const std::vector< isize > &nduals)
std::array< int, 3 > computeInertiaTuple(const Eigen::Ref< Eigen::VectorXi const > &signature)
@ DENSE
Use our dense LDLT.
@ BLOCKSPARSE
Use blocked LDLT.
@ PROXSUITE
Use Proxsuite's LDLT.
@ EIGEN
Use Eigen's implementation.
@ BUNCHKAUFMAN
Use Bunch-Kaufman factorization.
linalg::SymbolicBlockMatrix create_default_block_structure(const std::vector< isize > &dims_primal, const std::vector< isize > &dims_dual)
Main package namespace.
Definition bcl-params.hpp:5
const MatrixType & matrixLDLT() const
const IndicesType & pivots() const
const VecType & subdiag() const
EIGEN_DEVICE_FUNC Index rows() const EIGEN_NOEXCEPT
void operator()(const Eigen::BunchKaufman< MatType > &facto) const
void operator()(const Fac &facto) const
Block sparsity-aware LDLT factorization algorithm.
BlockLDLT & findSparsifyingPermutation()
Find a sparsity-maximizing permutation of the blocks. This will also compute the symbolic factorizati...
A fast, recursive divide-and-conquer LDLT algorithm.
Definition dense.hpp:164
Symbolic representation of the sparsity structure of a (square) block matrix.
Typedefs for math (Eigen vectors, matrices) depending on scalar type.
Definition math.hpp:43