Skip to content

Commit 6fccbd5

Browse files
authored
Merge pull request #163 from jcarpent/devel
Fix computation of duality gap quantity
2 parents c67c3b9 + 5af8cc0 commit 6fccbd5

File tree

17 files changed

+204
-132
lines changed

17 files changed

+204
-132
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
BSD 2-Clause License
22

3-
Copyright (c) 2022, Inria
3+
Copyright (c) 2022-2023, Inria
44
All rights reserved.
55

66
Redistribution and use in source and binary forms, with or without

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<a href="https://anaconda.org/conda-forge/proxsuite"><img src="https://anaconda.org/conda-forge/proxsuite/badges/version.svg" alt="Conda version" height="20"></a>
1010
</p>
1111

12-
**ProxSuite** is a collection of open-source, numerically robust, precise and efficient numerical solvers (e.g., LPs, QPs, etc.) rooted in revisited primal-dual proximal algorithms.
12+
**ProxSuite** is a collection of open-source, numerically robust, precise and efficient numerical solvers (e.g., LPs, QPs, etc.) rooted in revisited primal-dual proximal algorithms.
1313
Through **ProxSuite**, we aim to offer the community scalable optimizers that can deal with dense, sparse or matrix-free problems. While the first targeted application is Robotics, **ProxSuite** can be used in other contexts without limits.
1414

1515
**ProxSuite** is actively developped and supported by the [Willow](https://www.di.ens.fr/willow/) and [Sierra](https://www.di.ens.fr/sierra/) research groups, joint research teams between [Inria](https://www.inria.fr/en), [École Normale Supérieure de Paris](https://www.ens.fr) and [Centre National de la Recherche Scientifique](https://www.cnrs.fr) localized in France.

bindings/python/src/expose-results.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2022 INRIA
2+
// Copyright (c) 2022-2023 INRIA
33
//
44
#include <proxsuite/proxqp/results.hpp>
55
#include <pybind11/pybind11.h>
@@ -39,6 +39,7 @@ exposeResults(pybind11::module_ m)
3939
.def_readwrite("run_time", &Info<T>::run_time)
4040
.def_readwrite("setup_time", &Info<T>::setup_time)
4141
.def_readwrite("solve_time", &Info<T>::solve_time)
42+
.def_readwrite("duality_gap", &Info<T>::duality_gap)
4243
.def_readwrite("pri_res", &Info<T>::pri_res)
4344
.def_readwrite("dua_res", &Info<T>::dua_res)
4445
.def_readwrite("objValue", &Info<T>::objValue)

include/proxsuite/helpers/common.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ auto
5656
negative_part(T const& expr)
5757
PROXSUITE_DEDUCE_RET((expr.array() < 0).select(expr, T::Zero(expr.rows())));
5858

59+
/// @brief \brief Select the components of the expression if the condition is
60+
/// fullfiled. Otherwise, set the component to value
61+
template<typename Condition, typename T, typename Scalar>
62+
auto
63+
select(Condition const& condition, T const& expr, const Scalar value)
64+
PROXSUITE_DEDUCE_RET((condition).select(expr,
65+
T::Constant(expr.rows(), value)));
66+
5967
} // helpers
6068
} // proxsuite
6169

