11#include <boost/numeric/odeint.hpp>
12#include <smooth/compat/odeint.hpp>
13#include <smooth/concepts/lie_group.hpp>
14#include <smooth/diff.hpp>
23namespace smooth::feedback {
39template<LieGroup X, Manifold U>
40 requires(Dof<X> > 0 && Dof<U> > 0)
48 U u_des{Default<U>()};
50 Eigen::Matrix<double, Dof<U>, 1> W_u{Eigen::Matrix<double, Dof<U>, 1>::Ones()};
78template<LieGroup X, Manifold U>
79 requires(Dof<X> > 0 && Dof<U> > 0)
82 static constexpr int nx = Dof<X>;
83 static constexpr int nu = Dof<U>;
85 static_assert(nx > 0,
"State space dimension must be static");
86 static_assert(nu > 0,
"Input space dimension must be static");
88 const int M = K * nh + nu_ineq + 1;
104template<LieGroup X, Manifold U, diff::Type DT = diff::Type::Default>
105 requires(Dof<X> > 0 && Dof<U> > 0)
114 using boost::numeric::odeint::euler, boost::numeric::odeint::vector_space_algebra;
115 using std::placeholders::_1;
117 static constexpr int nx = Dof<X>;
118 static constexpr int nu = Dof<U>;
119 static constexpr int nh = std::invoke_result_t<
decltype(h),
double, X>::SizeAtCompileTime;
121 euler<X, double, Tangent<X>, double, vector_space_algebra> state_stepper{};
122 euler<TangentMap<X>, double, TangentMap<X>, double, vector_space_algebra> sensi_stepper{};
124 const int nu_ineq = pbm.
ulim.
A.rows();
126 [[maybe_unused]]
const int M = prm.
K * nh + nu_ineq + 1;
127 [[maybe_unused]]
const int N = nu + 1;
129 assert(qp.
A.rows() == M);
130 assert(qp.
A.cols() == N);
131 assert(qp.
l.rows() == M);
132 assert(qp.
u.rows() == M);
134 assert(qp.
P.rows() == N);
135 assert(qp.
P.cols() == N);
136 assert(qp.
q.rows() == N);
139 const double tau = pbm.
T /
static_cast<double>(prm.
K);
140 const double dt = std::min<double>(prm.
dt, tau);
143 TangentMap<X> dx_dx0 = TangentMap<X>::Identity();
146 const auto x_ode = [&f, &bu](
const X & xx, Tangent<X> & dd,
double tt) { dd = f(xx, bu(tt, xx)); };
148 const auto dx_dx0_ode = [&f, &bu, &x](
const auto & S_v,
auto & dS_dt_v,
double tt) {
149 auto f_cl = [&]<
typename T>(
const CastT<T, X> & vx) {
return f(vx, bu(T(tt), vx)); };
150 const auto [fcl, dr_fcl_dx] = diff::dr<1, DT>(std::move(f_cl), wrt(x));
151 dS_dt_v = (-ad<X>(fcl) + dr_fcl_dx) * S_v;
155 const auto [f0, d_f0_du] =
156 diff::dr<1, DT>([&]<
typename T>(
const CastT<T, U> & vu) {
return f(cast<T>(x), vu); }, wrt(pbm.
u_des));
159 for (
auto k = 0u; k != prm.
K; ++k) {
161 const auto [hval, dh_dtx] =
162 diff::dr<1, DT>([&h]<
typename T>(
const T & vt,
const CastT<T, X> & vx) {
return h(vt, vx); }, wrt(t, x));
164 const Eigen::Matrix<double, nh, 1> dh_dt = dh_dtx.template leftCols<1>();
165 const Eigen::Matrix<double, nh, nx> dh_dx = dh_dtx.template rightCols<nx>();
168 const Eigen::Matrix<double, nh, nx> dh_dx0 = dh_dx * dx_dx0;
169 qp.
A.template block<nh, nu>(k * nh, 0) = dh_dx0 * d_f0_du;
170 qp.
l.template segment<nh>(k * nh) = -dh_dt - prm.
alpha * hval - dh_dx0 * f0;
171 qp.
u.template segment<nh>(k * nh).setConstant(std::numeric_limits<double>::infinity());
174 double dt_act = std::min(dt, tau * (k + 1) - t);
175 while (t < tau * (k + 1)) {
176 state_stepper.do_step(x_ode, x, t, dt_act);
177 sensi_stepper.do_step(dx_dx0_ode, dx_dx0, t, dt_act);
183 qp.
A.block(0, nu, prm.
K * nh, 1).setConstant(1);
186 qp.
A.block(prm.
K * nh, 0, nu_ineq, nu) = pbm.
ulim.
A;
191 qp.
A(prm.
K * nh + nu_ineq, nu) = 1;
192 qp.
l(prm.
K * nh + nu_ineq) = 0;
193 qp.
u(prm.
K * nh + nu_ineq) = std::numeric_limits<double>::infinity();
195 qp.
P.template block<nu, nu>(0, 0) = pbm.
W_u.asDiagonal();
244template<LieGroup X, Manifold U, diff::Type DT = diff::Type::Default>
245QuadraticProgram<-1, -1,
double>
248 static constexpr int nh = std::invoke_result_t<
decltype(h),
double, X>::SizeAtCompileTime;
250 static_assert(Dof<X> > 0,
"State space dimension must be static");
251 static_assert(Dof<U> > 0,
"Input space dimension must be static");
252 static_assert(nh > 0,
"Safe set dimension must be static");
254 const int nu_ineq = pbm.
ulim.
A.rows();
256 asif_to_qp_allocate<X, U>(qp, prm.
K, nu_ineq, nh);
258 qp, pbm, prm, std::forward<
decltype(f)>(f), std::forward<
decltype(h)>(h), std::forward<
decltype(bu)>(bu));
void asif_to_qp_allocate(QuadraticProgram<-1, -1, double > &qp, std::size_t K, std::size_t nu_ineq, std::size_t nh)
Allocate QP matrices (part 1 of asif_to_qp())
QuadraticProgram<-1, -1, double > asif_to_qp(const ASIFProblem< X, U > &pbm, const ASIFtoQPParams &prm, auto &&f, auto &&h, auto &&bu)
Convert an ASIFProblem to a QuadraticProgram.
void asif_to_qp_update(QuadraticProgram<-1, -1, double > &qp, const ASIFProblem< X, U > &pbm, const ASIFtoQPParams &prm, auto &&f, auto &&h, auto &&bu)
Fill QP matrices (part 2 of asif_to_qp())
Quadratic Program definition.
Active set invariance problem definition.
ManifoldBounds< U > ulim
input bounds
Eigen::Matrix< double, Dof< U >, 1 > W_u
weights on desired input
Parameters for asif_to_qp.
double relax_cost
relaxation cost
double dt
maximal integration time step
std::size_t K
number of constraint instances (equally spaced over the time horizon)
double alpha
barrier function time constant s.t. .
Eigen::VectorXd u
Upper bound.
Eigen::VectorXd l
Lower bound.
Eigen::Matrix< double, -1, Dof< M > > A
Transformation matrix.
M c
Nominal point in constraint set.
Quadratic program definition.
Eigen::Matrix< Scalar, N, N > P
Positive semi-definite square cost (only upper triangular part is used)
Eigen::Matrix< Scalar, M, N > A
Inequality matrix.
Eigen::Matrix< Scalar, M, 1 > u
Inequality upper bound.
Eigen::Matrix< Scalar, M, 1 > l
Inequality lower bound.
Eigen::Matrix< Scalar, N, 1 > q
Linear cost.