Sleipnir C++ API
Loading...
Searching...
No Matches
kkt_error.hpp
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <algorithm>
6
7#include <Eigen/Core>
8#include <Eigen/SparseCore>
9
10// See docs/algorithms.md#Works_cited for citation definitions
11
12namespace slp {
13
15enum class KKTErrorType {
17 INF_NORM_SCALED,
19 ONE_NORM
20};
21
27template <typename Scalar, KKTErrorType T>
28Scalar kkt_error(const Eigen::Vector<Scalar, Eigen::Dynamic>& g) {
29 // The KKT conditions from docs/algorithms.md:
30 //
31 // ∇f = 0
32
33 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
34 return g.template lpNorm<Eigen::Infinity>();
35 } else if constexpr (T == KKTErrorType::ONE_NORM) {
36 return g.template lpNorm<1>();
37 }
38}
39
50template <typename Scalar, KKTErrorType T>
51Scalar kkt_error(const Eigen::Vector<Scalar, Eigen::Dynamic>& g,
52 const Eigen::SparseMatrix<Scalar>& A_e,
53 const Eigen::Vector<Scalar, Eigen::Dynamic>& c_e,
54 const Eigen::Vector<Scalar, Eigen::Dynamic>& y) {
55 // The KKT conditions from docs/algorithms.md:
56 //
57 // ∇f − Aₑᵀy = 0
58 // cₑ = 0
59
60 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
61 // See equation (5) of [2].
62
63 // s_d = max(sₘₐₓ, ‖y‖₁ / m) / sₘₐₓ
64 constexpr Scalar s_max(100);
65 Scalar s_d =
66 std::max(s_max, y.template lpNorm<1>() / Scalar(y.rows())) / s_max;
67
68 // ‖∇f − Aₑᵀy‖_∞ / s_d
69 // ‖cₑ‖_∞
70 return std::max(
71 {(g - A_e.transpose() * y).template lpNorm<Eigen::Infinity>() / s_d,
72 c_e.template lpNorm<Eigen::Infinity>()});
73 } else if constexpr (T == KKTErrorType::ONE_NORM) {
74 return (g - A_e.transpose() * y).template lpNorm<1>() +
75 c_e.template lpNorm<1>();
76 }
77}
78
96template <typename Scalar, KKTErrorType T>
97Scalar kkt_error(const Eigen::Vector<Scalar, Eigen::Dynamic>& g,
98 const Eigen::SparseMatrix<Scalar>& A_e,
99 const Eigen::Vector<Scalar, Eigen::Dynamic>& c_e,
100 const Eigen::SparseMatrix<Scalar>& A_i,
101 const Eigen::Vector<Scalar, Eigen::Dynamic>& c_i,
102 const Eigen::Vector<Scalar, Eigen::Dynamic>& s,
103 const Eigen::Vector<Scalar, Eigen::Dynamic>& y,
104 const Eigen::Vector<Scalar, Eigen::Dynamic>& z, Scalar μ) {
105 // The KKT conditions from docs/algorithms.md:
106 //
107 // ∇f − Aₑᵀy − Aᵢᵀz = 0
108 // Sz − μe = 0
109 // cₑ = 0
110 // cᵢ − s = 0
111
112 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
113 // See equation (5) of [2].
114
115 // s_d = max(sₘₐₓ, (‖y‖₁ + ‖z‖₁) / (m + n)) / sₘₐₓ
116 constexpr Scalar s_max(100);
117 Scalar s_d =
118 std::max(s_max, (y.template lpNorm<1>() + z.template lpNorm<1>()) /
119 Scalar(y.rows() + z.rows())) /
120 s_max;
121
122 // s_c = max(sₘₐₓ, ‖z‖₁ / n) / sₘₐₓ
123 Scalar s_c =
124 std::max(s_max, z.template lpNorm<1>() / Scalar(z.rows())) / s_max;
125
126 const auto S = s.asDiagonal();
127 const Eigen::Vector<Scalar, Eigen::Dynamic> μe =
128 Eigen::Vector<Scalar, Eigen::Dynamic>::Constant(s.rows(), μ);
129
130 // ‖∇f − Aₑᵀy − Aᵢᵀz‖_∞ / s_d
131 // ‖Sz − μe‖_∞ / s_c
132 // ‖cₑ‖_∞
133 // ‖cᵢ − s‖_∞
134 return std::max({(g - A_e.transpose() * y - A_i.transpose() * z)
135 .template lpNorm<Eigen::Infinity>() /
136 s_d,
137 (S * z - μe).template lpNorm<Eigen::Infinity>() / s_c,
138 c_e.template lpNorm<Eigen::Infinity>(),
139 (c_i - s).template lpNorm<Eigen::Infinity>()});
140 } else if constexpr (T == KKTErrorType::ONE_NORM) {
141 const auto S = s.asDiagonal();
142 const Eigen::Vector<Scalar, Eigen::Dynamic> μe =
143 Eigen::Vector<Scalar, Eigen::Dynamic>::Constant(s.rows(), μ);
144
145 return (g - A_e.transpose() * y - A_i.transpose() * z)
146 .template lpNorm<1>() +
147 (S * z - μe).template lpNorm<1>() + c_e.template lpNorm<1>() +
148 (c_i - s).template lpNorm<1>();
149 }
150}
151
152} // namespace slp