GCC Code Coverage Report


Directory: ./
File: unittest/test_cost_sum.cpp
Date: 2025-06-03 08:14:12
Exec Total Coverage
Lines: 0 300 0.0%
Functions: 0 13 0.0%
Branches: 0 1340 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, University of Edinburgh, Heriot-Watt University
5 // Copyright note valid unless otherwise stated in individual files.
6 // All rights reserved.
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #define BOOST_TEST_NO_MAIN
10 #define BOOST_TEST_ALTERNATIVE_INIT_API
11
12 #include "crocoddyl/core/actions/lqr.hpp"
13 #include "crocoddyl/multibody/data/multibody.hpp"
14 #include "factory/cost.hpp"
15 #include "unittest_common.hpp"
16
17 using namespace boost::unit_test;
18 using namespace crocoddyl::unittest;
19
20 //----------------------------------------------------------------------------//
21
22 ✗ void test_constructor(StateModelTypes::Type state_type) {
23 // Setup the test
24 ✗ StateModelFactory state_factory;
25 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
26
27 // Run the print function
28 ✗ std::ostringstream tmp;
29 ✗ tmp << model;
30
31 // Test the initial size of the map
32 ✗ BOOST_CHECK(model.get_costs().size() == 0);
33
34 // Checking that casted computation is the same
35 #ifdef NDEBUG // Run only in release mode
36 crocoddyl::CostModelSumTpl<float> casted_model = model.cast<float>();
37 BOOST_CHECK(casted_model.get_costs().size() == 0);
38 #endif
39 ✗ }
40
41 ✗ void test_addCost(StateModelTypes::Type state_type) {
42 // Setup the test
43 ✗ StateModelFactory state_factory;
44 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
45 ✗ crocoddyl::CostModelSumTpl<float> casted_model = model.cast<float>();
46
47 // add an active cost
48 std::shared_ptr<crocoddyl::CostModelAbstract> rand_cost_1 =
49 ✗ create_random_cost(state_type);
50 ✗ model.addCost("random_cost_1", rand_cost_1, 1.);
51 ✗ BOOST_CHECK(model.get_nr() == rand_cost_1->get_activation()->get_nr());
52 ✗ BOOST_CHECK(model.get_nr_total() == rand_cost_1->get_activation()->get_nr());
53
54 // add an inactive cost
55 std::shared_ptr<crocoddyl::CostModelAbstract> rand_cost_2 =
56 ✗ create_random_cost(state_type);
57 ✗ model.addCost("random_cost_2", rand_cost_2, 1., false);
58 ✗ BOOST_CHECK(model.get_nr() == rand_cost_1->get_activation()->get_nr());
59 ✗ BOOST_CHECK(model.get_nr_total() ==
60 rand_cost_1->get_activation()->get_nr() +
61 rand_cost_2->get_activation()->get_nr());
62
63 // change the random cost 2 status
64 ✗ model.changeCostStatus("random_cost_2", true);
65 ✗ BOOST_CHECK(model.get_nr() == rand_cost_1->get_activation()->get_nr() +
66 rand_cost_2->get_activation()->get_nr());
67 ✗ BOOST_CHECK(model.get_nr_total() ==
68 rand_cost_1->get_activation()->get_nr() +
69 rand_cost_2->get_activation()->get_nr());
70
71 // change the random cost 1 status
72 ✗ model.changeCostStatus("random_cost_1", false);
73 ✗ BOOST_CHECK(model.get_nr() == rand_cost_2->get_activation()->get_nr());
74 ✗ BOOST_CHECK(model.get_nr_total() ==
75 rand_cost_1->get_activation()->get_nr() +
76 rand_cost_2->get_activation()->get_nr());
77
78 // Checking that casted computation is the same
79 #ifdef NDEBUG // Run only in release mode
80 std::shared_ptr<crocoddyl::CostModelAbstractTpl<float>> casted_rand_cost_1 =
81 rand_cost_1->cast<float>();
82 casted_model.addCost("random_cost_1", casted_rand_cost_1, 1.f);
83 BOOST_CHECK(casted_model.get_nr() ==
84 casted_rand_cost_1->get_activation()->get_nr());
85 BOOST_CHECK(casted_model.get_nr_total() ==
86 casted_rand_cost_1->get_activation()->get_nr());
87 std::shared_ptr<crocoddyl::CostModelAbstractTpl<float>> casted_rand_cost_2 =
88 rand_cost_2->cast<float>();
89 casted_model.addCost("random_cost_2", casted_rand_cost_2, 1.f, false);
90 BOOST_CHECK(casted_model.get_nr() ==
91 casted_rand_cost_1->get_activation()->get_nr());
92 BOOST_CHECK(casted_model.get_nr_total() ==
93 casted_rand_cost_1->get_activation()->get_nr() +
94 casted_rand_cost_2->get_activation()->get_nr());
95 casted_model.changeCostStatus("random_cost_2", true);
96 BOOST_CHECK(casted_model.get_nr() ==
97 casted_rand_cost_1->get_activation()->get_nr() +
98 casted_rand_cost_2->get_activation()->get_nr());
99 BOOST_CHECK(casted_model.get_nr_total() ==
100 casted_rand_cost_1->get_activation()->get_nr() +
101 casted_rand_cost_2->get_activation()->get_nr());
102 casted_model.changeCostStatus("random_cost_1", false);
103 BOOST_CHECK(casted_model.get_nr() ==
104 casted_rand_cost_2->get_activation()->get_nr());
105 BOOST_CHECK(casted_model.get_nr_total() ==
106 casted_rand_cost_1->get_activation()->get_nr() +
107 casted_rand_cost_2->get_activation()->get_nr());
108 #endif
109 ✗ }
110
111 ✗ void test_addCost_error_message(StateModelTypes::Type state_type) {
112 // Setup the test
113 ✗ StateModelFactory state_factory;
114 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
115
116 // create an cost object
117 std::shared_ptr<crocoddyl::CostModelAbstract> rand_cost =
118 ✗ create_random_cost(state_type);
119
120 // add twice the same cost object to the container
121 ✗ model.addCost("random_cost", rand_cost, 1.);
122
123 // test error message when we add a duplicate cost
124 ✗ CaptureIOStream capture_ios;
125 ✗ capture_ios.beginCapture();
126 ✗ model.addCost("random_cost", rand_cost, 1.);
127 ✗ capture_ios.endCapture();
128 ✗ std::stringstream expected_buffer;
129 expected_buffer << "Warning: we couldn't add the random_cost cost item, it "
130 ✗ "already existed."
131 ✗ << std::endl;
132 ✗ BOOST_CHECK(capture_ios.str() == expected_buffer.str());
133
134 // test error message when we change the cost status of an inexistent cost
135 ✗ capture_ios.beginCapture();
136 ✗ model.changeCostStatus("no_exist_cost", true);
137 ✗ capture_ios.endCapture();
138 ✗ expected_buffer.clear();
139 expected_buffer << "Warning: we couldn't change the status of the "
140 ✗ "no_exist_cost cost item, it doesn't exist."
141 ✗ << std::endl;
142 ✗ BOOST_CHECK(capture_ios.str() == expected_buffer.str());
143 ✗ }
144
145 ✗ void test_removeCost(StateModelTypes::Type state_type) {
146 // Setup the test
147 ✗ StateModelFactory state_factory;
148 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
149 ✗ crocoddyl::CostModelSumTpl<float> casted_model = model.cast<float>();
150
151 // add an active cost
152 std::shared_ptr<crocoddyl::CostModelAbstract> rand_cost =
153 ✗ create_random_cost(state_type);
154 ✗ model.addCost("random_cost", rand_cost, 1.);
155 ✗ BOOST_CHECK(model.get_nr() == rand_cost->get_activation()->get_nr());
156
157 // remove the cost
158 ✗ model.removeCost("random_cost");
159 ✗ BOOST_CHECK(model.get_nr() == 0);
160 ✗ BOOST_CHECK(model.get_nr_total() == 0);
161
162 // Checking that casted computation is the same
163 #ifdef NDEBUG // Run only in release mode
164 std::shared_ptr<crocoddyl::CostModelAbstractTpl<float>> casted_rand_cost =
165 rand_cost->cast<float>();
166 casted_model.addCost("random_cost", casted_rand_cost, 1.f);
167 BOOST_CHECK(casted_model.get_nr() ==
168 casted_rand_cost->get_activation()->get_nr());
169 casted_model.removeCost("random_cost");
170 BOOST_CHECK(casted_model.get_nr() == 0);
171 BOOST_CHECK(casted_model.get_nr_total() == 0);
172 #endif
173 ✗ }
174
175 ✗ void test_removeCost_error_message(StateModelTypes::Type state_type) {
176 // Setup the test
177 ✗ StateModelFactory state_factory;
178 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
179
180 // remove a none existing cost form the container, we expect a cout message
181 // here
182 ✗ CaptureIOStream capture_ios;
183 ✗ capture_ios.beginCapture();
184 ✗ model.removeCost("random_cost");
185 ✗ capture_ios.endCapture();
186
187 // Test that the error message is sent.
188 ✗ std::stringstream expected_buffer;
189 expected_buffer << "Warning: we couldn't remove the random_cost cost item, "
190 ✗ "it doesn't exist."
191 ✗ << std::endl;
192 ✗ BOOST_CHECK(capture_ios.str() == expected_buffer.str());
193 ✗ }
194
195 ✗ void test_calc(StateModelTypes::Type state_type) {
196 // setup the test
197 ✗ StateModelFactory state_factory;
198 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
199 // create the corresponding data object
200 const std::shared_ptr<crocoddyl::StateMultibody>& state =
201 ✗ std::static_pointer_cast<crocoddyl::StateMultibody>(model.get_state());
202 ✗ pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
203 ✗ pinocchio::Data pinocchio_data(pinocchio_model);
204 ✗ crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
205
206 // create and add some cost objects
207 ✗ std::vector<std::shared_ptr<crocoddyl::CostModelAbstract>> models;
208 ✗ std::vector<std::shared_ptr<crocoddyl::CostDataAbstract>> datas;
209 ✗ for (std::size_t i = 0; i < 5; ++i) {
210 ✗ std::ostringstream os;
211 ✗ os << "random_cost_" << i;
212 const std::shared_ptr<crocoddyl::CostModelAbstract>& m =
213 ✗ create_random_cost(state_type);
214 ✗ model.addCost(os.str(), m, 1.);
215 ✗ models.push_back(m);
216 ✗ datas.push_back(m->createData(&shared_data));
217 ✗ }
218
219 // create the data of the cost sum
220 const std::shared_ptr<crocoddyl::CostDataSum>& data =
221 ✗ model.createData(&shared_data);
222
223 // compute the cost sum data for the case when all costs are defined as active
224 ✗ const Eigen::VectorXd x1 = state->rand();
225 ✗ const Eigen::VectorXd u1 = Eigen::VectorXd::Random(model.get_nu());
226 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
227 x1);
228 ✗ model.calc(data, x1, u1);
229
230 // check that the cost has been filled
231 ✗ BOOST_CHECK(data->cost > 0.);
232
233 // check the cost against single cost computations
234 ✗ double cost = 0;
235 ✗ for (std::size_t i = 0; i < 5; ++i) {
236 ✗ models[i]->calc(datas[i], x1, u1);
237 ✗ cost += datas[i]->cost;
238 }
239 ✗ BOOST_CHECK(data->cost == cost);
240
241 // compute the cost sum data for the case when the first three costs are
242 // defined as active
243 ✗ model.changeCostStatus("random_cost_3", false);
244 ✗ model.changeCostStatus("random_cost_4", false);
245 ✗ const Eigen::VectorXd x2 = state->rand();
246 ✗ const Eigen::VectorXd u2 = Eigen::VectorXd::Random(model.get_nu());
247 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
248 x1);
249 ✗ model.calc(data, x2, u2);
250 ✗ cost = 0;
251 ✗ for (std::size_t i = 0; i < 3;
252 ++i) { // we need to update data because this costs are active
253 ✗ models[i]->calc(datas[i], x2, u2);
254 ✗ cost += datas[i]->cost;
255 }
256 ✗ BOOST_CHECK(data->cost == cost);
257
258 // Checking that casted computation is the same
259 #ifdef NDEBUG // Run only in release mode
260 model.changeCostStatus("random_cost_3", true);
261 model.changeCostStatus("random_cost_4", true);
262 crocoddyl::CostModelSumTpl<float> casted_model = model.cast<float>();
263 const std::shared_ptr<crocoddyl::StateMultibodyTpl<float>>& casted_state =
264 std::static_pointer_cast<crocoddyl::StateMultibodyTpl<float>>(
265 casted_model.get_state());
266 pinocchio::ModelTpl<float>& casted_pinocchio_model =
267 *casted_state->get_pinocchio().get();
268 pinocchio::DataTpl<float> casted_pinocchio_data(casted_pinocchio_model);
269 crocoddyl::DataCollectorMultibodyTpl<float> casted_shared_data(
270 &casted_pinocchio_data);
271 std::vector<std::shared_ptr<crocoddyl::CostModelAbstractTpl<float>>>
272 casted_models;
273 std::vector<std::shared_ptr<crocoddyl::CostDataAbstractTpl<float>>>
274 casted_datas;
275 for (std::size_t i = 0; i < 5; ++i) {
276 casted_models.push_back(models[i]->cast<float>());
277 casted_datas.push_back(casted_models[i]->createData(&casted_shared_data));
278 }
279 const std::shared_ptr<crocoddyl::CostDataSumTpl<float>>& casted_data =
280 casted_model.createData(&casted_shared_data);
281 const Eigen::VectorXf x1_f = x1.cast<float>();
282 const Eigen::VectorXf u1_f = u1.cast<float>();
283 crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
284 x1);
285 crocoddyl::unittest::updateAllPinocchio(&casted_pinocchio_model,
286 &casted_pinocchio_data, x1_f);
287 model.calc(data, x1, u1);
288 casted_model.calc(casted_data, x1_f, u1_f);
289 BOOST_CHECK(casted_data->cost > 0.f);
290 float tol_f = std::sqrt(2.0f * std::numeric_limits<float>::epsilon());
291 BOOST_CHECK(std::abs(float(data->cost) - casted_data->cost) <= tol_f);
292 float cost_f = 0.f;
293 for (std::size_t i = 0; i < 5; ++i) {
294 casted_models[i]->calc(casted_datas[i], x1_f, u1_f);
295 cost_f += casted_datas[i]->cost;
296 }
297 BOOST_CHECK(casted_data->cost == cost_f);
298 #endif
299 ✗ }
300
301 ✗ void test_calcDiff(StateModelTypes::Type state_type) {
302 // setup the test
303 ✗ StateModelFactory state_factory;
304 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
305 // create the corresponding data object
306 const std::shared_ptr<crocoddyl::StateMultibody>& state =
307 ✗ std::static_pointer_cast<crocoddyl::StateMultibody>(model.get_state());
308 ✗ pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
309 ✗ pinocchio::Data pinocchio_data(pinocchio_model);
310 ✗ crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
311
312 // create and add some cost objects
313 ✗ std::vector<std::shared_ptr<crocoddyl::CostModelAbstract>> models;
314 ✗ std::vector<std::shared_ptr<crocoddyl::CostDataAbstract>> datas;
315 ✗ for (std::size_t i = 0; i < 5; ++i) {
316 ✗ std::ostringstream os;
317 ✗ os << "random_cost_" << i;
318 const std::shared_ptr<crocoddyl::CostModelAbstract>& m =
319 ✗ create_random_cost(state_type);
320 ✗ model.addCost(os.str(), m, 1.);
321 ✗ models.push_back(m);
322 ✗ datas.push_back(m->createData(&shared_data));
323 ✗ }
324
325 // create the data of the cost sum
326 const std::shared_ptr<crocoddyl::CostDataSum>& data =
327 ✗ model.createData(&shared_data);
328
329 // compute the cost sum data for the case when all costs are defined as active
330 ✗ Eigen::VectorXd x1 = state->rand();
331 ✗ const Eigen::VectorXd u1 = Eigen::VectorXd::Random(model.get_nu());
332 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
333 x1);
334 ✗ model.calc(data, x1, u1);
335 ✗ model.calcDiff(data, x1, u1);
336
337 // check that the cost has been filled
338 ✗ BOOST_CHECK(data->cost > 0.);
339
340 // check the cost against single cost computations
341 ✗ double cost = 0;
342 ✗ Eigen::VectorXd Lx = Eigen::VectorXd::Zero(state->get_ndx());
343 ✗ Eigen::VectorXd Lu = Eigen::VectorXd::Zero(model.get_nu());
344 Eigen::MatrixXd Lxx =
345 ✗ Eigen::MatrixXd::Zero(state->get_ndx(), state->get_ndx());
346 ✗ Eigen::MatrixXd Lxu = Eigen::MatrixXd::Zero(state->get_ndx(), model.get_nu());
347 ✗ Eigen::MatrixXd Luu = Eigen::MatrixXd::Zero(model.get_nu(), model.get_nu());
348 ✗ for (std::size_t i = 0; i < 5; ++i) {
349 ✗ models[i]->calc(datas[i], x1, u1);
350 ✗ models[i]->calcDiff(datas[i], x1, u1);
351 ✗ cost += datas[i]->cost;
352 ✗ Lx += datas[i]->Lx;
353 ✗ Lu += datas[i]->Lu;
354 ✗ Lxx += datas[i]->Lxx;
355 ✗ Lxu += datas[i]->Lxu;
356 ✗ Luu += datas[i]->Luu;
357 }
358 ✗ BOOST_CHECK(data->cost == cost);
359 ✗ BOOST_CHECK(data->Lx == Lx);
360 ✗ BOOST_CHECK(data->Lu == Lu);
361 ✗ BOOST_CHECK(data->Lxx == Lxx);
362 ✗ BOOST_CHECK(data->Lxu == Lxu);
363 ✗ BOOST_CHECK(data->Luu == Luu);
364
365 ✗ x1 = state->rand();
366 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
367 x1);
368 ✗ model.calc(data, x1);
369 ✗ model.calcDiff(data, x1);
370 ✗ cost = 0.;
371 ✗ Lx.setZero();
372 ✗ Lxx.setZero();
373 ✗ for (std::size_t i = 0; i < 5; ++i) {
374 ✗ models[i]->calc(datas[i], x1);
375 ✗ models[i]->calcDiff(datas[i], x1);
376 ✗ cost += datas[i]->cost;
377 ✗ Lx += datas[i]->Lx;
378 ✗ Lxx += datas[i]->Lxx;
379 }
380 ✗ BOOST_CHECK(data->cost == cost);
381 ✗ BOOST_CHECK(data->Lx == Lx);
382 ✗ BOOST_CHECK(data->Lxx == Lxx);
383
384 // compute the cost sum data for the case when the first three costs are
385 // defined as active
386 ✗ model.changeCostStatus("random_cost_3", false);
387 ✗ model.changeCostStatus("random_cost_4", false);
388 ✗ Eigen::VectorXd x2 = state->rand();
389 ✗ const Eigen::VectorXd u2 = Eigen::VectorXd::Random(model.get_nu());
390 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
391 x2);
392 ✗ model.calc(data, x2, u2);
393 ✗ model.calcDiff(data, x2, u2);
394 ✗ cost = 0;
395 ✗ Lx.setZero();
396 ✗ Lu.setZero();
397 ✗ Lxx.setZero();
398 ✗ Lxu.setZero();
399 ✗ Luu.setZero();
400 ✗ for (std::size_t i = 0; i < 3;
401 ++i) { // we need to update data because this costs are active
402 ✗ models[i]->calc(datas[i], x2, u2);
403 ✗ models[i]->calcDiff(datas[i], x2, u2);
404 ✗ cost += datas[i]->cost;
405 ✗ Lx += datas[i]->Lx;
406 ✗ Lu += datas[i]->Lu;
407 ✗ Lxx += datas[i]->Lxx;
408 ✗ Lxu += datas[i]->Lxu;
409 ✗ Luu += datas[i]->Luu;
410 }
411 ✗ BOOST_CHECK(data->cost == cost);
412 ✗ BOOST_CHECK(data->Lx == Lx);
413 ✗ BOOST_CHECK(data->Lu == Lu);
414 ✗ BOOST_CHECK(data->Lxx == Lxx);
415 ✗ BOOST_CHECK(data->Lxu == Lxu);
416 ✗ BOOST_CHECK(data->Luu == Luu);
417
418 ✗ x2 = state->rand();
419 ✗ crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
420 x2);
421 ✗ model.calc(data, x2);
422 ✗ model.calcDiff(data, x2);
423 ✗ cost = 0.;
424 ✗ Lx.setZero();
425 ✗ Lxx.setZero();
426 ✗ for (std::size_t i = 0; i < 3; ++i) {
427 ✗ models[i]->calc(datas[i], x2);
428 ✗ models[i]->calcDiff(datas[i], x2);
429 ✗ cost += datas[i]->cost;
430 ✗ Lx += datas[i]->Lx;
431 ✗ Lxx += datas[i]->Lxx;
432 }
433 ✗ BOOST_CHECK(data->cost == cost);
434 ✗ BOOST_CHECK(data->Lx == Lx);
435 ✗ BOOST_CHECK(data->Lxx == Lxx);
436
437 // Checking that casted computation is the same
438 #ifdef NDEBUG // Run only in release mode
439 model.changeCostStatus("random_cost_3", true);
440 model.changeCostStatus("random_cost_4", true);
441 crocoddyl::CostModelSumTpl<float> casted_model = model.cast<float>();
442 const std::shared_ptr<crocoddyl::StateMultibodyTpl<float>>& casted_state =
443 std::static_pointer_cast<crocoddyl::StateMultibodyTpl<float>>(
444 casted_model.get_state());
445 pinocchio::ModelTpl<float>& casted_pinocchio_model =
446 *casted_state->get_pinocchio().get();
447 pinocchio::DataTpl<float> casted_pinocchio_data(casted_pinocchio_model);
448 crocoddyl::DataCollectorMultibodyTpl<float> casted_shared_data(
449 &casted_pinocchio_data);
450 std::vector<std::shared_ptr<crocoddyl::CostModelAbstractTpl<float>>>
451 casted_models;
452 std::vector<std::shared_ptr<crocoddyl::CostDataAbstractTpl<float>>>
453 casted_datas;
454 for (std::size_t i = 0; i < 5; ++i) {
455 casted_models.push_back(models[i]->cast<float>());
456 casted_datas.push_back(casted_models[i]->createData(&casted_shared_data));
457 }
458 const std::shared_ptr<crocoddyl::CostDataSumTpl<float>>& casted_data =
459 casted_model.createData(&casted_shared_data);
460 const Eigen::VectorXf x1_f = x1.cast<float>();
461 const Eigen::VectorXf u1_f = u1.cast<float>();
462 crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data,
463 x1);
464 crocoddyl::unittest::updateAllPinocchio(&casted_pinocchio_model,
465 &casted_pinocchio_data, x1_f);
466 model.calc(data, x1, u1);
467 model.calcDiff(data, x1, u1);
468 casted_model.calc(casted_data, x1_f, u1_f);
469 casted_model.calcDiff(casted_data, x1_f, u1_f);
470 Lx.setZero();
471 Lu.setZero();
472 Lxx.setZero();
473 Lxu.setZero();
474 Luu.setZero();
475 float cost_f = 0.f;
476 Eigen::VectorXf Lx_f = Lx.cast<float>();
477 Eigen::VectorXf Lu_f = Lu.cast<float>();
478 Eigen::MatrixXf Lxx_f = Lxx.cast<float>();
479 Eigen::MatrixXf Lxu_f = Lxu.cast<float>();
480 Eigen::MatrixXf Luu_f = Luu.cast<float>();
481 for (std::size_t i = 0; i < 5;
482 ++i) { // we need to update data because this costs are active
483 casted_models[i]->calc(casted_datas[i], x1_f, u1_f);
484 casted_models[i]->calcDiff(casted_datas[i], x1_f, u1_f);
485 cost_f += casted_datas[i]->cost;
486 Lx_f += casted_datas[i]->Lx;
487 Lu_f += casted_datas[i]->Lu;
488 Lxx_f += casted_datas[i]->Lxx;
489 Lxu_f += casted_datas[i]->Lxu;
490 Luu_f += casted_datas[i]->Luu;
491 }
492 BOOST_CHECK(casted_data->cost == cost_f);
493 BOOST_CHECK(casted_data->Lx == Lx_f);
494 BOOST_CHECK(casted_data->Lu == Lu_f);
495 BOOST_CHECK(casted_data->Lxx == Lxx_f);
496 BOOST_CHECK(casted_data->Lxu == Lxu_f);
497 BOOST_CHECK(casted_data->Luu == Luu_f);
498 #endif
499 ✗ }
500
501 ✗ void test_get_costs(StateModelTypes::Type state_type) {
502 // setup the test
503 ✗ StateModelFactory state_factory;
504 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
505 // create the corresponding data object
506 const std::shared_ptr<crocoddyl::StateMultibody>& state =
507 ✗ std::static_pointer_cast<crocoddyl::StateMultibody>(model.get_state());
508 ✗ pinocchio::Data pinocchio_data(*state->get_pinocchio().get());
509
510 // create and add some contact objects
511 ✗ for (unsigned i = 0; i < 5; ++i) {
512 ✗ std::ostringstream os;
513 ✗ os << "random_cost_" << i;
514 ✗ model.addCost(os.str(), create_random_cost(state_type), 1.);
515 ✗ }
516
517 // get the contacts
518 ✗ const crocoddyl::CostModelSum::CostModelContainer& costs = model.get_costs();
519
520 // test
521 ✗ crocoddyl::CostModelSum::CostModelContainer::const_iterator it_m, end_m;
522 unsigned i;
523 ✗ for (i = 0, it_m = costs.begin(), end_m = costs.end(); it_m != end_m;
524 ✗ ++it_m, ++i) {
525 ✗ std::ostringstream os;
526 ✗ os << "random_cost_" << i;
527 ✗ BOOST_CHECK(it_m->first == os.str());
528 ✗ }
529 ✗ }
530
531 ✗ void test_get_nr(StateModelTypes::Type state_type) {
532 // Setup the test
533 ✗ StateModelFactory state_factory;
534 ✗ crocoddyl::CostModelSum model(state_factory.create(state_type));
535
536 // create the corresponding data object
537 const std::shared_ptr<crocoddyl::StateMultibody>& state =
538 ✗ std::static_pointer_cast<crocoddyl::StateMultibody>(model.get_state());
539 ✗ pinocchio::Data pinocchio_data(*state->get_pinocchio().get());
540
541 // create and add some contact objects
542 ✗ for (unsigned i = 0; i < 5; ++i) {
543 ✗ std::ostringstream os;
544 ✗ os << "random_cost_" << i;
545 ✗ model.addCost(os.str(), create_random_cost(state_type), 1.);
546 ✗ }
547
548 // compute ni
549 ✗ std::size_t nr = 0;
550 ✗ crocoddyl::CostModelSum::CostModelContainer::const_iterator it_m, end_m;
551 ✗ for (it_m = model.get_costs().begin(), end_m = model.get_costs().end();
552 ✗ it_m != end_m; ++it_m) {
553 ✗ nr += it_m->second->cost->get_activation()->get_nr();
554 }
555
556 ✗ BOOST_CHECK(nr == model.get_nr());
557 ✗ }
558
559 ✗ void test_shareMemory(StateModelTypes::Type state_type) {
560 // setup the test
561 ✗ StateModelFactory state_factory;
562 const std::shared_ptr<crocoddyl::StateAbstract> state =
563 ✗ state_factory.create(state_type);
564 ✗ crocoddyl::CostModelSum cost_model(state);
565 ✗ crocoddyl::DataCollectorAbstract shared_data;
566 const std::shared_ptr<crocoddyl::CostDataSum>& cost_data =
567 ✗ cost_model.createData(&shared_data);
568
569 ✗ const std::size_t ndx = state->get_ndx();
570 ✗ const std::size_t nu = cost_model.get_nu();
571 ✗ crocoddyl::ActionModelLQR action_model(ndx, nu);
572 const std::shared_ptr<crocoddyl::ActionDataAbstract>& action_data =
573 ✗ action_model.createData();
574
575 ✗ cost_data->shareMemory(action_data.get());
576 ✗ cost_data->Lx = Eigen::VectorXd::Random(ndx);
577 ✗ cost_data->Lu = Eigen::VectorXd::Random(nu);
578 ✗ cost_data->Lxx = Eigen::MatrixXd::Random(ndx, ndx);
579 ✗ cost_data->Luu = Eigen::MatrixXd::Random(nu, nu);
580 ✗ cost_data->Lxu = Eigen::MatrixXd::Random(ndx, nu);
581
582 // check that the data has been shared
583 ✗ BOOST_CHECK(action_data->Lx.isApprox(cost_data->Lx, 1e-9));
584 ✗ BOOST_CHECK(action_data->Lu.isApprox(cost_data->Lu, 1e-9));
585 ✗ BOOST_CHECK(action_data->Lxx.isApprox(cost_data->Lxx, 1e-9));
586 ✗ BOOST_CHECK(action_data->Luu.isApprox(cost_data->Luu, 1e-9));
587 ✗ BOOST_CHECK(action_data->Lxu.isApprox(cost_data->Lxu, 1e-9));
588 ✗ }
589
590 //----------------------------------------------------------------------------//
591
592 ✗ void register_unit_tests(StateModelTypes::Type state_type) {
593 ✗ boost::test_tools::output_test_stream test_name;
594 test_name << "test_CostModelSum"
595 ✗ << "_" << state_type;
596 ✗ std::cout << "Running " << test_name.str() << std::endl;
597 ✗ test_suite* ts = BOOST_TEST_SUITE(test_name.str());
598 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_constructor, state_type)));
599 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_addCost, state_type)));
600 ✗ ts->add(
601 ✗ BOOST_TEST_CASE(boost::bind(&test_addCost_error_message, state_type)));
602 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_removeCost, state_type)));
603 ✗ ts->add(
604 ✗ BOOST_TEST_CASE(boost::bind(&test_removeCost_error_message, state_type)));
605 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_calc, state_type)));
606 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_calcDiff, state_type)));
607 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_get_costs, state_type)));
608 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_get_nr, state_type)));
609 ✗ ts->add(BOOST_TEST_CASE(boost::bind(&test_shareMemory, state_type)));
610 ✗ framework::master_test_suite().add(ts);
611 ✗ }
612
613 ✗ bool init_function() {
614 ✗ register_unit_tests(StateModelTypes::StateMultibody_TalosArm);
615 ✗ register_unit_tests(StateModelTypes::StateMultibody_HyQ);
616 ✗ register_unit_tests(StateModelTypes::StateMultibody_Talos);
617 ✗ return true;
618 }
619
620 ✗ int main(int argc, char** argv) {
621 ✗ return ::boost::unit_test::unit_test_main(&init_function, argc, argv);
622 }
623