Directory: | ./ |
---|---|
File: | include/crocoddyl/core/costs/cost-sum.hpp |
Date: | 2025-01-30 11:01:55 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 49 | 74 | 66.2% |
Branches: | 45 | 211 | 21.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | ||
2 | // BSD 3-Clause License | ||
3 | // | ||
4 | // Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, | ||
5 | // Heriot-Watt University | ||
6 | // Copyright note valid unless otherwise stated in individual files. | ||
7 | // All rights reserved. | ||
8 | /////////////////////////////////////////////////////////////////////////////// | ||
9 | |||
10 | #ifndef CROCODDYL_CORE_COSTS_COST_SUM_HPP_ | ||
11 | #define CROCODDYL_CORE_COSTS_COST_SUM_HPP_ | ||
12 | |||
13 | #include <map> | ||
14 | #include <set> | ||
15 | #include <string> | ||
16 | #include <utility> | ||
17 | |||
18 | #include "crocoddyl/core/cost-base.hpp" | ||
19 | #include "crocoddyl/core/fwd.hpp" | ||
20 | #include "crocoddyl/core/utils/exception.hpp" | ||
21 | |||
22 | namespace crocoddyl { | ||
23 | |||
24 | template <typename _Scalar> | ||
25 | struct CostItemTpl { | ||
26 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
27 | |||
28 | typedef _Scalar Scalar; | ||
29 | typedef CostModelAbstractTpl<Scalar> CostModelAbstract; | ||
30 | |||
31 | CostItemTpl() {} | ||
32 | 6125 | CostItemTpl(const std::string& name, std::shared_ptr<CostModelAbstract> cost, | |
33 | const Scalar weight, const bool active = true) | ||
34 | 6125 | : name(name), cost(cost), weight(weight), active(active) {} | |
35 | |||
36 | /** | ||
37 | * @brief Print information on the cost item | ||
38 | */ | ||
39 | ✗ | friend std::ostream& operator<<(std::ostream& os, | |
40 | const CostItemTpl<Scalar>& model) { | ||
41 | ✗ | os << "{w=" << model.weight << ", " << *model.cost << "}"; | |
42 | ✗ | return os; | |
43 | } | ||
44 | |||
45 | std::string name; | ||
46 | std::shared_ptr<CostModelAbstract> cost; | ||
47 | Scalar weight; | ||
48 | bool active; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * @brief Summation of individual cost models | ||
53 | * | ||
54 | * This class serves to manage a set of added cost models. The cost functions | ||
55 | * might active or inactive, with this approach we avoid dynamic allocation of | ||
56 | * memory. Each cost model is added through `addCost`, where the weight and its | ||
57 | * status can be defined. | ||
58 | * | ||
59 | * The main computations are carring out in `calc()` and `calcDiff()` routines. | ||
60 | * `calc()` computes the costs (and its residuals) and `calcDiff()` computes the | ||
61 | * derivatives of the cost functions (and its residuals). Concretely speaking, | ||
62 | * `calcDiff()` builds a linear-quadratic approximation of the total cost | ||
63 | * function with the form: \f$\mathbf{\ell_x}\in\mathbb{R}^{ndx}\f$, | ||
64 | * \f$\mathbf{\ell_u}\in\mathbb{R}^{nu}\f$, | ||
65 | * \f$\mathbf{\ell_{xx}}\in\mathbb{R}^{ndx\times ndx}\f$, | ||
66 | * \f$\mathbf{\ell_{xu}}\in\mathbb{R}^{ndx\times nu}\f$, | ||
67 | * \f$\mathbf{\ell_{uu}}\in\mathbb{R}^{nu\times nu}\f$ are the Jacobians and | ||
68 | * Hessians, respectively. | ||
69 | * | ||
70 | * \sa `CostModelAbstractTpl`, `calc()`, `calcDiff()`, `createData()` | ||
71 | */ | ||
72 | template <typename _Scalar> | ||
73 | class CostModelSumTpl { | ||
74 | public: | ||
75 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
76 | |||
77 | typedef _Scalar Scalar; | ||
78 | typedef MathBaseTpl<Scalar> MathBase; | ||
79 | typedef CostDataSumTpl<Scalar> CostDataSum; | ||
80 | typedef StateAbstractTpl<Scalar> StateAbstract; | ||
81 | typedef CostModelAbstractTpl<Scalar> CostModelAbstract; | ||
82 | typedef CostDataAbstractTpl<Scalar> CostDataAbstract; | ||
83 | typedef DataCollectorAbstractTpl<Scalar> DataCollectorAbstract; | ||
84 | typedef CostItemTpl<Scalar> CostItem; | ||
85 | typedef typename MathBase::VectorXs VectorXs; | ||
86 | typedef typename MathBase::MatrixXs MatrixXs; | ||
87 | |||
88 | typedef std::map<std::string, std::shared_ptr<CostItem> > CostModelContainer; | ||
89 | typedef std::map<std::string, std::shared_ptr<CostDataAbstract> > | ||
90 | CostDataContainer; | ||
91 | |||
92 | /** | ||
93 | * @brief Initialize the cost-sum model | ||
94 | * | ||
95 | * @param[in] state State description | ||
96 | * @param[in] nu Dimension of control vector | ||
97 | */ | ||
98 | CostModelSumTpl(std::shared_ptr<StateAbstract> state, const std::size_t nu); | ||
99 | |||
100 | /** | ||
101 | * @brief Initialize the cost-sum model | ||
102 | * | ||
103 | * The default `nu` value is obtained from `StateAbstractTpl::get_nv()`. | ||
104 | * | ||
105 | * @param[in] state State description | ||
106 | */ | ||
107 | explicit CostModelSumTpl(std::shared_ptr<StateAbstract> state); | ||
108 | ~CostModelSumTpl(); | ||
109 | |||
110 | /** | ||
111 | * @brief Add a cost item | ||
112 | * | ||
113 | * @param[in] name Cost name | ||
114 | * @param[in] cost Cost model | ||
115 | * @param[in] weight Cost weight | ||
116 | * @param[in] active True if the cost is activated (default true) | ||
117 | */ | ||
118 | void addCost(const std::string& name, std::shared_ptr<CostModelAbstract> cost, | ||
119 | const Scalar weight, const bool active = true); | ||
120 | |||
121 | /** | ||
122 | * @brief Remove a cost item | ||
123 | * | ||
124 | * @param[in] name Cost name | ||
125 | */ | ||
126 | void removeCost(const std::string& name); | ||
127 | |||
128 | /** | ||
129 | * @brief Change the cost status | ||
130 | * | ||
131 | * @param[in] name Cost name | ||
132 | * @param[in] active Cost status (true for active and false for inactive) | ||
133 | */ | ||
134 | void changeCostStatus(const std::string& name, const bool active); | ||
135 | |||
136 | /** | ||
137 | * @brief Compute the total cost value | ||
138 | * | ||
139 | * @param[in] data Cost data | ||
140 | * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$ | ||
141 | * @param[in] u Control input \f$\mathbf{u}\in\mathbb{R}^{nu}\f$ | ||
142 | */ | ||
143 | void calc(const std::shared_ptr<CostDataSum>& data, | ||
144 | const Eigen::Ref<const VectorXs>& x, | ||
145 | const Eigen::Ref<const VectorXs>& u); | ||
146 | |||
147 | /** | ||
148 | * @brief Compute the total cost value for nodes that depends only on the | ||
149 | * state | ||
150 | * | ||
151 | * It updates the total cost based on the state only. This function is used in | ||
152 | * the terminal nodes of an optimal control problem. | ||
153 | * | ||
154 | * @param[in] data Cost data | ||
155 | * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$ | ||
156 | */ | ||
157 | void calc(const std::shared_ptr<CostDataSum>& data, | ||
158 | const Eigen::Ref<const VectorXs>& x); | ||
159 | |||
160 | /** | ||
161 | * @brief Compute the Jacobian and Hessian of the total cost | ||
162 | * | ||
163 | * @param[in] data Cost data | ||
164 | * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$ | ||
165 | * @param[in] u Control input \f$\mathbf{u}\in\mathbb{R}^{nu}\f$ | ||
166 | */ | ||
167 | void calcDiff(const std::shared_ptr<CostDataSum>& data, | ||
168 | const Eigen::Ref<const VectorXs>& x, | ||
169 | const Eigen::Ref<const VectorXs>& u); | ||
170 | |||
171 | /** | ||
172 | * @brief Compute the Jacobian and Hessian of the total cost for nodes that | ||
173 | * depends on the state only | ||
174 | * | ||
175 | * It updates the Jacobian and Hessian of the total cost based on the state | ||
176 | * only. This function is used in the terminal nodes of an optimal control | ||
177 | * problem. | ||
178 | * | ||
179 | * @param[in] data Cost data | ||
180 | * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$ | ||
181 | * @param[in] u Control input \f$\mathbf{u}\in\mathbb{R}^{nu}\f$ | ||
182 | */ | ||
183 | void calcDiff(const std::shared_ptr<CostDataSum>& data, | ||
184 | const Eigen::Ref<const VectorXs>& x); | ||
185 | |||
186 | /** | ||
187 | * @brief Create the cost data | ||
188 | * | ||
189 | * The default data contains objects to store the values of the cost, residual | ||
190 | * vector and their derivatives (first and second order derivatives). However, | ||
191 | * it is possible to specialize this function is we need to create additional | ||
192 | * data, for instance, to avoid dynamic memory allocation. | ||
193 | * | ||
194 | * @param data Data collector | ||
195 | * @return the cost data | ||
196 | */ | ||
197 | std::shared_ptr<CostDataSum> createData(DataCollectorAbstract* const data); | ||
198 | |||
199 | /** | ||
200 | * @brief Return the state | ||
201 | */ | ||
202 | const std::shared_ptr<StateAbstract>& get_state() const; | ||
203 | |||
204 | /** | ||
205 | * @brief Return the stack of cost models | ||
206 | */ | ||
207 | const CostModelContainer& get_costs() const; | ||
208 | |||
209 | /** | ||
210 | * @brief Return the dimension of the control input | ||
211 | */ | ||
212 | std::size_t get_nu() const; | ||
213 | |||
214 | /** | ||
215 | * @brief Return the dimension of the active residual vector | ||
216 | */ | ||
217 | std::size_t get_nr() const; | ||
218 | |||
219 | /** | ||
220 | * @brief Return the dimension of the total residual vector | ||
221 | */ | ||
222 | std::size_t get_nr_total() const; | ||
223 | |||
224 | /** | ||
225 | * @brief Return the names of the set of active costs | ||
226 | */ | ||
227 | const std::set<std::string>& get_active_set() const; | ||
228 | |||
229 | /** | ||
230 | * @brief Return the names of the set of inactive costs | ||
231 | */ | ||
232 | const std::set<std::string>& get_inactive_set() const; | ||
233 | |||
234 | ✗ | DEPRECATED( | |
235 | "get_active() is deprecated and will be replaced with get_active_set()", | ||
236 | const std::vector<std::string>& get_active() { | ||
237 | active_.clear(); | ||
238 | active_.reserve(active_set_.size()); | ||
239 | for (const auto& contact : active_set_) { | ||
240 | active_.push_back(contact); | ||
241 | } | ||
242 | return active_; | ||
243 | };) | ||
244 | |||
245 | ✗ | DEPRECATED( | |
246 | "get_inactive() is deprecated and will be replaced with " | ||
247 | "get_inactive_set()", | ||
248 | const std::vector<std::string>& get_inactive() { | ||
249 | inactive_.clear(); | ||
250 | inactive_.reserve(inactive_set_.size()); | ||
251 | for (const auto& contact : inactive_set_) { | ||
252 | inactive_.push_back(contact); | ||
253 | } | ||
254 | return inactive_; | ||
255 | };) | ||
256 | |||
257 | /** | ||
258 | * @brief Return the status of a given cost name | ||
259 | * | ||
260 | * @param[in] name Cost name | ||
261 | */ | ||
262 | bool getCostStatus(const std::string& name) const; | ||
263 | |||
264 | /** | ||
265 | * @brief Print information on the stack of costs | ||
266 | */ | ||
267 | template <class Scalar> | ||
268 | friend std::ostream& operator<<(std::ostream& os, | ||
269 | const CostModelSumTpl<Scalar>& model); | ||
270 | |||
271 | private: | ||
272 | std::shared_ptr<StateAbstract> state_; //!< State description | ||
273 | CostModelContainer costs_; //!< Stack of cost items | ||
274 | std::size_t nu_; //!< Dimension of the control input | ||
275 | std::size_t nr_; //!< Dimension of the active residual vector | ||
276 | std::size_t nr_total_; //!< Dimension of the total residual vector | ||
277 | std::set<std::string> active_set_; //!< Names of the active set of cost items | ||
278 | std::set<std::string> | ||
279 | inactive_set_; //!< Names of the inactive set of cost items | ||
280 | |||
281 | // Vector variants. These are to maintain the API compatibility for the | ||
282 | // deprecated syntax. These will be removed in future versions along with | ||
283 | // get_active() / get_inactive() | ||
284 | std::vector<std::string> active_; | ||
285 | std::vector<std::string> inactive_; | ||
286 | }; | ||
287 | |||
288 | template <typename _Scalar> | ||
289 | struct CostDataSumTpl { | ||
290 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
291 | |||
292 | typedef _Scalar Scalar; | ||
293 | typedef MathBaseTpl<Scalar> MathBase; | ||
294 | typedef DataCollectorAbstractTpl<Scalar> DataCollectorAbstract; | ||
295 | typedef CostItemTpl<Scalar> CostItem; | ||
296 | typedef typename MathBase::VectorXs VectorXs; | ||
297 | typedef typename MathBase::MatrixXs MatrixXs; | ||
298 | |||
299 | template <template <typename Scalar> class Model> | ||
300 | 96126 | CostDataSumTpl(Model<Scalar>* const model, DataCollectorAbstract* const data) | |
301 |
1/2✓ Branch 4 taken 96126 times.
✗ Branch 5 not taken.
|
96126 | : Lx_internal(model->get_state()->get_ndx()), |
302 |
1/2✓ Branch 2 taken 96126 times.
✗ Branch 3 not taken.
|
96126 | Lu_internal(model->get_nu()), |
303 |
1/2✓ Branch 3 taken 96126 times.
✗ Branch 4 not taken.
|
96126 | Lxx_internal(model->get_state()->get_ndx(), |
304 | 96126 | model->get_state()->get_ndx()), | |
305 |
1/2✓ Branch 5 taken 96126 times.
✗ Branch 6 not taken.
|
96126 | Lxu_internal(model->get_state()->get_ndx(), model->get_nu()), |
306 |
1/2✓ Branch 3 taken 96126 times.
✗ Branch 4 not taken.
|
96126 | Luu_internal(model->get_nu(), model->get_nu()), |
307 | 96126 | shared(data), | |
308 | 96126 | cost(Scalar(0.)), | |
309 |
5/9✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 96117 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 96117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
|
96126 | Lx(Lx_internal.data(), model->get_state()->get_ndx()), |
310 |
5/9✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96117 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 96117 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
|
96126 | Lu(Lu_internal.data(), model->get_nu()), |
311 |
5/9✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 96117 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 96117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
|
192252 | Lxx(Lxx_internal.data(), model->get_state()->get_ndx(), |
312 | 96126 | model->get_state()->get_ndx()), | |
313 |
5/9✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 96117 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 96117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
|
192252 | Lxu(Lxu_internal.data(), model->get_state()->get_ndx(), |
314 | 96126 | model->get_nu()), | |
315 |
5/9✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 96117 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 96117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
|
192252 | Luu(Luu_internal.data(), model->get_nu(), model->get_nu()) { |
316 |
1/2✓ Branch 1 taken 96126 times.
✗ Branch 2 not taken.
|
96126 | Lx.setZero(); |
317 |
1/2✓ Branch 1 taken 96126 times.
✗ Branch 2 not taken.
|
96126 | Lu.setZero(); |
318 |
1/2✓ Branch 1 taken 96126 times.
✗ Branch 2 not taken.
|
96126 | Lxx.setZero(); |
319 |
1/2✓ Branch 1 taken 96126 times.
✗ Branch 2 not taken.
|
96126 | Lxu.setZero(); |
320 |
1/2✓ Branch 1 taken 96126 times.
✗ Branch 2 not taken.
|
96126 | Luu.setZero(); |
321 | 96126 | for (typename CostModelSumTpl<Scalar>::CostModelContainer::const_iterator | |
322 | 96126 | it = model->get_costs().begin(); | |
323 |
2/2✓ Branch 3 taken 435411 times.
✓ Branch 4 taken 96126 times.
|
531537 | it != model->get_costs().end(); ++it) { |
324 | 435411 | const std::shared_ptr<CostItem>& item = it->second; | |
325 |
3/6✓ Branch 3 taken 435411 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 435411 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 435411 times.
✗ Branch 11 not taken.
|
435411 | costs.insert(std::make_pair(item->name, item->cost->createData(data))); |
326 | } | ||
327 | 96126 | } | |
328 | |||
329 | template <class ActionData> | ||
330 | 147096 | void shareMemory(ActionData* const data) { | |
331 | // Save memory by setting the internal variables with null dimension | ||
332 | 147096 | Lx_internal.resize(0); | |
333 | 147096 | Lu_internal.resize(0); | |
334 | 147096 | Lxx_internal.resize(0, 0); | |
335 | 147096 | Lxu_internal.resize(0, 0); | |
336 | 147096 | Luu_internal.resize(0, 0); | |
337 | // Share memory with the differential action data | ||
338 |
1/2✓ Branch 5 taken 95764 times.
✗ Branch 6 not taken.
|
147096 | new (&Lx) Eigen::Map<VectorXs>(data->Lx.data(), data->Lx.size()); |
339 |
1/2✓ Branch 5 taken 95764 times.
✗ Branch 6 not taken.
|
147096 | new (&Lu) Eigen::Map<VectorXs>(data->Lu.data(), data->Lu.size()); |
340 |
1/2✓ Branch 5 taken 95764 times.
✗ Branch 6 not taken.
|
294192 | new (&Lxx) Eigen::Map<MatrixXs>(data->Lxx.data(), data->Lxx.rows(), |
341 | 147096 | data->Lxx.cols()); | |
342 |
1/2✓ Branch 5 taken 95764 times.
✗ Branch 6 not taken.
|
294192 | new (&Lxu) Eigen::Map<MatrixXs>(data->Lxu.data(), data->Lxu.rows(), |
343 | 147096 | data->Lxu.cols()); | |
344 |
1/2✓ Branch 5 taken 95764 times.
✗ Branch 6 not taken.
|
294192 | new (&Luu) Eigen::Map<MatrixXs>(data->Luu.data(), data->Luu.rows(), |
345 | 147096 | data->Luu.cols()); | |
346 | 147096 | } | |
347 | |||
348 | 7 | VectorXs get_Lx() const { return Lx; } | |
349 | 7 | VectorXs get_Lu() const { return Lu; } | |
350 | 7 | MatrixXs get_Lxx() const { return Lxx; } | |
351 | 7 | MatrixXs get_Lxu() const { return Lxu; } | |
352 | 7 | MatrixXs get_Luu() const { return Luu; } | |
353 | |||
354 | ✗ | void set_Lx(const VectorXs& _Lx) { | |
355 | ✗ | if (Lx.size() != _Lx.size()) { | |
356 | ✗ | throw_pretty( | |
357 | "Invalid argument: " << "Lx has wrong dimension (it should be " + | ||
358 | std::to_string(Lx.size()) + ")"); | ||
359 | } | ||
360 | ✗ | Lx = _Lx; | |
361 | } | ||
362 | ✗ | void set_Lu(const VectorXs& _Lu) { | |
363 | ✗ | if (Lu.size() != _Lu.size()) { | |
364 | ✗ | throw_pretty( | |
365 | "Invalid argument: " << "Lu has wrong dimension (it should be " + | ||
366 | std::to_string(Lu.size()) + ")"); | ||
367 | } | ||
368 | ✗ | Lu = _Lu; | |
369 | } | ||
370 | ✗ | void set_Lxx(const MatrixXs& _Lxx) { | |
371 | ✗ | if (Lxx.rows() != _Lxx.rows() || Lxx.cols() != _Lxx.cols()) { | |
372 | ✗ | throw_pretty( | |
373 | "Invalid argument: " << "Lxx has wrong dimension (it should be " + | ||
374 | std::to_string(Lxx.rows()) + ", " + | ||
375 | std::to_string(Lxx.cols()) + ")"); | ||
376 | } | ||
377 | ✗ | Lxx = _Lxx; | |
378 | } | ||
379 | ✗ | void set_Lxu(const MatrixXs& _Lxu) { | |
380 | ✗ | if (Lxu.rows() != _Lxu.rows() || Lxu.cols() != _Lxu.cols()) { | |
381 | ✗ | throw_pretty( | |
382 | "Invalid argument: " << "Lxu has wrong dimension (it should be " + | ||
383 | std::to_string(Lxu.rows()) + ", " + | ||
384 | std::to_string(Lxu.cols()) + ")"); | ||
385 | } | ||
386 | ✗ | Lxu = _Lxu; | |
387 | } | ||
388 | ✗ | void set_Luu(const MatrixXs& _Luu) { | |
389 | ✗ | if (Luu.rows() != _Luu.rows() || Luu.cols() != _Luu.cols()) { | |
390 | ✗ | throw_pretty( | |
391 | "Invalid argument: " << "Luu has wrong dimension (it should be " + | ||
392 | std::to_string(Luu.rows()) + ", " + | ||
393 | std::to_string(Luu.cols()) + ")"); | ||
394 | } | ||
395 | ✗ | Luu = _Luu; | |
396 | } | ||
397 | |||
398 | // Creates internal data in case we don't share it externally | ||
399 | VectorXs Lx_internal; | ||
400 | VectorXs Lu_internal; | ||
401 | MatrixXs Lxx_internal; | ||
402 | MatrixXs Lxu_internal; | ||
403 | MatrixXs Luu_internal; | ||
404 | |||
405 | typename CostModelSumTpl<Scalar>::CostDataContainer costs; | ||
406 | DataCollectorAbstract* shared; | ||
407 | Scalar cost; | ||
408 | Eigen::Map<VectorXs> Lx; | ||
409 | Eigen::Map<VectorXs> Lu; | ||
410 | Eigen::Map<MatrixXs> Lxx; | ||
411 | Eigen::Map<MatrixXs> Lxu; | ||
412 | Eigen::Map<MatrixXs> Luu; | ||
413 | }; | ||
414 | |||
415 | } // namespace crocoddyl | ||
416 | |||
417 | /* --- Details -------------------------------------------------------------- */ | ||
418 | /* --- Details -------------------------------------------------------------- */ | ||
419 | /* --- Details -------------------------------------------------------------- */ | ||
420 | #include "crocoddyl/core/costs/cost-sum.hxx" | ||
421 | |||
422 | #endif // CROCODDYL_CORE_COSTS_COST_SUM_HPP_ | ||
423 |