Skip to content

Commit 5a1684c

Browse files
committed
simplifying API logic for estimating minimal H eigenvalue
1 parent 03d90e8 commit 5a1684c

20 files changed

+447
-489
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-settings.hpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,10 @@ exposeSettings(pybind11::module_ m)
4141
.value("MatrixFree", SparseBackend::MatrixFree)
4242
.value("SparseCholesky", SparseBackend::SparseCholesky)
4343
.export_values();
44-
::pybind11::enum_<HessianCostRegularization>(
45-
m, "HessianCostRegularization", pybind11::module_local())
46-
.value("NoRegularization", HessianCostRegularization::NoRegularization)
47-
.value("Manual", HessianCostRegularization::Manual)
48-
.value("PowerIteration", HessianCostRegularization::PowerIteration)
49-
.value("EigenRegularization",
50-
HessianCostRegularization::EigenRegularization)
44+
::pybind11::enum_<EigenValueEstimateMethodOption>(
45+
m, "EigenValueEstimateMethodOption", pybind11::module_local())
46+
.value("PowerIteration", EigenValueEstimateMethodOption::PowerIteration)
47+
.value("ExactMethod", EigenValueEstimateMethodOption::ExactMethod)
5148
.export_values();
5249

5350
::pybind11::class_<Settings<T>>(m, "Settings", pybind11::module_local())
@@ -95,15 +92,8 @@ exposeSettings(pybind11::module_ m)
9592
&Settings<T>::primal_infeasibility_solving)
9693
.def_readwrite("frequence_infeasibility_check",
9794
&Settings<T>::frequence_infeasibility_check)
98-
.def_readwrite("nb_power_iteration", &Settings<T>::nb_power_iteration)
99-
.def_readwrite("power_iteration_accuracy",
100-
&Settings<T>::power_iteration_accuracy)
101-
.def_readwrite("find_minimal_H_eigenvalue",
102-
&Settings<T>::find_minimal_H_eigenvalue)
10395
.def_readwrite("default_H_eigenvalue_estimate",
10496
&Settings<T>::default_H_eigenvalue_estimate)
105-
.def_readwrite("rho_regularization_scaling",
106-
&Settings<T>::rho_regularization_scaling)
10797
.def(pybind11::self == pybind11::self)
10898
.def(pybind11::self != pybind11::self)
10999
.def(pybind11::pickle(

bindings/python/src/expose-solve.hpp

Lines changed: 3 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ solveDenseQp(pybind11::module_ m)
4444
optional<T>,
4545
optional<T>,
4646
bool,
47-
optional<isize>,
48-
optional<T>,
49-
HessianCostRegularization,
50-
optional<T>,
5147
optional<T>>(&dense::solve<T>),
5248
"Function for solving a QP problem using PROXQP sparse backend directly "
5349
"without defining a QP object. It is possible to set up some of the solver "
@@ -109,32 +105,9 @@ solveDenseQp(pybind11::module_ m)
109105
false,
110106
"solves the closest feasible problem in L2 sense "
111107
"if the QP problem appears to be infeasible."),
112-
pybind11::arg_v("nb_power_iteration",
113-
1000,
114-
"Number of power iteration iteration used by default "
115-
"for estimating the lowest eigenvalue of H."),
116-
pybind11::arg_v("power_iteration_accuracy",
117-
1.E-6,
118-
"Accuracy target of the power iteration algorithm "
119-
"for estimating the lowest eigenvalue of H."),
120-
pybind11::arg_v("find_minimal_H_eigenvalue",
121-
HessianCostRegularization::NoRegularization,
122-
"Option for estimating the minimal eigen value of H "
123-
"and regularizing default_rho following "
124-
"default_rho=rho_regularization_scaling*abs(default_H_"
125-
"eigenvalue_estimate)."
126-
"This option can be used for solving non convex QPs."),
127108
pybind11::arg_v("default_H_eigenvalue_estimate",
128109
0.,
129-
"Default estimate of the minimal eigen value of H."),
130-
pybind11::arg_v("rho_regularization_scaling",
131-
1.5,
132-
"Scaling for regularizing default_rho according to the "
133-
"minimal eigen value of H "
134-
"following "
135-
"default_rho=rho_regularization_scaling*abs(default_H_"
136-
"eigenvalue_estimate)."
137-
"This option can be used for solving non convex QPs."));
110+
"Default estimate of the minimal eigen value of H."));
138111

