alpaqa 0.0.1
Nonconvex constrained optimization
CasADiLoader.cpp
Go to the documentation of this file.
3
4#include <casadi/core/external.hpp>
5
6#include <memory>
7#include <optional>
8#include <stdexcept>
9
10namespace alpaqa {
11
12#if 0
13std::function<alpaqa::Problem::f_sig>
14load_CasADi_objective(const std::string &so_name, const std::string &fun_name) {
15 return CasADiFun_1Vi1So(casadi::external(fun_name, so_name));
16}
17std::function<alpaqa::Problem::grad_f_sig>
18load_CasADi_gradient_objective(const std::string &so_name,
19 const std::string &fun_name) {
20 return CasADiFun_1Vi1Vo(casadi::external(fun_name, so_name));
21}
22std::function<alpaqa::Problem::g_sig>
23load_CasADi_constraints(const std::string &so_name,
24 const std::string &fun_name) {
25 return CasADiFun_1Vi1Vo(casadi::external(fun_name, so_name));
26}
27std::function<alpaqa::Problem::grad_g_prod_sig>
28load_CasADi_gradient_constraints_prod(const std::string &so_name,
29 const std::string &fun_name) {
30 return [csf{CasADiFun_2Vi1Vo(casadi::external(fun_name, so_name))}] //
32 if (y.size() == 0)
33 gradprod.setZero();
34 else
35 csf(x, y, gradprod);
36 };
37}
38std::function<alpaqa::Problem::hess_L_sig>
39load_CasADi_hessian_lagrangian(const std::string &so_name,
40 const std::string &fun_name) {
41 return [csf{CasADiFun_2Vi1Mo(casadi::external(fun_name, so_name))}] //
43 // Fix the stride if the matrix is larger than n
44 if (x.rows() != H.rows()) { // TODO: this is probably unnecessary
45 for (auto c = x.rows(); c-- > 1;)
46 for (auto r = x.rows(); r-- > 0;)
47 std::swap(H(r, c), H.data()[r + x.rows() * c]);
48 }
49 csf(x, y, H);
50 // Fix the stride if the matrix is larger than n
51 if (x.rows() != H.rows()) {
52 for (auto c = x.rows(); c-- > 1;)
53 for (auto r = x.rows(); r-- > 0;)
54 std::swap(H(r, c), H.data()[r + x.rows() * c]);
55 }
56 };
57}
58std::function<alpaqa::Problem::hess_L_prod_sig>
59load_CasADi_hessian_lagrangian_prod(const std::string &so_name,
60 const std::string &fun_name) {
61 return CasADiFun_3Vi1Vo(casadi::external(fun_name, so_name));
62}
63#endif
64
65template <class F>
66auto wrap_load(const std::string &so_name, const char *name, F f) {
67 try {
68 return f();
69 } catch (const std::invalid_argument &e) {
70 throw std::invalid_argument("Unable to load function '" + so_name +
71 ":" + name + "': " + e.what());
72 }
73}
74
75template <class T, class... Args>
76auto wrapped_load(const std::string &so_name, const char *name,
77 Args &&...args) {
78 return wrap_load(so_name, name, [&] {
79 return T(casadi::external(name, so_name), std::forward<Args>(args)...);
80 });
81}
82
83constexpr static auto dims = [](auto... a) {
84 return std::array<casadi_int, sizeof...(a)>{a...};
85};
86using dim = std::pair<casadi_int, casadi_int>;
87
88alpaqa::Problem load_CasADi_problem(const std::string &so_name, unsigned n,
89 unsigned m, bool second_order) {
90
91 auto load_g_unknown_dims = [&] {
92 CasADiFunctionEvaluator<1, 1> g{casadi::external("g", so_name)};
93 if (g.fun.size2_in(0) != 1)
94 throw std::invalid_argument(
95 "First input argument should be a column vector.");
96 if (g.fun.size2_out(0) != 1)
97 throw std::invalid_argument(
98 "First output argument should be a column vector.");
99 if (n == 0)
100 n = g.fun.size1_in(0);
101 if (m == 0)
102 m = g.fun.size1_out(0);
103 g.validate_dimensions({dim(n, 1)}, {dim(m, 1)});
104 return g;
105 };
106
107 auto load_g_known_dims = [&] {
109 casadi::external("g", so_name), {dim(n, 1)}, {dim(m, 1)}};
110 return g;
111 };
112
114 (n == 0 || m == 0)
115 // If not all dimensions are specified, load the function "g" to
116 //determine the missing dimensions.
117 ? wrap_load(so_name, "g", load_g_unknown_dims)
118 // Otherwise, load the function "g" and compare its dimensions to
119 // the dimensions specified by the user.
120 : wrap_load(so_name, "g", load_g_known_dims);
121
122 auto prob = alpaqa::Problem(n, m);
123
124 prob.f = wrapped_load<CasADiFun_1Vi1So>(so_name, "f", n);
125 prob.grad_f = wrapped_load<CasADiFun_1Vi1Vo>(so_name, "grad_f", n, n);
126 prob.g = CasADiFun_1Vi1Vo(std::move(g));
127 auto grad_g =
128 wrapped_load<CasADiFun_2Vi1Vo>(so_name, "grad_g", dims(n, m), n);
129 prob.grad_g_prod = grad_g;
130 if (second_order) {
131 alpaqa::vec w = alpaqa::vec::Zero(m);
132 prob.grad_gi = //
133 [grad_g, w](alpaqa::crvec x, unsigned i, alpaqa::rvec g) mutable {
134 w(i) = 1;
135 grad_g(x, w, g);
136 w(i) = 0;
137 };
138 prob.hess_L = //
139 wrapped_load<CasADiFun_2Vi1Mo>(so_name, "hess_L", //
140 dims(n, m), dim(n, n)); //
141 prob.hess_L_prod = //
142 wrapped_load<CasADiFun_3Vi1Vo>(so_name, "hess_L_prod", //
143 dims(n, m, n), n); //
144 }
145 return prob;
146}
147
149 : public ParamWrapper,
150 public std::enable_shared_from_this<CasADiParamWrapper> {
151
152 public:
153 struct Functions {
158 std::optional<CasADiFun_3Vi1Mo> hess_L;
159 std::optional<CasADiFun_4Vi1Vo> hess_L_prod;
160 } cs;
161
162 private:
163 CasADiParamWrapper(unsigned p, Functions &&functions)
164 : ParamWrapper(p), cs(std::move(functions)) {}
165
166 public:
167 static std::shared_ptr<CasADiParamWrapper> create(unsigned p,
168 Functions &&functions) {
169 return std::make_shared<CasADiParamWrapper>(CasADiParamWrapper{
170 p,
171 std::move(functions),
172 });
173 }
174
175 void wrap(Problem &prob) override {
176 auto param = this->shared_from_this();
177 prob.f = [param](crvec x) -> real_t {
178 return param->cs.f(x, param->param);
179 };
180 prob.grad_f = [param](crvec x, rvec gr) {
181 param->cs.grad_f(x, param->param, gr);
182 };
183 prob.g = [param](crvec x, rvec g) -> void {
184 param->cs.g(x, param->param, g);
185 };
186 prob.grad_g_prod = [param](crvec x, crvec y, rvec g) {
187 param->cs.grad_g_prod(x, param->param, y, g);
188 };
189 alpaqa::vec w = alpaqa::vec::Zero(prob.m);
190 prob.grad_gi = [param, w](crvec x, unsigned i, rvec g) mutable {
191 w(i) = 1;
192 param->cs.grad_g_prod(x, param->param, w, g);
193 w(i) = 0;
194 };
195 if (param->cs.hess_L) {
196 prob.hess_L = [param](crvec x, crvec y, rvec g) {
197 (*param->cs.hess_L)(x, param->param, y, g);
198 };
199 }
200 if (param->cs.hess_L_prod) {
201 prob.hess_L_prod = [param](crvec x, crvec y, crvec v, rvec g) {
202 (*param->cs.hess_L_prod)(x, param->param, y, v, g);
203 };
204 }
205 }
206
207 std::shared_ptr<ParamWrapper> clone() const override {
208 return std::make_shared<CasADiParamWrapper>(*this);
209 }
210};
211
213 unsigned n, unsigned m,
214 unsigned p, bool second_order) {
215
216 auto load_g_unknown_dims = [&] {
217 CasADiFunctionEvaluator<2, 1> g{casadi::external("g", so_name)};
218 if (g.fun.size2_in(0) != 1)
219 throw std::invalid_argument(
220 "First input argument should be a column vector.");
221 if (g.fun.size2_in(1) != 1)
222 throw std::invalid_argument(
223 "Second input argument should be a column vector.");
224 if (g.fun.size2_out(0) != 1)
225 throw std::invalid_argument(
226 "First output argument should be a column vector.");
227 if (n == 0)
228 n = g.fun.size1_in(0);
229 if (m == 0)
230 m = g.fun.size1_out(0);
231 if (p == 0)
232 p = g.fun.size1_in(1);
233 g.validate_dimensions({dim(n, 1), dim(p, 1)}, {dim(m, 1)});
234 return g;
235 };
236
237 auto load_g_known_dims = [&] {
238 CasADiFunctionEvaluator<2, 1> g{casadi::external("g", so_name),
239 {dim(n, 1), dim(p, 1)},
240 {dim(m, 1)}};
241 return g;
242 };
243
245 (n == 0 || m == 0 || p == 0)
246 // If not all dimensions are specified, load the function "g" to
247 // determine the missing dimensions.
248 ? wrap_load(so_name, "g", load_g_unknown_dims)
249 // Otherwise, load the function "g" and compare its dimensions to
250 // the dimensions specified by the user.
251 : wrap_load(so_name, "g", load_g_known_dims);
252
253 auto prob = ProblemWithParam(n, m);
254
256 p,
257 {
258 wrapped_load<CasADiFun_2Vi1So>(so_name, "f", dims(n, p)),
259 wrapped_load<CasADiFun_2Vi1Vo>(so_name, "grad_f", dims(n, p), n),
260 CasADiFun_2Vi1Vo(std::move(g)),
261 wrapped_load<CasADiFun_3Vi1Vo>(so_name, "grad_g", dims(n, p, m), n),
262 second_order ? std::make_optional(wrapped_load<CasADiFun_3Vi1Mo>(
263 so_name, "hess_L", dims(n, p, m), dim(n, n)))
264 : std::nullopt,
265 second_order ? std::make_optional(wrapped_load<CasADiFun_4Vi1Vo>(
266 so_name, "hess_L_prod", dims(n, p, m, n), n))
267 : std::nullopt,
268 });
269 prob.wrapper->wrap(prob);
270 return prob;
271}
272
273} // namespace alpaqa
Wrapper for CasADiFunctionEvaluator with 1 vector input, scalar output.
Wrapper for CasADiFunctionEvaluator with 1 vector input, 1 vector output.
Wrapper for CasADiFunctionEvaluator with 2 vector inputs, 1 matrix output.
Wrapper for CasADiFunctionEvaluator with 2 vector inputs, scalar output.
Wrapper for CasADiFunctionEvaluator with 2 vector inputs, 1 vector output.
Wrapper for CasADiFunctionEvaluator with 3 vector inputs, 1 vector output.
Class for evaluating CasADi functions, allocating the necessary workspace storage in advance for allo...
struct alpaqa::CasADiParamWrapper::Functions cs
std::shared_ptr< ParamWrapper > clone() const override
std::optional< CasADiFun_4Vi1Vo > hess_L_prod
std::optional< CasADiFun_3Vi1Mo > hess_L
void wrap(Problem &prob) override
static std::shared_ptr< CasADiParamWrapper > create(unsigned p, Functions &&functions)
CasADiParamWrapper(unsigned p, Functions &&functions)
ProblemWithParam load_CasADi_problem_with_param(const std::string &filename, unsigned n=0, unsigned m=0, unsigned p=0, bool second_order=false)
Load a problem generated by CasADi (with parameters).
alpaqa::Problem load_CasADi_problem(const std::string &filename, unsigned n=0, unsigned m=0, bool second_order=false)
Load a problem generated by CasADi (without parameters).
int m
Definition: test.py:41
int n
Definition: test.py:40
Eigen::Ref< const vec > crvec
Default type for immutable references to vectors.
Definition: vec.hpp:18
std::pair< casadi_int, casadi_int > dim
realvec vec
Default type for vectors.
Definition: vec.hpp:14
auto wrapped_load(const std::string &so_name, const char *name, Args &&...args)
constexpr static auto dims
Eigen::Ref< mat > rmat
Default type for mutable references to matrices.
Definition: vec.hpp:22
double real_t
Default floating point type.
Definition: vec.hpp:8
auto wrap_load(const std::string &so_name, const char *name, F f)
Eigen::Ref< vec > rvec
Default type for mutable references to vectors.
Definition: vec.hpp:16
H
Definition: main.py:8
Problem description for minimization problems.