include/proxsuite/proxqp/dense/solver.hpp

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,34 +1065,24 @@ qp_solve( //
10651065
<< std::endl;
10661066
std::cout << std::scientific << std::setw(2) << std::setprecision(2)
10671067
<< "| primal residual=" << qpresults.info.pri_res
1068-
<< "| dual residual=" << qpresults.info.dua_res
1069-
<< "| duality gap=" << qpresults.info.duality_gap
1070-
<< "| mu_in=" << qpresults.info.mu_in
1071-
<< "| rho=" << qpresults.info.rho << std::endl;
1068+
<< " | dual residual=" << qpresults.info.dua_res
1069+
<< " | duality gap=" << qpresults.info.duality_gap
1070+
<< " | mu_in=" << qpresults.info.mu_in
1071+
<< " | rho=" << qpresults.info.rho << std::endl;
10721072
ruiz.scale_primal_in_place(VectorViewMut<T>{ from_eigen, qpresults.x });
10731073
ruiz.scale_dual_in_place_eq(VectorViewMut<T>{ from_eigen, qpresults.y });
10741074
ruiz.scale_dual_in_place_in(VectorViewMut<T>{ from_eigen, qpresults.z });
10751075
}
1076-
if (is_primal_feasible) {
1077-
1078-
if (dual_feasibility_lhs >=
1079-
qpsettings.refactor_dual_feasibility_threshold &&
1080-
qpresults.info.rho != qpsettings.refactor_rho_threshold) {
1081-
1082-
T rho_new(qpsettings.refactor_rho_threshold);
1083-
1084-
refactorize(qpmodel, qpresults, qpwork, rho_new);
1085-
qpresults.info.rho_updates += 1;
1086-
1087-
qpresults.info.rho = rho_new;
1088-
}
1089-
if (is_dual_feasible) {
1090-
if (qpresults.info.duality_gap <=
1091-
qpsettings.eps_abs +
1092-
(qpsettings.eps_abs + qpsettings.eps_rel) * rhs_duality_gap) {
1076+
if (is_primal_feasible && is_dual_feasible) {
1077+
if (qpsettings.check_duality_gap) {
1078+
if (std::abs(qpresults.info.duality_gap) <=
1079+
qpsettings.eps_abs + qpsettings.eps_rel * rhs_duality_gap) {
10931080
qpresults.info.status = QPSolverOutput::PROXQP_SOLVED;
10941081
break;
10951082
}
1083+
} else {
1084+
qpresults.info.status = QPSolverOutput::PROXQP_SOLVED;
1085+
break;
10961086
}
10971087
}
10981088
qpresults.info.iter_ext += 1; // We start a new external loop update
@@ -1170,9 +1160,13 @@ qp_solve( //
11701160
std::max(dual_feasibility_rhs_1, qpwork.dual_feasibility_rhs_2)));
11711161

11721162
if (is_dual_feasible) {
1173-
if (qpresults.info.duality_gap <=
1174-
qpsettings.eps_abs +
1175-
(qpsettings.eps_abs + qpsettings.eps_rel) * rhs_duality_gap) {
1163+
if (qpsettings.check_duality_gap) {
1164+
if (std::abs(qpresults.info.duality_gap) <=
1165+
qpsettings.eps_abs + qpsettings.eps_rel * rhs_duality_gap) {
1166+
qpresults.info.status = QPSolverOutput::PROXQP_SOLVED;
1167+
break;
1168+
}
1169+
} else {
11761170
qpresults.info.status = QPSolverOutput::PROXQP_SOLVED;
11771171
break;
11781172
}

include/proxsuite/proxqp/dense/utils.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,13 +397,13 @@ global_dual_residual(Results<T>& qpresults,
397397
ruiz.unscale_dual_in_place_in(VectorViewMut<T>{ from_eigen, qpresults.z });
398398

399399
const T zu =
400-
helpers::positive_part(qpresults.z)
400+
helpers::select(qpwork.active_set_up, qpresults.z, 0)
401401
.dot(helpers::at_most(qpmodel.u, helpers::infinite_bound<T>::value()));
402402
rhs_duality_gap = std::max(rhs_duality_gap, std::abs(zu));
403403
duality_gap += zu;
404404

405405
const T zl =
406-
helpers::negative_part(qpresults.z)
406+
helpers::select(qpwork.active_set_low, qpresults.z, 0)
407407
.dot(helpers::at_least(qpmodel.l, -helpers::infinite_bound<T>::value()));
408408
rhs_duality_gap = std::max(rhs_duality_gap, std::abs(zl));
409409
duality_gap += zl;

include/proxsuite/proxqp/results.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ struct Results
6969
sparse::Vec<T> x;
7070
sparse::Vec<T> y;
7171
sparse::Vec<T> z;
72-
proxsuite::linalg::veg::Vec<bool> active_constraints;
7372

7473
Info<T> info;
7574

include/proxsuite/proxqp/settings.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct Settings
8484
bool update_preconditioner;
8585
bool compute_preconditioner;
8686
bool compute_timings;
87+
bool check_duality_gap;
8788

8889
isize preconditioner_max_iter;
8990
T preconditioner_accuracy;
@@ -136,6 +137,8 @@ struct Settings
136137
* @param compute_timings If set to true, timings will be computed by the
137138
* solver (setup time, solving time, and run time = setup time + solving
138139
* time).
140+
* @param check_duality_gap If set to true, duality gap will be calculated and
141+
* included in the stopping criterion.
139142
* @param preconditioner_max_iter maximal number of authorized iterations for
140143
* the preconditioner.
141144
* @param preconditioner_accuracy accuracy level of the preconditioner.
@@ -183,6 +186,7 @@ struct Settings
183186
bool update_preconditioner = true,
184187
bool compute_preconditioner = true,
185188
bool compute_timings = false,
189+
bool check_duality_gap = false,
186190
isize preconditioner_max_iter = 10,
187191
T preconditioner_accuracy = 1.e-3,
188192
T eps_primal_inf = 1.E-4,
@@ -218,6 +222,7 @@ struct Settings
218222
, update_preconditioner(update_preconditioner)
219223
, compute_preconditioner(compute_preconditioner)
220224
, compute_timings(compute_timings)
225+
, check_duality_gap(check_duality_gap)
221226
, preconditioner_max_iter(preconditioner_max_iter)
222227
, preconditioner_accuracy(preconditioner_accuracy)
223228
, eps_primal_inf(eps_primal_inf)
@@ -263,6 +268,7 @@ operator==(const Settings<T>& settings1, const Settings<T>& settings2)
263268
settings1.update_preconditioner == settings2.update_preconditioner &&
264269
settings1.compute_preconditioner == settings2.compute_preconditioner &&
265270
settings1.compute_timings == settings2.compute_timings &&
271+
settings1.check_duality_gap == settings2.check_duality_gap &&
266272
settings1.preconditioner_max_iter == settings2.preconditioner_max_iter &&
267273
settings1.preconditioner_accuracy == settings2.preconditioner_accuracy &&
268274
settings1.eps_primal_inf == settings2.eps_primal_inf &&

include/proxsuite/proxqp/sparse/fwd.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2022 INRIA
2+
// Copyright (c) 2022-2023 INRIA
33
//
44
/** \file */
55
#ifndef PROXSUITE_PROXQP_SPARSE_FWD_HPP
@@ -40,6 +40,16 @@ using Vec = Eigen::Matrix<T, DYN, 1>;
4040
template<typename T, typename I>
4141
using Mat = Eigen::SparseMatrix<T, Eigen::ColMajor, I>;
4242
// using Mat = Eigen::SparseMatrix<T, Eigen::RowMajor, I>;
43+
using VecBool = Eigen::Matrix<bool, DYN, 1>;
44+
45+
///
46+
/// @brief This class defines the workspace of the sparse solver.
47+
///
48+
/*!
49+
* Workspace class of the sparse solver.
50+
*/
51+
template<typename T, typename I>
52+
struct Workspace;
4353

4454
} // namespace sparse
4555
} // namespace proxqp

include/proxsuite/proxqp/sparse/helpers.hpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,22 @@ qp_setup(QpView<T, I> qp,
148148
results.z.resize(n_in);
149149
results.z.setZero();
150150
}
151-
if (results.active_constraints.len() != n_in) {
152-
results.active_constraints.resize(n_in);
151+
if (work.active_inequalities.len() != n_in) {
152+
work.active_inequalities.resize(n_in);
153153
for (isize i = 0; i < n_in; ++i) {
154-
results.active_constraints[i] = false;
154+
work.active_inequalities[i] = false;
155+
}
156+
}
157+
if (work.active_set_up.rows() != n_in) {
158+
work.active_set_up.resize(n_in);
159+
for (isize i = 0; i < n_in; ++i) {
160+
work.active_set_up[i] = false;
161+
}
162+
}
163+
if (work.active_set_low.rows() != n_in) {
164+
work.active_set_low.resize(n_in);
165+
for (isize i = 0; i < n_in; ++i) {
166+
work.active_set_low[i] = false;
155167
}
156168
}
157169
bool execute_preconditioner_or_not = false;

0 commit comments

Comments
 (0)