139112
m.def(
140113
"solve",
@@ -164,10 +137,6 @@ solveDenseQp(pybind11::module_ m)
164137
optional<T>,
165138
optional<T>,
166139
bool,
167-
optional<isize>,
168-
optional<T>,
169-
HessianCostRegularization,
170-
optional<T>,
171140
optional<T>>(&dense::solve<T>),
172141
"Function for solving a QP problem using PROXQP sparse backend directly "
173142
"without defining a QP object. It is possible to set up some of the solver "
@@ -231,32 +200,9 @@ solveDenseQp(pybind11::module_ m)
231200
false,
232201
"solves the closest feasible problem in L2 sense "
233202
"if the QP problem appears to be infeasible."),
234-
pybind11::arg_v("nb_power_iteration",
235-
1000,
236-
"Number of power iteration iteration used by default "
237-
"for estimating the lowest eigenvalue of H."),
238-
pybind11::arg_v("power_iteration_accuracy",
239-
1.E-6,
240-
"Accuracy target of the power iteration algorithm "
241-
"for estimating the lowest eigenvalue of H."),
242-
pybind11::arg_v("find_minimal_H_eigenvalue",
243-
HessianCostRegularization::NoRegularization,
244-
"Option for estimating the minimal eigen value of H "
245-
"and regularizing default_rho following "
246-
"default_rho=rho_regularization_scaling*abs(default_H_"
247-
"eigenvalue_estimate)."
248-
"This option can be used for solving non convex QPs."),
249203
pybind11::arg_v("default_H_eigenvalue_estimate",
250204
0.,
251-
"Default estimate of the minimal eigen value of H."),
252-
pybind11::arg_v("rho_regularization_scaling",
253-
1.5,
254-
"Scaling for regularizing default_rho according to the "
255-
"minimal eigen value of H "
256-
"following "
257-
"default_rho=rho_regularization_scaling*abs(default_H_"
258-
"eigenvalue_estimate)."
259-
"This option can be used for solving non convex QPs."));
205+
"Default estimate of the minimal eigen value of H."));
260206
}
261207

262208
} // namespace python
@@ -332,32 +278,9 @@ solveSparseQp(pybind11::module_ m)
332278
false,
333279
"solves the closest feasible problem in L2 sense "
334280
"if the QP problem appears to be infeasible."),
335-
pybind11::arg_v("nb_power_iteration",
336-
1000,
337-
"Number of power iteration iteration used by default "
338-
"for estimating the lowest eigenvalue of H."),
339-
pybind11::arg_v("power_iteration_accuracy",
340-
1.E-6,
341-
"Accuracy target of the power iteration algorithm "
342-
"for estimating the lowest eigenvalue of H."),
343-
pybind11::arg_v("find_minimal_H_eigenvalue",
344-
HessianCostRegularization::NoRegularization,
345-
"Option for estimating the minimal eigen value of H "
346-
"and regularizing default_rho following "
347-
"default_rho=rho_regularization_scaling*abs(default_H_"
348-
"eigenvalue_estimate)."
349-
"This option can be used for solving non convex QPs."),
350281
pybind11::arg_v("default_H_eigenvalue_estimate",
351282
0.,
352-
"Default estimate of the minimal eigen value of H."),
353-
pybind11::arg_v("rho_regularization_scaling",
354-
1.5,
355-
"Scaling for regularizing default_rho according to the "
356-
"minimal eigen value of H "
357-
"following "
358-
"default_rho=rho_regularization_scaling*abs(default_H_"
359-
"eigenvalue_estimate)."
360-
"This option can be used for solving non convex QPs."));
283+
"Default estimate of the minimal eigen value of H."));
361284
}
362285

363286
} // namespace python

doc/2-PROXQP_API/2-ProxQP_api.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ In this table, you have the three columns from left to right: the name of the se
415415
| nb_power_iteration | 1000 | Number of power iteration iteration used by default for estimating H lowest eigenvalue.
416416
| power_iteration_accuracy | 1.E-6 | If set to true, it solves the closest primal feasible problem if primal infeasibility is detected.
417417
| primal_infeasibility_solving | False | Accuracy target of the power iteration algorithm for estimating the lowest eigenvalue of H.
418-
| find_minimal_H_eigenvalue | NoRegularization | Option for estimating the minimal eigen value of H and regularizing default_rho default_rho=rho_regularization_scaling*abs(default_H_eigenvalue_estimate). This option can be used for solving non convex QPs.
418+
| estimate_method_option | NoRegularization | Option for estimating the minimal eigen value of H and regularizing default_rho default_rho=rho_regularization_scaling*abs(default_H_eigenvalue_estimate). This option can be used for solving non convex QPs.
419419
| default_H_eigenvalue_estimate | 0. | Default estimate of the minimal eigen value of H.
420420
| rho_regularization_scaling | 1.5 | Scaling for regularizing default_rho according to the minimal eigen value of H.
421421

@@ -436,15 +436,13 @@ If set to this option, the solver will start with no initial guess, which means
436436

437437
\subsection OverviewEstimatingHminimalEigenValue The different options for estimating H minimal Eigenvalue
438438

