10#include <Eigen/SparseCore>
12#include "sleipnir/optimization/solver/util/problem_scaling.hpp"
19enum class KKTErrorType {
31template <
typename Scalar, KKTErrorType T>
32Scalar kkt_error(
const Eigen::VectorX<Scalar>& g) {
37 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
38 return g.template lpNorm<Eigen::Infinity>();
39 }
else if constexpr (T == KKTErrorType::ONE_NORM) {
40 return g.template lpNorm<1>();
53template <
typename Scalar, KKTErrorType T>
54Scalar kkt_error(
const Eigen::VectorX<Scalar>& g,
55 const Eigen::SparseMatrix<Scalar>& A_e,
56 const Eigen::VectorX<Scalar>& c_e,
57 const Eigen::VectorX<Scalar>& y, Scalar tolerance) {
65 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
66 constexpr Scalar ε = std::numeric_limits<Scalar>::epsilon();
84 const Scalar ω = (g.cwiseAbs() + A_e.cwiseAbs().transpose() * y.cwiseAbs())
85 .
template lpNorm<Eigen::Infinity>();
87 Scalar s_d = std::max(Scalar(1), pow(ε, Scalar(0.625)) * ω / tolerance);
92 {(g - A_e.transpose() * y).template lpNorm<Eigen::Infinity>() / s_d,
93 c_e.template lpNorm<Eigen::Infinity>()});
94 }
else if constexpr (T == KKTErrorType::ONE_NORM) {
95 return (g - A_e.transpose() * y).
template lpNorm<1>() +
96 c_e.template lpNorm<1>();
114template <
typename Scalar, KKTErrorType T>
115Scalar kkt_error(
const Eigen::VectorX<Scalar>& g,
116 const Eigen::SparseMatrix<Scalar>& A_e,
117 const Eigen::VectorX<Scalar>& c_e,
118 const Eigen::SparseMatrix<Scalar>& A_i,
119 const Eigen::VectorX<Scalar>& c_i,
120 const Eigen::VectorX<Scalar>& s,
121 const Eigen::VectorX<Scalar>& y,
122 const Eigen::VectorX<Scalar>& z, Scalar μ, Scalar tolerance) {
132 if constexpr (T == KKTErrorType::INF_NORM_SCALED) {
133 constexpr Scalar ε = std::numeric_limits<Scalar>::epsilon();
151 const Scalar ω = (g.cwiseAbs() + A_e.cwiseAbs().transpose() * y.cwiseAbs() +
152 A_i.cwiseAbs().transpose() * z.cwiseAbs())
153 .
template lpNorm<Eigen::Infinity>();
155 Scalar s_d = std::max(Scalar(1), pow(ε, Scalar(0.625)) * ω / tolerance);
160 constexpr Scalar s_max(100);
162 std::max(s_max, z.template lpNorm<1>() / Scalar(z.rows())) / s_max;
164 const auto S = s.asDiagonal();
165 const Eigen::VectorX<Scalar> μe =
166 Eigen::VectorX<Scalar>::Constant(s.rows(), μ);
172 return std::max({(g - A_e.transpose() * y - A_i.transpose() * z)
173 .template lpNorm<Eigen::Infinity>() /
175 (S * z - μe).
template lpNorm<Eigen::Infinity>() / s_c,
176 c_e.template lpNorm<Eigen::Infinity>(),
177 (c_i - s).
template lpNorm<Eigen::Infinity>()});
178 }
else if constexpr (T == KKTErrorType::ONE_NORM) {
179 const auto S = s.asDiagonal();
180 const Eigen::VectorX<Scalar> μe =
181 Eigen::VectorX<Scalar>::Constant(s.rows(), μ);
183 return (g - A_e.transpose() * y - A_i.transpose() * z)
184 .template lpNorm<1>() +
185 (S * z - μe).
template lpNorm<1>() + c_e.template lpNorm<1>() +
186 (c_i - s).
template lpNorm<1>();
196template <
typename Scalar, KKTErrorType T>
197Scalar unscaled_kkt_error(
const ProblemScaling<Scalar>& scaling,
198 const Eigen::VectorX<Scalar>& g) {
199 using DenseVector = Eigen::VectorX<Scalar>;
201 if (scaling.is_identity()) {
202 return kkt_error<Scalar, T>(g);
205 const DenseVector g_unscaled = (Scalar(1) / scaling.f) * g;
207 return kkt_error<Scalar, T>(g_unscaled);
220template <
typename Scalar, KKTErrorType T>
221Scalar unscaled_kkt_error(
const ProblemScaling<Scalar>& scaling,
222 const Eigen::VectorX<Scalar>& g,
223 const Eigen::SparseMatrix<Scalar>& A_e,
224 const Eigen::VectorX<Scalar>& c_e,
225 const Eigen::VectorX<Scalar>& y, Scalar tolerance) {
226 using DenseVector = Eigen::VectorX<Scalar>;
227 using SparseMatrix = Eigen::SparseMatrix<Scalar>;
229 if (scaling.is_identity()) {
230 return kkt_error<Scalar, T>(g, A_e, c_e, y, tolerance);
233 const Scalar inv_d_f = Scalar(1) / scaling.f;
234 const DenseVector inv_d_c_e = scaling.c_e.cwiseInverse();
236 const DenseVector g_unscaled = inv_d_f * g;
237 const SparseMatrix A_e_unscaled = inv_d_c_e.asDiagonal() * A_e;
238 const DenseVector c_e_unscaled = inv_d_c_e.cwiseProduct(c_e);
239 const DenseVector y_unscaled = scaling.c_e.cwiseProduct(y) * inv_d_f;
241 return kkt_error<Scalar, T>(g_unscaled, A_e_unscaled, c_e_unscaled,
242 y_unscaled, tolerance);
260template <
typename Scalar, KKTErrorType T>
261Scalar unscaled_kkt_error(
262 const ProblemScaling<Scalar>& scaling,
const Eigen::VectorX<Scalar>& g,
263 const Eigen::SparseMatrix<Scalar>& A_e,
const Eigen::VectorX<Scalar>& c_e,
264 const Eigen::SparseMatrix<Scalar>& A_i,
const Eigen::VectorX<Scalar>& c_i,
265 const Eigen::VectorX<Scalar>& s,
const Eigen::VectorX<Scalar>& y,
266 const Eigen::VectorX<Scalar>& z, Scalar μ, Scalar tolerance) {
267 using DenseVector = Eigen::VectorX<Scalar>;
268 using SparseMatrix = Eigen::SparseMatrix<Scalar>;
270 if (scaling.is_identity()) {
271 return kkt_error<Scalar, T>(g, A_e, c_e, A_i, c_i, s, y, z, μ, tolerance);
274 const Scalar inv_d_f = Scalar(1) / scaling.f;
275 const DenseVector inv_d_c_e = scaling.c_e.cwiseInverse();
276 const DenseVector inv_d_c_i = scaling.c_i.cwiseInverse();
278 const DenseVector g_unscaled = inv_d_f * g;
279 const SparseMatrix A_e_unscaled = inv_d_c_e.asDiagonal() * A_e;
280 const DenseVector c_e_unscaled = inv_d_c_e.cwiseProduct(c_e);
281 const SparseMatrix A_i_unscaled = inv_d_c_i.asDiagonal() * A_i;
282 const DenseVector c_i_unscaled = inv_d_c_i.cwiseProduct(c_i);
283 const DenseVector s_unscaled = inv_d_c_i.cwiseProduct(s);
284 const DenseVector y_unscaled = scaling.c_e.cwiseProduct(y) * inv_d_f;
285 const DenseVector z_unscaled = scaling.c_i.cwiseProduct(z) * inv_d_f;
286 const Scalar μ_unscaled = inv_d_f * μ;
288 return kkt_error<Scalar, T>(g_unscaled, A_e_unscaled, c_e_unscaled,
289 A_i_unscaled, c_i_unscaled, s_unscaled,
290 y_unscaled, z_unscaled, μ_unscaled, tolerance);