GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/test_costs_collision.cpp Lines: 124 127 97.6 %
Date: 2024-02-13 11:12:33 Branches: 269 578 46.5 %

Line Branch Exec Source
1
///////////////////////////////////////////////////////////////////////////////
2
// BSD 3-Clause License
3
//
4
// Copyright (C) 2021-2023, LAAS-CNRS, University of Edinburgh
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
#ifdef PINOCCHIO_WITH_HPP_FCL
13
14
#include "crocoddyl/multibody/data/multibody.hpp"
15
#include "factory/cost.hpp"
16
#include "unittest_common.hpp"
17
18
using namespace boost::unit_test;
19
using namespace crocoddyl::unittest;
20
21
//----------------------------------------------------------------------------//
22
23
2
void test_calc_returns_a_cost(CostModelCollisionTypes::Type cost_type,
24
                              StateModelTypes::Type state_type) {
25
  // create the model
26
4
  CostModelFactory factory;
27
  const boost::shared_ptr<crocoddyl::CostModelAbstract>& model =
28
4
      factory.create(cost_type, state_type);
29
30
  // Run the print function
31
4
  std::ostringstream tmp;
32
2
  tmp << *model;
33
34
  // create the corresponding data object
35
  const boost::shared_ptr<crocoddyl::StateMultibody>& state =
36
4
      boost::static_pointer_cast<crocoddyl::StateMultibody>(model->get_state());
37
2
  pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
38
4
  pinocchio::Data pinocchio_data(pinocchio_model);
39
4
  crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
40
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data =
41
4
      model->createData(&shared_data);
42
2
  data->cost = nan("");
43
44
  // Generating random values for the state and control
45
4
  const Eigen::VectorXd x = model->get_state()->rand();
46

4
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
47
48
  // Compute all the pinocchio function needed for the models.
49

2
  crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x);
50
51
  // Getting the cost value computed by calc()
52

2
  model->calc(data, x, u);
53
54
  // Checking that calc returns a cost value
55



2
  BOOST_CHECK(!std::isnan(data->cost));
56
2
}
57
58
2
void test_calc_against_numdiff(CostModelCollisionTypes::Type cost_type,
59
                               StateModelTypes::Type state_type) {
60
  // create the model
61
4
  CostModelFactory factory;
62
  const boost::shared_ptr<crocoddyl::CostModelAbstract>& model =
63
4
      factory.create(cost_type, state_type);
64
65
  // create the corresponding data object
66
  const boost::shared_ptr<crocoddyl::StateMultibody>& state =
67
4
      boost::static_pointer_cast<crocoddyl::StateMultibody>(model->get_state());
68
2
  pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
69
4
  pinocchio::Data pinocchio_data(pinocchio_model);
70
4
  crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
71
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data =
72
4
      model->createData(&shared_data);
73
74
  // Create the equivalent num diff model and data.
75
4
  crocoddyl::CostModelNumDiff model_num_diff(model);
76
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data_num_diff =
77
4
      model_num_diff.createData(&shared_data);
78
79
  // Generating random values for the state and control
80
4
  const Eigen::VectorXd x = model->get_state()->rand();
81

4
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
82
83
  // Compute all the pinocchio function needed for the models.
84

2
  crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x);
85
86
  // Computing the cost derivatives
87

2
  model->calc(data, x, u);
88

2
  model_num_diff.calc(data_num_diff, x, u);
89
90
  // Checking the partial derivatives against NumDiff
91



2
  BOOST_CHECK(data->cost == data_num_diff->cost);
92
2
}
93
94
2
void test_partial_derivatives_against_numdiff(
95
    CostModelCollisionTypes::Type cost_type, StateModelTypes::Type state_type) {
96
  using namespace boost::placeholders;
97
98
  // create the model
99
4
  CostModelFactory factory;
100
  const boost::shared_ptr<crocoddyl::CostModelAbstract>& model =
101
4
      factory.create(cost_type, state_type);
102
103
  // create the corresponding data object
104
  const boost::shared_ptr<crocoddyl::StateMultibody>& state =
105
4
      boost::static_pointer_cast<crocoddyl::StateMultibody>(model->get_state());
106
2
  pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
107
4
  pinocchio::Data pinocchio_data(pinocchio_model);
108
4
  crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
109
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data =
110
4
      model->createData(&shared_data);
111
112
  // Create the equivalent num diff model and data.
113
4
  crocoddyl::CostModelNumDiff model_num_diff(model);
114
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data_num_diff =
115
4
      model_num_diff.createData(&shared_data);
116
117
  // Generating random values for the state and control
118
4
  const Eigen::VectorXd x = model->get_state()->rand();
119

4
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
120
121
  // Compute all the pinocchio function needed for the models.
122

2
  crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x);
