Nonconvex constrained optimization
Loading...
Searching...
No Matches
ocproblem.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <alpaqa/export.hpp>
8#include <guanaqo/not-implemented.hpp>
9#include <guanaqo/required-method.hpp>
10#include <guanaqo/timed.hpp>
11#include <guanaqo/type-erasure.hpp>
12#include <array>
13#include <concepts>
14#include <stdexcept>
15#include <type_traits>
16
17#if !ALPAQA_WITH_OCP
18#error "OCP support disabled"
19#endif
20
21#ifndef NDEBUG
22#include <iostream>
23#endif
24
25namespace alpaqa {
26
27using guanaqo::not_implemented_error;
28
29template <Config Conf>
30struct OCPDim {
33};
34
35template <Config Conf>
36struct ControlProblemVTable : guanaqo::BasicVTable {
39
40 template <class F>
41 using optional_function_t = guanaqo::optional_function_t<F, ControlProblemVTable>;
42 template <class F>
43 using required_function_t = guanaqo::required_function_t<F>;
44
45 // clang-format off
46 required_function_t<void(crvec z, rvec e) const>
48 required_function_t<void(rvec y, real_t M) const>
50 required_function_t<void(Box &U) const>
52 optional_function_t<void(Box &D) const>
53 get_D = nullptr;
54 optional_function_t<void(Box &D) const>
56 required_function_t<void(rvec x_init) const>
58 required_function_t<void(index_t timestep, crvec x, crvec u, rvec fxu) const>
60 required_function_t<void(index_t timestep, crvec x, crvec u, rmat J_fxu) const>
62 required_function_t<void(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const>
64 optional_function_t<void(index_t timestep, crvec x, crvec u, rvec h) const>
65 eval_h = nullptr;
66 optional_function_t<void(crvec x, rvec h) const>
67 eval_h_N = nullptr;
68 required_function_t<real_t(index_t timestep, crvec h) const>
72 required_function_t<void(index_t timestep, crvec xu, crvec h, rvec qr) const>
74 required_function_t<void(crvec x, crvec h, rvec q) const>
76 required_function_t<void(index_t timestep, crvec xu, crvec h, rmat Q) const>
78 optional_function_t<void(crvec x, crvec h, rmat Q) const>
80 required_function_t<void(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const>
82 required_function_t<void(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const>
84 optional_function_t<void(index_t timestep, crvec xu, crvec h, crindexvec mask_J, crindexvec mask_K, crvec v, rvec out, rvec work) const>
86 optional_function_t<void(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const>
92 optional_function_t<void(index_t timestep, crvec x, rvec c) const>
93 eval_constr = nullptr;
94 optional_function_t<void(crvec x, rvec c) const>
96 optional_function_t<void(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const>
98 optional_function_t<void(crvec x, crvec p, rvec grad_cx_p) const>
100 optional_function_t<void(index_t timestep, crvec x, crvec M, rmat out) const>
102 optional_function_t<void(crvec x, crvec M, rmat out) const>
104 required_function_t<void() const>
106 // clang-format on
107
109
110 template <class P>
111 ControlProblemVTable(std::in_place_t, P &p) : guanaqo::BasicVTable{std::in_place, p} {
112 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_projecting_difference_constraints);
113 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_projection_multipliers);
114 GUANAQO_TE_REQUIRED_METHOD(*this, P, get_U);
115 GUANAQO_TE_OPTIONAL_METHOD(*this, P, get_D, p);
116 GUANAQO_TE_OPTIONAL_METHOD(*this, P, get_D_N, p);
117 GUANAQO_TE_REQUIRED_METHOD(*this, P, get_x_init);
118 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_f);
119 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_jac_f);
120 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_grad_f_prod);
121 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_h, p);
122 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_h_N, p);
123 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_l);
124 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_l_N);
125 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_qr);
126 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_q_N);
127 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_add_Q);
128 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_add_Q_N, p);
129 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_add_R_masked);
130 GUANAQO_TE_REQUIRED_METHOD(*this, P, eval_add_S_masked);
131 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_add_R_prod_masked, p);
132 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_add_S_prod_masked, p);
133 GUANAQO_TE_OPTIONAL_METHOD(*this, P, get_R_work_size, p);
134 GUANAQO_TE_OPTIONAL_METHOD(*this, P, get_S_work_size, p);
135 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_constr, p);
136 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_constr_N, p);
137 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_grad_constr_prod, p);
138 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_grad_constr_prod_N, p);
139 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_add_gn_hess_constr, p);
140 GUANAQO_TE_OPTIONAL_METHOD(*this, P, eval_add_gn_hess_constr_N, p);
141 GUANAQO_TE_REQUIRED_METHOD(*this, P, check);
142 N = p.get_N();
143 nu = p.get_nu();
144 nx = p.get_nx();
145 nh = p.get_nh();
146 nh_N = p.get_nh_N();
147 nc = p.get_nc();
148 nc_N = p.get_nc_N();
149 if (nc > 0 && get_D == nullptr)
150 throw std::runtime_error("ControlProblem: missing 'get_D'");
151 if (nc > 0 && eval_constr == nullptr)
152 throw std::runtime_error("ControlProblem: missing 'eval_constr'");
153 if (nc > 0 && eval_grad_constr_prod == nullptr)
154 throw std::runtime_error("ControlProblem: missing 'eval_grad_constr_prod'");
155 if (nh > 0 && eval_h == nullptr)
156 throw std::runtime_error("ControlProblem: missing 'eval_h'");
157 if (nh_N > 0 && eval_h_N == nullptr)
158 throw std::runtime_error("ControlProblem: missing 'eval_h_N'");
159 }
161
162 ALPAQA_EXPORT static void default_get_D_N(const void *self, Box &D,
163 const ControlProblemVTable &vtable);
164 ALPAQA_EXPORT static void default_eval_add_Q_N(const void *self, crvec x, crvec h, rmat Q,
165 const ControlProblemVTable &vtable);
166 ALPAQA_EXPORT static void default_eval_add_R_prod_masked(const void *, index_t, crvec, crvec,
168 rvec, const ControlProblemVTable &);
169 ALPAQA_EXPORT static void default_eval_add_S_prod_masked(const void *, index_t, crvec, crvec,
171 const ControlProblemVTable &);
172 [[nodiscard]] ALPAQA_EXPORT static length_t
174 [[nodiscard]] ALPAQA_EXPORT static length_t
176 ALPAQA_EXPORT static void default_eval_constr_N(const void *self, crvec x, rvec c,
177 const ControlProblemVTable &vtable);
178 ALPAQA_EXPORT static void default_eval_grad_constr_prod_N(const void *self, crvec x, crvec p,
179 rvec grad_cx_p,
180 const ControlProblemVTable &vtable);
181 ALPAQA_EXPORT static void default_eval_add_gn_hess_constr_N(const void *self, crvec x, crvec M,
182 rmat out,
183 const ControlProblemVTable &vtable);
184};
185
186// clang-format off
191// clang-format on
192
193/**
194 * Nonlinear optimal control problem with finite horizon @f$ N @f$.
195 * @f[
196 * \newcommand\U{U}
197 * \newcommand\D{D}
198 * \newcommand\nnu{{n_u}}
199 * \newcommand\nnx{{n_x}}
200 * \newcommand\nny{{n_y}}
201 * \newcommand\xinit{x_\text{init}}
202 * \begin{equation}\label{eq:OCP} \tag{OCP}\hspace{-0.8em}
203 * \begin{aligned}
204 * &\minimize_{u,x} && \sum_{k=0}^{N-1} \ell_k\big(h_k(x^k, u^k)\big) + \ell_N\big(h_N(x^N)\big)\hspace{-0.8em} \\
205 * &\subjto && u^k \in \U \\
206 * &&& c_k(x^k) \in \D \\
207 * &&& c_N(x^N) \in \D_N \\
208 * &&& x^0 = \xinit \\
209 * &&& x^{k+1} = f(x^k, u^k) \quad\quad (0 \le k \lt N)
210 * \end{aligned}
211 * \end{equation}
212 * @f]
213 *
214 * The function @f$ f : \R^\nnx \times \R^\nnu \to \R^\nnx @f$ models the
215 * discrete-time, nonlinear dynamics of the system, which starts from an initial
216 * state @f$ \xinit @f$.
217 * The functions @f$ h_k : \R^\nnx \times \R^\nnu \to \R^{n_h} @f$ for
218 * @f$ 0 \le k \lt N @f$ and @f$ h_N : \R^\nnx \to \R^{n_h^N} @f$ can be used to
219 * represent the (possibly time-varying) output mapping of the system,
220 * and the convex functions @f$ \ell_k : \R^{n_h} \to \R @f$ and
221 * @f$ \ell_N : \R^{n_h^N} \to \R @f$ define the stage costs and the terminal
222 * cost respectively. Stage constraints and terminal constraints are represented
223 * by the functions @f$ c_k : \R^{n_x} \to \R^{n_c} @f$ and
224 * @f$ c_N : \R^{n_x} \to \R^{n_c^N} @f$, and the boxes @f$ D @f$ and
225 * @f$ D_N @f$.
226 *
227 * Additional functions for computing Gauss-Newton approximations of the cost
228 * Hessian are included as well:
229 * @f[ \begin{aligned}
230 * q^k &\defeq \tp{\jac_{h_k}^x\!(\barxuk)} \nabla \ell_k(\hhbar^k) \\
231 * r^k &\defeq \tp{\jac_{h_k}^u\!(\barxuk)} \nabla \ell_k(\hhbar^k) \\
232 * \Lambda_k &\defeq \partial^2 \ell_k(\hhbar^k) \\
233 * Q_k &\defeq \tp{\jac_{h_k}^x\!(\barxuk)} \Lambda_k\, \jac_{h_k}^x\!(\barxuk) \\
234 * S_k &\defeq \tp{\jac_{h_k}^u\!(\barxuk)} \Lambda_k\, \jac_{h_k}^x\!(\barxuk) \\
235 * R_k &\defeq \tp{\jac_{h_k}^u\!(\barxuk)} \Lambda_k\, \jac_{h_k}^u\!(\barxuk). \\
236 * \end{aligned} @f]
237 * See @cite pas2022gaussnewton for more details.
238 *
239 * @ingroup grp_Problems
240 */
241template <Config Conf = DefaultConfig, class Allocator = std::allocator<std::byte>>
242class TypeErasedControlProblem : public guanaqo::TypeErased<ControlProblemVTable<Conf>, Allocator> {
243 public:
246 using allocator_type = Allocator;
247 using Box = typename VTable::Box;
249 using TypeErased = guanaqo::TypeErased<VTable, allocator_type>;
250 using TypeErased::TypeErased;
251
252 protected:
253 using TypeErased::call;
254 using TypeErased::self;
255 using TypeErased::vtable;
256
257 public:
258 template <class T, class... Args>
259 static TypeErasedControlProblem make(Args &&...args) {
260 return TypeErased::template make<TypeErasedControlProblem, T>(std::forward<Args>(args)...);
261 }
262
263 /// @name Problem dimensions
264 /// @{
265
266 /// Horizon length.
267 [[nodiscard]] length_t get_N() const { return vtable.N; }
268 /// Number of inputs.
269 [[nodiscard]] length_t get_nu() const { return vtable.nu; }
270 /// Number of states.
271 [[nodiscard]] length_t get_nx() const { return vtable.nx; }
272 /// Number of outputs.
273 [[nodiscard]] length_t get_nh() const { return vtable.nh; }
274 [[nodiscard]] length_t get_nh_N() const { return vtable.nh_N; }
275 /// Number of constraints.
276 [[nodiscard]] length_t get_nc() const { return vtable.nc; }
277 [[nodiscard]] length_t get_nc_N() const { return vtable.nc_N; }
278 /// All dimensions
279 [[nodiscard]] Dim get_dim() const {
280 return {
281 .N = vtable.N,
282 .nx = vtable.nx,
283 .nu = vtable.nu,
284 .nh = vtable.nh,
285 .nh_N = vtable.nh_N,
286 .nc = vtable.nc,
287 .nc_N = vtable.nc_N,
288 };
289 }
290 /// Total number of variables.
291 [[nodiscard]] length_t get_num_variables() const { return get_N() * get_nu(); }
292 /// Total number of constraints.
293 [[nodiscard]] length_t get_num_constraints() const { return get_N() * get_nc() + get_nc_N(); }
294
295 /// @}
296
297 /// @name Projections onto constraint sets
298 /// @{
299
300 /// **[Required]**
301 /// Function that evaluates the difference between the given point @f$ z @f$
302 /// and its projection onto the constraint set @f$ D @f$.
303 /// @param [in] z
304 /// Slack variable, @f$ z \in \R^m @f$
305 /// @param [out] e
306 /// The difference relative to its projection,
307 /// @f$ e = z - \Pi_D(z) \in \R^m @f$
308 /// @note @p z and @p e can refer to the same vector.
310 /// **[Required]**
311 /// Function that projects the Lagrange multipliers for ALM.
312 /// @param [inout] y
313 /// Multipliers, @f$ y \leftarrow \Pi_Y(y) \in \R^m @f$
314 /// @param [in] M
315 /// The radius/size of the set @f$ Y @f$.
316 /// See @ref ALMParams::max_multiplier.
318
319 /// @}
320
321 /// @name Constraint sets
322 /// @{
323
324 /// Input box constraints @f$ U @f$.
325 void get_U(Box &U) const;
326 /// Stage box constraints @f$ D @f$.
327 void get_D(Box &D) const;
328 /// Terminal box constraints @f$ D_N @f$.
329 void get_D_N(Box &D) const;
330
331 /// @}
332
333 /// @name Dynamics and initial state
334 /// @{
335
336 /// Initial state @f$ x_\text{init} @f$.
337 void get_x_init(rvec x_init) const;
338 /// Discrete-time dynamics @f$ x^{k+1} = f_k(x^k, u^k) @f$.
339 void eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const;
340 /// Jacobian of discrete-time dynamics @f$ \jac_f(x^k, u^k) @f$.
341 void eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const;
342 /// Gradient-vector product of discrete-time dynamics @f$ \nabla f(x^k, u^k)\,p @f$.
343 void eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const;
344
345 /// @}
346
347 /// @name Output mapping
348 /// @{
349
350 /// Stage output mapping @f$ h_k(x^k, u^k) @f$.
351 void eval_h(index_t timestep, crvec x, crvec u, rvec h) const;
352 /// Terminal output mapping @f$ h_N(x^N) @f$.
353 void eval_h_N(crvec x, rvec h) const;
354
355 /// @}
356
357 /// @name Stage and terminal cost
358 /// @{
359
360 /// Stage cost @f$ \ell_k(\hbar^k) @f$.
361 [[nodiscard]] real_t eval_l(index_t timestep, crvec h) const;
362 /// Terminal cost @f$ \ell_N(\hbar^N) @f$.
363 [[nodiscard]] real_t eval_l_N(crvec h) const;
364
365 /// @}
366
367 /// @name Gauss-Newton approximations
368 /// @{
369
370 /// Cost gradients w.r.t. states and inputs
371 /// @f$ q^k = \tp{\jac_{h_k}^x\!(\barxuk)} \nabla \ell_k(\hbar^k) @f$ and
372 /// @f$ r^k = \tp{\jac_{h_k}^u\!(\barxuk)} \nabla \ell_k(\hbar^k) @f$.
373 void eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const;
374 /// Terminal cost gradient w.r.t. states
375 /// @f$ q^N = \tp{\jac_{h_N}(\bar x^N)} \nabla \ell_k(\hbar^N) @f$.
376 void eval_q_N(crvec x, crvec h, rvec q) const;
377 /// Cost Hessian w.r.t. states @f$ Q_k = \tp{\jac_{h_k}^x\!(\barxuk)}
378 /// \partial^2\ell_k(\hbar^k)\, \jac_{h_k}^x\!(\barxuk) @f$,
379 /// added to the given matrix @p Q.
380 /// @f$ Q \leftarrow Q + Q_k @f$.
381 void eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const;
382 /// Terminal cost Hessian w.r.t. states @f$ Q_N = \tp{\jac_{h_N}(\bar x^N)}
383 /// \partial^2\ell_N(\hbar^N)\, \jac_{h_N}(\bar x^N) @f$,
384 /// added to the given matrix @p Q.
385 /// @f$ Q \leftarrow Q + Q_N @f$.
386 void eval_add_Q_N(crvec x, crvec h, rmat Q) const;
387 /// Cost Hessian w.r.t. inputs @f$ R_k = \tp{\jac_{h_k}^u\!(\barxuk)}
388 /// \partial^2\ell_k(\hbar^k)\, \jac_{h_k}^u\!(\barxuk) @f$, keeping only
389 /// rows and columns in the mask @f$ \mathcal J @f$, added to the given
390 /// matrix @p R.
391 /// @f$ R \leftarrow R + R_k[\mathcal J, \mathcal J] @f$.
392 /// The size of @p work should be @ref get_R_work_size().
393 void eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R,
394 rvec work) const;
395 /// Cost Hessian w.r.t. inputs and states @f$ S_k = \tp{\jac_{h_k}^u\!(\barxuk)}
396 /// \partial^2\ell_k(\hbar^k)\, \jac_{h_k}^x\!(\barxuk) @f$, keeping only
397 /// rows in the mask @f$ \mathcal J @f$, added to the given matrix @p S.
398 /// @f$ S \leftarrow S + S_k[\mathcal J, \cdot] @f$.
399 /// The size of @p work should be @ref get_S_work_size().
400 void eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S,
401 rvec work) const;
402 /// @f$ out \leftarrow out + R[\mathcal J, \mathcal K]\,v[\mathcal K] @f$.
403 /// Work should contain the contents written to it by a prior call to
404 /// @ref eval_add_R_masked() in the same point.
406 crindexvec mask_K, crvec v, rvec out, rvec work) const;
407 /// @f$ out \leftarrow out + \tp{S[\mathcal K, \cdot]}\, v[\mathcal K] @f$.
408 /// Work should contain the contents written to it by a prior call to
409 /// @ref eval_add_S_masked() in the same point.
410 void eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v,
411 rvec out, rvec work) const;
412 /// Size of the workspace required by @ref eval_add_R_masked() and
413 /// @ref eval_add_R_prod_masked().
414 [[nodiscard]] length_t get_R_work_size() const;
415 /// Size of the workspace required by @ref eval_add_S_masked() and
416 /// @ref eval_add_S_prod_masked().
417 [[nodiscard]] length_t get_S_work_size() const;
418
419 /// @}
420
421 /// @name Constraints
422 /// @{
423
424 /// Stage constraints @f$ c_k(x^k) @f$.
425 void eval_constr(index_t timestep, crvec x, rvec c) const;
426 /// Terminal constraints @f$ c_N(x^N) @f$.
427 void eval_constr_N(crvec x, rvec c) const;
428 /// Gradient-vector product of stage constraints @f$ \nabla c_k(x^k)\, p @f$.
429 void eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const;
430 /// Gradient-vector product of terminal constraints @f$ \nabla c_N(x^N)\, p @f$.
431 void eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const;
432 /// Gauss-Newton Hessian of stage constraints @f$ \tp{\jac_{c_k}}(x^k)\,
433 /// \operatorname{diag}(M)\; \jac_{c_k}(x^k) @f$.
434 void eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const;
435 /// Gauss-Newton Hessian of terminal constraints @f$ \tp{\jac_{c_N}}(x^N)\,
436 /// \operatorname{diag}(M)\; \jac_{c_N}(x^N) @f$.
438
439 /// @}
440
441 /// @name Checks
442 /// @{
443
444 /// Check that the problem formulation is well-defined, the dimensions match,
445 /// etc. Throws an exception if this is not the case.
446 void check() const;
447
448 /// @}
449
450 /// @name Querying specialized implementations
451 /// @{
452
453 // clang-format off
454 [[nodiscard]] bool provides_get_D() const { return vtable.get_D != nullptr; }
455 [[nodiscard]] bool provides_get_D_N() const { return vtable.get_D_N != &vtable.default_get_D_N; }
456 [[nodiscard]] bool provides_eval_h() const { return vtable.eval_h != nullptr; }
457 [[nodiscard]] bool provides_eval_h_N() const { return vtable.eval_h_N != nullptr; }
458 [[nodiscard]] bool provides_eval_add_Q_N() const { return vtable.eval_add_Q_N != &vtable.default_eval_add_Q_N; }
459 [[nodiscard]] bool provides_eval_add_R_prod_masked() const { return vtable.eval_add_R_prod_masked != &vtable.default_eval_add_R_prod_masked; }
460 [[nodiscard]] bool provides_eval_add_S_prod_masked() const { return vtable.eval_add_S_prod_masked != &vtable.default_eval_add_S_prod_masked; }
461 [[nodiscard]] bool provides_get_R_work_size() const { return vtable.get_R_work_size != &vtable.default_get_R_work_size; }
462 [[nodiscard]] bool provides_get_S_work_size() const { return vtable.get_S_work_size != &vtable.default_get_S_work_size; }
463 [[nodiscard]] bool provides_eval_constr() const { return vtable.eval_constr != nullptr; }
464 [[nodiscard]] bool provides_eval_constr_N() const { return vtable.eval_constr_N != &vtable.default_eval_constr_N; }
465 [[nodiscard]] bool provides_eval_grad_constr_prod() const { return vtable.eval_grad_constr_prod != nullptr; }
466 [[nodiscard]] bool provides_eval_grad_constr_prod_N() const { return vtable.eval_grad_constr_prod_N != &vtable.default_eval_grad_constr_prod_N; }
467 [[nodiscard]] bool provides_eval_add_gn_hess_constr() const { return vtable.eval_add_gn_hess_constr != nullptr; }
468 [[nodiscard]] bool provides_eval_add_gn_hess_constr_N() const { return vtable.eval_add_gn_hess_constr_N != &vtable.default_eval_add_gn_hess_constr_N; }
469 // clang-format on
470
471 /// @}
472};
473
474// clang-format off
475#ifdef NDEBUG
476[[gnu::always_inline]] inline void check_finiteness(auto &&, auto &&) {}
477template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_projecting_difference_constraints(crvec z, rvec e) const { return call(vtable.eval_projecting_difference_constraints, z, e); }
478template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_projection_multipliers(rvec y, real_t M) const { return call(vtable.eval_projection_multipliers, y, M); }
479template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_U(Box &U) const { return call(vtable.get_U, U); }
480template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_D(Box &D) const { return call(vtable.get_D, D); }
481template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_D_N(Box &D) const { return call(vtable.get_D_N, D); }
482template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_x_init(rvec x_init) const { return call(vtable.get_x_init, x_init); }
483template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const { return call(vtable.eval_f, timestep, x, u, fxu); }
484template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const { return call(vtable.eval_jac_f, timestep, x, u, J_fxu); }
485template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const { return call(vtable.eval_grad_f_prod, timestep, x, u, p, grad_fxu_p); }
486template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_h(index_t timestep, crvec x, crvec u, rvec h) const { return call(vtable.eval_h, timestep, x, u, h); }
487template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_h_N(crvec x, rvec h) const { return call(vtable.eval_h_N, x, h); }
488template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::eval_l(index_t timestep, crvec h) const -> real_t { return call(vtable.eval_l, timestep, h); }
489template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::eval_l_N(crvec h) const -> real_t { return call(vtable.eval_l_N, h); }
490template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const { return call(vtable.eval_qr, timestep, xu, h, qr); }
491template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_q_N(crvec x, crvec h, rvec q) const { return call(vtable.eval_q_N, x, h, q); }
492template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const { return call(vtable.eval_add_Q, timestep, xu, h, Q); }
493template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_Q_N(crvec x, crvec h, rmat Q) const { return call(vtable.eval_add_Q_N, x, h, Q); }
494template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const { return call(vtable.eval_add_R_masked, timestep, xu, h, mask, R, work); }
495template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const { return call(vtable.eval_add_S_masked, timestep, xu, h, mask, S, work); }
496template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::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 { return call(vtable.eval_add_R_prod_masked, timestep, xu, h, mask_J, mask_K, v, out, work); }
497template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const { return call(vtable.eval_add_S_prod_masked, timestep, xu, h, mask_K, v, out, work); }
498template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::get_R_work_size() const -> length_t { return call(vtable.get_R_work_size); }
499template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::get_S_work_size() const -> length_t { return call(vtable.get_S_work_size); }
500template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_constr(index_t timestep, crvec x, rvec c) const { return call(vtable.eval_constr, timestep, x, c); }
501template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_constr_N(crvec x, rvec c) const { return call(vtable.eval_constr_N, x, c); }
502template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const { return call(vtable.eval_grad_constr_prod, timestep, x, p, grad_cx_p); }
503template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const { return call(vtable.eval_grad_constr_prod_N, x, p, grad_cx_p); }
504template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const { return call(vtable.eval_add_gn_hess_constr, timestep, x, M, out); }
505template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const { return call(vtable.eval_add_gn_hess_constr_N, x, M, out); }
506template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::check() const { return call(vtable.check); }
507#else
508/// If the given vector @p v is not finite, break or throw an exception with the
509/// given message @p msg.
510inline void check_finiteness(const auto &v, std::string_view msg) {
511 using std::begin;
512 using std::end;
513 if (!v.allFinite()) {
514 std::cout << msg << std::endl;
515 throw std::runtime_error(std::string(msg));
516 }
517}
518inline void check_finiteness(const std::floating_point auto &v, std::string_view msg) {
519 if (!std::isfinite(v)) {
520 std::cout << msg << std::endl;
521 throw std::runtime_error(std::string(msg));
522 }
523}
524template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_projecting_difference_constraints(crvec z, rvec e) const { return call(vtable.eval_projecting_difference_constraints, z, e); }
525template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_projection_multipliers(rvec y, real_t M) const { return call(vtable.eval_projection_multipliers, y, M); }
526template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_U(Box &U) const { return call(vtable.get_U, U); }
527template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_D(Box &D) const { return call(vtable.get_D, D); }
528template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_D_N(Box &D_N) const { return call(vtable.get_D_N, D_N); }
529template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::get_x_init(rvec x_init) const { call(vtable.get_x_init, x_init); check_finiteness(x_init, "Infinite output of get_x_init"); }
530template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const { check_finiteness(x, "Infinite input x of f"); check_finiteness(u, "Infinite input u of f"); call(vtable.eval_f, timestep, x, u, fxu); check_finiteness(fxu, "Infinite output of f"); }
531template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const { check_finiteness(x, "Infinite input x of jac_f"); check_finiteness(u, "Infinite input u of jac_f"); call(vtable.eval_jac_f, timestep, x, u, J_fxu); check_finiteness(J_fxu.reshaped(), "Infinite output of jac_f"); }
532template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const { check_finiteness(x, "Infinite input x of grad_f_prod"); check_finiteness(u, "Infinite input u of grad_f_prod"); check_finiteness(p, "Infinite input p of grad_f_prod"); call(vtable.eval_grad_f_prod, timestep, x, u, p, grad_fxu_p); check_finiteness(grad_fxu_p, "Infinite output of jac_f"); }
533template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_h(index_t timestep, crvec x, crvec u, rvec h) const { check_finiteness(x, "Infinite input x of h"); check_finiteness(u, "Infinite input u of h"); call(vtable.eval_h, timestep, x, u, h); check_finiteness(h, "Infinite output of h"); }
534template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_h_N(crvec x, rvec h) const { check_finiteness(x, "Infinite input x of h_N"); call(vtable.eval_h_N, x, h); check_finiteness(h, "Infinite output of h_N"); }
535template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::eval_l(index_t timestep, crvec h) const -> real_t { check_finiteness(h, "Infinite input h of l"); auto l = call(vtable.eval_l, timestep, h); check_finiteness(l, "Infinite output of l"); return l; }
536template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::eval_l_N(crvec h) const -> real_t { check_finiteness(h, "Infinite input h of l_N"); auto l = call(vtable.eval_l_N, h); check_finiteness(l, "Infinite output of l_N"); return l; }
537template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const { return call(vtable.eval_qr, timestep, xu, h, qr); }
538template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_q_N(crvec x, crvec h, rvec q) const { check_finiteness(x, "Infinite input x of q_N"); check_finiteness(h, "Infinite input h of q_N"); call(vtable.eval_q_N, x, h, q); check_finiteness(q, "Infinite output of q_N"); }
539template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const { return call(vtable.eval_add_Q, timestep, xu, h, Q); }
540template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_Q_N(crvec x, crvec h, rmat Q) const { return call(vtable.eval_add_Q_N, x, h, Q); }
541template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const { return call(vtable.eval_add_R_masked, timestep, xu, h, mask, R, work); }
542template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const { return call(vtable.eval_add_S_masked, timestep, xu, h, mask, S, work); }
543template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::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 { return call(vtable.eval_add_R_prod_masked, timestep, xu, h, mask_J, mask_K, v, out, work); }
544template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const { return call(vtable.eval_add_S_prod_masked, timestep, xu, h, mask_K, v, out, work); }
545template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::get_R_work_size() const -> length_t { return call(vtable.get_R_work_size); }
546template <Config Conf, class Allocator> [[gnu::always_inline]] inline auto TypeErasedControlProblem<Conf, Allocator>::get_S_work_size() const -> length_t { return call(vtable.get_S_work_size); }
547template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_constr(index_t timestep, crvec x, rvec c) const { return call(vtable.eval_constr, timestep, x, c); }
548template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_constr_N(crvec x, rvec c) const { return call(vtable.eval_constr_N, x, c); }
549template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const { return call(vtable.eval_grad_constr_prod, timestep, x, p, grad_cx_p); }
550template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const { return call(vtable.eval_grad_constr_prod_N, x, p, grad_cx_p); }
551template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const { return call(vtable.eval_add_gn_hess_constr, timestep, x, M, out); }
552template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const { return call(vtable.eval_add_gn_hess_constr_N, x, M, out); }
553template <Config Conf, class Allocator> [[gnu::always_inline]] inline void TypeErasedControlProblem<Conf, Allocator>::check() const { return call(vtable.check); }
554#endif
555// clang-format on
556
557template <class Problem>
559 USING_ALPAQA_CONFIG_TEMPLATE(std::remove_cvref_t<Problem>::config_t);
561
562 [[nodiscard, gnu::always_inline]] length_t get_N() const { return problem.get_N(); }
563 [[nodiscard, gnu::always_inline]] length_t get_nu() const { return problem.get_nu(); }
564 [[nodiscard, gnu::always_inline]] length_t get_nx() const { return problem.get_nx(); }
565 [[nodiscard, gnu::always_inline]] length_t get_nh() const { return problem.get_nh(); }
566 [[nodiscard, gnu::always_inline]] length_t get_nh_N() const { return problem.get_nh_N(); }
567 [[nodiscard, gnu::always_inline]] length_t get_nc() const { return problem.get_nc(); }
568 [[nodiscard, gnu::always_inline]] length_t get_nc_N() const { return problem.get_nc_N(); }
569
570 // clang-format off
571 [[gnu::always_inline]] void eval_projecting_difference_constraints(crvec z, rvec e) const { return problem.eval_projecting_difference_constraints(z, e); }
572 [[gnu::always_inline]] void eval_projection_multipliers(rvec y, real_t M) const { return problem.eval_projection_multipliers(y, M); }
573 [[gnu::always_inline]] void get_x_init(rvec x_init) const { return problem.get_x_init(x_init); }
574 [[nodiscard, gnu::always_inline]] length_t get_R_work_size() const requires requires { &std::remove_cvref_t<Problem>::get_R_work_size; } { return problem.get_R_work_size(); }
575 [[nodiscard, gnu::always_inline]] length_t get_S_work_size() const requires requires { &std::remove_cvref_t<Problem>::get_S_work_size; } { return problem.get_S_work_size(); }
576 [[gnu::always_inline]] void get_U(Box &U) const requires requires { &std::remove_cvref_t<Problem>::get_U; } { return problem.get_U(U); }
577 [[gnu::always_inline]] void get_D(Box &D) const requires requires { &std::remove_cvref_t<Problem>::get_D; } { return problem.get_D(D); }
578 [[gnu::always_inline]] void get_D_N(Box &D) const requires requires { &std::remove_cvref_t<Problem>::get_D_N; } { return problem.get_D_N(D); }
579 [[gnu::always_inline]] void eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const { ++evaluations->f; return timed(evaluations->time.f, [&] { return problem.eval_f(timestep, x, u, fxu); }); }
580 [[gnu::always_inline]] void eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const { ++evaluations->jac_f; return timed(evaluations->time.jac_f, [&] { return problem.eval_jac_f(timestep, x, u, J_fxu); }); }
581 [[gnu::always_inline]] void eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const { ++evaluations->grad_f_prod; return timed(evaluations->time.grad_f_prod, [&] { return problem.eval_grad_f_prod(timestep, x, u, p, grad_fxu_p); }); }
582 [[gnu::always_inline]] void eval_h(index_t timestep, crvec x, crvec u, rvec h) const { ++evaluations->h; return timed(evaluations->time.h, [&] { return problem.eval_h(timestep, x, u, h); }); }
583 [[gnu::always_inline]] void eval_h_N(crvec x, rvec h) const { ++evaluations->h_N; return timed(evaluations->time.h_N, [&] { return problem.eval_h_N(x, h); }); }
584 [[nodiscard, gnu::always_inline]] real_t eval_l(index_t timestep, crvec h) const { ++evaluations->l; return timed(evaluations->time.l, [&] { return problem.eval_l(timestep, h); }); }
585 [[nodiscard, gnu::always_inline]] real_t eval_l_N(crvec h) const { ++evaluations->l_N; return timed(evaluations->time.l_N, [&] { return problem.eval_l_N(h); }); }
586 [[gnu::always_inline]] void eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const { ++evaluations->qr; return timed(evaluations->time.qr, [&] { return problem.eval_qr(timestep, xu, h, qr); }); }
587 [[gnu::always_inline]] void eval_q_N(crvec x, crvec h, rvec q) const requires requires { &std::remove_cvref_t<Problem>::eval_q_N; } { ++evaluations->q_N; return timed(evaluations->time.q_N, [&] { return problem.eval_q_N(x, h, q); }); }
588 [[gnu::always_inline]] void eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const { ++evaluations->add_Q; return timed(evaluations->time.add_Q, [&] { return problem.eval_add_Q(timestep, xu, h, Q); }); }
589 [[gnu::always_inline]] void eval_add_Q_N(crvec x, crvec h, rmat Q) const requires requires { &std::remove_cvref_t<Problem>::eval_add_Q_N; } { ++evaluations->add_Q_N; return timed(evaluations->time.add_Q_N, [&] { return problem.eval_add_Q_N(x, h, Q); }); }
590 [[gnu::always_inline]] void eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const { ++evaluations->add_R_masked; return timed(evaluations->time.add_R_masked, [&] { return problem.eval_add_R_masked(timestep, xu, h, mask, R, work); }); }
591 [[gnu::always_inline]] void eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const { ++evaluations->add_S_masked; return timed(evaluations->time.add_S_masked, [&] { return problem.eval_add_S_masked(timestep, xu, h, mask, S, work); }); }
592 [[gnu::always_inline]] 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 requires requires { &std::remove_cvref_t<Problem>::eval_add_R_prod_masked; } { ++evaluations->add_R_prod_masked; return timed(evaluations->time.add_R_prod_masked, [&] { return problem.eval_add_R_prod_masked(timestep, xu, h, mask_J, mask_K, v, out, work); }); }
593 [[gnu::always_inline]] void eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const requires requires { &std::remove_cvref_t<Problem>::eval_add_S_prod_masked; } { ++evaluations->add_S_prod_masked; return timed(evaluations->time.add_S_prod_masked, [&] { return problem.eval_add_S_prod_masked(timestep, xu, h, mask_K, v, out, work); }); }
594 [[gnu::always_inline]] void eval_constr(index_t timestep, crvec x, rvec c) const requires requires { &std::remove_cvref_t<Problem>::eval_constr; } { ++evaluations->constr; return timed(evaluations->time.constr, [&] { return problem.eval_constr(timestep, x, c); }); }
595 [[gnu::always_inline]] void eval_constr_N(crvec x, rvec c) const requires requires { &std::remove_cvref_t<Problem>::eval_constr_N; } { ++evaluations->constr_N; return timed(evaluations->time.constr_N, [&] { return problem.eval_constr_N(x, c); }); }
596 [[gnu::always_inline]] void eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const requires requires { &std::remove_cvref_t<Problem>::eval_grad_constr_prod; } { ++evaluations->grad_constr_prod; return timed(evaluations->time.grad_constr_prod, [&] { return problem.eval_grad_constr_prod(timestep, x, p, grad_cx_p); }); }
597 [[gnu::always_inline]] void eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const requires requires { &std::remove_cvref_t<Problem>::eval_grad_constr_prod_N; } { ++evaluations->grad_constr_prod_N; return timed(evaluations->time.grad_constr_prod_N, [&] { return problem.eval_grad_constr_prod_N(x, p, grad_cx_p); }); }
598 [[gnu::always_inline]] void eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const requires requires { &std::remove_cvref_t<Problem>::eval_add_gn_hess_constr; } { ++evaluations->add_gn_hess_constr; return timed(evaluations->time.add_gn_hess_constr, [&] { return problem.eval_add_gn_hess_constr(timestep, x, M, out); }); }
599 [[gnu::always_inline]] void eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const requires requires { &std::remove_cvref_t<Problem>::eval_add_gn_hess_constr_N; } { ++evaluations->add_gn_hess_constr_N; return timed(evaluations->time.add_gn_hess_constr_N, [&] { return problem.eval_add_gn_hess_constr_N(x, M, out); }); }
600 [[gnu::always_inline]] void check() const { problem.check(); }
601
602 [[nodiscard]] bool provides_get_D() const requires requires (Problem p) { { p.provides_get_D() } -> std::convertible_to<bool>; } { return problem.provides_get_D(); }
603 [[nodiscard]] bool provides_get_D_N() const requires requires (Problem p) { { p.provides_get_D_N() } -> std::convertible_to<bool>; } { return problem.provides_get_D_N(); }
604 [[nodiscard]] bool provides_eval_add_Q_N() const requires requires (Problem p) { { p.provides_eval_add_Q_N() } -> std::convertible_to<bool>; } { return problem.provides_eval_add_Q_N(); }
605 [[nodiscard]] bool provides_eval_add_R_prod_masked() const requires requires (Problem p) { { p.provides_eval_add_R_prod_masked() } -> std::convertible_to<bool>; } { return problem.provides_eval_add_R_prod_masked(); }
606 [[nodiscard]] bool provides_eval_add_S_prod_masked() const requires requires (Problem p) { { p.provides_eval_add_S_prod_masked() } -> std::convertible_to<bool>; } { return problem.provides_eval_add_S_prod_masked(); }
607 [[nodiscard]] bool provides_get_R_work_size() const requires requires (Problem p) { { p.provides_get_R_work_size() } -> std::convertible_to<bool>; } { return problem.provides_get_R_work_size(); }
608 [[nodiscard]] bool provides_get_S_work_size() const requires requires (Problem p) { { p.provides_get_S_work_size() } -> std::convertible_to<bool>; } { return problem.provides_get_S_work_size(); }
609 [[nodiscard]] bool provides_eval_constr() const requires requires (Problem p) { { p.provides_eval_constr() } -> std::convertible_to<bool>; } { return problem.provides_eval_constr(); }
610 [[nodiscard]] bool provides_eval_constr_N() const requires requires (Problem p) { { p.provides_eval_constr_N() } -> std::convertible_to<bool>; } { return problem.provides_eval_constr_N(); }
611 [[nodiscard]] bool provides_eval_grad_constr_prod() const requires requires (Problem p) { { p.provides_eval_grad_constr_prod() } -> std::convertible_to<bool>; } { return problem.provides_eval_grad_constr_prod(); }
612 [[nodiscard]] bool provides_eval_grad_constr_prod_N() const requires requires (Problem p) { { p.provides_eval_grad_constr_prod_N() } -> std::convertible_to<bool>; } { return problem.provides_eval_grad_constr_prod_N(); }
613 [[nodiscard]] bool provides_eval_add_gn_hess_constr() const requires requires (Problem p) { { p.provides_eval_add_gn_hess_constr() } -> std::convertible_to<bool>; } { return problem.provides_eval_add_gn_hess_constr(); }
614 [[nodiscard]] bool provides_eval_add_gn_hess_constr_N() const requires requires (Problem p) { { p.provides_eval_add_gn_hess_constr_N() } -> std::convertible_to<bool>; } { return problem.provides_eval_add_gn_hess_constr_N(); }
615 // clang-format on
616
617 std::shared_ptr<OCPEvalCounter> evaluations = std::make_shared<OCPEvalCounter>();
618 Problem problem;
619
621 requires std::is_default_constructible_v<Problem>
622 = default;
623 template <class P>
625 requires std::is_same_v<std::remove_cvref_t<P>, std::remove_cvref_t<Problem>>
626 : problem{std::forward<P>(problem)} {}
627 template <class... Args>
628 explicit ControlProblemWithCounters(std::in_place_t, Args &&...args)
629 requires(!std::is_lvalue_reference_v<Problem>)
630 : problem{std::forward<Args>(args)...} {}
631
632 /// Reset all evaluation counters and timers to zero. Affects all instances
633 /// that share the same evaluations. If you only want to reset the counters
634 /// of this instance, use @ref decouple_evaluations first.
635 void reset_evaluations() { evaluations.reset(); }
636 /// Give this instance its own evaluation counters and timers, decoupling
637 /// it from any other instances they might have previously been shared with.
638 /// The evaluation counters and timers are preserved (a copy is made).
639 void decouple_evaluations() { evaluations = std::make_shared<OCPEvalCounter>(*evaluations); }
640
641 private:
642 template <class TimeT, class FunT>
643 [[gnu::always_inline]] static decltype(auto) timed(TimeT &time, FunT &&f) {
644 guanaqo::Timed timed{time};
645 return std::forward<FunT>(f)();
646 }
647};
648
649template <class Problem>
650[[nodiscard]] auto ocproblem_with_counters(Problem &&p) {
651 using Prob = std::remove_cvref_t<Problem>;
652 using ProbWithCnt = ControlProblemWithCounters<Prob>;
653 return ProbWithCnt{std::forward<Problem>(p)};
654}
655
656template <class Problem>
657[[nodiscard]] auto ocproblem_with_counters_ref(Problem &p) {
658 using Prob = std::remove_cvref_t<Problem>;
660 return ProbWithCnt{p};
661}
662
663} // namespace alpaqa
Nonlinear optimal control problem with finite horizon .
Dim get_dim() const
All dimensions.
void eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const
Jacobian of discrete-time dynamics .
bool provides_eval_grad_constr_prod() const
ControlProblemVTable< config_t > VTable
bool provides_eval_add_gn_hess_constr() const
std::allocator< std::byte > allocator_type
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
.
bool provides_eval_add_R_prod_masked() const
length_t get_nc() const
Number of constraints.
void eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const
Gauss-Newton Hessian of terminal constraints .
void eval_projection_multipliers(rvec y, real_t M) const
[Required] Function that projects the Lagrange multipliers for ALM.
length_t get_S_work_size() const
Size of the workspace required by eval_add_S_masked() and eval_add_S_prod_masked().
void check() const
Check that the problem formulation is well-defined, the dimensions match, etc.
void eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const
Cost gradients w.r.t.
void eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const
.
void eval_constr_N(crvec x, rvec c) const
Terminal constraints .
void eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const
Gradient-vector product of terminal constraints .
length_t get_nu() const
Number of inputs.
void eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const
Cost Hessian w.r.t.
void get_U(Box &U) const
Input box constraints .
real_t eval_l_N(crvec h) const
Terminal cost .
real_t eval_l(index_t timestep, crvec h) const
Stage cost .
void eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const
Gradient-vector product of discrete-time dynamics .
void eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const
Gauss-Newton Hessian of stage constraints .
void eval_constr(index_t timestep, crvec x, rvec c) const
Stage constraints .
length_t get_nh() const
Number of outputs.
void eval_h(index_t timestep, crvec x, crvec u, rvec h) const
Stage output mapping .
void get_D_N(Box &D) const
Terminal box constraints .
static TypeErasedControlProblem make(Args &&...args)
bool provides_eval_grad_constr_prod_N() const
length_t get_R_work_size() const
Size of the workspace required by eval_add_R_masked() and eval_add_R_prod_masked().
length_t get_nx() const
Number of states.
void eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const
Cost Hessian w.r.t.
void get_x_init(rvec x_init) const
Initial state .
void get_D(Box &D) const
Stage box constraints .
void eval_q_N(crvec x, crvec h, rvec q) const
Terminal cost gradient w.r.t.
guanaqo::TypeErased< VTable, allocator_type > TypeErased
bool provides_eval_add_S_prod_masked() const
void eval_projecting_difference_constraints(crvec z, rvec e) const
[Required] Function that evaluates the difference between the given point and its projection onto th...
void eval_add_Q_N(crvec x, crvec h, rmat Q) const
Terminal cost Hessian w.r.t.
void eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const
Gradient-vector product of stage constraints .
length_t get_num_constraints() const
Total number of constraints.
void eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const
Cost Hessian w.r.t.
void eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const
Discrete-time dynamics .
length_t get_num_variables() const
Total number of variables.
void eval_h_N(crvec x, rvec h) const
Terminal output mapping .
bool provides_eval_add_gn_hess_constr_N() const
length_t get_N() const
Horizon length.
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
#define ALPAQA_IF_QUADF(...)
Definition config.hpp:223
#define ALPAQA_IF_LONGD(...)
Definition config.hpp:235
#define ALPAQA_IF_FLOAT(...)
Definition config.hpp:229
#define USING_ALPAQA_CONFIG_TEMPLATE(Conf)
Definition config.hpp:81
#define ALPAQA_EXPORT_EXTERN_TEMPLATE(...)
Definition export.hpp:23
auto ocproblem_with_counters_ref(Problem &p)
typename Conf::rmat rmat
Definition config.hpp:96
auto ocproblem_with_counters(Problem &&p)
EigenConfigd DefaultConfig
Definition config.hpp:31
typename Conf::real_t real_t
Definition config.hpp:86
typename Conf::index_t index_t
Definition config.hpp:104
void check_finiteness(const auto &v, std::string_view msg)
If the given vector v is not finite, break or throw an exception with the given message msg.
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
required_function_t< void(index_t timestep, crvec x, crvec u, rmat J_fxu) const > eval_jac_f
Definition ocproblem.hpp:61
required_function_t< void(index_t timestep, crvec x, crvec u, rvec fxu) const > eval_f
Definition ocproblem.hpp:59
guanaqo::required_function_t< F > required_function_t
Definition ocproblem.hpp:43
required_function_t< void(rvec x_init) const > get_x_init
Definition ocproblem.hpp:57
optional_function_t< void(index_t timestep, crvec x, crvec M, rmat out) const > eval_add_gn_hess_constr
optional_function_t< void(index_t timestep, crvec x, rvec c) const > eval_constr
Definition ocproblem.hpp:93
ControlProblemVTable(std::in_place_t, P &p)
required_function_t< void(index_t timestep, crvec xu, crvec h, rvec qr) const > eval_qr
Definition ocproblem.hpp:73
required_function_t< void(rvec y, real_t M) const > eval_projection_multipliers
Definition ocproblem.hpp:49
static length_t default_get_R_work_size(const void *, const ControlProblemVTable &)
static length_t default_get_S_work_size(const void *, const ControlProblemVTable &)
optional_function_t< void(crvec x, rvec c) const > eval_constr_N
Definition ocproblem.hpp:95
static void default_eval_add_S_prod_masked(const void *, index_t, crvec, crvec, crindexvec, crvec, rvec, rvec, const ControlProblemVTable &)
optional_function_t< void(crvec x, crvec M, rmat out) const > eval_add_gn_hess_constr_N
optional_function_t< void(crvec x, rvec h) const > eval_h_N
Definition ocproblem.hpp:67
optional_function_t< void(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const > eval_grad_constr_prod
Definition ocproblem.hpp:97
optional_function_t< length_t() const > get_R_work_size
Definition ocproblem.hpp:89
required_function_t< void(crvec z, rvec e) const > eval_projecting_difference_constraints
Definition ocproblem.hpp:47
optional_function_t< void(crvec x, crvec p, rvec grad_cx_p) const > eval_grad_constr_prod_N
Definition ocproblem.hpp:99
required_function_t< void() const > check
static void default_eval_constr_N(const void *self, crvec x, rvec c, const ControlProblemVTable &vtable)
optional_function_t< void(index_t timestep, crvec x, crvec u, rvec h) const > eval_h
Definition ocproblem.hpp:65
optional_function_t< void(index_t timestep, crvec xu, crvec h, crindexvec mask_J, crindexvec mask_K, crvec v, rvec out, rvec work) const > eval_add_R_prod_masked
Definition ocproblem.hpp:85
guanaqo::optional_function_t< F, ControlProblemVTable > optional_function_t
Definition ocproblem.hpp:41
optional_function_t< void(Box &D) const > get_D_N
Definition ocproblem.hpp:55
required_function_t< void(Box &U) const > get_U
Definition ocproblem.hpp:51
static void default_eval_add_R_prod_masked(const void *, index_t, crvec, crvec, crindexvec, crindexvec, crvec, rvec, rvec, const ControlProblemVTable &)
alpaqa::Box< config_t > Box
Definition ocproblem.hpp:38
static void default_eval_grad_constr_prod_N(const void *self, crvec x, crvec p, rvec grad_cx_p, const ControlProblemVTable &vtable)
required_function_t< void(crvec x, crvec h, rvec q) const > eval_q_N
Definition ocproblem.hpp:75
required_function_t< void(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const > eval_add_S_masked
Definition ocproblem.hpp:83
required_function_t< real_t(index_t timestep, crvec h) const > eval_l
Definition ocproblem.hpp:69
optional_function_t< void(Box &D) const > get_D
Definition ocproblem.hpp:53
static void default_eval_add_gn_hess_constr_N(const void *self, crvec x, crvec M, rmat out, const ControlProblemVTable &vtable)
static void default_eval_add_Q_N(const void *self, crvec x, crvec h, rmat Q, const ControlProblemVTable &vtable)
static void default_get_D_N(const void *self, Box &D, const ControlProblemVTable &vtable)
required_function_t< real_t(crvec h) const > eval_l_N
Definition ocproblem.hpp:71
required_function_t< void(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const > eval_grad_f_prod
Definition ocproblem.hpp:63
required_function_t< void(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const > eval_add_R_masked
Definition ocproblem.hpp:81
optional_function_t< void(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const > eval_add_S_prod_masked
Definition ocproblem.hpp:87
optional_function_t< void(crvec x, crvec h, rmat Q) const > eval_add_Q_N
Definition ocproblem.hpp:79
optional_function_t< length_t() const > get_S_work_size
Definition ocproblem.hpp:91
required_function_t< void(index_t timestep, crvec xu, crvec h, rmat Q) const > eval_add_Q
Definition ocproblem.hpp:77
void eval_jac_f(index_t timestep, crvec x, crvec u, rmat J_fxu) const
void eval_add_gn_hess_constr_N(crvec x, crvec M, rmat out) const
void eval_add_gn_hess_constr(index_t timestep, crvec x, crvec M, rmat out) const
void decouple_evaluations()
Give this instance its own evaluation counters and timers, decoupling it from any other instances the...
void eval_projection_multipliers(rvec y, real_t M) const
void eval_qr(index_t timestep, crvec xu, crvec h, rvec qr) const
void eval_add_R_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat R, rvec work) const
void eval_grad_f_prod(index_t timestep, crvec x, crvec u, crvec p, rvec grad_fxu_p) const
void eval_constr(index_t timestep, crvec x, rvec c) const
real_t eval_l(index_t timestep, crvec h) const
void eval_grad_constr_prod_N(crvec x, crvec p, rvec grad_cx_p) const
void eval_h(index_t timestep, crvec x, crvec u, rvec h) const
void reset_evaluations()
Reset all evaluation counters and timers to zero.
void eval_add_S_prod_masked(index_t timestep, crvec xu, crvec h, crindexvec mask_K, crvec v, rvec out, rvec work) const
void eval_q_N(crvec x, crvec h, rvec q) const
void eval_add_S_masked(index_t timestep, crvec xu, crvec h, crindexvec mask, rmat S, rvec work) const
std::shared_ptr< OCPEvalCounter > evaluations
ControlProblemWithCounters(std::in_place_t, Args &&...args)
void get_x_init(rvec x_init) const
typename TypeErasedControlProblem< config_t >::Box Box
void eval_projecting_difference_constraints(crvec z, rvec e) const
void eval_add_Q_N(crvec x, crvec h, rmat Q) const
real_t eval_l_N(crvec h) const
void eval_add_Q(index_t timestep, crvec xu, crvec h, rmat Q) const
void eval_constr_N(crvec x, rvec c) const
void eval_grad_constr_prod(index_t timestep, crvec x, crvec p, rvec grad_cx_p) const
void eval_f(index_t timestep, crvec x, crvec u, rvec fxu) const
static decltype(auto) timed(TimeT &time, FunT &&f)
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
bool provides_eval_add_gn_hess_constr_N() const
void eval_h_N(crvec x, rvec h) const
Double-precision double configuration.
Definition config.hpp:176
Single-precision float configuration.
Definition config.hpp:172
long double configuration.
Definition config.hpp:181