cyqlone develop
Fast, parallel and vectorized solver for linear systems with optimal control structure.
Loading...
Searching...
No Matches
ocp-backend-cyqlone.tpp
Go to the documentation of this file.
1#pragma once
2
3#include <cyqlone/config.hpp>
4#include <cyqlone/cyqlone.hpp>
5#include <cyqlone/linalg.hpp>
9#include <cyqlone/reduce.hpp>
10#include <batmat/assume.hpp>
11#include <batmat/config.hpp>
12#include <batmat/linalg/copy.hpp>
13#include <batmat/openmp.h>
14#include <batmat/simd.hpp>
15#include <guanaqo/print.hpp>
16#include <guanaqo/timed-cpu.hpp>
17#include <guanaqo/trace.hpp>
18
19#include <algorithm>
20#include <array>
21#include <cassert>
22#include <cmath>
23#include <functional>
24#include <limits>
25#include <map>
26#include <memory>
27#include <numeric>
28#include <optional>
29#include <string>
30#include <tuple>
31#include <utility>
32
33namespace CYQLONE_NS(cyqlone::qpalm) {
34
35namespace datapar = batmat::datapar;
36
37template <index_t VL, StorageOrder DefaultOrder>
40 using Context = typename OCP_t::Context;
41 using storage_t = typename OCP_t::template matrix<>;
42 using simd = typename OCP_t::simd;
43 static constexpr auto norms = cyqlone::norms<real_t, simd>{};
44 // clang-format off
45 struct var_vec_t : storage_t { friend CyQPALMBackend; var_vec_t() = default; private: var_vec_t(storage_t &&o) : storage_t{std::move(o)} {} };
46 struct eq_constr_vec_t : storage_t { friend CyQPALMBackend; eq_constr_vec_t() = default; private: eq_constr_vec_t(storage_t &&o) : storage_t{std::move(o)} {} };
47 struct ineq_constr_vec_t : storage_t { friend CyQPALMBackend; ineq_constr_vec_t() = default; private: ineq_constr_vec_t(storage_t &&o) : storage_t{std::move(o)} {} };
48 struct active_set_t : storage_t { friend CyQPALMBackend; active_set_t() = default; private: active_set_t(storage_t &&o) : storage_t{std::move(o)} {} };
49 // clang-format on
50
78
80 std::unique_ptr<typename OCP_t::SharedContext> parallel_ctx = ocp.create_parallel_context();
86 std::optional<var_vec_t> x0;
87 std::optional<ineq_constr_vec_t> y0;
88 std::optional<eq_constr_vec_t> λ0;
89 std::vector<std::array<size_t, 4>> thread_indices;
90 std::vector<Breakpoint> breakpoints_temp;
91
93 bool update_pending = false;
94 index_t num_updates = 0;
95 std::unique_ptr<Timings> ocp_timings;
96
99 : ocp{OCP_t::build(ocp, settings.processors)}, settings{settings} {
100 this->parallel_ctx->barrier.spin_count = settings.spin_count;
101 this->ocp.update_tricyqle_params(settings.tricyqle_params);
107 this->ocp.initialize_rhs(ocp, b_eq_strided);
108 this->ocp.initialize_gradient(ocp, grad_strided);
109 this->ocp.initialize_bounds(ocp, b_min_strided, b_max_strided);
110 if (!data.initial_variables.empty()) {
111 x0 = var_vec();
112 this->ocp.pack_variables(data.initial_variables, x0->view());
113 }
114 if (!data.initial_inequality_multipliers.empty()) {
116 this->ocp.pack_constraints(data.initial_inequality_multipliers, y0->view());
117 }
118 if (!data.initial_equality_multipliers.empty()) {
119 λ0 = eq_constr_vec();
120 this->ocp.pack_dynamics(data.initial_equality_multipliers, λ0->view());
121 }
122 if (settings.detailed_timings)
123 ocp_timings = std::make_unique<Timings>();
124 }
125
127 this->ocp.update_data(ocp);
128 this->ocp.initialize_rhs(ocp, b_eq_strided);
129 this->ocp.initialize_gradient(ocp, grad_strided);
130 this->ocp.initialize_bounds(ocp, b_min_strided, b_max_strided);
131 }
132
133 void set_b_eq(std::span<const real_t> b_eq) {
134 this->ocp.pack_dynamics(b_eq, b_eq_strided.view());
135 }
136 void set_b_lb(std::span<const real_t> b_lb) {
137 this->ocp.pack_constraints(b_lb, b_min_strided.view());
138 }
139 void set_b_ub(std::span<const real_t> b_ub) {
140 this->ocp.pack_constraints(b_ub, b_max_strided.view());
141 }
142
143 void warm_start(const var_vec_t &x, const ineq_constr_vec_t &y, const eq_constr_vec_t &λ) {
144 // TODO: this does not handle the case N_horiz != ceil_N() correctly
145 const auto k_to_l = [&](index_t k) {
146 const auto num_stages = ocp.n;
147 const auto i = (ocp.ceil_N() - k) % num_stages;
148 const auto k1 = (k + i) / num_stages;
149 const auto k2 = k1 >> ocp.lp();
150 const auto v = k2 % (1 << ocp.lv());
151 const auto t = k1 - (k2 << ocp.lp());
152 return ((num_stages * t + i) << ocp.lv()) + v;
153 };
154
155 switch (settings.strategy) {
157 this->x0.reset();
158 this->λ0.reset();
159 this->y0.reset();
160 break;
162 this->x0 = x;
163 this->λ0 = λ;
164 this->y0 = y;
165 break;
167 auto &x0 = this->x0.emplace(var_vec()); // TODO: zero init is redundant
168 auto &λ0 = this->λ0.emplace(eq_constr_vec()); // TODO: zero init is redundant
169 auto &y0 = this->y0.emplace(ineq_constr_vec()); // TODO: zero init is redundant
170 for (index_t k = 1; k < ocp.N_horiz; ++k) // TODO: vectorize?
171 x0(k_to_l(k - 1)) = x(k_to_l(k));
172 x0(k_to_l(ocp.N_horiz - 1)) = x(k_to_l(ocp.N_horiz - 1));
173 for (index_t k = 1; k < ocp.N_horiz; ++k) // TODO: vectorize?
174 y0(k_to_l(k - 1)) = y(k_to_l(k));
175 y0(k_to_l(ocp.N_horiz - 1)) = y(k_to_l(ocp.N_horiz - 1));
176 for (index_t k = 1; k < ocp.N_horiz; ++k) // TODO: vectorize?
177 λ0(k_to_l(k - 1)) = λ(k_to_l(k));
178 λ0(k_to_l(ocp.N_horiz - 1)) = λ(k_to_l(ocp.N_horiz - 1));
179 } break;
181 auto &x0 = this->x0.emplace(var_vec()); // TODO: zero init is redundant
182 auto &λ0 = this->λ0.emplace(eq_constr_vec()); // TODO: zero init is redundant
183 this->y0.emplace(y);
184 for (index_t k = 1; k < ocp.N_horiz; ++k) // TODO: vectorize?
185 x0(k_to_l(k - 1)) = x(k_to_l(k));
186 x0(k_to_l(ocp.N_horiz - 1)) = x(k_to_l(ocp.N_horiz - 1));
187 for (index_t k = 1; k < ocp.N_horiz; ++k) // TODO: vectorize?
188 λ0(k_to_l(k - 1)) = λ(k_to_l(k));
189 λ0(k_to_l(ocp.N_horiz - 1)) = λ(k_to_l(ocp.N_horiz - 1));
190 } break;
191 default: BATMAT_ASSERT(false);
192 }
193 }
194
195 void reset() {
196 num_updates = 0;
197 reset_factorization = true;
198 update_pending = false;
199 if (ocp_timings)
200 std::exchange(*ocp_timings, {});
201 }
202
203 [[nodiscard]] index_t num_var() const { return ocp.num_variables(); }
204 [[nodiscard]] index_t num_eq_constr() const { return ocp.num_dynamics_constraints(); }
205 [[nodiscard]] index_t num_ineq_constr() const { return ocp.num_general_constraints(); }
206
207 [[nodiscard]] var_vec_t var_vec() const { return var_vec_t(ocp.initialize_variables()); }
208 [[nodiscard]] eq_constr_vec_t eq_constr_vec() const {
209 return eq_constr_vec_t(ocp.initialize_dynamics_constraints());
210 }
211 [[nodiscard]] ineq_constr_vec_t ineq_constr_vec() const {
212 return ineq_constr_vec_t(ocp.initialize_general_constraints());
213 }
214 [[nodiscard]] active_set_t active_set() const {
215 return active_set_t(ocp.initialize_general_constraints());
216 }
217
218 template <class... Js>
219 void initialize_active_set(Js &...js) const {
220 ([this](active_set_t &j) { j = active_set(); }(js), ...);
221 }
222 template <class... Xs>
223 void initialize_var_vec(Xs &...xs) const {
224 ([this](var_vec_t &x) { x = var_vec(); }(xs), ...);
225 }
226 template <class... Ys>
227 void initialize_ineq_constr_vec(Ys &...ys) const {
228 ([this](ineq_constr_vec_t &y) { y = ineq_constr_vec(); }(ys), ...);
229 }
230 template <class... Λs>
231 void initialize_eq_constr_vec(Λs &...λs) const {
232 ([this](eq_constr_vec_t &λ) { λ = eq_constr_vec(); }(λs), ...);
233 }
234
235 void initial_variables(Context &ctx, var_vec_t &x) const {
236 x0 ? xcopy(ctx, *x0, x) : set_constant(ctx, x, real_t{});
237 }
239 λ0 ? xcopy(ctx, *λ0, λ) : set_constant(ctx, λ, real_t{});
240 }
242 y0 ? xcopy(ctx, *y0, y) : set_constant(ctx, y, real_t{});
243 }
244
245 // e = Ax - clamp(Ax, b_min, b_max)
246 void ineq_constr_resid(Context &ctx, const ineq_constr_vec_t &Ax, ineq_constr_vec_t &e) const;
247
248 void project_multipliers_ineq(Context &ctx, ineq_constr_vec_t &y) const;
249
250 real_t ineq_constr_viol(Context &ctx, const ineq_constr_vec_t &Ax) const;
251
252 real_t ineq_constr_resid_al(Context &ctx, const ineq_constr_vec_t &y,
253 const ineq_constr_vec_t &ŷ, const ineq_constr_vec_t &Σ,
254 ineq_constr_vec_t &e);
255
257 ocp.residual_dynamics_constr(ctx, x, b_eq_strided, Mxb);
258 }
259
260 void mat_vec_MT(Context &ctx, const eq_constr_vec_t &λ, var_vec_t &Mᵀλ) {
261 ocp.transposed_dynamics_constr(ctx, λ, Mᵀλ);
262 }
263
264 real_t unscaled_eq_constr_viol(Context &ctx, const eq_constr_vec_t &Mxb) const {
265 return norm_inf(ctx, Mxb);
266 }
267
268 void mat_vec_AT(Context &ctx, const ineq_constr_vec_t &y, var_vec_t &Aᵀy) {
269 ocp.transposed_general_constr(ctx, y, Aᵀy);
270 }
271
272 void mat_vec_AT(const ineq_constr_vec_t &y, var_vec_t &Aᵀy) {
273 ocp.transposed_general_constr(y, Aᵀy);
274 }
275
276 void mat_vec_A(Context &ctx, const var_vec_t &x, ineq_constr_vec_t &Ax) {
277 ocp.general_constr(ctx, x, Ax);
278 }
280 auto Ax = ineq_constr_vec();
281 mat_vec_A(ctx, x, Ax);
282 return Ax;
283 }
284
285 void grad_f(Context &ctx, const var_vec_t &x, var_vec_t &grad_f) {
286 ocp.cost_gradient(ctx, x, 1, grad_strided, 0, grad_f);
287 }
288 void grad_f_regularized(Context &ctx, real_t S, const var_vec_t &x, const var_vec_t &x_reg,
289 var_vec_t &grad_f) {
290 using std::isfinite;
291 if (isfinite(S))
292 ocp.cost_gradient_regularized(ctx, S, x, x_reg, grad_strided, grad_f);
293 else
294 ocp.cost_gradient(ctx, x, 1, grad_strided, 0, grad_f);
295 }
296 void grad_f_remove_regularization(Context &ctx, real_t S, const var_vec_t &x,
297 const var_vec_t &x_reg, var_vec_t &grad_f) {
298 using std::isfinite;
299 if (isfinite(S))
300 ocp.cost_gradient_remove_regularization(ctx, S, x, x_reg, grad_f);
301 }
302 real_t f_grad_f(Context &ctx, const var_vec_t &x, var_vec_t &grad_f) {
303 ocp.cost_gradient(ctx, x, 1, grad_strided, 0, grad_f);
304 return std::numeric_limits<real_t>::quiet_NaN(); // TODO: compute f
305 }
306 std::tuple<real_t, var_vec_t> f_grad_f(Context &ctx, const var_vec_t &x) {
307 auto grad_f = var_vec();
308 real_t f = f_grad_f(ctx, x, grad_f);
309 return {f, std::move(grad_f)};
310 }
311
313 real_t θ;
316 };
317
318 /// Increase the penalty parameters Σ for which the violation e has not decreased sufficiently
319 /// compared to e_old.
321 const ineq_constr_vec_t &e_old, const PenaltySettings &settings);
322
323 /// Called when the primal regularization S has changed: causes the factorization to be reset.
324 void update_regularization_changed(Context &ctx, real_t S_new, real_t S_old) {
325 if (S_new != S_old)
326 ctx.run_single_sync([&] { reset_factorization = true; });
327 }
328
329 /// Decrease the primal regularization S to S_boost, to boost convergence when close to the
330 /// solution.
331 real_t boost_regularization(Context &ctx, real_t S, real_t S_boost) {
332 update_regularization_changed(ctx, S_boost, S);
333 return S_boost;
334 }
335
336 /// Called when the penalty parameters Σ have been updated: causes the factorization to be reset
337 /// if any of the penalty parameters have changed.
338 void update_penalty_changed(Context &ctx, const ineq_constr_vec_t &Σ, index_t num_Σ_changed) {
339 std::ignore = Σ;
340 if (num_Σ_changed > 0)
341 ctx.run_single_sync([&] { reset_factorization = true; });
342 }
343
344 /// @name Line search
345 /// @{
346
347 template <class T, size_t N>
348 static void merge_chunk(std::span<const T> chunk, size_t chunk_index,
349 std::span<const std::array<size_t, N>> separators, std::span<T> out);
350
352 compute_partition_breakpoints(Context &ctx, std::vector<Breakpoint> &breakpoints,
353 const ineq_constr_vec_t &Σ, const ineq_constr_vec_t &y,
354 const ineq_constr_vec_t &Ad, const ineq_constr_vec_t &Ax,
355 const ineq_constr_vec_t &b_min, const ineq_constr_vec_t &b_max);
356
357 friend BreakpointsResult
359 std::vector<Breakpoint> &breakpoints, const ineq_constr_vec_t &Σ,
360 const ineq_constr_vec_t &y, const ineq_constr_vec_t &Ad,
361 const ineq_constr_vec_t &Ax, const ineq_constr_vec_t &b_min,
362 const ineq_constr_vec_t &b_max) {
363 return backend.compute_partition_breakpoints(ctx, breakpoints, Σ, y, Ad, Ax, b_min, b_max);
364 }
365
366 /// @}
367
368 /// @name Linear algebra operations (level 1 BLAS-like)
369 /// @{
370
371 /// Compute y = a x + y.
372 template <class T, class U>
373 void xaxpy(Context &ctx, real_t a, const T &x, U &y);
374 /// Copy x to y.
375 template <class T, class U>
376 void xcopy(Context &ctx, const T &x, U &y) const;
377 /// Set each element of x to the constant value y.
378 template <class T, class U>
379 void set_constant(Context &ctx, T &x, const U &y) const;
380 /// Multiply a vector x by a scalar s.
381 template <class T>
382 void scale(Context &ctx, real_t s, T &x) const;
383 /// Dot product of a and b.
384 [[nodiscard]] real_t dot(Context &ctx, const var_vec_t &a, const var_vec_t &b) const;
385 /// Compute multiple partial dot products, without reducing across threads.
386 template <class... Args>
387 void local_dots(std::span<real_t, 1 + sizeof...(Args) / 2> out, const auto &a, const auto &b,
388 const Args &...others) const;
389 /// Compute multiple dot products at once. This is more efficient than computing them separately
390 /// because only a single reduction across threads is needed.
391 template <class... Args>
392 [[nodiscard]] std::array<real_t, sizeof...(Args) / 2> dots(Context &ctx,
393 const Args &...args) const;
394 /// Compute the infinity, l1 and l2 norms of x.
395 template <class T>
396 [[nodiscard]] auto norm_inf_l1_sq(Context &ctx, const T &x) const;
397 /// Infinity or max norm of x.
398 template <class T>
399 [[nodiscard]] real_t norm_inf(Context &ctx, const T &x) const;
400 /// Squared l2 norm of x.
401 template <class T>
402 [[nodiscard]] real_t norm_squared(Context &ctx, const T &x) const;
403
404 /// @}
405
406 const ineq_constr_vec_t &Ax_min() const { return b_min_strided; }
407 const ineq_constr_vec_t &Ax_max() const { return b_max_strided; }
408
409 index_t calc_ŷ_Aᵀŷ(Context &ctx, const ineq_constr_vec_t &Ax, const ineq_constr_vec_t &Σ,
410 const ineq_constr_vec_t &y, ineq_constr_vec_t &ŷ, var_vec_t &Aᵀŷ,
411 active_set_t &J);
412
413 real_t unscaled_aug_lagr_norm(Context &ctx, const var_vec_t &grad_f, const var_vec_t &Mᵀλ,
414 const var_vec_t &Aᵀŷ) const {
415 GUANAQO_TRACE("unscaled_aug_lagr_norm", 0);
416 auto nrm_simd = norms.zero_simd();
417 const auto grad_norm_simd = [&](auto grad_fji, auto Mᵀλji, auto Aᵀŷji) {
418 nrm_simd = norms(nrm_simd, grad_fji + Mᵀλji + Aᵀŷji);
419 };
420 const auto grad_norm_batch = [&](auto, auto, auto grad_fj, auto Mᵀλj, auto Aᵀŷj) {
421 linalg::for_each_elementwise(grad_norm_simd, grad_fj, Mᵀλj, Aᵀŷj);
422 };
423 ocp.foreach_stage(ctx, grad_norm_batch, grad_f, Mᵀλ, Aᵀŷ);
424 return ctx.reduce(norms(nrm_simd), norms).norm_inf();
425 }
426
427 void scale_variables(std::span<const real_t> in, var_vec_t &out) const {
428 ocp.pack_variables(in, out);
429 }
430 void scale_ineq_constr(std::span<const real_t> in, ineq_constr_vec_t &out) const {
431 ocp.pack_constraints(in, out);
432 }
433 void scale_eq_constr(std::span<const real_t> in, eq_constr_vec_t &out) const {
434 ocp.pack_dynamics(in, out);
435 }
436
437 void unscale_variables(const var_vec_t &in, std::span<real_t> out) const {
438 ocp.unpack_variables(in, out);
439 }
440 void unscale_ineq_constr(const ineq_constr_vec_t &in, std::span<real_t> out) const {
441 ocp.unpack_constraints(in, out);
442 }
443 void unscale_ineq_constr(const active_set_t &in, std::span<real_t> out) const {
444 ocp.unpack_constraints(in, out);
445 }
446 void unscale_eq_constr(const eq_constr_vec_t &in, std::span<real_t> out) const {
447 ocp.unpack_dynamics(in, out);
448 }
449
450 index_t active_set_change(Context &ctx, real_t, [[maybe_unused]] const ineq_constr_vec_t &Σ,
451 const active_set_t &J, const active_set_t &J_old) {
452 BATMAT_ASSERT(J.rows() == J_old.rows() && J.cols() == J_old.cols());
453 BATMAT_ASSERT(J.depth() == J_old.depth());
454 BATMAT_ASSERT(J.cols() == 1);
455 index_t num_different = 0;
456 const auto active_set_change = [&](auto, auto, auto Ji, auto J_oldi) {
457 num_different += std::inner_product(Ji.data(), Ji.data() + Ji.size(), J_oldi.data(), //
458 index_t{0}, std::plus<>{}, std::not_equal_to<>{});
459 };
460 {
461 GUANAQO_TRACE("active_set_change", 0);
463 ocp.foreach_stage(ctx, active_set_change, J, J_old);
464 }
465 num_different = ctx.reduce(num_different);
466 // If there are no changing constraints, or if we were going to
467 // re-factorize anyway, we don't need to do anything.
468 if (num_different == 0 || reset_factorization)
469 return num_different;
470 bool do_reset_fac = num_updates >= settings.max_update_count;
471 do_reset_fac |= static_cast<double>(num_different) >=
472 static_cast<double>(num_ineq_constr()) * settings.changing_constr_factor;
473 bool prev_update_pending = update_pending;
474 if (do_reset_fac) {
475 ctx.run_single_sync([&] { reset_factorization = true; });
476 return num_different;
477 }
478 ctx.run_single_sync([&] {
479 update_pending = true;
480 ++num_updates;
481 ++stats.num_updates;
482 stats.rank_updates += num_different;
483 });
485 if (prev_update_pending) {
486 const auto delta = [&](auto, auto, auto Ji, auto J_oldi, auto ΔΣi) {
487 linalg::axpy(ΔΣi, {1, -1}, Ji, J_oldi);
488 };
489 ocp.foreach_stage(ctx, delta, J, J_old, ΔΣ);
490 } else {
491 const auto delta = [&](auto, auto, auto Ji, auto J_oldi, auto ΔΣi) {
492 linalg::sub(Ji, J_oldi, ΔΣi);
493 };
494 ocp.foreach_stage(ctx, delta, J, J_old, ΔΣ);
495 }
496 return num_different;
497 }
498
499 void recompute_inner(Context &ctx, real_t S, const var_vec_t &x_outer, const var_vec_t &x,
500 const eq_constr_vec_t &λ, var_vec_t &grad, ineq_constr_vec_t &Ax,
501 var_vec_t &Mᵀλ) {
502 {
504 grad_f_regularized(ctx, S, x, x_outer, grad);
505 }
506 {
508 mat_vec_A(ctx, x, Ax);
509 }
510 {
512 mat_vec_MT(ctx, λ, Mᵀλ);
513 }
514 }
515
516 real_t recompute_outer(Context &ctx, const var_vec_t &x, const var_vec_t &Aᵀŷ,
517 const eq_constr_vec_t &λ, var_vec_t &grad, ineq_constr_vec_t &Ax,
518 var_vec_t &Mᵀλ) {
519 {
521 grad_f(ctx, x, grad); // ∇f = Q * x + q
522 }
523 {
525 mat_vec_A(ctx, x, Ax); // Ax = A * x
526 }
527 {
529 mat_vec_MT(ctx, λ, Mᵀλ); // Mᵀλ = Mᵀ * λ
530 }
531 {
533 return unscaled_aug_lagr_norm(ctx, grad, Mᵀλ, Aᵀŷ);
534 }
535 }
536
540
541 void print_solve_rhs_norms(Context &ctx, const var_vec_t &d, const eq_constr_vec_t &Δλ,
542 const var_vec_t &grad, const var_vec_t &Mᵀλ,
543 const var_vec_t &Aᵀŷ) const;
544
545 void print_solve_resid_norms(Context &ctx, const var_vec_t &x, const var_vec_t &d,
546 const var_vec_t &grad, const var_vec_t &ξ, const var_vec_t &Mᵀλ,
547 const var_vec_t &Aᵀŷ, const var_vec_t &MᵀΔλ,
548 const ineq_constr_vec_t &Ad, const active_set_t &J);
549 void solve(Context &ctx, [[maybe_unused]] const var_vec_t &x, const var_vec_t &grad,
550 const var_vec_t &Mᵀλ, const var_vec_t &Aᵀŷ, const eq_constr_vec_t &Mxb, real_t S,
551 [[maybe_unused]] const ineq_constr_vec_t &Σ,
552 const active_set_t &J, //
554 var_vec_t &MᵀΔλ);
555
556 auto get_timed(Timings::type Timings::*member) const {
557 return ocp_timings ? std::optional<typename Timings::timed_t>((*ocp_timings).*member)
558 : std::nullopt;
559 }
560
563 Stats clear_stats() { return std::exchange(stats, {}); }
564
565 std::map<std::string, typename Timings::type> clear_timings() {
566 if (!ocp_timings)
567 return {};
568 const auto t = std::exchange(*ocp_timings, {});
569 return {
570 {"breakpoints", t.breakpoints},
571 {"calc_y_hat", t.calc_y_hat},
572 {"calc_y_hat_AT", t.calc_y_hat_AT},
573 {"update_active_set_change", t.update_active_set_change},
574 {"update_factorization", t.update_factorization},
575 {"factor", t.factor},
576 {"solve", t.solve},
577 {"solve_MT", t.solve_MT},
578 {"solve_A", t.solve_A},
579 {"solve_grad", t.solve_grad},
580 {"solve_resid", t.solve_resid},
581 {"recompute_outer_grad", t.recompute_outer_grad},
582 {"recompute_outer_A", t.recompute_outer_A},
583 {"recompute_outer_AT", t.recompute_outer_AT},
584 {"recompute_outer_MT", t.recompute_outer_MT},
585 {"recompute_outer_norm", t.recompute_outer_norm},
586 {"recompute_inner_grad", t.recompute_inner_grad},
587 {"recompute_inner_A", t.recompute_inner_A},
588 {"recompute_inner_MT", t.recompute_inner_MT},
589 {"ineq_constr_resid", t.ineq_constr_resid},
590 {"ineq_constr_viol", t.ineq_constr_viol},
591 {"ineq_constr_resid_al", t.ineq_constr_resid_al},
592 {"update_penalty_y", t.update_penalty_y},
593 };
594 }
595};
596
597template <index_t VL, StorageOrder DefaultOrder>
598unique_CyQPALMBackend<VL, DefaultOrder>::~unique_CyQPALMBackend() = default;
599
600template <index_t VL, StorageOrder DefaultOrder>
601unique_CyQPALMBackend<VL, DefaultOrder>
603 const CyQPALMBackendSettings &settings) {
604 return {std::make_unique<CyQPALMBackend<VL, DefaultOrder>>(ocp, data, settings)};
605}
606
607template <index_t VL, StorageOrder DefaultOrder>
612
613template <index_t VL, StorageOrder DefaultOrder>
615 const LinearOCPStorage &ocp) {
616 const auto cocp = cyqlone::CyqloneStorage<>::build(ocp, backend.ocp.ny_0);
617 update_cyqpalm_backend(backend, cocp);
618}
619
620} // namespace CYQLONE_NS(cyqlone::qpalm)
621
#define BATMAT_ASSERT(x)
#define CYQLONE_NS(ns)
Definition config.hpp:10
The main header for the Cyqlone and Tricyqle linear solvers.
std::decay_t< decltype(Tag)> tag_t
simdified_value_t< Vx > norm_inf(Vx &&x)
Compute the infinity norm of a vector.
Definition linalg.hpp:260
void axpy(Vy &&y, const std::array< simdified_value_t< Vy >, sizeof...(Vx)> &alphas, Vx &&...x)
Add scaled vector y = ∑ᵢ αᵢxᵢ + βy.
Definition linalg.hpp:361
void for_each_elementwise(F &&fun, VA &&A, VAs &&...As)
Apply a function to all elements of the given matrices or vectors.
Definition linalg.hpp:433
simdified_value_t< Vx > dot(Vx &&x, Vy &&y)
Compute the dot product of two vectors.
Definition linalg.hpp:286
void scale(T alpha, Vx &&x, Vz &&z)
Multiply a vector by a scalar z = αx.
Definition linalg.hpp:294
void sub(VA &&A, VB &&B, VC &&C, with_rotate_t< Rotate >={})
Subtract two matrices or vectors C = A - B. Rotate affects B.
Definition linalg.hpp:401
unique_CyQPALMBackend< VL, DefaultOrder > make_cyqpalm_backend(const CyqloneStorage< real_t > &ocp, CyqloneData data, const CyQPALMBackendSettings &settings)
void update_cyqpalm_backend(CyQPALMBackend< VL, DefaultOrder > &backend, const CyqloneStorage< real_t > &ocp)
#define GUANAQO_TRACE(name, instance,...)
simd_view_types< std::remove_const_t< T >, Abi >::template matrix< T, Order > matrix
batmat::DefaultTimings DefaultTimings
Definition timing.hpp:7
Kahan-Babuška-Neumaier compensated summation.
Vector reductions.
constexpr index_t v
Functions for the factorization and solution of Newton system in QPALM for the Cyqlone backend.
Linear solver for systems with optimal control structure.
Definition cyqlone.hpp:561
void pack_constraints(std::span< const value_type > y_lin, mut_view<> y, value_type fill=0) const
Definition data.tpp:366
void pack_dynamics(std::span< const value_type > λ_lin, mut_view<> λ) const
Definition data.tpp:316
const index_t ny_0
Number of general constraints at stage 0, D(0) u(0).
Definition cyqlone.hpp:571
Storage for a linear-quadratic OCP with the initial states x₀ eliminated.
static CyqloneStorage build(const LinearOCPStorage &ocp, index_t ny_0=-1)
Storage for a linear-quadratic OCP of the form.
Definition ocp.hpp:37
Utilities for computing vector norms.
Definition reduce.hpp:26
CyQPALMBackend(const CyqloneStorage<> &ocp, CyqloneData data, const CyQPALMBackendSettings &settings)
void initialize_active_set(Js &...js) const
void recompute_inner(Context &ctx, real_t S, const var_vec_t &x_outer, const var_vec_t &x, const eq_constr_vec_t &λ, var_vec_t &grad, ineq_constr_vec_t &Ax, var_vec_t &Mᵀλ)
void initial_variables(Context &ctx, var_vec_t &x) const
void set_b_eq(std::span< const real_t > b_eq)
void xcopy(Context &ctx, const T &x, U &y) const
Copy x to y.
Definition linalg.tpp:20
void initial_multipliers_ineq(Context &ctx, ineq_constr_vec_t &y) const
real_t recompute_outer(Context &ctx, const var_vec_t &x, const var_vec_t &Aᵀŷ, const eq_constr_vec_t &λ, var_vec_t &grad, ineq_constr_vec_t &Ax, var_vec_t &Mᵀλ)
real_t norm_inf(Context &ctx, const T &x) const
Infinity or max norm of x.
Definition linalg.tpp:88
void update_regularization_changed(Context &ctx, real_t S_new, real_t S_old)
Called when the primal regularization S has changed: causes the factorization to be reset.
cyqlone::CyqloneSolver< VL, real_t, DefaultOrder > OCP_t
real_t unscaled_eq_constr_viol(Context &ctx, const eq_constr_vec_t &Mxb) const
const ineq_constr_vec_t & Ax_min() const
auto get_timed(Timings::type Timings::*member) const
void grad_f_remove_regularization(Context &ctx, real_t S, const var_vec_t &x, const var_vec_t &x_reg, var_vec_t &grad_f)
std::vector< std::array< size_t, 4 > > thread_indices
void update_data(const CyqloneStorage<> &ocp)
std::tuple< real_t, var_vec_t > f_grad_f(Context &ctx, const var_vec_t &x)
void unscale_ineq_constr(const active_set_t &in, std::span< real_t > out) const
void set_b_ub(std::span< const real_t > b_ub)
eq_constr_vec_t eq_constr_vec() const
const ineq_constr_vec_t & Ax_max() const
real_t boost_regularization(Context &ctx, real_t S, real_t S_boost)
Decrease the primal regularization S to S_boost, to boost convergence when close to the solution.
void initial_multipliers_eq(Context &ctx, eq_constr_vec_t &λ) const
index_t active_set_change(Context &ctx, real_t, const ineq_constr_vec_t &Σ, const active_set_t &J, const active_set_t &J_old)
void unscale_ineq_constr(const ineq_constr_vec_t &in, std::span< real_t > out) const
void warm_start(const var_vec_t &x, const ineq_constr_vec_t &y, const eq_constr_vec_t &λ)
BreakpointsResult compute_partition_breakpoints(Context &ctx, std::vector< Breakpoint > &breakpoints, const ineq_constr_vec_t &Σ, const ineq_constr_vec_t &y, const ineq_constr_vec_t &Ad, const ineq_constr_vec_t &Ax, const ineq_constr_vec_t &b_min, const ineq_constr_vec_t &b_max)
std::map< std::string, typename Timings::type > clear_timings()
void set_b_lb(std::span< const real_t > b_lb)
void mat_vec_MT(Context &ctx, const eq_constr_vec_t &λ, var_vec_t &Mᵀλ)
index_t update_penalty_y(Context &ctx, ineq_constr_vec_t &Σ, const ineq_constr_vec_t &e, const ineq_constr_vec_t &e_old, const PenaltySettings &settings)
Increase the penalty parameters Σ for which the violation e has not decreased sufficiently compared t...
void scale_ineq_constr(std::span< const real_t > in, ineq_constr_vec_t &out) const
void print_solve_rhs_norms(Context &ctx, const var_vec_t &d, const eq_constr_vec_t &Δλ, const var_vec_t &grad, const var_vec_t &Mᵀλ, const var_vec_t &Aᵀŷ) const
Definition solve.tpp:68
void eq_constr_resid(Context &ctx, const var_vec_t &x, eq_constr_vec_t &Mxb)
void update_penalty_changed(Context &ctx, const ineq_constr_vec_t &Σ, index_t num_Σ_changed)
Called when the penalty parameters Σ have been updated: causes the factorization to be reset if any o...
void unscale_variables(const var_vec_t &in, std::span< real_t > out) const
ineq_constr_vec_t ineq_constr_vec() const
void print_solve_resid_norms(Context &ctx, const var_vec_t &x, const var_vec_t &d, const var_vec_t &grad, const var_vec_t &ξ, const var_vec_t &Mᵀλ, const var_vec_t &Aᵀŷ, const var_vec_t &MᵀΔλ, const ineq_constr_vec_t &Ad, const active_set_t &J)
Definition solve.tpp:93
void scale_variables(std::span< const real_t > in, var_vec_t &out) const
void mat_vec_AT(const ineq_constr_vec_t &y, var_vec_t &Aᵀy)
void initialize_eq_constr_vec(Λs &...λs) const
friend BreakpointsResult guanaqo_tag_invoke(guanaqo::tag_t< get_breakpoints >, CyQPALMBackend &backend, Context &ctx, std::vector< Breakpoint > &breakpoints, const ineq_constr_vec_t &Σ, const ineq_constr_vec_t &y, const ineq_constr_vec_t &Ad, const ineq_constr_vec_t &Ax, const ineq_constr_vec_t &b_min, const ineq_constr_vec_t &b_max)
void initialize_ineq_constr_vec(Ys &...ys) const
void grad_f(Context &ctx, const var_vec_t &x, var_vec_t &grad_f)
guanaqo::Timed< batmat::DefaultTimings > timed_t
void solve(Context &ctx, const var_vec_t &x, const var_vec_t &grad, const var_vec_t &Mᵀλ, const var_vec_t &Aᵀŷ, const eq_constr_vec_t &Mxb, real_t S, const ineq_constr_vec_t &Σ, const active_set_t &J, var_vec_t &d, var_vec_t &ξ, ineq_constr_vec_t &Ad, eq_constr_vec_t &Δλ, var_vec_t &MᵀΔλ)
Definition solve.tpp:16
void mat_vec_A(Context &ctx, const var_vec_t &x, ineq_constr_vec_t &Ax)
std::optional< ineq_constr_vec_t > y0
std::optional< var_vec_t > x0
void grad_f_regularized(Context &ctx, real_t S, const var_vec_t &x, const var_vec_t &x_reg, var_vec_t &grad_f)
typename OCP_t::template matrix<> storage_t
ineq_constr_vec_t mat_vec_A(Context &ctx, const var_vec_t &x)
std::vector< Breakpoint > breakpoints_temp
std::optional< eq_constr_vec_t > λ0
void scale_eq_constr(std::span< const real_t > in, eq_constr_vec_t &out) const
void unscale_eq_constr(const eq_constr_vec_t &in, std::span< real_t > out) const
real_t unscaled_aug_lagr_norm(Context &ctx, const var_vec_t &grad_f, const var_vec_t &Mᵀλ, const var_vec_t &Aᵀŷ) const
std::unique_ptr< typename OCP_t::SharedContext > parallel_ctx
void set_constant(Context &ctx, T &x, const U &y) const
Set each element of x to the constant value y.
Definition linalg.tpp:27
void mat_vec_AT(Context &ctx, const ineq_constr_vec_t &y, var_vec_t &Aᵀy)
real_t f_grad_f(Context &ctx, const var_vec_t &x, var_vec_t &grad_f)
std::unique_ptr< Timings > ocp_timings