123
124
  // set the function that needs to be called at every step of the numdiff
125
4
  std::vector<crocoddyl::CostModelNumDiff::ReevaluationFunction> reevals;
126

2
  reevals.push_back(boost::bind(&crocoddyl::unittest::updateAllPinocchio,
127
                                &pinocchio_model, &pinocchio_data, _1, _2));
128
2
  model_num_diff.set_reevals(reevals);
129
130
  // Computing the cost derivatives
131

2
  model->calc(data, x, u);
132

2
  model->calcDiff(data, x, u);
133

2
  model_num_diff.calc(data_num_diff, x, u);
134

2
  model_num_diff.calcDiff(data_num_diff, x, u);
135
  // Tolerance defined as in
136
  // http://www.it.uom.gr/teaching/linearalgebra/NumericalRecipiesInC/c5-7.pdf
137
2
  double tol = std::pow(model_num_diff.get_disturbance(), 1. / 3.);
138




2
  BOOST_CHECK((data->Lx - data_num_diff->Lx).isZero(tol));
139




2
  BOOST_CHECK((data->Lu - data_num_diff->Lu).isZero(tol));
140

2
  if (model_num_diff.get_with_gauss_approx()) {
141
    // The num diff is not precise enough to be tested here.
142




2
    BOOST_CHECK((data->Lxx - data_num_diff->Lxx).isZero(tol));
143




2
    BOOST_CHECK((data->Lxu - data_num_diff->Lxu).isZero(tol));
144




2
    BOOST_CHECK((data->Luu - data_num_diff->Luu).isZero(tol));
145
  } else {
146
    BOOST_CHECK((data_num_diff->Lxx).isZero(tol));
147
    BOOST_CHECK((data_num_diff->Lxu).isZero(tol));
148
    BOOST_CHECK((data_num_diff->Luu).isZero(tol));
149
  }
150
2
}
151
152
2
void test_dimensions_in_cost_sum(CostModelCollisionTypes::Type cost_type,
153
                                 StateModelTypes::Type state_type) {
154
  // create the model
155
4
  CostModelFactory factory;
156
  const boost::shared_ptr<crocoddyl::CostModelAbstract>& model =
157
4
      factory.create(cost_type, state_type);
158
159
  // create the corresponding data object
160
  const boost::shared_ptr<crocoddyl::StateMultibody>& state =
161
4
      boost::static_pointer_cast<crocoddyl::StateMultibody>(model->get_state());
162
2
  pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
163
4
  pinocchio::Data pinocchio_data(pinocchio_model);
164
4
  crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
165
166
  // create the cost sum model
167
4
  crocoddyl::CostModelSum cost_sum(state, model->get_nu());
168

2
  cost_sum.addCost("myCost", model, 1.);
169
170
  // Generating random values for the state and control
171
4
  const Eigen::VectorXd x = state->rand();
172
173
  // Compute all the pinocchio function needed for the models.
174

2
  crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x);
175
176



2
  BOOST_CHECK(model->get_state()->get_nx() == cost_sum.get_state()->get_nx());
177



2
  BOOST_CHECK(model->get_state()->get_ndx() == cost_sum.get_state()->get_ndx());
178



2
  BOOST_CHECK(model->get_nu() == cost_sum.get_nu());
179



2
  BOOST_CHECK(model->get_state()->get_nq() == cost_sum.get_state()->get_nq());
180



2
  BOOST_CHECK(model->get_state()->get_nv() == cost_sum.get_state()->get_nv());
181



2
  BOOST_CHECK(model->get_activation()->get_nr() == cost_sum.get_nr());
