Skip to content

Commit 3a60ec7

Browse files
authored
Merge pull request #152 from fabinsch/topic/serialize-qp-model-cereal
Add serialization of dense qp model using cereal
2 parents 37c48f5 + 6194fb4 commit 3a60ec7

File tree

21 files changed

+1042
-12
lines changed

21 files changed

+1042
-12
lines changed

.gitmodules

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
url = https://github.com/pybind/pybind11
44
[submodule "cmake-module"]
55
path = cmake-module
6-
url = https://github.com/jrl-umi3218/jrl-cmakemodules.git
6+
url = https://github.com/jrl-umi3218/jrl-cmakemodules.git
7+
[submodule "external/cereal"]
8+
path = external/cereal
9+
url = https://github.com/USCiLab/cereal.git

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ if(BUILD_WITH_VECTORIZATION_SUPPORT)
141141
list(APPEND EXPORTED_TARGETS_LIST proxsuite-vectorized)
142142
endif()
143143

144+
if(BUILD_TESTING OR BUILD_PYTHON_INTERFACE)
145+
# Download cereal for pything bindings and unittests
146+
set(cereal_dir ${PROJECT_SOURCE_DIR}/external/cereal)
147+
set(cereal ${cereal_dir}/README.md)
148+
find_package(Git REQUIRED)
149+
if(NOT EXISTS ${cereal})
150+
execute_process(
151+
COMMAND ${GIT_EXECUTABLE} submodule update --init ${cereal_dir}
152+
WORKING_DIRECTORY ${cereal_dir} COMMAND_ERROR_IS_FATAL ANY)
153+
endif()
154+
endif()
155+
144156
if(NOT PROXSUITE_AS_SUBPROJECT)
145157
install(
146158
TARGETS ${EXPORTED_TARGETS_LIST}

bindings/python/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ function(CREATE_PYTHON_TARGET target_name COMPILE_OPTIONS dependencies)
5151
target_link_libraries(${target_name} PRIVATE proxsuite pybind11::module)
5252
target_compile_definitions(${target_name}
5353
PRIVATE PYTHON_MODULE_NAME=${target_name})
54+
target_include_directories(
55+
${target_name} PRIVATE ${PROJECT_SOURCE_DIR}/external/cereal/include)
5456
set_target_properties(
5557
${target_name}
5658
PROPERTIES OUTPUT_NAME ${target_name}

bindings/python/src/expose-model.hpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
//
22
// Copyright (c) 2022 INRIA
33
//
4-
#include <proxsuite/proxqp/dense/model.hpp>
5-
#include <proxsuite/proxqp/sparse/model.hpp>
4+
65
#include <pybind11/pybind11.h>
76
#include <pybind11/eigen.h>
7+
#include <pybind11/operators.h>
8+
9+
#include <proxsuite/proxqp/dense/model.hpp>
10+
#include <proxsuite/proxqp/sparse/model.hpp>
811
#include <proxsuite/proxqp/dense/utils.hpp>
12+
#include <proxsuite/serialization/archive.hpp>
13+
#include <proxsuite/serialization/eigen.hpp>
14+
#include <proxsuite/serialization/model.hpp>
915

1016
namespace proxsuite {
1117
namespace proxqp {
@@ -34,7 +40,21 @@ exposeDenseModel(pybind11::module_ m)
3440
.def_readonly("n_total", &Model<T>::n_total)
3541
.def("is_valid",
3642
&Model<T>::is_valid,
37-
"Check if model is containing valid data.");
43+
"Check if model is containing valid data.")
44+
.def(pybind11::self == pybind11::self)
45+
.def(pybind11::self != pybind11::self)
46+
.def(pybind11::pickle(
47+
48+
[](const proxsuite::proxqp::dense::Model<T>& model) {
49+
return pybind11::bytes(proxsuite::serialization::saveToString(model));
50+
},
51+
[](pybind11::bytes& s) {
52+
// create qp model which will be updated by loaded data
53+
proxsuite::proxqp::dense::Model<T> model(1, 1, 1);
54+
proxsuite::serialization::loadFromString(model, s);
55+
56+
return model;
57+
}));
3858
}
3959
} // namespace python
4060
} // namespace dense

bindings/python/src/expose-qpobject.hpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
// Copyright (c) 2022 INRIA
33
//
44

5-
#include <proxsuite/proxqp/dense/wrapper.hpp>
6-
#include <proxsuite/proxqp/sparse/wrapper.hpp>
7-
#include <proxsuite/proxqp/status.hpp>
85
#include <pybind11/pybind11.h>
96
#include <pybind11/eigen.h>
107
#include <pybind11/stl.h>
118

9+
#include <proxsuite/proxqp/dense/wrapper.hpp>
10+
#include <proxsuite/proxqp/sparse/wrapper.hpp>
11+
#include <proxsuite/proxqp/status.hpp>
12+
#include <proxsuite/serialization/archive.hpp>
13+
#include <proxsuite/serialization/wrapper.hpp>
14+
1215
namespace proxsuite {
1316
namespace proxqp {
1417
using proxsuite::linalg::veg::isize;
@@ -114,7 +117,20 @@ exposeQpObjectDense(pybind11::module_ m)
114117
.def("cleanup",
115118
&dense::QP<T>::cleanup,
116119
"function used for cleaning the workspace and result "
117-
"classes.");
120+
"classes.")
121+
.def(pybind11::self == pybind11::self)
122+
.def(pybind11::self != pybind11::self)
123+
.def(pybind11::pickle(
124+
125+
[](const dense::QP<T>& qp) {
126+
return pybind11::bytes(proxsuite::serialization::saveToString(qp));
127+
},
128+
[](pybind11::bytes& s) {
129+
proxsuite::proxqp::dense::QP<T> qp(1, 1, 1);
130+
proxsuite::serialization::loadFromString(qp, s);
131+
return qp;
132+
}));
133+
;
118134
}
119135
} // namespace python
120136
} // namespace dense

