GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/test_actions.cpp Lines: 175 179 97.8 %
Date: 2024-02-13 11:12:33 Branches: 322 702 45.9 %

Line Branch Exec Source
1
///////////////////////////////////////////////////////////////////////////////
2
// BSD 3-Clause License
3
//
4
// Copyright (C) 2019-2023, LAAS-CNRS, New York University, Max Planck
5
// Gesellschaft
6
//                          University of Edinburgh, INRIA
7
// Copyright note valid unless otherwise stated in individual files.
8
// All rights reserved.
9
///////////////////////////////////////////////////////////////////////////////
10
11
#define BOOST_TEST_NO_MAIN
12
#define BOOST_TEST_ALTERNATIVE_INIT_API
13
14
#include "factory/action.hpp"
15
#include "factory/control.hpp"
16
#include "factory/diff_action.hpp"
17
#include "factory/integrator.hpp"
18
#include "unittest_common.hpp"
19
20
using namespace boost::unit_test;
21
using namespace crocoddyl::unittest;
22
23
//----------------------------------------------------------------------------//
24
25
203
void test_check_data(
26
    const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model) {
27
  // Run the print function
28
406
  std::ostringstream tmp;
29
203
  tmp << *model;
30
31
  // create the corresponding data object
32
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data =
33
406
      model->createData();
34



203
  BOOST_CHECK(model->checkData(data));
35
203
}
36
37
203
void test_calc(const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model) {
38
  // create the corresponding data object
39
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data =
40
406
      model->createData();
41
203
  data->cost = nan("");
42
43
  // Generating random state and control vectors
44
406
  const Eigen::VectorXd x = model->get_state()->rand();
45

406
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
46
47
  // Getting the state dimension from calc() call
48

203
  model->calc(data, x, u);
49



203
  BOOST_CHECK(static_cast<std::size_t>(data->xnext.size()) ==
50
              model->get_state()->get_nx());
51
52
  // Checking that calc returns a cost value
53



203
  BOOST_CHECK(!std::isnan(data->cost));
54
55
  // Checking the termninal state
56
203
  double tol = std::sqrt(2.0 * std::numeric_limits<double>::epsilon());
57

203
  model->calc(data, x);
58




203
  BOOST_CHECK((data->xnext - x).head(model->get_state()->get_nq()).isZero(tol));
59
203
}
60
61
203
void test_partial_derivatives_against_numdiff(
62
    const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model) {
63
  // create the corresponding data object and set the cost to nan
64
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data =
65
406
      model->createData();
66
67
406
  crocoddyl::ActionModelNumDiff model_num_diff(model);
68
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data_num_diff =
69
406
      model_num_diff.createData();
70
71
  // Generating random values for the state and control
72
406
  Eigen::VectorXd x = model->get_state()->rand();
73

406
  const Eigen::VectorXd u = Eigen::VectorXd::Random(model->get_nu());
74
75
  // Computing the action derivatives
76

203
  model->calc(data, x, u);
77

203
  model->calcDiff(data, x, u);
78

203
  model_num_diff.calc(data_num_diff, x, u);
79

203
  model_num_diff.calcDiff(data_num_diff, x, u);
80
  // Tolerance defined as in
81
  // http://www.it.uom.gr/teaching/linearalgebra/NumericalRecipiesInC/c5-7.pdf
82
203
  double tol = std::pow(model_num_diff.get_disturbance(), 1. / 3.);
83




203
  BOOST_CHECK((data->Fx - data_num_diff->Fx).isZero(tol));
84




203
  BOOST_CHECK((data->Fu - data_num_diff->Fu).isZero(tol));
85




203
  BOOST_CHECK((data->Lx - data_num_diff->Lx).isZero(tol));
86




203
  BOOST_CHECK((data->Lu - data_num_diff->Lu).isZero(tol));
87
203
  if (model_num_diff.get_with_gauss_approx()) {
88
    BOOST_CHECK((data->Lxx - data_num_diff->Lxx).isZero(tol));
89
    BOOST_CHECK((data->Lxu - data_num_diff->Lxu).isZero(tol));
90
    BOOST_CHECK((data->Luu - data_num_diff->Luu).isZero(tol));
91
  }
92




203
  BOOST_CHECK((data->Hx - data_num_diff->Hx).isZero(tol));
93




203
  BOOST_CHECK((data->Hu - data_num_diff->Hu).isZero(tol));
94




203
  BOOST_CHECK((data->Gx - data_num_diff->Gx).isZero(tol));
95




203
  BOOST_CHECK((data->Gu - data_num_diff->Gu).isZero(tol));
96
97
  // Computing the action derivatives
98
203
  x = model->get_state()->rand();
99

203
  model->calc(data, x);
100

203
  model->calcDiff(data, x);
101

203
  model_num_diff.calc(data_num_diff, x);
102

203
  model_num_diff.calcDiff(data_num_diff, x);
103




203
  BOOST_CHECK((data->Lx - data_num_diff->Lx).isZero(tol));
104
203
  if (model_num_diff.get_with_gauss_approx()) {
105
    BOOST_CHECK((data->Lxx - data_num_diff->Lxx).isZero(tol));
106
  }
107




203
  BOOST_CHECK((data->Hx - data_num_diff->Hx).isZero(tol));
108




203
  BOOST_CHECK((data->Gx - data_num_diff->Gx).isZero(tol));
109
203
}
110
111
5
void test_check_action_data(ActionModelTypes::Type action_model_type) {
112
  // create the model
113
10
  ActionModelFactory factory;
114
  const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model =
115
10
      factory.create(action_model_type);
116
5
  test_check_data(model);
117
5
}
118
119
198
void test_check_integrated_action_data(
120
    DifferentialActionModelTypes::Type dam_type,
121
    IntegratorTypes::Type integrator_type, ControlTypes::Type control_type) {
122
  // create the differential action model
123
396
  DifferentialActionModelFactory factory_dam;
124
  const boost::shared_ptr<crocoddyl::DifferentialActionModelAbstract>& dam =
125
396
      factory_dam.create(dam_type);
126
  // create the control discretization
127
396
  ControlFactory factory_ctrl;
128
  const boost::shared_ptr<crocoddyl::ControlParametrizationModelAbstract>&
129
396
      ctrl = factory_ctrl.create(control_type, dam->get_nu());
130
  // create the integrator
131
396
  IntegratorFactory factory_int;
132
  const boost::shared_ptr<crocoddyl::IntegratedActionModelAbstract>& model =
133
198
      factory_int.create(integrator_type, dam, ctrl);
134
198
  test_check_data(model);
135
198
}
136
137
5
void test_calc_action_model(ActionModelTypes::Type action_model_type) {
138
  // create the model
139
10
  ActionModelFactory factory;
140
  const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model =
141
10
      factory.create(action_model_type);
142
5
  test_calc(model);
143
5
}
144
145
198
void test_calc_integrated_action_model(
146
    DifferentialActionModelTypes::Type dam_type,
147
    IntegratorTypes::Type integrator_type, ControlTypes::Type control_type) {
148
  // create the differential action model
149
396
  DifferentialActionModelFactory factory_dam;
150
  const boost::shared_ptr<crocoddyl::DifferentialActionModelAbstract>& dam =
151
396
      factory_dam.create(dam_type);
152
  // create the control discretization
153
396
  ControlFactory factory_ctrl;
154
  const boost::shared_ptr<crocoddyl::ControlParametrizationModelAbstract>&
155
396
      ctrl = factory_ctrl.create(control_type, dam->get_nu());
156
  // create the integrator
157
396
  IntegratorFactory factory_int;
158
  const boost::shared_ptr<crocoddyl::IntegratedActionModelAbstract>& model =
159
198
      factory_int.create(integrator_type, dam, ctrl);
160
198
  test_calc(model);
161
198
}
162
163
5
void test_partial_derivatives_action_model(
164
    ActionModelTypes::Type action_model_type) {
165
  // create the model
166
10
  ActionModelFactory factory;
167
  const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model =
168
10
      factory.create(action_model_type);
169
5
  test_partial_derivatives_against_numdiff(model);
170
5
}
171
172
198
void test_partial_derivatives_integrated_action_model(
173
    DifferentialActionModelTypes::Type dam_type,
174
    IntegratorTypes::Type integrator_type, ControlTypes::Type control_type) {
175
  // create the differential action model
176
396
  DifferentialActionModelFactory factory_dam;
177
  const boost::shared_ptr<crocoddyl::DifferentialActionModelAbstract>& dam =
178
396
      factory_dam.create(dam_type);
179
  // create the control discretization
180
396
  ControlFactory factory_ctrl;
181
  const boost::shared_ptr<crocoddyl::ControlParametrizationModelAbstract>&
182
396
      ctrl = factory_ctrl.create(control_type, dam->get_nu());
183
  // create the integrator
184
396
  IntegratorFactory factory_int;
185
  const boost::shared_ptr<crocoddyl::IntegratedActionModelAbstract>& model =
186
198
      factory_int.create(integrator_type, dam, ctrl);
187
198
  test_partial_derivatives_against_numdiff(model);
188
198
}
189
190
/**
191
 * Test two action models that should provide the same result when calling calc
192
 * if the first part of the control input u of model2 is equal to the control
193
 * input of model1. A typical case would be an integrated action model using an
194
 * Euler integration scheme, which can be coupled either with a constant control
195
 * parametrization (model1) or a linear control parametrization (model2), and
196
 * should thus provide the same result as long as the control input at the
197
 * beginning of the step has the same value.
198
 */
