Skip to content

Commit 7374db8

Browse files
authored
Merge pull request #257 from Bambade/non_convex_qp
Estimate minimal eigenvalue of quadratic cost hessian
2 parents 41812e6 + 63fb999 commit 7374db8

22 files changed

+1572
-57
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ We are ready to integrate **ProxSuite** within other optimization ecosystems.
4242
- Python and Julia bindings for easy code prototyping without sacrificing performance.
4343

4444
**Proxsuite** has a dedicated feature for solving batches of QPs.
45+
**Proxsuite** has a dedicated feature for solving nonconvex QPs.
4546
**Proxsuite** has a dedicated feature for solving the closest feasible QPs if they appear to be primal infeasible.
4647
**Proxsuite** is extensible.
4748
**Proxsuite** is reliable and extensively tested, showing the best performances on the hardest problems of the literature.

bindings/python/src/algorithms.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "expose-qpobject.hpp"
1212
#include "expose-qpvector.hpp"
1313
#include "expose-solve.hpp"
14+
#include "expose-helpers.hpp"
1415
#ifdef PROXSUITE_PYTHON_INTERFACE_WITH_OPENMP
1516
#include "expose-parallel.hpp"
1617
#endif

bindings/python/src/expose-all.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ exposeSparseAlgorithms(pybind11::module_ m)
3535
sparse::python::exposeQpObjectSparse<T, I>(m);
3636
sparse::python::exposeQPVectorSparse<T, I>(m);
3737
sparse::python::solveSparseQp<T, I>(m);
38+
sparse::python::exposeSparseHelpers<T, I>(m);
3839
}
3940

4041
template<typename T>
@@ -45,6 +46,7 @@ exposeDenseAlgorithms(pybind11::module_ m)
4546
dense::python::exposeQpObjectDense<T>(m);
4647
dense::python::exposeQPVectorDense<T>(m);
4748
dense::python::solveDenseQp<T>(m);
49+
dense::python::exposeDenseHelpers<T>(m);
4850
}
4951

5052
#ifdef PROXSUITE_PYTHON_INTERFACE_WITH_OPENMP
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//
2+
// Copyright (c) 2022 INRIA
3+
//
4+
5+
#include <pybind11/pybind11.h>
6+
#include <pybind11/eigen.h>
7+
#include <pybind11/stl.h>
8+
9+
#include <proxsuite/proxqp/dense/helpers.hpp>
10+
#include <proxsuite/proxqp/sparse/helpers.hpp>
11+
12+
namespace proxsuite {
13+
namespace proxqp {
14+
15+
namespace dense {
16+
17+
namespace python {
18+
19+
template<typename T>
20+
void
21+
exposeDenseHelpers(pybind11::module_ m)
22+
{
23+
m.def("estimate_minimal_eigen_value_of_symmetric_matrix",
24+
&dense::estimate_minimal_eigen_value_of_symmetric_matrix<T>,
25+
"Function for estimating the minimal eigenvalue of a dense symmetric "
26+
"matrix. "
27+
"Two options are available: an exact method using "
28+
"SelfAdjointEigenSolver from Eigen, "
29+
"or a Power Iteration algorithm (with parameters : "
30+
"power_iteration_accuracy and nb_power_iteration).",
31+
pybind11::arg("H"),
32+
pybind11::arg_v("estimate_method_option",
33+
EigenValueEstimateMethodOption::ExactMethod,
34+
"Two options are available for "
35+
"estimating smallest eigenvalue: either a power "
36+
"iteration algorithm, or an exact method from Eigen."),
37+
pybind11::arg_v(
38+
"power_iteration_accuracy", T(1.E-3), "power iteration accuracy."),
39+
pybind11::arg_v("nb_power_iteration",
40+
1000,
41+
"maximal number of power iteration executed."));
42+
}
43+
} // namespace python
44+
} // namespace dense
45+
46+
namespace sparse {
47+
48+
namespace python {
49+
50+
template<typename T, typename I>
51+
void
52+
exposeSparseHelpers(pybind11::module_ m)
53+
{
54+
m.def("estimate_minimal_eigen_value_of_symmetric_matrix",
55+
&sparse::estimate_minimal_eigen_value_of_symmetric_matrix<T, I>,
56+
"Function for estimating the minimal eigenvalue of a sparse symmetric "
57+
"matrix, "
58+
" using aPower Iteration algorithm (with parameters : "
59+
"power_iteration_accuracy and nb_power_iteration).",
60+
pybind11::arg("H"),
61+
pybind11::arg_v(
62+
"power_iteration_accuracy", T(1.E-3), "power iteration accuracy."),
63+
pybind11::arg_v("nb_power_iteration",
64+
1000,
65+
"maximal number of power iteration executed."));
66+
}
67+
68+
} // namespace python
69+
} // namespace sparse
70+
71+
} // namespace proxqp
72+
} // namespace proxsuite

