15#include <Eigen/Sparse>
16#include <smooth/bundle.hpp>
17#include <smooth/diff.hpp>
20#include "smooth/lie_sparse.hpp"
23namespace smooth::feedback {
29static constexpr std::array<double, 23> kBn{
59inline auto generators_sparse_reordered = []() -> std::array<Eigen::SparseMatrix<double, Eigen::RowMajor>, Dof<G>> {
60 std::array<Eigen::SparseMatrix<double, Eigen::RowMajor>, Dof<G>> ret;
61 for (
auto k = 0u; k < Dof<G>; ++k) {
62 ret[k].resize(Dof<G>, Dof<G>);
63 for (
auto i = 0u; i < Dof<G>; ++i) { ret[k].row(i) = ::smooth::generators_sparse<G>[i].row(k); }
64 ret[k].makeCompressed();
73inline Eigen::SparseMatrix<double> d_ad = []() -> Eigen::SparseMatrix<double> {
74 Eigen::SparseMatrix<double> ret;
75 ret.resize(Dof<G>, Dof<G> * Dof<G>);
76 for (
auto i = 0u; i < Dof<G>; ++i) {
77 for (
auto j = 0u; j < Dof<G>; ++j) { ret.col(j * Dof<G> + i) = smooth::generators_sparse<G>[i].row(j).transpose(); }
89template<LieGroup X, Manifold U,
typename F,
typename Xl,
typename Ul>
93 using BundleT = smooth::Bundle<Eigen::Vector<double, 1>, X, U>;
95 static constexpr auto Nx = Dof<X>;
96 static constexpr auto Nu = Dof<U>;
97 static constexpr auto Nouts = Nx;
98 static constexpr auto Nvars = 1 + Nx + Nu;
100 static constexpr auto t_B = 0;
101 static constexpr auto x_B = t_B + 1;
102 static constexpr auto u_B = x_B + Nx;
104 using E = Tangent<X>;
105 using V = Tangent<U>;
111 Eigen::SparseMatrix<double> ad_e_ = smooth::ad_sparse_pattern<X>;
112 Eigen::SparseMatrix<double> ad_vi = smooth::ad_sparse_pattern<X>;
114 Eigen::SparseMatrix<double> Joplus_ = smooth::d_exp_sparse_pattern<BundleT>;
115 Eigen::SparseMatrix<double> Hoplus_ = smooth::d2_exp_sparse_pattern<BundleT>;
117 Eigen::SparseMatrix<double> dexpinv_e_ = smooth::d_exp_sparse_pattern<X>;
118 Eigen::SparseMatrix<double> d2expinv_e_ = smooth::d2_exp_sparse_pattern<X>;
120 Eigen::SparseMatrix<double> J_{Nouts, Nvars};
121 Eigen::SparseMatrix<double> H_{Nvars, Nouts * Nvars};
124 Eigen::SparseMatrix<double> ji_{Nouts, Nvars}, ji_tmp_{Nouts, Nvars}, hi_{Nvars, Nouts *Nvars},
125 hi_tmp_{Nvars, Nouts *Nvars};
128 void update_joplus(
const E & e,
const V & v,
const E & dxl,
const V & dul)
130 dr_exp_sparse<BundleT>(Joplus_, (Tangent<BundleT>() << 1, e, v).finished());
132 block_write(Joplus_, x_B, t_B, Ad<X>(smooth::exp<X>(-e)) * dxl);
133 block_write(Joplus_, u_B, t_B, Ad<U>(smooth::exp<U>(-v)) * dul);
135 Joplus_.makeCompressed();
139 void update_hoplus(
const E & e,
const V & v,
const E & dxl,
const V & dul)
141 d2r_exp_sparse<BundleT>(Hoplus_, (Tangent<BundleT>() << 1, e, v).finished());
144 const TangentMap<X> Adexp_X = Ad<X>(smooth::exp<X>(-e));
145 const TangentMap<X> dAdexp_X = ad<X>(Adexp_X * dxl) * Adexp_X * dr_exp<X>(-e);
146 const TangentMap<U> Adexp_U = Ad<U>(smooth::exp<U>(-v));
147 const TangentMap<U> dAdexp_U = ad<U>(Adexp_U * dul) * Adexp_U * dr_exp<U>(-v);
149 for (
auto nx = 0u; nx < Nx; ++nx) {
150 const auto b0 = Nvars * (x_B + nx);
151 block_write(Hoplus_, t_B, b0 + x_B, dAdexp_X.middleRows(nx, 1));
153 for (
auto nu = 0u; nu < Nu; ++nu) {
154 const auto b0 = Nvars * (u_B + nu);
155 block_write(Hoplus_, t_B, b0 + u_B, dAdexp_U.middleRows(nu, 1));
158 Hoplus_.makeCompressed();
162 template<
typename A1,
typename A2,
typename A3>
163 FlatDyn(A1 && a1, A2 && a2, A3 && a3) : f(std::forward<A1>(a1)), xl(std::forward<A2>(a2)), ul(std::forward<A3>(a3))
167 CastT<T, E> operator()(
const T & t,
const CastT<T, E> & e,
const CastT<T, V> & v)
const
169 using XT = CastT<T, X>;
172 const double tdbl =
static_cast<double>(t);
173 const auto [unused, dxlval] = diff::dr<1>(xl, wrt(tdbl));
175 return dr_expinv<XT>(e) * (f(t, rplus(xl(t), e), rplus(ul(t), v)) - dxlval.template cast<T>())
176 + ad<XT>(e) * dxlval.template cast<T>();
180 std::reference_wrapper<const Eigen::SparseMatrix<double>>
181 jacobian(
double t,
const E & e,
const V & v)
requires(diff::detail::diffable_order1<F, std::tuple<double, X, U>>)
183 const double tdbl =
static_cast<double>(t);
184 const auto [xlval, dxlval] = diff::dr<1>(xl, wrt(tdbl));
185 const auto [ulval, dulval] = diff::dr<1>(ul, wrt(tdbl));
186 const auto x = rplus(xlval, e);
187 const auto u = rplus(ulval, v);
189 dr_expinv_sparse<X>(dexpinv_e_, e);
190 d2r_expinv_sparse<X>(d2expinv_e_, e);
191 update_joplus(e, v, dxlval, dulval);
194 const auto fval = f(t, x, u);
195 const auto & Jf = f.jacobian(t, x, u);
200 J_ = dexpinv_e_ * Jf * Joplus_;
202 for (
auto i = 0u; i < d2expinv_e_.outerSize(); ++i) {
203 for (Eigen::InnerIterator it(d2expinv_e_, i); it; ++it) {
204 J_.coeffRef(it.col() / Nx, 1 + (it.col() % Nx)) += (fval(it.row()) - dxlval(it.row())) * it.value();
208 for (
auto i = 0u; i < d_ad<X>.outerSize(); ++i) {
209 for (Eigen::InnerIterator it(d_ad<X>, i); it; ++it) {
210 J_.coeffRef(it.col() / Nx, 1 + (it.col() % Nx)) += dxlval(it.row()) * it.value();
220 std::reference_wrapper<const Eigen::SparseMatrix<double>>
221 hessian(
double t,
const E & e,
const V & v)
requires(diff::detail::diffable_order1<F, std::tuple<double, X, U>> &&
222 diff::detail::diffable_order2<F, std::tuple<double, X, U>>)
224 const double tdbl =
static_cast<double>(t);
225 const auto [xlval, dxlval] = diff::dr<1>(xl, wrt(tdbl));
226 const auto [ulval, dulval] = diff::dr<1>(ul, wrt(tdbl));
228 const auto x = rplus(xlval, e);
229 const auto u = rplus(ul(t), v);
230 const auto & Jf = f.jacobian(t, x, u);
231 const auto & Hf = f.hessian(t, x, u);
233 ad_sparse<X>(ad_e_, e);
234 update_joplus(e, v, dxlval, dulval);
235 update_hoplus(e, v, dxlval, dulval);
238 Tangent<X> vi = f(t, x, u) - dxlval;
241 d2r_fog(hi_, Jf, Hf, Joplus_, Hoplus_);
244 for (
auto iter = 0u; iter < std::tuple_size_v<
decltype(kBn)>; ++iter) {
245 if (kBn[iter] != 0) {
block_add(H_, 0, 0, hi_, kBn[iter] * coef); }
249 for (
auto i = 0u; i < ad_e_.outerSize(); ++i) {
250 for (Eigen::InnerIterator it(ad_e_, i); it; ++it) {
251 const auto b0 = it.row() * Nvars;
252 block_add(hi_tmp_, 0, b0, hi_.middleCols(it.col() * Nvars, Nvars), it.value());
255 for (
auto k = 0u; k < Nx; ++k) {
256 const auto b0 = k * Nvars;
257 block_add(hi_tmp_, 1, b0, generators_sparse_reordered<X>[k] * ji_);
258 block_add(hi_tmp_, 0, b0 + 1, ji_.transpose() * generators_sparse_reordered<X>[k], -1);
260 std::swap(hi_, hi_tmp_);
264 ji_tmp_ = ad_e_ * ji_;
265 ad_sparse<X>(ad_vi, vi);
267 std::swap(ji_, ji_tmp_);
270 vi.applyOnTheLeft(ad_e_);
272 coef *= (-1.) / (iter + 1);
285template<LieGroup X, Manifold U, std::
size_t Nouts,
typename F,
typename Xl,
typename Ul>
289 using BundleT = smooth::Bundle<Eigen::Vector<double, 1>, X, U>;
295 static constexpr auto Nx = Dof<X>;
296 static constexpr auto Nu = Dof<U>;
297 static constexpr auto Nvars = 1 + Nx + Nu;
299 using E = Tangent<X>;
300 using V = Tangent<U>;
302 static constexpr auto t_B = 0;
303 static constexpr auto x_B = t_B + 1;
304 static constexpr auto u_B = x_B + Nx;
306 Eigen::SparseMatrix<double> Joplus_ = smooth::d_exp_sparse_pattern<BundleT>;
307 Eigen::SparseMatrix<double> Hoplus_ = smooth::d2_exp_sparse_pattern<BundleT>;
309 Eigen::SparseMatrix<double> J_{Nouts, Nvars};
310 Eigen::SparseMatrix<double> H_{Nvars, Nouts * Nvars};
313 void update_joplus(
const E & e,
const V & v,
const E & dxl,
const V & dul)
315 dr_exp_sparse<BundleT>(Joplus_, (Tangent<BundleT>() << 1, e, v).finished());
317 block_write(Joplus_, x_B, t_B, Ad<X>(smooth::exp<X>(-e)) * dxl);
318 block_write(Joplus_, u_B, t_B, Ad<U>(smooth::exp<U>(-v)) * dul);
320 Joplus_.makeCompressed();
324 void update_hoplus(
const E & e,
const V & v,
const E & dxl,
const V & dul)
326 d2r_exp_sparse<BundleT>(Hoplus_, (Tangent<BundleT>() << 1, e, v).finished());
329 const TangentMap<X> Adexp_X = Ad<X>(smooth::exp<X>(-e));
330 const TangentMap<X> dAdexp_X = ad<X>(Adexp_X * dxl) * Adexp_X * dr_exp<X>(-e);
331 const TangentMap<U> Adexp_U = Ad<U>(smooth::exp<U>(-v));
332 const TangentMap<U> dAdexp_U = ad<U>(Adexp_U * dul) * Adexp_U * dr_exp<U>(-v);
334 for (
auto nx = 0u; nx < Nx; ++nx) {
335 const auto b0 = Nvars * (x_B + nx);
336 block_write(Hoplus_, t_B, b0 + x_B, dAdexp_X.middleRows(nx, 1));
338 for (
auto nu = 0u; nu < Nu; ++nu) {
339 const auto b0 = Nvars * (u_B + nu);
340 block_write(Hoplus_, t_B, b0 + u_B, dAdexp_U.middleRows(nu, 1));
343 Hoplus_.makeCompressed();
347 template<
typename A1,
typename A2,
typename A3>
348 FlatInnerFun(A1 && a1, A2 && a2, A3 && a3)
349 : f(std::forward<A1>(a1)), xl(std::forward<A2>(a2)), ul(std::forward<A3>(a3))
353 Eigen::Vector<T, Nouts> operator()(
const T & t,
const CastT<T, E> & e,
const CastT<T, V> & v)
const
355 return f.template operator()<T>(t, rplus(xl(t), e), rplus(ul(t), v));
358 std::reference_wrapper<const Eigen::SparseMatrix<double>>
359 jacobian(
double t,
const E & e,
const V & v)
requires(diff::detail::diffable_order1<F, std::tuple<double, X, U>>)
361 const auto & [xlval, dxlval] = diff::dr<1>(xl, wrt(t));
362 const auto & [ulval, dulval] = diff::dr<1>(ul, wrt(t));
363 const auto & Jf = f.jacobian(t, rplus(xlval, e), rplus(ulval, v));
365 update_joplus(e, v, dxlval, dulval);
372 std::reference_wrapper<const Eigen::SparseMatrix<double>>
373 hessian(
double t,
const E & e,
const V & v)
requires(diff::detail::diffable_order1<F, std::tuple<double, X, U>> &&
374 diff::detail::diffable_order2<F, std::tuple<double, X, U>>)
376 const auto & [xlval, dxlval] = diff::dr<1>(xl, wrt(t));
377 const auto & [ulval, dulval] = diff::dr<1>(ul, wrt(t));
378 const auto x = rplus(xlval, e);
379 const auto u = rplus(ulval, v);
380 const auto & Jf = f.jacobian(t, x, u);
381 const auto & Hf = f.hessian(t, x, u);
383 update_joplus(e, v, dxlval, dulval);
384 update_hoplus(e, v, dxlval, dulval);
387 d2r_fog(H_, Jf, Hf, Joplus_, Hoplus_);
398template<LieGroup X, Manifold U, std::
size_t Nq, std::
size_t Nouts,
typename F,
typename Xl>
402 using E = Tangent<X>;
403 using Q = Eigen::Vector<Scalar<X>, Nq>;
404 using BundleT = smooth::Bundle<Eigen::Vector<double, 1>, X, X, Q>;
409 static constexpr auto Nx = Dof<X>;
410 static constexpr auto Nvars = 1 + 2 * Nx + Nq;
412 static constexpr auto tf_B = 0;
413 static constexpr auto x0_B = tf_B + 1;
414 static constexpr auto xf_B = x0_B + Nx;
415 static constexpr auto q_B = xf_B + Nx;
417 Eigen::SparseMatrix<double> Joplus_ = d_exp_sparse_pattern<BundleT>;
418 Eigen::SparseMatrix<double> Hoplus_ = d2_exp_sparse_pattern<BundleT>;
420 Eigen::SparseMatrix<double> J_{Nouts, Nvars};
421 Eigen::SparseMatrix<double> H_{Nvars, Nouts * Nvars};
424 void update_joplus(
const E & e0,
const E & ef,
const E & dxlf)
426 dr_exp_sparse<BundleT>(Joplus_, (Tangent<BundleT>() << 1, e0, ef, Q::Ones()).finished());
428 block_write(Joplus_, xf_B, tf_B, Ad<X>(smooth::exp<X>(-ef)) * dxlf);
430 Joplus_.makeCompressed();
434 void update_hoplus(
const E & e0,
const E & ef, [[maybe_unused]]
const E & dxlf)
436 d2r_exp_sparse<BundleT>(Hoplus_, (Tangent<BundleT>() << 1, e0, ef, Q::Ones()).finished());
439 const TangentMap<X> Adexp_f = Ad<X>(smooth::exp<X>(-ef));
440 const TangentMap<X> dAdexp_f = ad<X>(Adexp_f * dxlf) * Adexp_f * dr_exp<X>(-ef);
442 for (
auto nx = 0u; nx < Nx; ++nx) {
443 const auto b0 = Nvars * (xf_B + nx);
444 block_write(Hoplus_, tf_B, b0 + xf_B, dAdexp_f.middleRows(nx, 1));
447 Hoplus_.makeCompressed();
451 template<
typename A1,
typename A2>
452 FlatEndptFun(A1 && a1, A2 && a2) : f(std::forward<A1>(a1)), xl(std::forward<A2>(a2))
456 auto operator()(
const T & tf,
const CastT<T, E> & e0,
const CastT<T, E> & ef,
const CastT<T, Q> & q)
const
458 return f.template operator()<T>(tf, rplus(xl(T(0.)), e0), rplus(xl(tf), ef), q);
461 std::reference_wrapper<const Eigen::SparseMatrix<double>>
462 jacobian(
double tf,
const E & e0,
const E & ef,
const Q & q)
requires(
463 diff::detail::diffable_order1<F, std::tuple<double, X, X, Q>>)
465 const auto & [xlfval, dxlfval] = diff::dr<1>(xl, wrt(tf));
466 const auto & Jf = f.jacobian(tf, rplus(xl(0.), e0), rplus(xlfval, ef), q);
468 update_joplus(e0, ef, dxlfval);
475 std::reference_wrapper<const Eigen::SparseMatrix<double>>
476 hessian(
double tf,
const E & e0,
const E & ef,
const Q & q)
requires(
477 diff::detail::diffable_order1<F, std::tuple<double, X, X, Q>> &&
478 diff::detail::diffable_order2<F, std::tuple<double, X, X, Q>>)
480 const auto & [xlfval, dxlfval] = diff::dr<1>(xl, wrt(tf));
481 const auto x0 = rplus(xl(0.), e0);
482 const auto xf = rplus(xlfval, ef);
483 const auto & Jf = f.jacobian(tf, x0, xf, q);
484 const auto & Hf = f.hessian(tf, x0, xf, q);
486 update_joplus(e0, ef, dxlfval);
487 update_hoplus(e0, ef, dxlfval);
490 d2r_fog(H_, Jf, Hf, Joplus_, Hoplus_);
515 using ocp_t = std::decay_t<
decltype(ocp)>;
516 using X =
typename ocp_t::X;
517 using U =
typename ocp_t::U;
518 using Xl =
decltype(xl);
519 using Ul =
decltype(ul);
521 static constexpr auto Nq = ocp_t::Nq;
526 detail::FlatEndptFun<X, U, Nq, 1,
decltype(ocp.theta), Xl>,
527 detail::FlatDyn<X, U,
decltype(ocp.f), Xl, Ul>,
528 detail::FlatInnerFun<X, U, Nq,
decltype(ocp.g), Xl, Ul>,
529 detail::FlatInnerFun<X, U, ocp_t::Ncr,
decltype(ocp.cr), Xl, Ul>,
530 detail::FlatEndptFun<X, U, Nq, ocp_t::Nce,
decltype(ocp.ce), Xl>>{
531 .
theta = detail::FlatEndptFun<X, U, Nq, 1,
decltype(ocp.theta), Xl>{ocp.theta, xl},
532 .f = detail::FlatDyn<X, U,
decltype(ocp.f), Xl, Ul>{ocp.f, xl, ul},
533 .g = detail::FlatInnerFun<X, U, Nq,
decltype(ocp.g), Xl, Ul>{ocp.g, xl, ul},
534 .cr = detail::FlatInnerFun<X, U, ocp_t::Ncr,
decltype(ocp.cr), Xl, Ul>{ocp.cr, xl, ul},
537 .ce = detail::FlatEndptFun<X, U, Nq, ocp_t::Nce,
decltype(ocp.ce), Xl>{ocp.ce, xl},
549template<LieGroup X, Manifold U>
552 using ocpsol_t = std::decay_t<
decltype(flatsol)>;
554 auto u_unflat = [ul_fun = std::forward<decltype(ul_fun)>(ul_fun), usol = flatsol.u](
double t) -> U {
555 return rplus(ul_fun(t), usol(t));
558 auto x_unflat = [xl_fun = std::forward<decltype(xl_fun)>(xl_fun), xsol = flatsol.x](
double t) -> X {
559 return rplus(xl_fun(t), xsol(t));
566 .u = std::move(u_unflat),
567 .x = std::move(x_unflat),
568 .lambda_q = flatsol.lambda_q,
569 .lambda_ce = flatsol.lambda_ce,
570 .lambda_dyn = flatsol.lambda_dyn,
571 .lambda_cr = flatsol.lambda_cr,
Concept that is true for OCP specializations.
void set_zero(MeshValue< Deriv > &mv)
Reset MeshValue to zeros.
Optimal control problem definition.
auto unflatten_ocpsol(const auto &flatsol, auto &&xl_fun, auto &&ul_fun)
Unflatten a FlatOCPSolution.
auto flatten_ocp(const OCPType auto &ocp, auto &&xl, auto &&ul)
Flatten a LieGroup OCP by defining it in the tangent space around a trajectory.
void d2r_fog(Eigen::SparseMatrix< double > &out, const S1 &Jf, const S2 &Hf, const S3 &Jg, const S4 &Hg, Eigen::Index r0=0, Eigen::Index c0=0)
(Right) Hessian of composed function .
void block_write(Eigen::SparseMatrix< double, Options > &dest, Eigen::Index row0, Eigen::Index col0, const Source &source, double scale=1, bool upper_only=false)
Write block into a 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.
double t0
Initial and final time.
Optimal control problem definition.
Theta theta
Objective function .