199
44
void test_calc_against_calc(
200
    const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model1,
201
    const boost::shared_ptr<crocoddyl::ActionModelAbstract>& model2) {
202
  // create the corresponding data object and set the cost to nan
203
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data1 =
204
88
      model1->createData();
205
  const boost::shared_ptr<crocoddyl::ActionDataAbstract>& data2 =
206
88
      model2->createData();
207
208
  // Generating random values for the state and control
209
88
  const Eigen::VectorXd x = model1->get_state()->rand();
210

88
  Eigen::VectorXd u1 = Eigen::VectorXd::Random(model1->get_nu());
211

88
  Eigen::VectorXd u2 = Eigen::VectorXd::Random(model2->get_nu());
212
  // copy u1 to the first part of u2 (assuming u2 is larger than u1)
213

44
  u2.head(u1.size()) = u1;
214
215
  // Computing the action
216

44
  model1->calc(data1, x, u1);
217

44
  model2->calc(data2, x, u2);
218
219
  // Checking the state and cost integration
220




44
  BOOST_CHECK((data1->xnext - data2->xnext).isZero(1e-9));
221



44
  BOOST_CHECK(abs(data1->cost - data2->cost) < 1e-9);
222
44
}
223
224
44
void register_test_calc_integrated_action_model(
225
    DifferentialActionModelTypes::Type dam_type,
226
    IntegratorTypes::Type integrator_type, ControlTypes::Type control_type1,
227
    ControlTypes::Type control_type2) {
228
  // create the differential action model
229
88
  DifferentialActionModelFactory factory_dam;
230
  const boost::shared_ptr<crocoddyl::DifferentialActionModelAbstract>& dam =
231
88
      factory_dam.create(dam_type);
232
  // create the control discretization
233
88
  ControlFactory factory_ctrl;
234
  const boost::shared_ptr<crocoddyl::ControlParametrizationModelAbstract>&
235
88
      ctrl1 = factory_ctrl.create(control_type1, dam->get_nu());
236
  const boost::shared_ptr<crocoddyl::ControlParametrizationModelAbstract>&
237
88
      ctrl2 = factory_ctrl.create(control_type2, dam->get_nu());
238
  // create the integrator
239
88
  IntegratorFactory factory_int;
240
  const boost::shared_ptr<crocoddyl::IntegratedActionModelAbstract>& model1 =
241
88
      factory_int.create(integrator_type, dam, ctrl1);
242
  const boost::shared_ptr<crocoddyl::IntegratedActionModelAbstract>& model2 =
243
88
      factory_int.create(integrator_type, dam, ctrl2);
244
245

88
  boost::test_tools::output_test_stream test_name;
246

44
  test_name << "test_calc_integrated_action_model_" << dam_type << "_"
247


44
            << integrator_type << "_" << control_type1 << "_" << control_type2;
248


44
  std::cout << "Running " << test_name.str() << std::endl;
249


44
  test_suite* ts = BOOST_TEST_SUITE(test_name.str());
250
44
  ts->add(
251


44
      BOOST_TEST_CASE(boost::bind(&test_calc_against_calc, model1, model2)));
252

44
  framework::master_test_suite().add(ts);
253
44
}
254
255
//----------------------------------------------------------------------------//
256
257
5
void register_action_model_unit_tests(
258
    ActionModelTypes::Type action_model_type) {
259

10
  boost::test_tools::output_test_stream test_name;
260

5
  test_name << "test_" << action_model_type;
261


5
  std::cout << "Running " << test_name.str() << std::endl;
262


5
  test_suite* ts = BOOST_TEST_SUITE(test_name.str());
263
5
  ts->add(
264


5
      BOOST_TEST_CASE(boost::bind(&test_check_action_data, action_model_type)));
265
5
  ts->add(
266


5
      BOOST_TEST_CASE(boost::bind(&test_calc_action_model, action_model_type)));
267


5
  ts->add(BOOST_TEST_CASE(
268
      boost::bind(&test_partial_derivatives_action_model, action_model_type)));
269

5
  framework::master_test_suite().add(ts);
270
5
}
271
272
198
void register_integrated_action_model_unit_tests(
273
    DifferentialActionModelTypes::Type dam_type,
274
    IntegratorTypes::Type integrator_type, ControlTypes::Type control_type) {
275

396
  boost::test_tools::output_test_stream test_name;
276


198
  test_name << "test_" << dam_type << "_" << integrator_type << "_"
277
198
            << control_type;
278


198
  std::cout << "Running " << test_name.str() << std::endl;
279


198
  test_suite* ts = BOOST_TEST_SUITE(test_name.str());
280
198
  ts->add(
281


198
      BOOST_TEST_CASE(boost::bind(&test_check_integrated_action_data, dam_type,
282
                                  integrator_type, control_type)));
283
198
  ts->add(
284


198
      BOOST_TEST_CASE(boost::bind(&test_calc_integrated_action_model, dam_type,
285
                                  integrator_type, control_type)));
286


198
  ts->add(BOOST_TEST_CASE(
287
      boost::bind(&test_partial_derivatives_integrated_action_model, dam_type,
288
                  integrator_type, control_type)));
289

198
  framework::master_test_suite().add(ts);
290
198
}
291
292
1
bool init_function() {
293
6
  for (size_t i = 0; i < ActionModelTypes::all.size(); ++i) {
294
5
    register_action_model_unit_tests(ActionModelTypes::all[i]);
295
  }
296
297
23
  for (size_t i = 0; i < DifferentialActionModelTypes::all.size(); ++i) {
298
22
    register_integrated_action_model_unit_tests(
299
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorEuler,
300
        ControlTypes::PolyZero);
301
22
    register_integrated_action_model_unit_tests(
302
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK2,
303
        ControlTypes::PolyZero);
304
22
    register_integrated_action_model_unit_tests(
305
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK2,
306
        ControlTypes::PolyOne);
307
22
    register_integrated_action_model_unit_tests(
308
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK3,
309
        ControlTypes::PolyZero);
310
22
    register_integrated_action_model_unit_tests(
311
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK3,
312
        ControlTypes::PolyOne);
313
22
    register_integrated_action_model_unit_tests(
314
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK3,
315
        ControlTypes::PolyTwoRK3);
316
22
    register_integrated_action_model_unit_tests(
317
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK4,
318
        ControlTypes::PolyZero);
319
22
    register_integrated_action_model_unit_tests(
320
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK4,
321
        ControlTypes::PolyOne);
322
22
    register_integrated_action_model_unit_tests(
323
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorRK4,
324
        ControlTypes::PolyTwoRK4);
325
  }
326
327
23
  for (size_t i = 0; i < DifferentialActionModelTypes::all.size(); ++i) {
328
22
    register_test_calc_integrated_action_model(
329
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorEuler,
330
        ControlTypes::PolyZero, ControlTypes::PolyOne);
331
22
    register_test_calc_integrated_action_model(
332
22
        DifferentialActionModelTypes::all[i], IntegratorTypes::IntegratorEuler,
333
        ControlTypes::PolyOne, ControlTypes::PolyTwoRK4);
334
  }
335
1
  return true;
336
}
337
338
1
int main(int argc, char** argv) {
339
1
  return ::boost::unit_test::unit_test_main(&init_function, argc, argv);
340
}