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