aligator  0.16.0
A versatile and efficient C++ library for real-time constrained trajectory optimization.
Loading...
Searching...
No Matches
traj-opt-problem.hpp
Go to the documentation of this file.
1
3#pragma once
4
8
9namespace aligator {
10
64
67template <typename T1, typename T2>
68[[nodiscard]] bool assign_no_resize(const std::vector<T1> &lhs,
69 std::vector<T2> &rhs) {
70 static_assert(std::is_base_of_v<Eigen::EigenBase<T1>, T1>,
71 "T1 should be an Eigen object!");
72 static_assert(std::is_base_of_v<Eigen::EigenBase<T2>, T2>,
73 "T2 should be an Eigen object!");
74 if (lhs.size() != rhs.size())
75 return false;
76
77 const auto same_dims = [](auto &x, auto &y) {
78 return (x.cols() == y.cols()) && (x.rows() == y.rows());
79 };
80
81 for (std::size_t i = 0; i < lhs.size(); i++) {
82 if (!same_dims(lhs[i], rhs[i]))
83 return false;
84 rhs[i] = lhs[i];
85 }
86 return true;
87}
88
102template <typename _Scalar> struct TrajOptProblemTpl {
104 using Scalar = _Scalar;
105
107
117 std::function<void(const Self &, std::vector<VectorXs> &)>;
118
120 xyz::polymorphic<UnaryFunction> init_constraint_;
122 std::vector<xyz::polymorphic<StageModel>> stages_;
124 xyz::polymorphic<CostAbstract> term_cost_;
128 VectorXs unone_;
129
132
134 TrajOptProblemTpl(xyz::polymorphic<UnaryFunction> init_constraint,
135 const std::vector<xyz::polymorphic<StageModel>> &stages,
136 xyz::polymorphic<CostAbstract> term_cost);
137
139 TrajOptProblemTpl(const ConstVectorRef &x0,
140 const std::vector<xyz::polymorphic<StageModel>> &stages,
141 xyz::polymorphic<CostAbstract> term_cost);
143
146
148 TrajOptProblemTpl(xyz::polymorphic<UnaryFunction> init_constraint,
149 xyz::polymorphic<CostAbstract> term_cost);
150
152 TrajOptProblemTpl(const ConstVectorRef &x0, const int nu,
153 xyz::polymorphic<Manifold> space,
154 xyz::polymorphic<CostAbstract> term_cost);
156
157 bool initCondIsStateError() const {
158 assert(init_cond_is_state_error_ == checkInitCondIsStateError());
159 return init_cond_is_state_error_;
160 }
161
163 void addStage(const xyz::polymorphic<StageModel> &stage);
164
166 ConstVectorRef getInitState() const {
167 if (!initCondIsStateError()) {
169 "Initial condition is not a StateErrorResidual.\n");
170 }
171 return static_cast<StateErrorResidual const *>(&*init_constraint_)->target_;
172 }
173
175 void setInitState(const ConstVectorRef &x0) {
176 if (!initCondIsStateError()) {
178 "Initial condition is not a StateErrorResidual.\n");
179 }
180 static_cast<StateErrorResidual *>(&*init_constraint_)->target_ = x0;
181 }
182
184 void addTerminalConstraint(const xyz::polymorphic<StageFunction> &func,
185 const xyz::polymorphic<ConstraintSet> &set) {
186 this->term_cstrs_.pushBack(func, set);
187 }
188
191
192 [[nodiscard]] std::size_t numSteps() const;
193
195 Scalar evaluate(const std::vector<VectorXs> &xs,
196 const std::vector<VectorXs> &us, Data &prob_data,
197 std::size_t num_threads = 1) const;
198
208 void computeDerivatives(const std::vector<VectorXs> &xs,
209 const std::vector<VectorXs> &us, Data &prob_data,
210 std::size_t num_threads = 1,
211 bool compute_second_order = true) const;
212
215 void replaceStageCircular(const xyz::polymorphic<StageModel> &model);
216
217 bool checkIntegrity() const;
218
220 //
226 template <typename Callable> void setInitializationStrategy(Callable &&func) {
227 static_assert(std::is_convertible_v<Callable, InitializationStrategy>);
228 this->xs_init_strategy_ = std::forward<Callable>(func);
229 }
230
235 void initializeSolution(std::vector<VectorXs> &xs,
236 std::vector<VectorXs> &us) const {
237 xs_init_strategy_(*this, xs);
238 us_default_init(*this, us);
239 }
240
242 void initializeSolution(std::vector<VectorXs> &xs, std::vector<VectorXs> &us,
243 std::vector<VectorXs> &vs,
244 std::vector<VectorXs> &lbdas) const {
245 const size_t nsteps = numSteps();
246 initializeSolution(xs, us);
247 // initialize multipliers...
248 vs.resize(nsteps + 1);
249 lbdas.resize(nsteps + 1);
250 lbdas[0].setZero(init_constraint_->nr);
251 for (size_t i = 0; i < nsteps; i++) {
252 const StageModelTpl<Scalar> &sm = *stages_[i];
253 lbdas[i + 1].setZero(sm.ndx2());
254 vs[i].setZero(sm.nc());
255 }
256
257 if (!term_cstrs_.empty()) {
258 vs[nsteps].setZero(term_cstrs_.totalDim());
259 }
260 }
261
263 [[nodiscard]] auto initializeSolution() const {
264 std::vector<VectorXs> xs, us, vs, lbdas;
265 initializeSolution(xs, us, vs, lbdas);
266 return std::make_tuple(std::move(xs), std::move(us), std::move(vs),
267 std::move(lbdas));
268 }
269
270private:
271 InitializationStrategy xs_init_strategy_;
272
273 // Check if the initial state is a StateErrorResidual.
274 // Since this is a costly operation (dynamic_cast), we cache the result.
275 bool checkInitCondIsStateError() const;
276 bool init_cond_is_state_error_ = false;
277};
278
281template <typename Scalar>
283 std::vector<typename math_types<Scalar>::VectorXs> &xs) {
284 const std::size_t nsteps = problem.numSteps();
285 xs.resize(nsteps + 1);
286 if (problem.initCondIsStateError()) {
287 xs[0] = problem.getInitState();
288 } else {
289 if (problem.stages_.size() > 0) {
290 xs[0] = problem.stages_[0]->xspace().neutral();
291 } else {
293 "The problem should have either a StateErrorResidual as an initial "
294 "condition or at least one stage.");
295 }
296 }
297 for (std::size_t i = 0; i < nsteps; i++) {
298 const StageModelTpl<Scalar> &sm = *problem.stages_[i];
299 xs[i + 1] = sm.xspace_next().neutral();
300 }
301}
302
305template <typename Scalar>
307 std::vector<typename math_types<Scalar>::VectorXs> &us) {
308 const std::size_t nsteps = problem.numSteps();
309 us.resize(nsteps);
310 for (std::size_t i = 0; i < nsteps; i++) {
311 const StageModelTpl<Scalar> &sm = *problem.stages_[i];
312 us[i] = sm.uspace().neutral();
313 }
314}
315
325template <typename Scalar>
327 const TrajOptProblemTpl<Scalar> &problem,
328 const typename math_types<Scalar>::VectorOfVectors &xs_in,
329 const typename math_types<Scalar>::VectorOfVectors &us_in,
331 typename math_types<Scalar>::VectorOfVectors &us_out) {
332 if (xs_in.empty()) {
333 problem.initializeSolution(xs_out, us_out);
334 } else if (us_in.empty()) {
335 us_default_init(problem, us_out);
336 } else {
337 if (!assign_no_resize(xs_in, xs_out))
338 ALIGATOR_RUNTIME_ERROR("warm-start for xs has wrong size!");
339 if (!assign_no_resize(us_in, us_out))
340 ALIGATOR_RUNTIME_ERROR("warm-start for us has wrong size!");
341 }
342}
343
344namespace internal {
346template <typename Scalar>
347int problem_last_ndx_helper(const TrajOptProblemTpl<Scalar> &problem) {
348 return problem.term_cost_->ndx();
349}
350} // namespace internal
351
352#ifdef ALIGATOR_ENABLE_TEMPLATE_INSTANTIATION
353extern template struct TrajOptProblemTpl<context::Scalar>;
354#endif
355} // namespace aligator
#define ALIGATOR_RUNTIME_ERROR(...)
Definition exceptions.hpp:7
Main package namespace.
bool assign_no_resize(const std::vector< T1 > &lhs, std::vector< T2 > &rhs)
Assign a vector of Eigen types into another, ensure there is no resize.
void check_initial_guess_and_assign(const TrajOptProblemTpl< Scalar > &problem, const typename math_types< Scalar >::VectorOfVectors &xs_in, const typename math_types< Scalar >::VectorOfVectors &us_in, typename math_types< Scalar >::VectorOfVectors &xs_out, typename math_types< Scalar >::VectorOfVectors &us_out)
Check the input state-control trajectory is a consistent warm-start for the output.
void us_default_init(const TrajOptProblemTpl< Scalar > &problem, std::vector< typename math_types< Scalar >::VectorXs > &us)
Default-initialize a controls trajectory from the neutral element of each control space.
void xs_default_init(const TrajOptProblemTpl< Scalar > &problem, std::vector< typename math_types< Scalar >::VectorXs > &xs)
Default-initialize a trajectory to the neutral states for each state space at each stage.
Base constraint set type.
Convenience class to manage a stack of constraints.
ALIGATOR_DEPRECATED void pushBack(Cstr &&el)
Stage costs for control problems.
Base class for manifolds, to use in cost funcs, solvers...
VectorXs neutral() const
Get the neutral element from the manifold (if this makes sense).
Class representing ternary functions .
A stage in the control problem.
const Manifold & xspace_next() const
const Manifold & uspace() const
int nc() const
Total number of constraints.
Problem data struct.
Trajectory optimization problem.
void addStage(const xyz::polymorphic< StageModel > &stage)
Add a stage to the control problem.
void addTerminalConstraint(const xyz::polymorphic< StageFunction > &func, const xyz::polymorphic< ConstraintSet > &set)
Add a terminal constraint for the model.
TrajOptProblemTpl(const ConstVectorRef &x0, const std::vector< xyz::polymorphic< StageModel > > &stages, xyz::polymorphic< CostAbstract > term_cost)
Constructor for an initial value problem.
TrajOptProblemTpl(const ConstVectorRef &x0, const int nu, xyz::polymorphic< Manifold > space, xyz::polymorphic< CostAbstract > term_cost)
Constructor for an initial value problem.
ConstraintSetTpl< Scalar > ConstraintSet
ConstraintStackTpl< Scalar > term_cstrs_
StageFunctionTpl< Scalar > StageFunction
void setInitState(const ConstVectorRef &x0)
Set initial state constraint.
void computeDerivatives(const std::vector< VectorXs > &xs, const std::vector< VectorXs > &us, Data &prob_data, std::size_t num_threads=1, bool compute_second_order=true) const
Rollout the problem derivatives, stage per stage.
void initializeSolution(std::vector< VectorXs > &xs, std::vector< VectorXs > &us) const
Execute the initialization strategy to generate an initial candidate solution to the problem.
xyz::polymorphic< UnaryFunction > init_constraint_
TrajOptProblemTpl(xyz::polymorphic< UnaryFunction > init_constraint, xyz::polymorphic< CostAbstract > term_cost)
Constructor with a given constraint function of any given type.
void setInitializationStrategy(Callable &&func)
Set a function to initialize the state trajectory.
UnaryFunctionTpl< Scalar > UnaryFunction
void removeTerminalConstraints()
Remove all terminal constraints.
xyz::polymorphic< CostAbstract > term_cost_
Scalar evaluate(const std::vector< VectorXs > &xs, const std::vector< VectorXs > &us, Data &prob_data, std::size_t num_threads=1) const
Rollout the problem costs, constraints, dynamics, stage per stage.
void replaceStageCircular(const xyz::polymorphic< StageModel > &model)
Pop out the first StageModel and replace by the supplied one; updates the supplied problem data (Traj...
ConstVectorRef getInitState() const
Get initial state constraint.
auto initializeSolution() const
Execute the initialization strategy to generate an initial candidate solution to the problem.
std::vector< xyz::polymorphic< StageModel > > stages_
StateErrorResidualTpl< Scalar > StateErrorResidual
std::function< void(const Self &, std::vector< VectorXs > &)> InitializationStrategy
TrajOptProblemTpl(xyz::polymorphic< UnaryFunction > init_constraint, const std::vector< xyz::polymorphic< StageModel > > &stages, xyz::polymorphic< CostAbstract > term_cost)
Constructor with a given constraint function of any given type.
std::size_t numSteps() const
ManifoldAbstractTpl< Scalar > Manifold
void initializeSolution(std::vector< VectorXs > &xs, std::vector< VectorXs > &us, std::vector< VectorXs > &vs, std::vector< VectorXs > &lbdas) const
Execute the initialization strategy to generate an initial candidate solution to the problem.
Represents unary functions of the form , with no control (or next-state) arguments.
Typedefs for math (Eigen vectors, matrices) depending on scalar type.
Definition math.hpp:122