Skip to content

Commit 2700f84

Browse files
committed
bindings osqp
1 parent 528a5c4 commit 2700f84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+4587
-2133
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
build*
22
Xcode*
33
*.pyc
4-
.vscode*
4+
.vscode*
5+
.cache/

bindings/python/src/common/expose.hpp

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
//
2+
// Copyright (c) 2022-2024 INRIA
3+
//
4+
5+
#ifndef bindings_python_src_common_expose
6+
#define bindings_python_src_common_expose
7+
8+
#include <nanobind/nanobind.h>
9+
#include <nanobind/eigen/dense.h>
10+
#include <nanobind/eigen/sparse.h>
11+
#include <nanobind/operators.h>
12+
13+
#include <proxsuite/proxqp/status.hpp>
14+
#include <proxsuite/serialization/archive.hpp>
15+
#include <proxsuite/serialization/wrapper.hpp>
16+
17+
#include <proxsuite/proxqp/dense/wrapper.hpp>
18+
#include <proxsuite/osqp/dense/wrapper.hpp>
19+
20+
#include <proxsuite/solvers/common/utils.hpp>
21+
22+
namespace proxsuite {
23+
namespace common {
24+
using proxsuite::linalg::veg::isize;
25+
26+
namespace dense {
27+
namespace python {
28+
29+
template<typename T, typename QPClass>
30+
void
31+
exposeDenseQP(nanobind::module_& m)
32+
{
33+
34+
::nanobind::class_<QPClass>(m, "QP")
35+
.def(::nanobind::init<isize,
36+
isize,
37+
isize,
38+
bool,
39+
proxsuite::proxqp::HessianType,
40+
proxsuite::proxqp::DenseBackend>(),
41+
nanobind::arg("n") = 0,
42+
nanobind::arg("n_eq") = 0,
43+
nanobind::arg("n_in") = 0,
44+
nanobind::arg("box_constraints") = false,
45+
nanobind::arg("hessian_type") = proxsuite::proxqp::HessianType::Dense,
46+
nanobind::arg("dense_backend") =
47+
proxsuite::proxqp::DenseBackend::Automatic,
48+
"Default constructor using QP model dimensions.") // constructor
49+
.def_rw("results",
50+
&QPClass::results,
51+
"class containing the solution or certificate of infeasibility, "
52+
"and "
53+
"information statistics in an info subclass.")
54+
.def_rw("settings", &QPClass::settings, "Settings of the solver.")
55+
.def_rw("model", &QPClass::model, "class containing the QP model")
56+
.def("is_box_constrained",
57+
&QPClass::is_box_constrained,
58+
"precise whether or not the QP is designed with box constraints.")
59+
.def("which_hessian_type",
60+
&QPClass::which_hessian_type,
61+
"precise which problem type is to be solved.")
62+
.def("which_dense_backend",
63+
&QPClass::which_dense_backend,
64+
"precise which dense backend is chosen.")
65+
.def("init",
66+
static_cast<void (QPClass::*)(optional<proxqp::dense::MatRef<T>>,
67+
optional<proxqp::dense::VecRef<T>>,
68+
optional<proxqp::dense::MatRef<T>>,
69+
optional<proxqp::dense::VecRef<T>>,
70+
optional<proxqp::dense::MatRef<T>>,
71+
optional<proxqp::dense::VecRef<T>>,
72+
optional<proxqp::dense::VecRef<T>>,
73+
bool compute_preconditioner,
74+
optional<T>,
75+
optional<T>,
76+
optional<T>,
77+
optional<T>)>(&QPClass::init),
78+
"function for initialize the QP model.",
79+
nanobind::arg("H"),
80+
nanobind::arg("g"),
81+
nanobind::arg("A") = nanobind::none(),
82+
nanobind::arg("b") = nanobind::none(),
83+
nanobind::arg("C") = nanobind::none(),
84+
nanobind::arg("l") = nanobind::none(),
85+
nanobind::arg("u") = nanobind::none(),
86+
nanobind::arg("compute_preconditioner") = true,
87+
nanobind::arg("rho") = nanobind::none(),
88+
nanobind::arg("mu_eq") = nanobind::none(),
89+
nanobind::arg("mu_in") = nanobind::none(),
90+
nanobind::arg("manual_minimal_H_eigenvalue") = nanobind::none())
91+
.def("init",
92+
static_cast<void (QPClass::*)(optional<proxqp::dense::MatRef<T>>,
93+
optional<proxqp::dense::VecRef<T>>,
94+
optional<proxqp::dense::MatRef<T>>,
95+
optional<proxqp::dense::VecRef<T>>,
96+
optional<proxqp::dense::MatRef<T>>,
97+
optional<proxqp::dense::VecRef<T>>,
98+
optional<proxqp::dense::VecRef<T>>,
99+
optional<proxqp::dense::VecRef<T>>,
100+
optional<proxqp::dense::VecRef<T>>,
101+
bool compute_preconditioner,
102+
optional<T>,
103+
optional<T>,
104+
optional<T>,
105+
optional<T>)>(&QPClass::init),
106+
"function for initialize the QP model.",
107+
nanobind::arg("H") = nanobind::none(),
108+
nanobind::arg("g") = nanobind::none(),
109+
nanobind::arg("A") = nanobind::none(),
110+
nanobind::arg("b") = nanobind::none(),
111+
nanobind::arg("C") = nanobind::none(),
112+
nanobind::arg("l") = nanobind::none(),
113+
nanobind::arg("u") = nanobind::none(),
114+
nanobind::arg("l_box") = nanobind::none(),
115+
nanobind::arg("u_box") = nanobind::none(),
116+
nanobind::arg("compute_preconditioner") = true,
117+
nanobind::arg("rho") = nanobind::none(),
118+
nanobind::arg("mu_eq") = nanobind::none(),
119+
nanobind::arg("mu_in") = nanobind::none(),
120+
nanobind::arg("manual_minimal_H_eigenvalue") = nanobind::none())
121+
.def("solve",
122+
static_cast<void (QPClass::*)()>(&QPClass::solve),
123+
"function used for solving the QP problem, using default parameters.")
124+
.def("solve",
125+
static_cast<void (QPClass::*)(optional<proxqp::dense::VecRef<T>> x,
126+
optional<proxqp::dense::VecRef<T>> y,
127+
optional<proxqp::dense::VecRef<T>> z)>(
128+
&QPClass::solve),
129+
"function used for solving the QP problem, when passing a warm start.")
130+
131+
.def("update",
132+
static_cast<void (QPClass::*)(optional<proxqp::dense::MatRef<T>>,
133+
optional<proxqp::dense::VecRef<T>>,
134+
optional<proxqp::dense::MatRef<T>>,
135+
optional<proxqp::dense::VecRef<T>>,
136+
optional<proxqp::dense::MatRef<T>>,
137+
optional<proxqp::dense::VecRef<T>>,
138+
optional<proxqp::dense::VecRef<T>>,
139+
bool update_preconditioner,
140+
optional<T>,
141+
optional<T>,
142+
optional<T>,
143+
optional<T>)>(&QPClass::update),
144+
"function used for updating matrix or vector entry of the model using "
145+
"dense matrix entries.",
146+
nanobind::arg("H") = nanobind::none(),
147+
nanobind::arg("g") = nanobind::none(),
148+
nanobind::arg("A") = nanobind::none(),
149+
nanobind::arg("b") = nanobind::none(),
150+
nanobind::arg("C") = nanobind::none(),
151+
nanobind::arg("l") = nanobind::none(),
152+
nanobind::arg("u") = nanobind::none(),
153+
nanobind::arg("update_preconditioner") = false,
154+
nanobind::arg("rho") = nanobind::none(),
155+
nanobind::arg("mu_eq") = nanobind::none(),
156+
nanobind::arg("mu_in") = nanobind::none(),
157+
nanobind::arg("manual_minimal_H_eigenvalue") = nanobind::none())
158+
.def("update",
159+
static_cast<void (QPClass::*)(optional<proxqp::dense::MatRef<T>>,
160+
optional<proxqp::dense::VecRef<T>>,
161+
optional<proxqp::dense::MatRef<T>>,
162+
optional<proxqp::dense::VecRef<T>>,
163+
optional<proxqp::dense::MatRef<T>>,
164+
optional<proxqp::dense::VecRef<T>>,
165+
optional<proxqp::dense::VecRef<T>>,
166+
optional<proxqp::dense::VecRef<T>>,
167+
optional<proxqp::dense::VecRef<T>>,
168+
bool update_preconditioner,
169+
optional<T>,
170+
optional<T>,
171+
optional<T>,
172+
optional<T>)>(&QPClass::update),
173+
"function used for updating matrix or vector entry of the model using "
174+
"dense matrix entries.",
175+
nanobind::arg("H") = nanobind::none(),
176+
nanobind::arg("g") = nanobind::none(),
177+
nanobind::arg("A") = nanobind::none(),
178+
nanobind::arg("b") = nanobind::none(),
179+
nanobind::arg("C") = nanobind::none(),
180+
nanobind::arg("l") = nanobind::none(),
181+
nanobind::arg("u") = nanobind::none(),
182+
nanobind::arg("l_box") = nanobind::none(),
183+
nanobind::arg("u_box") = nanobind::none(),
184+
nanobind::arg("update_preconditioner") = false,
185+
nanobind::arg("rho") = nanobind::none(),
186+
nanobind::arg("mu_eq") = nanobind::none(),
187+
nanobind::arg("mu_in") = nanobind::none(),
188+
nanobind::arg("manual_minimal_H_eigenvalue") = nanobind::none())
189+
.def("cleanup",
190+
&QPClass::cleanup,
191+
"function used for cleaning the workspace and result "
192+
"classes.")
193+
.def(nanobind::self == nanobind::self)
194+
.def(nanobind::self != nanobind::self)
195+
.def("__getstate__",
196+
[](const QPClass& qp) {
197+
return proxsuite::serialization::saveToString(qp);
198+
})
199+
.def("__setstate__", [](QPClass& qp, const std::string& s) {
200+
new (&qp) QPClass(1, 1, 1);
201+
proxsuite::serialization::loadFromString(qp, s);
202+
});
203+
;
204+
}
205+
206+
// TODO: Define some function solveDenseQP with templates or other to avoid code
207+
// duplication (2 functions solveDenseQP in the expose-solve.hpp files)
208+
// Challenge: The functions are not gievn by means of a class like previously,
209+
// by definition of the solve function without API. Then, find some way to
210+
// provide generic coding on namespaces (as wa have
211+
// proxsuite::proxqp::dense::solve<T> and proxsuite::osqp::dense::solve<T>)
212+
213+
} // namespace python
214+
} // namespace dense
215+
216+
} // namespace common
217+
} // namespace proxsuite
218+
219+
#endif // bindings_python_src_common_expose
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Copyright (c) 2022-2024 INRIA
3+
//
4+
5+
#include "pytypedefs.h"
6+
#include <nanobind/nanobind.h>
7+
#include <nanobind/eigen/dense.h>
8+
#include <nanobind/eigen/sparse.h>
9+
10+
namespace proxsuite {
11+
namespace common {
12+
namespace python {
13+
14+
namespace detail {
15+
inline auto
16+
type_name_short(nanobind::handle h)
17+
{
18+
namespace nb = nanobind;
19+
assert(h.is_type());
20+
assert(nb::type_check(h));
21+
return nb::steal<nb::str>(PyType_GetName((PyTypeObject*)h.ptr()));
22+
}
23+
} // namespace detail
24+
25+
/*!
26+
* Exposes a type and export its values given the first definition in proxqp
27+
* module.
28+
*
29+
* @param m nanobind module (proxsuite).
30+
*/
31+
template<typename E>
32+
void
33+
exposeAndExportValues(nanobind::module_& m, bool export_values = true)
34+
{
35+
namespace nb = nanobind;
36+
nb::handle t = nb::type<E>();
37+
if (!t.is_valid()) {
38+
throw std::runtime_error("Invalid type");
39+
}
40+
#ifndef NDEBUG
41+
assert(t.is_type());
42+
#endif
43+
nb::enum_<E>& t_ = static_cast<nb::enum_<E>&>(t);
44+
nb::str name = detail::type_name_short(t);
45+
46+
m.attr(name) = t_;
47+
if (export_values) {
48+
for (nb::handle item : t) {
49+
m.attr(item.attr("name")) = item;
50+
}
51+
}
52+
}
53+
54+
} // namespace python
55+
} // namespace common
56+
} // namespace proxsuite

0 commit comments

Comments
 (0)