11#include <smooth/concepts/lie_group.hpp>
18namespace smooth::feedback {
24auto ocp_nlp_structure(
const FlatOCPType
auto & ocp,
const MeshType
auto & mesh)
26 std::size_t N = mesh.N_colloc();
29 std::array<std::size_t, 4> var_len{
37 std::array<std::size_t, 4> con_len{
44 std::array<std::size_t, 5> var_beg{0};
45 std::partial_sum(var_len.begin(), var_len.end(), var_beg.begin() + 1);
47 std::array<std::size_t, 5> con_beg{0};
48 std::partial_sum(con_len.begin(), con_len.end(), con_beg.begin() + 1);
50 return std::make_tuple(var_beg, var_len, con_beg, con_len);
58template<FlatOCPType Ocp, MeshType Mesh, diff::Type DT = diff::Type::Default>
62 static constexpr auto Nx = std::decay_t<Ocp>::Nx;
63 static constexpr auto Nu = std::decay_t<Ocp>::Nu;
64 static constexpr auto Nq = std::decay_t<Ocp>::Nq;
70 std::size_t tfvar_B, qvar_B, xvar_B, uvar_B, n_;
71 std::size_t tfvar_L, qvar_L, xvar_L, uvar_L;
73 std::size_t dcon_B, qcon_B, crcon_B, cecon_B, m_;
74 std::size_t dcon_L, qcon_L, crcon_L, cecon_L;
80 Eigen::VectorXd xl_, xu_, gl_, gu_;
84 Eigen::SparseMatrix<double> df_dx_, dg_dx_, d2f_dx2_, d2g_dx2_;
87 MeshValue<0> dyn_out0_, int_out0_, cr_out0_;
88 MeshValue<1> dyn_out1_, int_out1_, cr_out1_;
89 MeshValue<2> dyn_out2_, int_out2_, cr_out2_;
93 template<
typename OcpArg,
typename MeshArg>
94 OCPNLP(OcpArg && ocp, MeshArg && mesh)
95 : ocp_(std::forward<OcpArg>(ocp)), mesh_(std::forward<MeshArg>(mesh)), N_(mesh_.N_colloc())
97 const auto [var_beg, var_len, con_beg, con_len] = detail::ocp_nlp_structure(ocp_, mesh_);
105 tfvar_L = var_len[0];
112 crcon_B = con_beg[2];
113 cecon_B = con_beg[3];
118 crcon_L = con_len[2];
119 cecon_L = con_len[3];
122 double max_weight = 1e-6;
123 for (
auto w : mesh_.all_weights()) { max_weight = std::max(max_weight, w); }
124 w_scaling_ = 1. / max_weight;
128 xl_.setConstant(n_, -std::numeric_limits<double>::infinity());
129 xl_.segment(tfvar_B, tfvar_L).setZero();
130 xu_.setConstant(n_, std::numeric_limits<double>::infinity());
138 gl_.segment(dcon_B, dcon_L).setZero();
139 gu_.segment(dcon_B, dcon_L).setZero();
142 gl_.segment(qcon_B, qcon_L).setZero();
143 gu_.segment(qcon_B, qcon_L).setZero();
146 gl_.segment(crcon_B, crcon_L) = ocp.crl.replicate(N_, 1);
147 gu_.segment(crcon_B, crcon_L) = ocp.cru.replicate(N_, 1);
148 for (
const auto & [i, w] : utils::zip(std::views::iota(0u, N_), mesh_.all_weights())) {
149 gl_.segment(crcon_B + i * ocp_.Ncr, ocp_.Ncr) *= w_scaling_ * w;
150 gu_.segment(crcon_B + i * ocp_.Ncr, ocp_.Ncr) *= w_scaling_ * w;
154 gl_.segment(cecon_B, cecon_L) = ocp.cel;
155 gu_.segment(cecon_B, cecon_L) = ocp.ceu;
160 df_dx_.resize(1, n_);
161 df_dx_.reserve(Eigen::VectorXi::Constant(n_, 1));
163 d2f_dx2_.resize(n_, n_);
164 dg_dx_.resize(m_, n_);
165 d2g_dx2_.resize(n_, n_);
170 std::size_t n()
const {
return n_; }
171 std::size_t m()
const {
return m_; }
172 const Eigen::VectorXd & xl()
const {
return xl_; }
173 const Eigen::VectorXd & xu()
const {
return xu_; }
175 double f(
const Eigen::Ref<const Eigen::VectorXd> x)
const
177 assert(
static_cast<std::size_t
>(x.size()) == n_);
179 const auto x0var_B = xvar_B;
180 const auto xfvar_B = xvar_B + xvar_L - Nx;
182 const double tf = x(tfvar_B);
183 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
184 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
185 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
187 return ocp_.theta(tf, x0, xf, q);
190 const Eigen::SparseMatrix<double> & df_dx(
const Eigen::Ref<const Eigen::VectorXd> x)
192 assert(
static_cast<std::size_t
>(x.size()) == n_);
194 const auto x0var_B = xvar_B;
195 const auto xfvar_B = xvar_B + xvar_L - Nx;
197 const double tf = x(tfvar_B);
198 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
199 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
200 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
202 const auto & [fval, dfval] = diff::dr<1, DT>(ocp_.theta, wrt(tf, x0, xf, q));
206 block_add(df_dx_, 0, tfvar_B, dfval.middleCols(0, 1));
207 block_add(df_dx_, 0, x0var_B, dfval.middleCols(1, Nx));
208 block_add(df_dx_, 0, xfvar_B, dfval.middleCols(1 + Nx, Nx));
209 block_add(df_dx_, 0, qvar_B, dfval.middleCols(1 + 2 * Nx, Nq));
211 df_dx_.makeCompressed();
215 const Eigen::SparseMatrix<double> & d2f_dx2(Eigen::Ref<const Eigen::VectorXd> x)
217 assert(
static_cast<std::size_t
>(x.size()) == n_);
219 const auto x0var_B = xvar_B;
220 const auto xfvar_B = xvar_B + xvar_L - Nx;
222 const double tf = x(tfvar_B);
223 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
224 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
225 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
227 const auto & [fval, dfval, d2fval] = diff::dr<2, DT>(ocp_.theta, wrt(tf, x0, xf, q));
232 block_add(d2f_dx2_, tfvar_B, tfvar_B, d2fval.block( 0, 0, 1, 1), 1,
true);
233 block_add(d2f_dx2_, tfvar_B, x0var_B, d2fval.block( 0, 1, 1, Nx), 1,
true);
234 block_add(d2f_dx2_, tfvar_B, xfvar_B, d2fval.block( 0, 1 + Nx, 1, Nx), 1,
true);
235 block_add(d2f_dx2_, tfvar_B, qvar_B, d2fval.block( 0, 1 + 2 * Nx, 1, Nq), 1,
true);
237 block_add(d2f_dx2_, x0var_B, x0var_B, d2fval.block( 1, 1, Nx, Nx), 1,
true);
238 block_add(d2f_dx2_, x0var_B, xfvar_B, d2fval.block( 1, 1 + Nx, Nx, Nx), 1,
true);
239 block_add(d2f_dx2_, x0var_B, qvar_B, d2fval.block( 1, 1 + 2 * Nx, Nx, Nq), 1,
true);
241 block_add(d2f_dx2_, xfvar_B, xfvar_B, d2fval.block( 1 + Nx, 1 + Nx, Nx, Nx), 1,
true);
242 block_add(d2f_dx2_, xfvar_B, qvar_B, d2fval.block( 1 + Nx, 1 + 2 * Nx, Nx, Nq), 1,
true);
244 block_add(d2f_dx2_, qvar_B, qvar_B, d2fval.block(1 + 2 * Nx, 1 + 2 * Nx, Nq, Nq), 1,
true);
247 d2f_dx2_.makeCompressed();
251 const Eigen::VectorXd & g(
const Eigen::Ref<const Eigen::VectorXd> x)
253 assert(
static_cast<std::size_t
>(x.size()) == n_);
255 const auto x0var_B = xvar_B;
256 const auto xfvar_B = xvar_B + xvar_L - Nx;
259 const double tf = x(tfvar_B);
260 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
261 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
262 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
264 const Eigen::Map<
const Eigen::Matrix<double, Nx, -1>> X(x.data() + xvar_B, Nx, N_ + 1);
265 const Eigen::Map<
const Eigen::Matrix<double, Nu, -1>> U(x.data() + uvar_B, Nu, N_);
267 mesh_dyn<0>(dyn_out0_, mesh_, ocp_.f, t0, tf, X.colwise(), U.colwise());
268 mesh_integrate<0>(int_out0_, mesh_, ocp_.g, t0, tf, X.colwise(), U.colwise());
269 mesh_eval<0>(cr_out0_, mesh_, ocp_.cr, t0, tf, X.colwise(), U.colwise(),
true);
271 g_.segment(dcon_B, dcon_L) = w_scaling_ * dyn_out0_.F;
272 g_.segment(qcon_B, qcon_L) = w_scaling_ * (int_out0_.F - q);
273 g_.segment(crcon_B, crcon_L) = w_scaling_ * cr_out0_.F;
274 g_.segment(cecon_B, cecon_L) = ocp_.ce(tf, x0, xf, q);
278 const Eigen::VectorXd & gl()
const {
return gl_; }
279 const Eigen::VectorXd & gu()
const {
return gu_; }
280 const Eigen::SparseMatrix<double> & dg_dx(
const Eigen::Ref<const Eigen::VectorXd> x)
282 assert(
static_cast<std::size_t
>(x.size()) == n_);
284 const auto x0var_B = xvar_B;
285 const auto xfvar_B = xvar_B + xvar_L - Nx;
288 const double tf = x(tfvar_B);
289 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
290 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
291 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
293 const Eigen::Map<
const Eigen::Matrix<double, Nx, -1>> X(x.data() + xvar_B, Nx, N_ + 1);
294 const Eigen::Map<
const Eigen::Matrix<double, Nu, -1>> U(x.data() + uvar_B, Nu, N_);
296 mesh_dyn<1, DT>(dyn_out1_, mesh_, ocp_.f, t0, tf, X.colwise(), U.colwise());
297 mesh_integrate<1, DT>(int_out1_, mesh_, ocp_.g, t0, tf, X.colwise(), U.colwise());
298 mesh_eval<1, DT>(cr_out1_, mesh_, ocp_.cr, t0, tf, X.colwise(), U.colwise(),
true);
299 const auto & [ceval, dceval] = diff::dr<1, DT>(ocp_.ce, wrt(tf, x0, xf, q));
301 dyn_out1_.dF.makeCompressed();
302 int_out1_.dF.makeCompressed();
303 cr_out1_.dF.makeCompressed();
308 block_add(dg_dx_, dcon_B, tfvar_B, dyn_out1_.dF.middleCols(1, 1), w_scaling_);
309 block_add(dg_dx_, dcon_B, xvar_B, dyn_out1_.dF.middleCols(2, xvar_L), w_scaling_);
310 block_add(dg_dx_, dcon_B, uvar_B, dyn_out1_.dF.middleCols(2 + xvar_L, uvar_L), w_scaling_);
313 block_add(dg_dx_, qcon_B, tfvar_B, int_out1_.dF.middleCols(1, 1), w_scaling_);
314 block_add(dg_dx_, qcon_B, xvar_B, int_out1_.dF.middleCols(2, xvar_L), w_scaling_);
315 block_add(dg_dx_, qcon_B, uvar_B, int_out1_.dF.middleCols(2 + xvar_L, uvar_L), w_scaling_);
319 block_add(dg_dx_, crcon_B, tfvar_B, cr_out1_.dF.middleCols(1, 1), w_scaling_);
320 block_add(dg_dx_, crcon_B, xvar_B, cr_out1_.dF.middleCols(2, xvar_L), w_scaling_);
321 block_add(dg_dx_, crcon_B, uvar_B, cr_out1_.dF.middleCols(2 + xvar_L, uvar_L), w_scaling_);
324 block_add(dg_dx_, cecon_B, tfvar_B, dceval.middleCols(0, 1));
325 block_add(dg_dx_, cecon_B, xvar_B, dceval.middleCols(1, Nx));
326 block_add(dg_dx_, cecon_B, xvar_B + xvar_L - Nx, dceval.middleCols(1 + Nx, Nx));
327 block_add(dg_dx_, cecon_B, qvar_B, dceval.middleCols(1 + 2 * Nx, Nq));
329 dg_dx_.makeCompressed();
333 const Eigen::SparseMatrix<double> &
334 d2g_dx2(
const Eigen::Ref<const Eigen::VectorXd> x,
const Eigen::Ref<const Eigen::VectorXd> lambda)
336 assert(
static_cast<std::size_t
>(x.size()) == n_);
337 assert(
static_cast<std::size_t
>(lambda.size()) == m_);
339 const auto x0var_B = xvar_B;
340 const auto xfvar_B = xvar_B + xvar_L - Nx;
343 const double tf = x(tfvar_B);
344 const Eigen::Vector<double, Nx> x0 = x.segment(x0var_B, Nx);
345 const Eigen::Vector<double, Nx> xf = x.segment(xfvar_B, Nx);
346 const Eigen::Vector<double, Nq> q = x.segment(qvar_B, qvar_L);
348 const Eigen::Map<
const Eigen::Matrix<double, Nx, -1>> X(x.data() + xvar_B, Nx, N_ + 1);
349 const Eigen::Map<
const Eigen::Matrix<double, Nu, -1>> U(x.data() + uvar_B, Nu, N_);
351 dyn_out2_.lambda = lambda.segment(dcon_B, dcon_L);
352 int_out2_.lambda = lambda.segment(qcon_B, qcon_L);
353 cr_out2_.lambda = lambda.segment(crcon_B, crcon_L);
354 mesh_dyn<2, DT>(dyn_out2_, mesh_, ocp_.f, t0, tf, X.colwise(), U.colwise());
355 mesh_integrate<2, DT>(int_out2_, mesh_, ocp_.g, t0, tf, X.colwise(), U.colwise());
356 mesh_eval<2, DT>(cr_out2_, mesh_, ocp_.cr, t0, tf, X.colwise(), U.colwise(),
true);
357 const auto & [ceval, dceval, d2ceval] = diff::dr<2, DT>(ocp_.ce, wrt(tf, x0, xf, q));
359 dyn_out2_.dF.makeCompressed();
360 int_out2_.dF.makeCompressed();
361 cr_out2_.dF.makeCompressed();
363 dyn_out2_.d2F.makeCompressed();
364 int_out2_.d2F.makeCompressed();
365 cr_out2_.d2F.makeCompressed();
370 block_add(d2g_dx2_, tfvar_B, tfvar_B, dyn_out2_.d2F.block(1, 1, 1, 1), w_scaling_,
true);
371 block_add(d2g_dx2_, tfvar_B, tfvar_B, int_out2_.d2F.block(1, 1, 1, 1), w_scaling_,
true);
372 block_add(d2g_dx2_, tfvar_B, tfvar_B, cr_out2_.d2F.block(1, 1, 1, 1), w_scaling_,
true);
374 block_add(d2g_dx2_, tfvar_B, xvar_B, dyn_out2_.d2F.block(1, 2, 1, xvar_L), w_scaling_,
true);
375 block_add(d2g_dx2_, tfvar_B, xvar_B, int_out2_.d2F.block(1, 2, 1, xvar_L), w_scaling_,
true);
376 block_add(d2g_dx2_, tfvar_B, xvar_B, cr_out2_.d2F.block(1, 2, 1, xvar_L), w_scaling_,
true);
378 block_add(d2g_dx2_, tfvar_B, uvar_B, dyn_out2_.d2F.block(1, 2 + xvar_L, 1, uvar_L), w_scaling_,
true);
379 block_add(d2g_dx2_, tfvar_B, uvar_B, int_out2_.d2F.block(1, 2 + xvar_L, 1, uvar_L), w_scaling_,
true);
380 block_add(d2g_dx2_, tfvar_B, uvar_B, cr_out2_.d2F.block(1, 2 + xvar_L, 1, uvar_L), w_scaling_,
true);
382 block_add(d2g_dx2_, xvar_B, xvar_B, dyn_out2_.d2F.block(2, 2, xvar_L, xvar_L), w_scaling_,
true);
383 block_add(d2g_dx2_, xvar_B, xvar_B, int_out2_.d2F.block(2, 2, xvar_L, xvar_L), w_scaling_,
true);
384 block_add(d2g_dx2_, xvar_B, xvar_B, cr_out2_.d2F.block(2, 2, xvar_L, xvar_L), w_scaling_,
true);
386 block_add(d2g_dx2_, xvar_B, uvar_B, dyn_out2_.d2F.block(2, 2 + xvar_L, xvar_L, uvar_L), w_scaling_,
true);
387 block_add(d2g_dx2_, xvar_B, uvar_B, int_out2_.d2F.block(2, 2 + xvar_L, xvar_L, uvar_L), w_scaling_,
true);
388 block_add(d2g_dx2_, xvar_B, uvar_B, cr_out2_.d2F.block(2, 2 + xvar_L, xvar_L, uvar_L), w_scaling_,
true);
390 block_add(d2g_dx2_, uvar_B, uvar_B, dyn_out2_.d2F.block(2 + xvar_L, 2 + xvar_L, uvar_L, uvar_L), w_scaling_,
true);
391 block_add(d2g_dx2_, uvar_B, uvar_B, int_out2_.d2F.block(2 + xvar_L, 2 + xvar_L, uvar_L, uvar_L), w_scaling_,
true);
392 block_add(d2g_dx2_, uvar_B, uvar_B, cr_out2_.d2F.block(2 + xvar_L, 2 + xvar_L, uvar_L, uvar_L), w_scaling_,
true);
395 for (
auto j = 0u; j < ocp_.Nce; ++j) {
396 const auto b0 = (1 + 2 * Nx + ocp_.Nq) * j;
398 block_add(d2g_dx2_, tfvar_B, tfvar_B, d2ceval.block( 0, b0 + 0, 1, 1), lambda(cecon_B + j),
true);
399 block_add(d2g_dx2_, tfvar_B, x0var_B, d2ceval.block( 0, b0 + 1, 1, Nx), lambda(cecon_B + j),
true);
400 block_add(d2g_dx2_, tfvar_B, xfvar_B, d2ceval.block( 0, b0 + 1 + Nx, 1, Nx), lambda(cecon_B + j),
true);
401 block_add(d2g_dx2_, tfvar_B, qvar_B, d2ceval.block( 0, b0 + 1 + 2 * Nx, 1, Nq), lambda(cecon_B + j),
true);
403 block_add(d2g_dx2_, x0var_B, x0var_B, d2ceval.block( 1, b0 + 1, Nx, Nx), lambda(cecon_B + j),
true);
404 block_add(d2g_dx2_, x0var_B, xfvar_B, d2ceval.block( 1, b0 + 1 + Nx, Nx, Nx), lambda(cecon_B + j),
true);
405 block_add(d2g_dx2_, x0var_B, qvar_B, d2ceval.block( 1, b0 + 1 + 2 * Nx, Nx, Nq), lambda(cecon_B + j),
true);
407 block_add(d2g_dx2_, xfvar_B, xfvar_B, d2ceval.block( 1 + Nx, b0 + 1 + Nx, Nx, Nx), lambda(cecon_B + j),
true);
408 block_add(d2g_dx2_, xfvar_B, qvar_B, d2ceval.block( 1 + Nx, b0 + 1 + 2 * Nx, Nx, Nq), lambda(cecon_B + j),
true);
410 block_add(d2g_dx2_, qvar_B, qvar_B, d2ceval.block(1 + 2 * Nx, b0 + 1 + 2 * Nx, Nq, Nq), lambda(cecon_B + j),
true);
414 d2g_dx2_.makeCompressed();
431template<diff::Type DT = diff::Type::Default>
433 -> detail::OCPNLP<std::decay_t<
decltype(ocp)>, std::decay_t<
decltype(mesh)>, DT>
435 return detail::OCPNLP<std::decay_t<
decltype(ocp)>, std::decay_t<
decltype(mesh)>, DT>(
436 std::forward<decltype(ocp)>(ocp), std::forward<decltype(mesh)>(mesh));
444 using ocp_t = std::decay_t<
decltype(ocp)>;
446 static constexpr auto Nx = ocp_t::Nx;
447 static constexpr auto Nu = ocp_t::Nu;
448 static constexpr auto Nq = ocp_t::Nq;
449 static constexpr auto Ncr = ocp_t::Ncr;
451 const std::size_t N = mesh.N_colloc();
452 const auto [var_beg, var_len, con_beg, con_len] = detail::ocp_nlp_structure(ocp, mesh);
454 const auto [tfvar_B, qvar_B, xvar_B, uvar_B, n] = var_beg;
455 const auto [tfvar_L, qvar_L, xvar_L, uvar_L] = var_len;
457 const auto [dcon_B, qcon_B, crcon_B, cecon_B, m] = con_beg;
458 const auto [dcon_L, qcon_L, crcon_L, cecon_L] = con_len;
461 const double tf = nlp_sol.
x(tfvar_B);
463 const Eigen::Vector<double, Nq> Q = nlp_sol.
x.segment(qvar_B, qvar_L);
467 Eigen::MatrixXd X(ocp.Nx, N + 1);
468 X = nlp_sol.
x.segment(xvar_B, xvar_L).reshaped(ocp.Nx, xvar_L / ocp.Nx);
470 auto xfun = [t0 = t0, tf = tf, mesh = mesh, X = std::move(X)](
double t) -> Eigen::Vector<double, Nx> {
471 return mesh.template eval<Eigen::Vector<double, Nx>>((t - t0) / (tf - t0), X.colwise(), 0,
true);
476 Eigen::MatrixXd U(ocp.Nu, N);
477 U = nlp_sol.
x.segment(uvar_B, uvar_L).reshaped(ocp.Nu, uvar_L / ocp.Nu);
479 auto ufun = [t0 = t0, tf = tf, mesh = mesh, U = std::move(U)](
double t) -> Eigen::Vector<double, Nu> {
480 return mesh.template eval<Eigen::Vector<double, Nu>>((t - t0) / (tf - t0), U.colwise(), 0,
false);
483 Eigen::MatrixXd Ldyn(ocp.Nx, N);
484 Ldyn = nlp_sol.
lambda.segment(dcon_B, dcon_L).reshaped(ocp.Nx, dcon_L / ocp.Nx);
486 auto ldfun = [t0 = t0, tf = tf, mesh = mesh, Ldyn = std::move(Ldyn)](
double t) -> Eigen::Vector<double, Nx> {
487 return mesh.template eval<Eigen::Vector<double, Nx>>((t - t0) / (tf - t0), Ldyn.colwise(), 0,
false);
490 Eigen::MatrixXd Lcr(ocp.Ncr, N);
491 Lcr = nlp_sol.
lambda.segment(crcon_B, crcon_L).reshaped(ocp.Ncr, crcon_L / ocp.Ncr);
493 auto lcrfun = [t0 = t0, tf = tf, mesh = mesh, Lcr = std::move(Lcr)](
double t) -> Eigen::Vector<double, Ncr> {
494 return mesh.template eval<Eigen::Vector<double, Ncr>>((t - t0) / (tf - t0), Lcr.colwise(), 0,
false);
501 .u = std::move(ufun),
502 .x = std::move(xfun),
503 .lambda_q = nlp_sol.
lambda.segment(qcon_B, qcon_L),
504 .lambda_ce = nlp_sol.
lambda.segment(cecon_B, cecon_L),
505 .lambda_dyn = std::move(ldfun),
506 .lambda_cr = std::move(lcrfun),
517 const auto N = mesh.N_colloc();
519 const auto [var_beg, var_len, con_beg, con_len] = detail::ocp_nlp_structure(ocp, mesh);
521 const auto [tfvar_B, qvar_B, xvar_B, uvar_B, n] = var_beg;
522 const auto [tfvar_L, qvar_L, xvar_L, uvar_L] = var_len;
524 const auto [dcon_B, qcon_B, crcon_B, cecon_B, m] = con_beg;
525 const auto [dcon_L, qcon_L, crcon_L, cecon_L] = con_len;
528 const double tf = ocpsol.tf;
530 Eigen::VectorXd x(n), lambda(m);
532 x(tfvar_B) = ocpsol.tf;
533 x.segment(qvar_B, qvar_L) = ocpsol.Q;
535 lambda.segment(qcon_B, qcon_L) = ocpsol.lambda_q;
536 lambda.segment(cecon_B, cecon_L) = ocpsol.lambda_ce;
538 for (
const auto & [i, tau] : utils::zip(std::views::iota(0u), mesh.all_nodes())) {
539 x.segment(xvar_B + i * ocp.Nx, ocp.Nx) = ocpsol.x(t0 + tau * (tf - t0));
541 x.segment(uvar_B + i * ocp.Nu, ocp.Nu) = ocpsol.u(t0 + tau * (tf - t0));
542 lambda.segment(dcon_B + i * ocp.Nx, ocp.Nx) = ocpsol.lambda_dyn(t0 + tau * (tf - t0));
543 lambda.segment(crcon_B + i * ocp.Ncr, ocp.Ncr) = ocpsol.lambda_cr(t0 + tau * (tf - t0));
548 .status = NLPSolution::Status::Unknown,
550 .zl = Eigen::VectorXd::Zero(n),
551 .zu = Eigen::VectorXd::Zero(n),
552 .lambda = std::move(lambda),
Concept that is true for FlatOCP specializations.
MeshType is a specialization of Mesh.
Refinable Legendre-Gauss-Radau mesh of time interval [0, 1].
Evaluate transform-like functions and derivatives on collocation points.
void set_zero(MeshValue< Deriv > &mv)
Reset MeshValue to zeros.
Nonlinear program definition.
Optimal control problem definition.
NLPSolution ocpsol_to_nlpsol(const FlatOCPType auto &ocp, const MeshType auto &mesh, const auto &ocpsol)
Convert ocp solution to nonlinear program solution.
auto ocp_to_nlp(FlatOCPType auto &&ocp, MeshType auto &&mesh) -> detail::OCPNLP< std::decay_t< decltype(ocp)>, std::decay_t< decltype(mesh)>, DT >
Formulate an OCP as a NLP using collocation on a Mesh.
auto nlpsol_to_ocpsol(const FlatOCPType auto &ocp, const MeshType auto &mesh, const NLPSolution &nlp_sol)
Convert nonlinear program solution to ocp solution.
void block_add_identity(Eigen::SparseMatrix< double, Options > &dest, Eigen::Index row0, Eigen::Index col0, Eigen::Index n, double scale=1)
Add identity matrix block into sparse matrix.
void block_add(Eigen::SparseMatrix< double, Options > &dest, Eigen::Index row0, Eigen::Index col0, const Source &source, double scale=1, bool upper_only=false)
Add block into a sparse matrix.
Solution to a Nonlinear Programming Problem.
Eigen::VectorXd lambda
Constraint multipliers.
Eigen::VectorXd x
Variable values.
double t0
Initial and final time.