439-
The solver has four options for estimating the minimal eigenvalue of H within the struct HessianCostRegularization:
440-
* NoRegularization : set by default, it means the solver does not try to estimate it,
441-
* Manual: the user can provide an estimate of it through the init method,
439+
The solver environment provides an independent function for estimating the minimal eigenvalue of a dense or sparse symmetric matrix. It is named "estimate_minimal_eigen_value_of_symmetric_matrix". In the sparse case, it uses a power iteration algorithm (with two options: the maximal number of iterations and the accuracy target for the estimate). In the dense case, we provide two options within the struct EigenValueEstimateMethodOption:
442440
* PowerIteration: a power iteration algorithm will be used for estimating H minimal eigenvalue,
443-
* EigenRegularization: in case the dense backend is used, the solver make use of Eigen method for estimating it.
441+
* ExactMethod: in this case, an exact method from EigenSolver is used to provide an estimate.
444442

445-
This option is particularly usefull when solving QP with non convex quadratics. Indeed, if default_rho is set to a value strictly higher than the minimal eigenvalue of H, then ProxQP is guaranteed for find a local minimum to the problem since it relies on a Proximal Method of Multipliers (for more detail for example this [work](https://arxiv.org/pdf/2010.02653.pdf) providing convergence proof of this property).
443+
Estimating minimal eigenvalue is particularly usefull for solving QP with non convex quadratics. Indeed, if default_rho is set to a value strictly higher than the minimal eigenvalue of H, then ProxQP is guaranteed for find a local minimum to the problem since it relies on a Proximal Method of Multipliers (for more detail for example this [work](https://arxiv.org/pdf/2010.02653.pdf) providing convergence proof of this property).
446444

447-
More precisely, when HessianCostRegularization is set to a value different of NoRegularization, then ProxQP first estimate a minimal eigenvalue for H and then update default_rho following the rule: default_rho = rho_regularization_scaling * abs(default_H_eigenvalue_estimate), which guarantees for appropriate scaling than the proximal step-size is larger than the minimal eigenvalue of H. We provide below examples in C++ and python for using this feature appropriately with the dense backend (it is similar with the sparse one)
445+
More precisely, ProxQP API enables the user to provide for the init or update methods estimate of the minimal eigenvalue of H (i.e., manual_minimal_H_eigenvalue). It the values are not empty, then the values of primal proximal step size rho will be updated according to: rho = rho + abs(manual_minimal_H_eigenvalue). It guarantees that the proximal step-size is larger than the minimal eigenvalue of H and hence to converging towards a local minimum of the QP. We provide below examples in C++ and python for using this feature appropriately with the dense backend (it is similar with the sparse one)
448446

449447
<table class="manual">
450448
<tr>

doc/3-ProxQP_solve.md

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,4 @@ Note that if some elements of your QP model are not defined (for example a QP wi
161161
</tr>
162162
</table>
163163

164-
Finally, note that you can also you ProxQP for solving QP with non convex quadratic. For doing so, you need first to estimate the smallest eigenvalue of the quadratic cost H. ProxQP has four internal options for estimating using the setting HessianCostRegularization:
165-
* NoRegularization : set by default, it means the solver does not try to estimate it,
166-
* Manual: the user can provide an estimate of it through the init method,
167-
* PowerIteration: a power iteration algorithm will be used for estimating H minimal eigenvalue,
168-
* EigenRegularization: in case the dense backend is used, the solver make use of Eigen method for estimating it.
169-
170-
This option is particularly usefull when solving QP with non convex quadratics. Indeed, if default_rho is set to a value strictly higher than the minimal eigenvalue of H, then ProxQP is guaranteed for find a local minimum to the problem since it relies on a Proximal Method of Multipliers (for more detail for example this [work](https://arxiv.org/pdf/2010.02653.pdf) providing convergence proof of this property).
171-
172-
More precisely, when HessianCostRegularization is set to a value different of NoRegularization, then ProxQP first estimate a minimal eigenvalue for H and then update default_rho following the rule: default_rho = rho_regularization_scaling * abs(default_H_eigenvalue_estimate), which guarantees for appropriate scaling than the proximal step-size is larger than the minimal eigenvalue of H. We provide below examples in C++ and python for using this feature appropriately with the dense backend (it is similar with the sparse one).
173-
174-
The solve function enables using this option directly by passing accordingly the parameters "HessianCostRegularization" and "rho_regularization_scaling". You can find more details in [ProxQP API with examples](2-ProxQP_api.md) about the different other settings that can be used for setting other related parameters (e.g., for using PowerIteration algorithm with other options).
164+
Finally, note that you can also you ProxQP for solving QP with non convex quadratic. For doing so, you just need to provide to the solve function an estimate of the smallest eigenvalue of the quadratic cost H. The solver environment provides an independent function for estimating the minimal eigenvalue of a dense or sparse symmetric matrix. It is named "estimate_minimal_eigen_value_of_symmetric_matrix". You can find more details in [ProxQP API with examples](2-ProxQP_api.md) about the different other settings that can be used for setting other related parameters (e.g., for using a Power Iteration algorithm).

0 commit comments

Comments
 (0)