Skip to content

Commit 0d3629d

Browse files
authored
Merge pull request #167 from Simple-Robotics/fix/pycheck_duality_gap
Expose check_duality_gap in Python settings
2 parents 73ed27a + 7b861e3 commit 0d3629d

File tree

6 files changed

+50
-11
lines changed

6 files changed

+50
-11
lines changed

bindings/python/src/expose-settings.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ exposeSettings(pybind11::module_ m)
7070
.def_readwrite("compute_preconditioner",
7171
&Settings<T>::compute_preconditioner)
7272
.def_readwrite("update_preconditioner", &Settings<T>::update_preconditioner)
73+
.def_readwrite("check_duality_gap", &Settings<T>::check_duality_gap)
7374
.def_readwrite("verbose", &Settings<T>::verbose)
7475
.def_readwrite("bcl_update", &Settings<T>::bcl_update)
7576
.def(pybind11::self == pybind11::self)

bindings/python/src/expose-solve.hpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ solveDenseQp(pybind11::module_ m)
3939
bool,
4040
bool,
4141
optional<isize>,
42-
proxsuite::proxqp::InitialGuessStatus>(
43-
&dense::solve<T>),
42+
proxsuite::proxqp::InitialGuessStatus,
43+
bool>(&dense::solve<T>),
4444
"Function for solving a QP problem using PROXQP sparse backend directly "
4545
"without defining a QP object. It is possible to set up some of the solver "
4646
"parameters (warm start, initial guess option, proximal step sizes, "
@@ -83,7 +83,12 @@ solveDenseQp(pybind11::module_ m)
8383
pybind11::arg_v(
8484
"initial_guess",
8585
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS,
86-
"maximum number of iteration."));
86+
"maximum number of iteration."),
87+
pybind11::arg_v(
88+
"check_duality_gap",
89+
false,
90+
"if set to true, include the duality gap in absolute and relative "
91+
"stopping criteria."));
8792
}
8893

8994
} // namespace python
@@ -96,7 +101,6 @@ template<typename T, typename I>
96101
void
97102
solveSparseQp(pybind11::module_ m)
98103
{
99-
100104
m.def(
101105
"solve",
102106
&sparse::solve<T, I>,
@@ -143,7 +147,11 @@ solveSparseQp(pybind11::module_ m)
143147
proxsuite::proxqp::InitialGuessStatus::
144148
EQUALITY_CONSTRAINED_INITIAL_GUESS),
145149
pybind11::arg_v("sparse_backend",
146-
proxsuite::proxqp::SparseBackend::Automatic));
150+
proxsuite::proxqp::SparseBackend::Automatic),
151+
pybind11::arg_v("check_duality_gap",
152+
false,
153+
"if set to true, include the duality gap in absolute and "
154+
"relative stopping criteria."));
147155
}
148156

149157
} // namespace python

doc/2-PROXQP_API/2-ProxQP_api.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $$\begin{equation}\label{qp:kkt}\tag{KKT}
3535

3636
where the last equation involves the Hadamard product (i.e., for two vectors u and v, the Hadamard product is the vector whose ith entry is u_i v_i).
3737

38-
In practice, we look for a triplet (x,y,z) satisfying these optimality conditions \eqref{qp:kkt} up to a certain level of absolute accuracy (dependent of the application), leading us to the following natural absolute stopping criterion:
38+
In practice, we look for a triplet (x,y,z) satisfying these optimality conditions \eqref{qp:kkt} up to a certain level of absolute accuracy (dependent of the application), leading us to the following absolute stopping criterion on the primal and dual residuals:
3939

4040
$$\begin{equation}\label{eq:approx_qp_sol}
4141
\begin{aligned}
@@ -49,7 +49,7 @@ $$\begin{equation}\label{eq:approx_qp_sol}
4949
\end{aligned}
5050
\end{equation}$$
5151