182
2
}
183
184
2
void test_partial_derivatives_in_cost_sum(
185
    CostModelCollisionTypes::Type cost_type, StateModelTypes::Type state_type) {
186
  // create the model
187
4
  CostModelFactory factory;
188
  const boost::shared_ptr<crocoddyl::CostModelAbstract>& model =
189
4
      factory.create(cost_type, state_type);
190
191
  // create the corresponding data object
192
  const boost::shared_ptr<crocoddyl::StateMultibody>& state =
193
4
      boost::static_pointer_cast<crocoddyl::StateMultibody>(model->get_state());
194
2
  pinocchio::Model& pinocchio_model = *state->get_pinocchio().get();
195
4
  pinocchio::Data pinocchio_data(pinocchio_model);
196
4
  crocoddyl::DataCollectorMultibody shared_data(&pinocchio_data);
197
  const boost::shared_ptr<crocoddyl::CostDataAbstract>& data =
198
4
      model->createData(&shared_data);
199
200
  // create the cost sum model
201
4
  crocoddyl::CostModelSum cost_sum(state, model->get_nu());
202

2
  cost_sum.addCost("myCost", model, 1.);
203
  const boost::shared_ptr<crocoddyl::CostDataSum>& data_sum =
204
4
      cost_sum.createData(&shared_data);
205
206
  // Generating random values for the state and control
207
4
  const Eigen::VectorXd x = state->rand();
208

4
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
209
210
  // Compute all the pinocchio function needed for the models.
211

2
  crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x);
212
213
  // Computing the cost derivatives
214

2
  model->calc(data, x, u);
215

2
  model->calcDiff(data, x, u);
216

2
  cost_sum.calc(data_sum, x, u);
217

2
  cost_sum.calcDiff(data_sum, x, u);
218
219




2
  BOOST_CHECK((data->Lx - data_sum->Lx).isZero());
220




2
  BOOST_CHECK((data->Lu - data_sum->Lu).isZero());
221




2
  BOOST_CHECK((data->Lxx - data_sum->Lxx).isZero());
222




2
  BOOST_CHECK((data->Lxu - data_sum->Lxu).isZero());
223




2
  BOOST_CHECK((data->Luu - data_sum->Luu).isZero());
224
2
}
225
226
//----------------------------------------------------------------------------//
227
228
2
void register_cost_model_unit_tests(CostModelCollisionTypes::Type cost_type,
229
                                    StateModelTypes::Type state_type) {
230

4
  boost::test_tools::output_test_stream test_name;
231


2
  test_name << "test_" << cost_type << "_2norm_barrier_" << state_type;
232


2
  std::cout << "Running " << test_name.str() << std::endl;
233


2
  test_suite* ts = BOOST_TEST_SUITE(test_name.str());
234


2
  ts->add(BOOST_TEST_CASE(
235
      boost::bind(&test_calc_returns_a_cost, cost_type, state_type)));
236


2
  ts->add(BOOST_TEST_CASE(
237
      boost::bind(&test_calc_against_numdiff, cost_type, state_type)));
238


2
  ts->add(BOOST_TEST_CASE(boost::bind(&test_partial_derivatives_against_numdiff,
239
                                      cost_type, state_type)));
240


2
  ts->add(BOOST_TEST_CASE(
241
      boost::bind(&test_dimensions_in_cost_sum, cost_type, state_type)));
242


2
  ts->add(BOOST_TEST_CASE(boost::bind(&test_partial_derivatives_in_cost_sum,
243
                                      cost_type, state_type)));
244

2
  framework::master_test_suite().add(ts);
245
2
}
246
247
1
bool init_function() {
248
  // Test all costs available with all the activation types with all available
249
  // states types.
250
2
  for (size_t cost_type = 0; cost_type < CostModelCollisionTypes::all.size();
251
       ++cost_type) {
252
1
    register_cost_model_unit_tests(CostModelCollisionTypes::all[cost_type],
253
                                   StateModelTypes::StateMultibody_HyQ);
254
1
    register_cost_model_unit_tests(
255
1
        CostModelCollisionTypes::all[cost_type],
256
        StateModelTypes::StateMultibody_RandomHumanoid);
257
  }
258
1
  return true;
259
}
260
261
1
int main(int argc, char** argv) {
262
1
  return ::boost::unit_test::unit_test_main(&init_function, argc, argv);
263
}
264
265
#else
266
267
int main(int, char**) {}
268
269
#endif  // PINOCCHIO_WITH_HPP_FCL