9#include <Eigen/SparseCholesky>
10#include <Eigen/SparseCore>
12#include "sleipnir/optimization/solver/util/inertia.hpp"
21template <
typename Scalar>
36 : m_num_decision_variables{num_decision_variables},
37 m_num_equality_constraints{num_equality_constraints} {}
48 : m_num_decision_variables{num_decision_variables},
49 m_num_equality_constraints{num_equality_constraints},
55 Eigen::ComputationInfo
info()
const {
return m_info; }
67 m_lhs = lhs + regularization(Scalar(0), Scalar(0));
69 if (!m_analyzed_pattern) {
70 m_solver.analyzePattern(m_lhs);
71 m_analyzed_pattern =
true;
77 if (m_prev_δ == Scalar(0) || m_prev_δ > Scalar(1e-2)) {
78 m_solver.factorize(m_lhs);
79 m_info = m_solver.info();
81 if (m_info == Eigen::Success) {
84 if (inertia() == ideal_inertia &&
85 (m_solver.vectorD().cwiseAbs().array() >= Scalar(1e-4)).all()) {
97 constexpr Scalar δ_min(1e-10);
101 constexpr Scalar γ_max(1e-8);
104 constexpr Scalar γ_initial(1e-10);
111 Scalar δ = m_prev_δ == Scalar(0) ? Scalar(1e-4)
112 : std::max(m_prev_δ / Scalar(2), δ_min);
119 m_lhs = lhs + regularization(δ, γ);
120 m_solver.factorize(m_lhs);
121 m_info = m_solver.info();
123 if (m_info == Eigen::Success) {
124 Inertia inertia = this->inertia();
126 if (inertia == ideal_inertia) {
131 }
else if (inertia.
zero > 0) {
132 if (γ == Scalar(0)) {
140 γ = std::min(γ * Scalar(10), γ_max);
155 if (γ < γ_max && !smallest_pivot_is_hessian()) {
156 γ = γ == Scalar(0) ? γ_initial : std::min(γ * Scalar(10), γ_max);
165 γ = γ == Scalar(0) ? γ_initial : std::min(γ * Scalar(10), γ_max);
170 if (δ > Scalar(1e20) || γ > Scalar(1e20)) {
171 m_info = Eigen::NumericalIssue;
183 template <
typename Rhs>
190 constexpr int max_refinement_steps = 3;
191 for (
int i = 0; i < max_refinement_steps; ++i) {
192 DenseVector r = rhs - m_lhs.template selfadjointView<Eigen::Lower>() * x;
193 if (r.norm() <= Scalar(1e-12) * rhs.norm()) {
196 x += m_solver.solve(r);
206 template <
typename Rhs>
208 return solve(rhs.toDense());
222 using Solver = Eigen::SimplicialLDLT<SparseMatrix>;
225 bool m_analyzed_pattern =
false;
230 Eigen::ComputationInfo m_info = Eigen::Success;
233 int m_num_decision_variables = 0;
236 int m_num_equality_constraints = 0;
239 Scalar m_γ_min{1e-10};
242 Inertia ideal_inertia{m_num_decision_variables, m_num_equality_constraints,
258 Inertia inertia()
const {
259 constexpr Scalar ε = std::numeric_limits<Scalar>::epsilon();
262 for (
const auto& d : m_solver.vectorD()) {
279 bool smallest_pivot_is_hessian()
const {
281 m_solver.vectorD().cwiseAbs().minCoeff(&k);
284 return m_solver.permutationPinv().indices()(k) < m_num_decision_variables;
296 DenseVector vec{m_num_decision_variables + m_num_equality_constraints};
297 vec.segment(0, m_num_decision_variables).setConstant(δ);
298 vec.segment(m_num_decision_variables, m_num_equality_constraints)
Definition inertia.hpp:11
int zero
The number of zero eigenvalues.
Definition inertia.hpp:18
int positive
The number of positive eigenvalues.
Definition inertia.hpp:14
int negative
The number of negative eigenvalues.
Definition inertia.hpp:16
Definition sparse_kkt_solver.hpp:22
Scalar constraint_jacobian_regularization() const
Definition sparse_kkt_solver.hpp:219
SparseKKTSolver(int num_decision_variables, int num_equality_constraints, Scalar γ_min)
Definition sparse_kkt_solver.hpp:46
SparseKKTSolver(int num_decision_variables, int num_equality_constraints)
Definition sparse_kkt_solver.hpp:35
Eigen::VectorX< Scalar > DenseVector
Type alias for dense vector.
Definition sparse_kkt_solver.hpp:25
DenseVector solve(const Eigen::MatrixBase< Rhs > &rhs) const
Definition sparse_kkt_solver.hpp:184
Scalar hessian_regularization() const
Definition sparse_kkt_solver.hpp:214
Eigen::ComputationInfo info() const
Definition sparse_kkt_solver.hpp:55
Eigen::SparseMatrix< Scalar > SparseMatrix
Type alias for sparse matrix.
Definition sparse_kkt_solver.hpp:27
DenseVector solve(const Eigen::SparseMatrixBase< Rhs > &rhs) const
Definition sparse_kkt_solver.hpp:207
SparseKKTSolver & compute(const SparseMatrix &lhs)
Definition sparse_kkt_solver.hpp:64