bindings/python/src/expose-results.hpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include <proxsuite/proxqp/results.hpp>
55
#include <pybind11/pybind11.h>
66
#include <pybind11/eigen.h>
7+
#include <pybind11/operators.h>
8+
9+
#include <proxsuite/serialization/archive.hpp>
10+
#include <proxsuite/serialization/results.hpp>
711

812
#include "helpers.hpp"
913
#include "optional.hpp"
@@ -61,7 +65,20 @@ exposeResults(pybind11::module_ m)
6165
Results<T>,
6266
z,
6367
"The dual solution associated to the inequality constraints.")
64-
.def_readwrite("info", &Results<T>::info);
68+
.def_readwrite("info", &Results<T>::info)
69+
.def(pybind11::self == pybind11::self)
70+
.def(pybind11::self != pybind11::self)
71+
.def(pybind11::pickle(
72+
73+
[](const Results<T>& results) {
74+
return pybind11::bytes(proxsuite::serialization::saveToString(results));
75+
},
76+
[](pybind11::bytes& s) {
77+
Results<T> results;
78+
proxsuite::serialization::loadFromString(results, s);
79+
return results;
80+
}));
81+
;
6582
}
6683
} // namespace python
6784
} // namespace proxqp

bindings/python/src/expose-settings.hpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
//
22
// Copyright (c) 2022 INRIA
33
//
4-
#include <proxsuite/proxqp/settings.hpp>
5-
#include <proxsuite/proxqp/status.hpp>
64
#include <pybind11/pybind11.h>
75
#include <pybind11/eigen.h>
6+
#include <pybind11/operators.h>
7+
8+
#include <proxsuite/proxqp/settings.hpp>
9+
#include <proxsuite/proxqp/status.hpp>
10+
#include <proxsuite/serialization/archive.hpp>
11+
#include <proxsuite/serialization/settings.hpp>
812

913
namespace proxsuite {
1014
namespace proxqp {
@@ -67,7 +71,21 @@ exposeSettings(pybind11::module_ m)
6771
&Settings<T>::compute_preconditioner)
6872
.def_readwrite("update_preconditioner", &Settings<T>::update_preconditioner)
6973
.def_readwrite("verbose", &Settings<T>::verbose)
70-
.def_readwrite("bcl_update", &Settings<T>::bcl_update);
74+
.def_readwrite("bcl_update", &Settings<T>::bcl_update)
75+
.def(pybind11::self == pybind11::self)
76+
.def(pybind11::self != pybind11::self)
77+
.def(pybind11::pickle(
78+
79+
[](const Settings<T>& settings) {
80+
return pybind11::bytes(
81+
proxsuite::serialization::saveToString(settings));
82+
},
83+
[](pybind11::bytes& s) {
84+
Settings<T> settings;
85+
proxsuite::serialization::loadFromString(settings, s);
86+
return settings;
87+
}));
88+
;
7189
}
7290
} // namespace python
7391
} // namespace proxqp

external/cereal

Submodule cereal added at ddd4672

include/proxsuite/proxqp/dense/model.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,27 @@ struct Model
119119
#undef PROXSUITE_CHECK_SIZE
120120
}
121121
};
122+
123+
template<typename T>
124+
bool
125+
operator==(const Model<T>& model1, const Model<T>& model2)
126+
{
127+
bool value = model1.dim == model2.dim && model1.n_eq == model2.n_eq &&
128+
model1.n_in == model2.n_in && model1.n_total == model2.n_total &&
129+
model1.H == model2.H && model1.g == model2.g &&
130+
model1.A == model2.A && model1.b == model2.b &&
131+
model1.C == model2.C && model1.l == model2.l &&
132+
model1.u == model2.u;
133+
return value;
134+
}
135+
136+
template<typename T>
137+
bool
138+
operator!=(const Model<T>& model1, const Model<T>& model2)
139+
{
140+
return !(model1 == model2);
141+
}
142+
122143
} // namespace dense
123144
} // namespace proxqp
124145
} // namespace proxsuite

include/proxsuite/proxqp/dense/wrapper.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,23 @@ solve(
451451

452452
return Qp.results;
453453
}
454+
455+
template<typename T>
456+
bool
457+
operator==(const QP<T>& qp1, const QP<T>& qp2)
458+
{
459+
bool value = qp1.model == qp2.model && qp1.settings == qp2.settings &&
460+
qp1.results == qp2.results;
461+
return value;
462+
}
463+
464+
template<typename T>
465+
bool
466+
operator!=(const QP<T>& qp1, const QP<T>& qp2)
467+
{
468+
return !(qp1 == qp2);
469+
}
470+
454471
} // namespace dense
455472
} // namespace proxqp
456473
} // namespace proxsuite

0 commit comments

Comments
 (0)