aligator  0.6.1
A primal-dual augmented Lagrangian-type solver for nonlinear trajectory optimization.
Loading...
Searching...
No Matches
utils.hpp
Go to the documentation of this file.
1
2#pragma once
3
4#include "lqr-problem.hpp"
6
7namespace aligator {
8namespace gar {
9
10template <typename Scalar>
12 const LQRProblemTpl<Scalar> &problem,
13 boost::span<const typename math_types<Scalar>::VectorXs> xs,
14 boost::span<const typename math_types<Scalar>::VectorXs> us,
15 boost::span<const typename math_types<Scalar>::VectorXs> vs,
16 boost::span<const typename math_types<Scalar>::VectorXs> lbdas,
17 const Scalar mudyn, const Scalar mueq,
18 const std::optional<typename math_types<Scalar>::ConstVectorRef> &theta_,
19 bool verbose = false) {
20 fmt::print("[{}] ", __func__);
21 uint N = (uint)problem.horizon();
22 using VectorXs = typename math_types<Scalar>::VectorXs;
23 using KnotType = LQRKnotTpl<Scalar>;
24
25 Scalar dynErr = 0.;
26 Scalar cstErr = 0.;
27 Scalar dualErr = 0.;
28 Scalar dNorm;
29
30 VectorXs _dyn;
31 VectorXs _cst;
32 VectorXs _gx;
33 VectorXs _gu;
34 VectorXs _gt;
35
36 // initial stage
37 {
38 _dyn = problem.g0 + problem.G0 * xs[0] - mudyn * lbdas[0];
39 dNorm = math::infty_norm(_dyn);
40 dynErr = std::max(dynErr, dNorm);
41 if (verbose)
42 fmt::print("d0 = {:.3e} \n", dNorm);
43 }
44 for (uint t = 0; t <= N; t++) {
45 const KnotType &knot = problem.stages[t];
46 auto _Str = knot.S.transpose();
47
48 if (verbose)
49 fmt::print("[{: >2d}] ", t);
50 _gx.setZero(knot.nx);
51 _gu.setZero(knot.nu);
52 _gt.setZero(knot.nth);
53
54 _cst = knot.C * xs[t] + knot.d - mueq * vs[t];
55 _gx.noalias() = knot.q + knot.Q * xs[t] + knot.C.transpose() * vs[t];
56 _gu.noalias() = knot.r + _Str * xs[t] + knot.D.transpose() * vs[t];
57
58 if (knot.nu > 0) {
59 _cst.noalias() += knot.D * us[t];
60 _gx.noalias() += knot.S * us[t];
61 _gu.noalias() += knot.R * us[t];
62 }
63
64 if (t == 0) {
65 _gx += problem.G0.transpose() * lbdas[0];
66 } else {
67 auto Et = problem.stages[t - 1].E.transpose();
68 _gx += Et * lbdas[t];
69 }
70
71 if (t < N) {
72 _dyn = knot.A * xs[t] + knot.B * us[t] + knot.f + knot.E * xs[t + 1] -
73 mudyn * lbdas[t + 1];
74 _gx += knot.A.transpose() * lbdas[t + 1];
75 _gu += knot.B.transpose() * lbdas[t + 1];
76
77 dNorm = math::infty_norm(_dyn);
78 if (verbose)
79 fmt::print(" |d| = {:.3e} | ", dNorm);
80 dynErr = std::max(dynErr, dNorm);
81 }
82
83 if (theta_.has_value()) {
84 Eigen::Ref<const VectorXs> th = theta_.value();
85 _gx.noalias() += knot.Gx * th;
86 _gu.noalias() += knot.Gu * th;
87 _gt = knot.gamma;
88 _gt.noalias() += knot.Gx.transpose() * xs[t];
89 if (knot.nu > 0)
90 _gt.noalias() += knot.Gu.transpose() * us[t];
91 _gt.noalias() += knot.Gth * th;
92 }
93
94 Scalar gxNorm = math::infty_norm(_gx);
95 Scalar guNorm = math::infty_norm(_gu);
96 Scalar cstNorm = math::infty_norm(_cst);
97 if (verbose)
98 fmt::print("|gx| = {:.3e} | |gu| = {:.3e} | |cst| = {:.3e}\n", gxNorm,
99 guNorm, cstNorm);
100
101 dualErr = std::max({dualErr, gxNorm, guNorm});
102 cstErr = std::max(cstErr, cstNorm);
103 }
104
105 return std::array{dynErr, cstErr, dualErr};
106}
107
111template <typename Scalar>
112bool lqrDenseMatrix(const LQRProblemTpl<Scalar> &problem, Scalar mudyn,
113 Scalar mueq, typename math_types<Scalar>::MatrixXs &mat,
114 typename math_types<Scalar>::VectorXs &rhs) {
115 using knot_t = LQRKnotTpl<Scalar>;
116 const auto &knots = problem.stages;
117 const size_t N = size_t(problem.horizon());
118
119 if (!problem.isInitialized())
120 return false;
121
122 mat.setZero();
123
124 uint idx = 0;
125 {
126 const uint nc0 = problem.nc0();
127 const uint nx0 = knots[0].nx;
128 mat.block(nc0, 0, nx0, nc0) = problem.G0.transpose();
129 mat.block(0, nc0, nc0, nx0) = problem.G0;
130 mat.topLeftCorner(nc0, nc0).diagonal().setConstant(-mudyn);
131
132 rhs.head(nc0) = problem.g0;
133 idx += nc0;
134 }
135
136 for (size_t t = 0; t <= N; t++) {
137 const knot_t &model = knots[t];
138 // get block for current variables
139 const uint n = model.nx + model.nu + model.nc;
140 auto block = mat.block(idx, idx, n, n);
141 auto rhsblk = rhs.segment(idx, n);
142 auto Q = block.topLeftCorner(model.nx, model.nx);
143 auto St = block.leftCols(model.nx).middleRows(model.nx, model.nu);
144 auto R = block.block(model.nx, model.nx, model.nu, model.nu);
145 auto C = block.bottomRows(model.nc).leftCols(model.nx);
146 auto D = block.bottomRows(model.nc).middleCols(model.nx, model.nu);
147 auto dual = block.bottomRightCorner(model.nc, model.nc).diagonal();
148 dual.array() = -mueq;
149
150 Q = model.Q;
151 St = model.S.transpose();
152 R = model.R;
153 C = model.C;
154 D = model.D;
155
156 block = block.template selfadjointView<Eigen::Lower>();
157
158 rhsblk.head(model.nx) = model.q;
159 rhsblk.segment(model.nx, model.nu) = model.r;
160 rhsblk.tail(model.nc) = model.d;
161
162 // fill in dynamics
163 // row contains [A; B; 0; -mu*I, E] -> nx + nu + nc + nx + nx2 cols
164 if (t != N) {
165 uint ncols = model.nx + model.nx2 + n;
166 auto row = mat.block(idx + n, idx, model.nx, ncols);
167 row.leftCols(model.nx) = model.A;
168 row.middleCols(model.nx, model.nu) = model.B;
169 row.middleCols(n, model.nx).diagonal().array() = -mudyn;
170 row.rightCols(model.nx) = model.E;
171
172 rhs.segment(idx + n, model.nx2) = model.f;
173
174 auto col = mat.transpose().block(idx + n, idx, model.nx, ncols);
175 col = row;
176
177 // shift by size of block + costate size (nx2)
178 idx += n + model.nx2;
179 }
180 }
181 return true;
182}
183
185template <typename Scalar>
186uint lqrNumRows(const LQRProblemTpl<Scalar> &problem) {
187 const auto &knots = problem.stages;
188 const uint nc0 = problem.nc0();
189 const size_t N = knots.size() - 1UL;
190 uint nrows = nc0;
191 for (size_t t = 0; t <= N; t++) {
192 const auto &model = knots[t];
193 nrows += model.nx + model.nu + model.nc;
194 if (t != N)
195 nrows += model.nx;
196 }
197 return nrows;
198}
199
201template <typename Scalar>
202auto lqrDenseMatrix(const LQRProblemTpl<Scalar> &problem, Scalar mudyn,
203 Scalar mueq) {
204
205 decltype(auto) knots = problem.stages;
206 using MatrixXs = typename math_types<Scalar>::MatrixXs;
207 using VectorXs = typename math_types<Scalar>::VectorXs;
208 const uint nrows = lqrNumRows(problem);
209
210 MatrixXs mat(nrows, nrows);
211 VectorXs rhs(nrows);
212
213 if (!lqrDenseMatrix(problem, mudyn, mueq, mat, rhs)) {
214 ALIGATOR_RUNTIME_ERROR("Problem was not initialized.");
215 }
216 return std::make_pair(mat, rhs);
217}
218
220template <typename Scalar>
222 const LQRProblemTpl<Scalar> &problem,
223 const typename math_types<Scalar>::ConstVectorRef solution,
224 std::vector<typename math_types<Scalar>::VectorXs> &xs,
225 std::vector<typename math_types<Scalar>::VectorXs> &us,
226 std::vector<typename math_types<Scalar>::VectorXs> &vs,
227 std::vector<typename math_types<Scalar>::VectorXs> &lbdas) {
228 const uint N = (uint)problem.horizon();
229 xs.resize(N + 1);
230 us.resize(N + 1);
231 vs.resize(N + 1);
232 lbdas.resize(N + 1);
233 const uint nc0 = problem.nc0();
234
235 lbdas[0] = solution.head(nc0);
236
237 uint idx = nc0;
238 for (size_t t = 0; t <= N; t++) {
239 const LQRKnotTpl<Scalar> &knot = problem.stages[t];
240 const uint n = knot.nx + knot.nu + knot.nc;
241 auto seg = solution.segment(idx, n);
242 xs[t] = seg.head(knot.nx);
243 us[t] = seg.segment(knot.nx, knot.nu);
244 vs[t] = seg.segment(knot.nx + knot.nu, knot.nc);
245 idx += n;
246 if (t < N) {
247 lbdas[t + 1] = solution.segment(idx, knot.nx2);
248 idx += knot.nx2;
249 }
250 }
251}
252
253template <typename Scalar>
254auto lqrInitializeSolution(const LQRProblemTpl<Scalar> &problem) {
255 using VectorXs = typename math_types<Scalar>::VectorXs;
256 using knot_t = LQRKnotTpl<Scalar>;
257 std::vector<VectorXs> xs;
258 std::vector<VectorXs> us;
259 std::vector<VectorXs> vs;
260 std::vector<VectorXs> lbdas;
261 const uint N = (uint)problem.horizon();
262
263 xs.resize(N + 1);
264 us.resize(N + 1);
265 vs.resize(N + 1);
266 lbdas.resize(N + 1);
267
268 lbdas[0].setZero(problem.nc0());
269 for (uint i = 0; i <= N; i++) {
270 const knot_t &kn = problem.stages[i];
271 xs[i].setZero(kn.nx);
272 us[i].setZero(kn.nu);
273 vs[i].setZero(kn.nc);
274 if (i == N)
275 break;
276 lbdas[i + 1].setZero(kn.nx2);
277 }
278 if (problem.stages.back().nu == 0) {
279 us.pop_back();
280 }
281 return std::make_tuple(std::move(xs), std::move(us), std::move(vs),
282 std::move(lbdas));
283}
284
285#ifdef ALIGATOR_ENABLE_TEMPLATE_INSTANTIATION
286extern template auto lqrComputeKktError<context::Scalar>(
287 const LQRProblemTpl<context::Scalar> &,
290 const context::Scalar, const context::Scalar,
291 const std::optional<context::ConstVectorRef> &, bool);
292extern template auto
293lqrDenseMatrix<context::Scalar>(const LQRProblemTpl<context::Scalar> &,
295#endif
296
297} // namespace gar
298} // namespace aligator
#define ALIGATOR_RUNTIME_ERROR(msg)
Definition exceptions.hpp:6
auto lqrInitializeSolution(const LQRProblemTpl< Scalar > &problem)
Definition utils.hpp:254
bool lqrDenseMatrix(const LQRProblemTpl< Scalar > &problem, Scalar mudyn, Scalar mueq, typename math_types< Scalar >::MatrixXs &mat, typename math_types< Scalar >::VectorXs &rhs)
Fill in a KKT constraint matrix and vector for the given LQ problem with the given dual-regularizatio...
Definition utils.hpp:112
template auto lqrDenseMatrix< context::Scalar >(const LQRProblemTpl< context::Scalar > &, context::Scalar, context::Scalar)
template auto lqrComputeKktError< context::Scalar >(const LQRProblemTpl< context::Scalar > &, boost::span< const context::VectorXs >, boost::span< const context::VectorXs >, boost::span< const context::VectorXs >, boost::span< const context::VectorXs >, const context::Scalar, const context::Scalar, const std::optional< context::ConstVectorRef > &, bool)
auto lqrComputeKktError(const LQRProblemTpl< Scalar > &problem, boost::span< const typename math_types< Scalar >::VectorXs > xs, boost::span< const typename math_types< Scalar >::VectorXs > us, boost::span< const typename math_types< Scalar >::VectorXs > vs, boost::span< const typename math_types< Scalar >::VectorXs > lbdas, const Scalar mudyn, const Scalar mueq, const std::optional< typename math_types< Scalar >::ConstVectorRef > &theta_, bool verbose=false)
Definition utils.hpp:11
void lqrDenseSolutionToTraj(const LQRProblemTpl< Scalar > &problem, const typename math_types< Scalar >::ConstVectorRef solution, std::vector< typename math_types< Scalar >::VectorXs > &xs, std::vector< typename math_types< Scalar >::VectorXs > &us, std::vector< typename math_types< Scalar >::VectorXs > &vs, std::vector< typename math_types< Scalar >::VectorXs > &lbdas)
Convert dense RHS solution to its trajectory [x,u,v,lambda] solution.
Definition utils.hpp:221
uint lqrNumRows(const LQRProblemTpl< Scalar > &problem)
Compute the number of rows in the problem matrix.
Definition utils.hpp:186
Main package namespace.
unsigned int uint
Definition logger.hpp:11