Nonconvex constrained optimization
Loading...
Searching...
No Matches
dl-problem.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <alpaqa/dl-loader-export.h>
8#include <guanaqo/demangled-typename.hpp>
9#include <guanaqo/dl-flags.hpp>
10#include <guanaqo/dl.hpp>
11
12#include <filesystem>
13#include <memory>
14#include <span>
15#include <stdexcept>
16#include <string>
17#include <string_view>
18#include <type_traits>
19
20namespace alpaqa::dl {
21
22using guanaqo::dynamic_load_error;
23using guanaqo::DynamicLoadFlags;
24
25struct invalid_abi_error : dynamic_load_error {
26 using dynamic_load_error::dynamic_load_error;
27};
28
30 public:
31 /// Unique type for calling an extra function that is a member function.
32 struct instance_t;
33
34 ExtraFuncs() = default;
35 ExtraFuncs(std::shared_ptr<function_dict_t> &&extra_funcs)
36 : extra_functions(std::move(extra_funcs)) {}
37
38 /// An associative array of additional functions exposed by the problem.
39 std::shared_ptr<function_dict_t> extra_functions;
40
41 template <class Signature>
42 requires std::is_function_v<Signature>
43 const std::function<Signature> &extra_func(const std::string &name) const {
44 if (!extra_functions)
45 throw std::out_of_range("DLProblem: no extra functions");
46 auto it = extra_functions->dict.find(name);
47 if (it == extra_functions->dict.end())
48 throw std::out_of_range("DLProblem: no extra function named \"" +
49 name + '"');
50 try {
52 return std::any_cast<const func_t &>(it->second).function;
53 } catch (const std::bad_any_cast &) {
54 throw std::logic_error(
55 "DLProblem: incorrect type for extra function \"" + name +
56 "\" (stored type: " +
57 guanaqo::demangled_typename(it->second.type()) + ')');
58 }
59 }
60
61 template <class Func>
62 struct FuncTag {};
63
64 template <class Ret, class... FArgs, class... Args>
65 decltype(auto)
66 call_extra_func_helper(const void *instance,
67 FuncTag<Ret(const instance_t *, FArgs...)>,
68 const std::string &name, Args &&...args) const {
69 return extra_func<Ret(const void *, FArgs...)>(name)(
70 instance, std::forward<Args>(args)...);
71 }
72
73 template <class Ret, class... FArgs, class... Args>
74 decltype(auto)
75 call_extra_func_helper(void *instance, FuncTag<Ret(instance_t *, FArgs...)>,
76 const std::string &name, Args &&...args) {
77 return extra_func<Ret(void *, FArgs...)>(name)(
78 instance, std::forward<Args>(args)...);
79 }
80
81 template <class Ret, class... FArgs, class... Args>
82 decltype(auto) call_extra_func_helper(const void *, FuncTag<Ret(FArgs...)>,
83 const std::string &name,
84 Args &&...args) const {
85 return extra_func<Ret(FArgs...)>(name)(std::forward<Args>(args)...);
86 }
87};
88
89/// Class that loads a problem using `dlopen`.
90///
91/// The shared library should export a C function with the name @c function_name
92/// that accepts a void pointer with user data, and returns a struct of type
93/// @ref alpaqa_problem_register_t that contains all data to represent the
94/// problem, as well as function pointers for all required operations.
95/// See @ref C++/DLProblem/main.cpp and
96/// @ref problems/sparse-logistic-regression.cpp for examples.
97///
98/// @note Copies are shallow, they all share the same problem instance, take
99/// that into account when using multiple threads.
100///
101/// @ingroup grp_Problems
102/// @see @ref TypeErasedProblem
103/// @see @ref alpaqa_problem_functions_t
104/// @see @ref alpaqa_problem_register_t
105class DL_LOADER_EXPORT DLProblem : public BoxConstrProblem<DefaultConfig> {
106 public:
108
109 /// Load a problem from a shared library.
110 DLProblem(
111 /// Filename of the shared library to load.
112 const std::filesystem::path &so_filename,
113 /// Name of the problem registration function.
114 /// Should have signature
115 /// `alpaqa_problem_register_t(alpaqa_register_arg_t user_param)`.
116 const std::string &function_name = "register_alpaqa_problem",
117 /// Pointer to custom user data to pass to the registration function.
118 alpaqa_register_arg_t user_param = {},
119 /// Flags passed to dlopen when loading the problem.
120 DynamicLoadFlags dl_flags = {});
121 /// Load a problem from a shared library.
122 DLProblem(
123 /// Filename of the shared library to load.
124 const std::filesystem::path &so_filename,
125 /// Name of the problem registration function.
126 /// Should have signature
127 /// `alpaqa_problem_register_t(alpaqa_register_arg_t user_param)`.
128 const std::string &function_name,
129 /// Custom user data to pass to the registration function.
130 std::any &user_param,
131 /// Flags passed to dlopen when loading the problem.
132 DynamicLoadFlags dl_flags = {});
133 /// Load a problem from a shared library.
134 DLProblem(
135 /// Filename of the shared library to load.
136 const std::filesystem::path &so_filename,
137 /// Name of the problem registration function.
138 /// Should have signature
139 /// `alpaqa_problem_register_t(alpaqa_register_arg_t user_param)`.
140 const std::string &function_name,
141 /// Custom string arguments to pass to the registration function.
142 std::span<std::string_view> user_param,
143 /// Flags passed to dlopen when loading the problem.
144 DynamicLoadFlags dl_flags = {});
145
146 private:
147 /// Path to the shared module file.
148 std::filesystem::path file;
149 /// Handle to the shared module defining the problem.
150 std::shared_ptr<void> handle;
151 /// Problem instance created by the registration function, including the
152 /// deleter to destroy it.
153 std::shared_ptr<void> instance;
154 /// Pointer to the struct of function pointers for evaluating the objective,
155 /// constraints, their gradients, etc.
157 /// Dictionary of extra functions that were registered by the problem.
159
160 public:
161 // clang-format off
163 void eval_projection_multipliers(rvec y, real_t M) const;
164 real_t eval_proximal_gradient_step(real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p) const;
166 real_t eval_objective(crvec x) const;
167 void eval_objective_gradient(crvec x, rvec grad_fx) const;
168 void eval_constraints(crvec x, rvec gx) const;
169 void eval_constraints_gradient_product(crvec x, crvec y, rvec grad_gxy) const;
170 void eval_constraints_jacobian(crvec x, rvec J_values) const;
171 Sparsity get_constraints_jacobian_sparsity() const;
172 void eval_grad_gi(crvec x, index_t i, rvec grad_gi) const;
173 void eval_lagrangian_hessian_product(crvec x, crvec y, real_t scale, crvec v, rvec Hv) const;
174 void eval_lagrangian_hessian(crvec x, crvec y, real_t scale, rvec H_values) const;
175 Sparsity get_lagrangian_hessian_sparsity() const;
177 void eval_augmented_lagrangian_hessian(crvec x, crvec y, crvec Σ, real_t scale, rvec H_values) const;
182 void eval_lagrangian_gradient(crvec x, crvec y, rvec grad_L, rvec work_n) const;
184 void eval_augmented_lagrangian_gradient(crvec x, crvec y, crvec Σ, rvec grad_ψ, rvec work_n, rvec work_m) const;
185 real_t eval_augmented_lagrangian_and_gradient(crvec x, crvec y, crvec Σ, rvec grad_ψ, rvec work_n, rvec work_m) const;
186 std::string get_name() const;
187
188 [[nodiscard]] bool provides_eval_objective() const;
189 [[nodiscard]] bool provides_eval_objective_gradient() const;
190 [[nodiscard]] bool provides_eval_constraints() const;
191 [[nodiscard]] bool provides_eval_constraints_gradient_product() const;
192 [[nodiscard]] bool provides_eval_constraints_jacobian() const;
193 [[nodiscard]] bool provides_get_constraints_jacobian_sparsity() const;
194 [[nodiscard]] bool provides_eval_grad_gi() const;
195 [[nodiscard]] bool provides_eval_lagrangian_hessian_product() const;
196 [[nodiscard]] bool provides_eval_lagrangian_hessian() const;
197 [[nodiscard]] bool provides_get_lagrangian_hessian_sparsity() const;
199 [[nodiscard]] bool provides_eval_augmented_lagrangian_hessian() const;
201 [[nodiscard]] bool provides_eval_objective_and_gradient() const;
202 [[nodiscard]] bool provides_eval_objective_and_constraints() const;
204 [[nodiscard]] bool provides_eval_lagrangian_gradient() const;
205 [[nodiscard]] bool provides_eval_augmented_lagrangian() const;
206 [[nodiscard]] bool provides_eval_augmented_lagrangian_gradient() const;
207 [[nodiscard]] bool provides_eval_augmented_lagrangian_and_gradient() const;
208 [[nodiscard]] bool provides_get_variable_bounds() const;
209 [[nodiscard]] bool provides_get_general_bounds() const;
210 [[nodiscard]] bool provides_eval_inactive_indices_res_lna() const;
211 // clang-format on
212
213 using instance_t = ExtraFuncs::instance_t;
214
215 template <class Signature, class... Args>
216 decltype(auto) call_extra_func(const std::string &name,
217 Args &&...args) const {
218 return call_extra_func_helper(instance.get(),
220 std::forward<Args>(args)...);
221 }
222
223 template <class Signature, class... Args>
224 decltype(auto) call_extra_func(const std::string &name, Args &&...args) {
225 return extra_funcs.call_extra_func_helper(
227 std::forward<Args>(args)...);
228 }
229};
230
231#if ALPAQA_WITH_OCP
232
233/// Class that loads an optimal control problem using `dlopen`.
234///
235/// The shared library should export a C function with the name @c function_name
236/// that accepts a void pointer with user data, and returns a struct of type
237/// @ref alpaqa_control_problem_register_t that contains all data to represent
238/// the problem, as well as function pointers for all required operations.
239///
240/// @note Copies are shallow, they all share the same problem instance, take
241/// that into account when using multiple threads.
242///
243/// @ingroup grp_Problems
244/// @see @ref TypeErasedControlProblem
245class DL_LOADER_EXPORT DLControlProblem {
246 public:
249
250 /// Load a problem from a shared library.
252 /// Filename of the shared library to load.
253 const std::filesystem::path &so_filename,
254 /// Name of the problem registration function.
255 /// Should have signature
256 /// `alpaqa_control_problem_register_t(alpaqa_register_arg_t user_param)`.
257 const std::string &function_name = "register_alpaqa_control_problem",
258 /// Pointer to custom user data to pass to the registration function.
259 alpaqa_register_arg_t user_param = {},
260 /// Flags passed to dlopen when loading the problem.
261 DynamicLoadFlags dl_flags = {});
262
263 private:
264 /// Handle to the shared module defining the problem.
265 std::shared_ptr<void> handle;
266 /// Problem instance created by the registration function, including the
267 /// deleter to destroy it.
268 std::shared_ptr<void> instance;
269 /// Pointer to the struct of function pointers for evaluating the objective,
270 /// constraints, their gradients, etc.
272 /// Dictionary of extra functions that were registered by the problem.
274
275 public:
276 length_t get_N() const { return functions->N; }
277 length_t get_nx() const { return functions->nx; }
278 length_t get_nu() const { return functions->nu; }
279 length_t get_nh() const { return functions->nh; }
280 length_t get_nh_N() const { return functions->nh_N; }
281 length_t get_nc() const { return functions->nc; }
282 length_t get_nc_N() const { return functions->nc_N; }
283
284 void check() const {} // TODO
285
286 // clang-format off
287 void get_U(Box &U) const;
288 void get_D(Box &D) const;
289 void get_D_N(Box &D) const;
290 void get_x_init(rvec x_init) const;
291 void eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const;
292 void eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const;
293 void eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const;
294 void eval_h(index_t timestep, crvec x, crvec u, rvec h) const;
295 void eval_h_N(crvec x, rvec h) const;
296 [[nodiscard]] real_t eval_l(index_t timestep, crvec h) const;
297 [[nodiscard]] real_t eval_l_N(crvec h) const;
298 void eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const;
299 void eval_q_N(crvec x, crvec h, rvec q) const;
300 void eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const;
301 void eval_add_Q_N(crvec x, crvec h, rmat Q) const;
302 void eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const;
303 void eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const;
304 void eval_add_R_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_J, crindexvec mask_K, crvec v, rvec out, rvec work) const;
305 void eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const;
306 [[nodiscard]] length_t get_R_work_size() const;
307 [[nodiscard]] length_t get_S_work_size() const;
308 void eval_constr(index_t timestep, crvec x, rvec c) const;
309 void eval_constr_N(crvec x, rvec c) const;
310 void eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const;
311 void eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const;
312 void eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const;
313 void eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const;
314
315 [[nodiscard]] bool provides_get_D() const;
316 [[nodiscard]] bool provides_get_D_N() const;
317 [[nodiscard]] bool provides_eval_add_Q_N() const;
318 [[nodiscard]] bool provides_eval_add_R_prod_masked() const;
319 [[nodiscard]] bool provides_eval_add_S_prod_masked() const;
320 [[nodiscard]] bool provides_get_R_work_size() const;
321 [[nodiscard]] bool provides_get_S_work_size() const;
322 [[nodiscard]] bool provides_eval_constr() const;
323 [[nodiscard]] bool provides_eval_constr_N() const;
324 [[nodiscard]] bool provides_eval_grad_constr_prod() const;
325 [[nodiscard]] bool provides_eval_grad_constr_prod_N() const;
326 [[nodiscard]] bool provides_eval_add_gn_hess_constr() const;
327 [[nodiscard]] bool provides_eval_add_gn_hess_constr_N() const;
328 // clang-format on
329
330 using instance_t = ExtraFuncs::instance_t;
331
332 template <class Signature, class... Args>
333 decltype(auto) call_extra_func(const std::string &name,
334 Args &&...args) const {
335 return extra_funcs.call_extra_func_helper(
337 std::forward<Args>(args)...);
338 }
339
340 template <class Signature, class... Args>
341 decltype(auto) call_extra_func(const std::string &name, Args &&...args) {
342 return extra_funcs.call_extra_func_helper(
344 std::forward<Args>(args)...);
345 }
346};
347
348#endif
349
350} // namespace alpaqa::dl
BoxConstrProblem(length_t num_variables, length_t num_constraints)
ExtraFuncs::instance_t instance_t
DLControlProblem(const std::filesystem::path &so_filename, const std::string &function_name="register_alpaqa_control_problem", alpaqa_register_arg_t user_param={}, DynamicLoadFlags dl_flags={})
Load a problem from a shared library.
std::shared_ptr< void > instance
Problem instance created by the registration function, including the deleter to destroy it.
control_problem_functions_t * functions
Pointer to the struct of function pointers for evaluating the objective, constraints,...
decltype(auto) call_extra_func(const std::string &name, Args &&...args) const
alpaqa::Box< config_t > Box
decltype(auto) call_extra_func(const std::string &name, Args &&...args)
std::shared_ptr< void > handle
Handle to the shared module defining the problem.
ExtraFuncs extra_funcs
Dictionary of extra functions that were registered by the problem.
bool provides_eval_constraints_jacobian() const
ExtraFuncs::instance_t instance_t
bool provides_eval_objective() const
void eval_projection_multipliers(rvec y, real_t M) const
void eval_grad_gi(crvec x, index_t i, rvec grad_gi) const
Sparsity get_lagrangian_hessian_sparsity() const
void eval_objective_gradient(crvec x, rvec grad_fx) const
void eval_constraints(crvec x, rvec gx) const
void eval_constraints_gradient_product(crvec x, crvec y, rvec grad_gxy) const
real_t eval_augmented_lagrangian_and_gradient(crvec x, crvec y, crvec Σ, rvec grad_ψ, rvec work_n, rvec work_m) const
bool provides_eval_augmented_lagrangian() const
real_t eval_objective_and_gradient(crvec x, rvec grad_fx) const
bool provides_eval_constraints_gradient_product() const
bool provides_eval_objective_and_gradient() const
bool provides_eval_augmented_lagrangian_and_gradient() const
bool provides_eval_inactive_indices_res_lna() const
void eval_objective_gradient_and_constraints_gradient_product(crvec x, crvec y, rvec grad_f, rvec grad_gxy) const
std::shared_ptr< void > instance
Problem instance created by the registration function, including the deleter to destroy it.
bool provides_eval_objective_gradient_and_constraints_gradient_product() const
bool provides_eval_objective_and_constraints() const
real_t eval_objective(crvec x) const
decltype(auto) call_extra_func(const std::string &name, Args &&...args) const
DLProblem(const std::filesystem::path &so_filename, const std::string &function_name="register_alpaqa_problem", alpaqa_register_arg_t user_param={}, DynamicLoadFlags dl_flags={})
Load a problem from a shared library.
bool provides_get_lagrangian_hessian_sparsity() const
index_t eval_inactive_indices_res_lna(real_t γ, crvec x, crvec grad_ψ, rindexvec J) const
bool provides_eval_lagrangian_hessian_product() const
bool provides_get_constraints_jacobian_sparsity() const
void eval_augmented_lagrangian_hessian(crvec x, crvec y, crvec Σ, real_t scale, rvec H_values) const
void eval_augmented_lagrangian_gradient(crvec x, crvec y, crvec Σ, rvec grad_ψ, rvec work_n, rvec work_m) const
Sparsity get_constraints_jacobian_sparsity() const
bool provides_eval_constraints() const
bool provides_eval_augmented_lagrangian_hessian() const
void eval_lagrangian_gradient(crvec x, crvec y, rvec grad_L, rvec work_n) const
void eval_constraints_jacobian(crvec x, rvec J_values) const
real_t eval_objective_and_constraints(crvec x, rvec g) const
bool provides_eval_augmented_lagrangian_gradient() const
bool provides_get_variable_bounds() const
bool provides_eval_grad_gi() const
std::filesystem::path file
Path to the shared module file.
problem_functions_t * functions
Pointer to the struct of function pointers for evaluating the objective, constraints,...
bool provides_eval_augmented_lagrangian_hessian_product() const
decltype(auto) call_extra_func(const std::string &name, Args &&...args)
bool provides_get_general_bounds() const
bool provides_eval_lagrangian_hessian() const
std::shared_ptr< void > handle
Handle to the shared module defining the problem.
void eval_lagrangian_hessian_product(crvec x, crvec y, real_t scale, crvec v, rvec Hv) const
ExtraFuncs extra_funcs
Dictionary of extra functions that were registered by the problem.
bool provides_get_augmented_lagrangian_hessian_sparsity() const
Sparsity get_augmented_lagrangian_hessian_sparsity() const
bool provides_eval_objective_gradient() const
real_t eval_augmented_lagrangian(crvec x, crvec y, crvec Σ, rvec ŷ) const
bool provides_eval_lagrangian_gradient() const
void eval_lagrangian_hessian(crvec x, crvec y, real_t scale, rvec H_values) const
void eval_projecting_difference_constraints(crvec z, rvec e) const
void eval_augmented_lagrangian_hessian_product(crvec x, crvec y, crvec Σ, real_t scale, crvec v, rvec Hv) const
std::string get_name() const
real_t eval_proximal_gradient_step(real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p) const
decltype(auto) call_extra_func_helper(const void *instance, FuncTag< Ret(const instance_t *, FArgs...)>, const std::string &name, Args &&...args) const
decltype(auto) call_extra_func_helper(void *instance, FuncTag< Ret(instance_t *, FArgs...)>, const std::string &name, Args &&...args)
const std::function< Signature > & extra_func(const std::string &name) const
std::shared_ptr< function_dict_t > extra_functions
An associative array of additional functions exposed by the problem.
ExtraFuncs(std::shared_ptr< function_dict_t > &&extra_funcs)
decltype(auto) call_extra_func_helper(const void *, FuncTag< Ret(FArgs...)>, const std::string &name, Args &&...args) const
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
User-provided argument that is passed to the problem registration functions.
Definition dl-problem.h:60
std::function< Signature > function
Definition dl-problem.h:698
Custom type for which we can export the RTTI to support std::any across shared library boundaries whe...
Definition dl-problem.h:697
typename Conf::rmat rmat
Definition config.hpp:96
alpaqa_problem_functions_t problem_functions_t
Definition dl-problem.h:690
EigenConfigd DefaultConfig
Definition config.hpp:31
typename Conf::real_t real_t
Definition config.hpp:86
typename Conf::rindexvec rindexvec
Definition config.hpp:106
typename Conf::index_t index_t
Definition config.hpp:104
alpaqa_control_problem_functions_t control_problem_functions_t
Definition dl-problem.h:691
typename Conf::length_t length_t
Definition config.hpp:103
typename Conf::rvec rvec
Definition config.hpp:91
typename Conf::crvec crvec
Definition config.hpp:92
typename Conf::crindexvec crindexvec
Definition config.hpp:107
Result(const MemberGetter &) func_t