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__);
22 using VectorXs =
typename math_types<Scalar>::VectorXs;
23 using KnotType = LQRKnotTpl<Scalar>;
38 _dyn = problem.g0 + problem.G0 * xs[0] - mudyn * lbdas[0];
39 dNorm = math::infty_norm(_dyn);
40 dynErr = std::max(dynErr, dNorm);
42 fmt::print(
"d0 = {:.3e} \n", dNorm);
44 for (
uint t = 0; t <= N; t++) {
45 const KnotType &knot = problem.stages[t];
46 auto _Str = knot.S.transpose();
49 fmt::print(
"[{: >2d}] ", t);
52 _gt.setZero(knot.nth);
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];
59 _cst.noalias() += knot.D * us[t];
60 _gx.noalias() += knot.S * us[t];
61 _gu.noalias() += knot.R * us[t];
65 _gx += problem.G0.transpose() * lbdas[0];
67 auto Et = problem.stages[t - 1].E.transpose();
72 _dyn = knot.A * xs[t] + knot.B * us[t] + knot.f + knot.E * xs[t + 1] -
74 _gx += knot.A.transpose() * lbdas[t + 1];
75 _gu += knot.B.transpose() * lbdas[t + 1];
77 dNorm = math::infty_norm(_dyn);
79 fmt::print(
" |d| = {:.3e} | ", dNorm);
80 dynErr = std::max(dynErr, dNorm);
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;
88 _gt.noalias() += knot.Gx.transpose() * xs[t];
90 _gt.noalias() += knot.Gu.transpose() * us[t];
91 _gt.noalias() += knot.Gth * th;
94 Scalar gxNorm = math::infty_norm(_gx);
95 Scalar guNorm = math::infty_norm(_gu);
96 Scalar cstNorm = math::infty_norm(_cst);
98 fmt::print(
"|gx| = {:.3e} | |gu| = {:.3e} | |cst| = {:.3e}\n", gxNorm,
101 dualErr = std::max({dualErr, gxNorm, guNorm});
102 cstErr = std::max(cstErr, cstNorm);
105 return std::array{dynErr, cstErr, dualErr};
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());
119 if (!problem.isInitialized())
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);
132 rhs.head(nc0) = problem.g0;
136 for (
size_t t = 0; t <= N; t++) {
137 const knot_t &model = knots[t];
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;
151 St = model.S.transpose();
156 block = block.template selfadjointView<Eigen::Lower>();
158 rhsblk.head(model.nx) = model.q;
159 rhsblk.segment(model.nx, model.nu) = model.r;
160 rhsblk.tail(model.nc) = model.d;
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;
172 rhs.segment(idx + n, model.nx2) = model.f;
174 auto col = mat.transpose().block(idx + n, idx, model.nx, ncols);
178 idx += n + model.nx2;
205 decltype(
auto) knots = problem.stages;
206 using MatrixXs =
typename math_types<Scalar>::MatrixXs;
207 using VectorXs =
typename math_types<Scalar>::VectorXs;
210 MatrixXs mat(nrows, nrows);
216 return std::make_pair(mat, rhs);
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();
233 const uint nc0 = problem.nc0();
235 lbdas[0] = solution.head(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);
247 lbdas[t + 1] = solution.segment(idx, knot.nx2);
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();
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);
276 lbdas[i + 1].setZero(kn.nx2);
278 if (problem.stages.back().nu == 0) {
281 return std::make_tuple(std::move(xs), std::move(us), std::move(vs),
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...
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)
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.