bindings/python/src/expose-qpobject.hpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ exposeQpObjectDense(pybind11::module_ m)
8888
bool compute_preconditioner,
8989
optional<T>,
9090
optional<T>,
91+
optional<T>,
9192
optional<T>)>(&dense::QP<T>::init),
9293
"function for initialize the QP model.",
9394
pybind11::arg_v("H", nullopt, "quadratic cost"),
@@ -105,7 +106,11 @@ exposeQpObjectDense(pybind11::module_ m)
105106
pybind11::arg_v(
106107
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
107108
pybind11::arg_v(
108-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
109+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
110+
pybind11::arg_v("manual_minimal_H_eigenvalue",
111+
nullopt,
112+
"manual minimal H eigenvalue proposed to regularize H"
113+
" in case it is non convex."))
109114
.def("init",
110115
static_cast<void (dense::QP<T>::*)(optional<dense::MatRef<T>>,
111116
optional<dense::VecRef<T>>,
@@ -119,6 +124,7 @@ exposeQpObjectDense(pybind11::module_ m)
119124
bool compute_preconditioner,
120125
optional<T>,
121126
optional<T>,
127+
optional<T>,
122128
optional<T>)>(&dense::QP<T>::init),
123129
"function for initialize the QP model.",
124130
pybind11::arg_v("H", nullopt, "quadratic cost"),
@@ -140,7 +146,11 @@ exposeQpObjectDense(pybind11::module_ m)
140146
pybind11::arg_v(
141147
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
142148
pybind11::arg_v(
143-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
149+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
150+
pybind11::arg_v("manual_minimal_H_eigenvalue",
151+
nullopt,
152+
"manual minimal H eigenvalue proposed to regularize H"
153+
" in case it is non convex."))
144154
.def("solve",
145155
static_cast<void (dense::QP<T>::*)()>(&dense::QP<T>::solve),
146156
"function used for solving the QP problem, using default parameters.")
@@ -163,6 +173,7 @@ exposeQpObjectDense(pybind11::module_ m)
163173
bool update_preconditioner,
164174
optional<T>,
165175
optional<T>,
176+
optional<T>,
166177
optional<T>)>(&dense::QP<T>::update),
167178
"function used for updating matrix or vector entry of the model using "
168179
"dense matrix entries.",
@@ -183,7 +194,11 @@ exposeQpObjectDense(pybind11::module_ m)
183194
pybind11::arg_v(
184195
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
185196
pybind11::arg_v(
186-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
197+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
198+
pybind11::arg_v("manual_minimal_H_eigenvalue",
199+
nullopt,
200+
"manual minimal H eigenvalue proposed to regularize H"
201+
" in case it is non convex."))
187202
.def(
188203
"update",
189204
static_cast<void (dense::QP<T>::*)(optional<dense::MatRef<T>>,
@@ -198,6 +213,7 @@ exposeQpObjectDense(pybind11::module_ m)
198213
bool update_preconditioner,
199214
optional<T>,
200215
optional<T>,
216+
optional<T>,
201217
optional<T>)>(&dense::QP<T>::update),
202218
"function used for updating matrix or vector entry of the model using "
203219
"dense matrix entries.",
@@ -222,7 +238,11 @@ exposeQpObjectDense(pybind11::module_ m)
222238
pybind11::arg_v(
223239
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
224240
pybind11::arg_v(
225-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
241+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
242+
pybind11::arg_v("manual_minimal_H_eigenvalue",
243+
nullopt,
244+
"manual minimal H eigenvalue proposed to regularize H"
245+
" in case it is non convex."))
226246
.def("cleanup",
227247
&dense::QP<T>::cleanup,
228248
"function used for cleaning the workspace and result "
@@ -297,7 +317,11 @@ exposeQpObjectSparse(pybind11::module_ m)
297317
pybind11::arg_v(
298318
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
299319
pybind11::arg_v(
300-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
320+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
321+
pybind11::arg_v("manual_minimal_H_eigenvalue",
322+
nullopt,
323+
"manual minimal H eigenvalue proposed to regularize H"
324+
" in case it is non convex."))
301325

302326
.def("update",
303327
&sparse::QP<T, I>::update,
@@ -319,7 +343,11 @@ exposeQpObjectSparse(pybind11::module_ m)
319343
pybind11::arg_v(
320344
"mu_eq", nullopt, "dual equality constraint proximal parameter"),
321345
pybind11::arg_v(
322-
"mu_in", nullopt, "dual inequality constraint proximal parameter"))
346+
"mu_in", nullopt, "dual inequality constraint proximal parameter"),
347+
pybind11::arg_v("manual_minimal_H_eigenvalue",
348+
nullopt,
349+
"manual minimal H eigenvalue proposed to regularize H"
350+
" in case it is non convex."))
323351
.def("solve",
324352
static_cast<void (sparse::QP<T, I>::*)()>(&sparse::QP<T, I>::solve),
325353
"function used for solving the QP problem, using default parameters.")

bindings/python/src/expose-results.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ exposeResults(pybind11::module_ m)
5151
.def_readwrite("sparse_backend",
5252
&Info<T>::sparse_backend,
5353
"Sparse backend used to solve the qp, either SparseCholesky "
54-
"or MatrixFree.");
54+
"or MatrixFree.")
55+
.def_readwrite("minimal_H_eigenvalue_estimate",
56+
&Info<T>::minimal_H_eigenvalue_estimate,
57+
"By default it equals 0, in order to get an estimate, set "
58+
"appropriately the setting option "
59+
"find_H_minimal_eigenvalue.");
5560

5661
::pybind11::class_<Results<T>>(m, "Results", pybind11::module_local())
5762
.def(::pybind11::init<i64, i64, i64>(),

bindings/python/src/expose-settings.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ exposeSettings(pybind11::module_ m)
4141
.value("MatrixFree", SparseBackend::MatrixFree)
4242
.value("SparseCholesky", SparseBackend::SparseCholesky)
4343
.export_values();
44+
::pybind11::enum_<EigenValueEstimateMethodOption>(
45+
m, "EigenValueEstimateMethodOption", pybind11::module_local())
46+
.value("PowerIteration", EigenValueEstimateMethodOption::PowerIteration)
47+
.value("ExactMethod", EigenValueEstimateMethodOption::ExactMethod)
48+
.export_values();
4449

4550
::pybind11::class_<Settings<T>>(m, "Settings", pybind11::module_local())
4651
.def(::pybind11::init(), "Default constructor.") // constructor
@@ -87,6 +92,8 @@ exposeSettings(pybind11::module_ m)
8792
&Settings<T>::primal_infeasibility_solving)
8893
.def_readwrite("frequence_infeasibility_check",
8994
&Settings<T>::frequence_infeasibility_check)
95+
.def_readwrite("default_H_eigenvalue_estimate",
96+
&Settings<T>::default_H_eigenvalue_estimate)
9097
.def(pybind11::self == pybind11::self)
9198
.def(pybind11::self != pybind11::self)
9299
.def(pybind11::pickle(

bindings/python/src/expose-solve.hpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ solveDenseQp(pybind11::module_ m)
4343
bool,
4444
optional<T>,
4545
optional<T>,
46-
bool>(&dense::solve<T>),
46+
bool,
47+
optional<T>>(&dense::solve<T>),
4748
"Function for solving a QP problem using PROXQP sparse backend directly "
4849
"without defining a QP object. It is possible to set up some of the solver "
4950
"parameters (warm start, initial guess option, proximal step sizes, "
@@ -103,7 +104,10 @@ solveDenseQp(pybind11::module_ m)
103104
pybind11::arg_v("primal_infeasibility_solving",
104105
false,
105106
"solves the closest feasible problem in L2 sense "
106-
"if the QP problem appears to be infeasible."));
107+
"if the QP problem appears to be infeasible."),
108+
pybind11::arg_v("default_H_eigenvalue_estimate",
109+
0.,
110+
"Default estimate of the minimal eigen value of H."));
107111

108112
m.def(
109113
"solve",
@@ -132,7 +136,8 @@ solveDenseQp(pybind11::module_ m)
132136
bool,
133137
optional<T>,
134138
optional<T>,
135-
bool>(&dense::solve<T>),
139+
bool,
140+
optional<T>>(&dense::solve<T>),
136141
"Function for solving a QP problem using PROXQP sparse backend directly "
137142
"without defining a QP object. It is possible to set up some of the solver "
138143
"parameters (warm start, initial guess option, proximal step sizes, "
@@ -194,7 +199,10 @@ solveDenseQp(pybind11::module_ m)
194199
pybind11::arg_v("primal_infeasibility_solving",
195200
false,
196201
"solves the closest feasible problem in L2 sense "
197-
"if the QP problem appears to be infeasible."));
202+
"if the QP problem appears to be infeasible."),
203+
pybind11::arg_v("default_H_eigenvalue_estimate",
204+
0.,
205+
"Default estimate of the minimal eigen value of H."));
198206
}
199207

200208
} // namespace python
@@ -269,7 +277,10 @@ solveSparseQp(pybind11::module_ m)
269277
pybind11::arg_v("primal_infeasibility_solving",
270278
false,
271279
"solves the closest feasible problem in L2 sense "
272-
"if the QP problem appears to be infeasible."));
280+
"if the QP problem appears to be infeasible."),
281+
pybind11::arg_v("default_H_eigenvalue_estimate",
282+
0.,
283+
"Default estimate of the minimal eigen value of H."));
273284
}
274285

275286
} // namespace python

0 commit comments

Comments
 (0)