52-
The infite norm is preferred to the L2 norm as it is independent of the problem dimensions. It is also common to consider relative convergence criteria for early-stopping, as absolute targets might not bet reached due to numerical issues. ProxQP provides it in a similar way as OSQP (for more details see, e.g., [section 3.4](https://web.stanford.edu/~boyd/papers/pdf/osqp.pdf)). Hence more generally the following stopping criterion can be used.
52+
The infite norm is preferred to the L2 norm as it is independent of the problem dimensions. It is also common to consider relative convergence criteria for early-stopping, as absolute targets might not bet reached due to numerical issues. ProxQP provides it in a similar way as OSQP (for more details see, e.g., OSQP's [convergence](https://osqp.org/docs/solver/index.html#convergence) criteria or [section 3.4](https://web.stanford.edu/~boyd/papers/pdf/osqp.pdf) in the corresponding paper). Hence more generally the following stopping criterion can be used:
5353

5454
$$\begin{equation}\label{eq:approx_qp_sol_relative_criterion}
5555
\begin{aligned}
@@ -63,6 +63,16 @@ $$\begin{equation}\label{eq:approx_qp_sol_relative_criterion}
6363
\end{aligned}
6464
\end{equation}$$
6565

66+
It is important to note that this stopping criterion on primal and dual residuals is not enough to guarantee that the returned solution satisfies all \eqref{qp:kkt} conditions. Indeed, as the problem has affine constraints and the objective is quadratic and convex, then as soon as the primal or the dual problem is feasible, then strong duality holds (see e.g., [Theorem 2](https://people.eecs.berkeley.edu/~elghaoui/Teaching/EE227A/lecture8.pdf) from L. El Ghaoui's lesson) and to satisfy all optimality conditions we need to add a third criterion on the *duality gap* $r_g$:
67+
68+
$$\begin{equation}\label{eq:approx_dg_sol}
69+
\begin{aligned}
70+
r_g := | x^T H x + g^T x + b^T y + u^T [z]_+ + l^T [z]_- | \leq \epsilon_{\text{abs}} + \epsilon_{\text{rel}} \max(\|x^T H x\|, \|g^T x\|, \|b^T y\|, \|u^T [z]_+\|, \|l^T [z]_-\|), \\
71+
\end{aligned}
72+
\end{equation}$$
73+
74+
where $[z]_+$ and $[z]_-$ stand for the projection of z onto the positive and negative orthant. ProxQP provides the ``check_duality_gap`` option to include this duality gap in the stopping criterion. Note that it is disabled by default, as other solvers don't check in general this criterion. Enable this option if you want a stronger guarantee that your solution is optimal. ProxQP will then check the same termination condition as SCS (for more details see, e.g., SCS's [optimality conditions checks](https://www.cvxgrp.org/scs/algorithm/index.html#optimality-conditions) as well as [section 7.2](https://doi.org/10.1137/20M1366307) in the corresponding paper). Note finally that meeting all these criteria can be difficult for ill-conditioned problems.
75+
6676
\section OverviewAPIstructure ProxQP unified API for dense and sparse backends
6777

6878
ProxQP algorithm is implemented in two versions specialized for dense and sparse matrices. One simple and unified API has been designed for loading the dense and sparse backends. Concretely, it contains three methods:
@@ -301,6 +311,7 @@ In this table you have on the three columns from left to right: the name of the
301311
| ----------------------------------- | ---------------------------------- | -----------------------------------------
302312
| eps_abs | 1.E-5 | Asbolute stopping criterion of the solver.
303313
| eps_rel | 0 | Relative stopping criterion of the solver.
314+
| check_duality_gap | False | If set to true, include the duality gap in absolute and relative stopping criteria.
304315
| VERBOSE | False | If set to true, the solver prints information at each loop.
305316
| default_rho | 1.E-6 | Default rho parameter of result class (i.e., for each initial guess, except WARM_START_WITH_PREVIOUS_RESULT, after a new solve or update, the solver initializes rho to this value).
306317
| default_mu_eq | 1.E-3 | Default mu_eq parameter of result class (i.e., for each initial guess, except WARM_START_WITH_PREVIOUS_RESULT, after a new solve or update, the solver initializes mu_eq to this value).

doc/3-ProxQP_solve.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $$\begin{equation}\label{qp:kkt}\tag{KKT}
3535

3636
where the last equation involves the Hadamard product (i.e., for two vectors u and v, the Hadamard product is the vector whose ith entry is u_i v_i).
3737

38-
In practice, we look for a triplet (x,y,z) satisfying these optimality conditions \eqref{qp:kkt} up to a certain level of absolute accuracy (dependent of the application), leading us to the following natural absolute stopping criterion:
38+
In practice, we look for a triplet (x,y,z) satisfying these optimality conditions \eqref{qp:kkt} up to a certain level of absolute accuracy (dependent of the application), leading us to the following absolute stopping criterion on the primal and dual residuals:
3939

4040
$$\begin{equation}\label{eq:approx_qp_sol}
4141
\begin{aligned}
@@ -49,7 +49,7 @@ $$\begin{equation}\label{eq:approx_qp_sol}
4949
\end{aligned}
5050
\end{equation}$$
5151

52-
The infite norm is preferred to the L2 norm as it is independent of the problem dimensions. It is also common to consider relative convergence criteria for early-stopping, as absolute targets might not bet reached due to numerical issues. ProxQP provides it in a similar way as OSQP (for more details see, e.g., [section 3.4](https://web.stanford.edu/~boyd/papers/pdf/osqp.pdf)). Hence more generally the following stopping criterion can be used.
52+
The infite norm is preferred to the L2 norm as it is independent of the problem dimensions. It is also common to consider relative convergence criteria for early-stopping, as absolute targets might not bet reached due to numerical issues. ProxQP provides it in a similar way as OSQP (for more details see, e.g., OSQP's [convergence](https://osqp.org/docs/solver/index.html#convergence) criteria or [section 3.4](https://web.stanford.edu/~boyd/papers/pdf/osqp.pdf) in the corresponding paper). Hence more generally the following stopping criterion can be used:
5353

5454
$$\begin{equation}\label{eq:approx_qp_sol_relative_criterion}
5555
\begin{aligned}
@@ -63,6 +63,16 @@ $$\begin{equation}\label{eq:approx_qp_sol_relative_criterion}
6363
\end{aligned}
6464
\end{equation}$$
6565

66+
It is important to note that this stopping criterion on primal and dual residuals is not enough to guarantee that the returned solution satisfies all \eqref{qp:kkt} conditions. Indeed, as the problem has affine constraints and the objective is quadratic and convex, then as soon as the primal or the dual problem is feasible, then strong duality holds (see e.g., [Theorem 2](https://people.eecs.berkeley.edu/~elghaoui/Teaching/EE227A/lecture8.pdf) from L. El Ghaoui's lesson) and to satisfy all optimality conditions we need to add a third criterion on the *duality gap* $r_g$:
67+
68+
$$\begin{equation}\label{eq:approx_dg_sol}
69+
\begin{aligned}
70+
r_g := | x^T H x + g^T x + b^T y + u^T [z]_+ + l^T [z]_- | \leq \epsilon_{\text{abs}} + \epsilon_{\text{rel}} \max(\|x^T H x\|, \|g^T x\|, \|b^T y\|, \|u^T [z]_+\|, \|l^T [z]_-\|), \\
71+
\end{aligned}
72+
\end{equation}$$
73+
74+
where $[z]_+$ and $[z]_-$ stand for the projection of z onto the positive and negative orthant. ProxQP provides the ``check_duality_gap`` option to include this duality gap in the stopping criterion. Note that it is disabled by default, as other solvers don't check in general this criterion. Enable this option if you want a stronger guarantee that your solution is optimal. ProxQP will then check the same termination condition as SCS (for more details see, e.g., SCS's [optimality conditions checks](https://www.cvxgrp.org/scs/algorithm/index.html#optimality-conditions) as well as [section 7.2](https://doi.org/10.1137/20M1366307) in the corresponding paper). Note finally that meeting all these criteria can be difficult for ill-conditioned problems.
75+
6676
\section OverviewAsingleSolveFunction A single solve function for dense and sparse backends
6777

6878
If if you don't want to pass through [ProxQP API](2-ProxQP_api.md), it is also possible to use one single solve function. We will show how to do so with examples.
@@ -95,6 +105,7 @@ Different options are available for the solve function. In the table below you h
95105
| z | 0 | Warm start value for the dual Lagrange multiplier for inequality constraints.
96106
| eps_abs | 1.E-5 | Asbolute stopping criterion of the solver.
97107
| eps_rel | 0 | Relative stopping criterion of the solver.
108+
| check_duality_gap | False | If set to true, include the duality gap in absolute and relative stopping criteria.
98109
| mu_eq | 1.E-3 | Proximal step size wrt equality constraints multiplier.
99110
| mu_in | 1.E-1 | Proximal step size wrt inequality constraints multiplier.
100111
| rho | 1.E-6 | Proximal step size wrt primal variable.

include/proxsuite/proxqp/dense/wrapper.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ struct QP
391391
* @param max_iter maximum number of iteration.
392392
* @param initial_guess initial guess option for warm starting or not the
393393
* initial iterate values.
394+
* @param check_duality_gap If set to true, include the duality gap in absolute
395+
* and relative stopping criteria.
394396
*/
395397
template<typename T>
396398
proxqp::Results<T>
@@ -415,7 +417,8 @@ solve(
415417
bool compute_timings = false,
416418
optional<isize> max_iter = nullopt,
417419
proxsuite::proxqp::InitialGuessStatus initial_guess =
418-
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS)
420+
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS,
421+
bool check_duality_gap = false)
419422
{
420423
isize n(0);
421424
isize n_eq(0);
@@ -432,6 +435,7 @@ solve(
432435

433436
QP<T> Qp(n, n_eq, n_in);
434437
Qp.settings.initial_guess = initial_guess;
438+
Qp.settings.check_duality_gap = check_duality_gap;
435439

436440
if (eps_abs != nullopt) {
437441
Qp.settings.eps_abs = eps_abs.value();

include/proxsuite/proxqp/sparse/wrapper.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,8 @@ struct QP
684684
* @param max_iter maximum number of iteration.
685685
* @param initial_guess initial guess option for warm starting or not the
686686
* initial iterate values.
687+
* @param check_duality_gap If set to true, include the duality gap in absolute
688+
* and relative stopping criteria.
687689
*/
688690
template<typename T, typename I>
689691
proxqp::Results<T>
@@ -710,7 +712,8 @@ solve(
710712
proxsuite::proxqp::InitialGuessStatus initial_guess =
711713
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS,
712714
proxsuite::proxqp::SparseBackend sparse_backend =
713-
proxsuite::proxqp::SparseBackend::Automatic)
715+
proxsuite::proxqp::SparseBackend::Automatic,
716+
bool check_duality_gap = false)
714717
{
715718

716719
isize n(0);
@@ -728,6 +731,7 @@ solve(
728731

729732
proxqp::sparse::QP<T, I> Qp(n, n_eq, n_in);
730733
Qp.settings.initial_guess = initial_guess;
734+
Qp.settings.check_duality_gap = check_duality_gap;
731735

732736
if (eps_abs != nullopt) {
733737
Qp.settings.eps_abs = eps_abs.value();

0 commit comments

Comments
 (0)