Line |
Branch |
Exec |
Source |
1 |
|
|
/////////////////////////////////////////////////////////////////////////////// |
2 |
|
|
// BSD 3-Clause License |
3 |
|
|
// |
4 |
|
|
// Copyright (C) 2019-2025, LAAS-CNRS, New York University, |
5 |
|
|
// Max Planck Gesellschaft, University of Edinburgh, |
6 |
|
|
// INRIA, Heriot-Watt University |
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 "crocoddyl/core/activations/quadratic-barrier.hpp" |
15 |
|
|
#include "factory/activation.hpp" |
16 |
|
|
#include "unittest_common.hpp" |
17 |
|
|
|
18 |
|
|
using namespace boost::unit_test; |
19 |
|
|
using namespace crocoddyl::unittest; |
20 |
|
|
|
21 |
|
|
//----------------------------------------------------------------------------// |
22 |
|
|
|
23 |
|
✗ |
void test_construct_data(ActivationModelTypes::Type activation_type) { |
24 |
|
|
// create the model |
25 |
|
✗ |
ActivationModelFactory factory; |
26 |
|
|
const std::shared_ptr<crocoddyl::ActivationModelAbstract>& model = |
27 |
|
✗ |
factory.create(activation_type); |
28 |
|
|
|
29 |
|
|
// Run the print function |
30 |
|
✗ |
std::ostringstream tmp; |
31 |
|
✗ |
tmp << *model; |
32 |
|
|
|
33 |
|
|
// create the corresponding data object |
34 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstract>& data = |
35 |
|
✗ |
model->createData(); |
36 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstractTpl<float>>& |
37 |
|
✗ |
casted_data = model->cast<float>()->createData(); |
38 |
|
|
} |
39 |
|
|
|
40 |
|
✗ |
void test_calc_returns_a_value(ActivationModelTypes::Type activation_type) { |
41 |
|
|
// create the model |
42 |
|
✗ |
ActivationModelFactory factory; |
43 |
|
|
const std::shared_ptr<crocoddyl::ActivationModelAbstract>& model = |
44 |
|
✗ |
factory.create(activation_type); |
45 |
|
|
|
46 |
|
|
// create the corresponding data object |
47 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstract>& data = |
48 |
|
✗ |
model->createData(); |
49 |
|
|
|
50 |
|
|
// Generating random input vector |
51 |
|
✗ |
const Eigen::VectorXd r = Eigen::VectorXd::Random(model->get_nr()); |
52 |
|
✗ |
data->a_value = nan(""); |
53 |
|
|
|
54 |
|
|
// Getting the state dimension from calc() call |
55 |
|
✗ |
model->calc(data, r); |
56 |
|
|
|
57 |
|
|
// Checking that calc returns a value |
58 |
|
✗ |
BOOST_CHECK(!std::isnan(data->a_value)); |
59 |
|
|
|
60 |
|
|
// Checking that casted computation is the same |
61 |
|
|
const std::shared_ptr<crocoddyl::ActivationModelAbstractTpl<float>>& |
62 |
|
✗ |
casted_model = model->cast<float>(); |
63 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstractTpl<float>>& |
64 |
|
✗ |
casted_data = casted_model->createData(); |
65 |
|
✗ |
const Eigen::VectorXf r_f = r.cast<float>(); |
66 |
|
✗ |
casted_data->a_value = float(nan("")); |
67 |
|
✗ |
casted_model->calc(casted_data, r_f); |
68 |
|
✗ |
BOOST_CHECK(!std::isnan(casted_data->a_value)); |
69 |
|
✗ |
BOOST_CHECK(std::abs(data->a_value - casted_data->a_value) < 1e-6); |
70 |
|
|
} |
71 |
|
|
|
72 |
|
✗ |
void test_partial_derivatives_against_numdiff( |
73 |
|
|
ActivationModelTypes::Type activation_type) { |
74 |
|
|
// create the model |
75 |
|
✗ |
ActivationModelFactory factory; |
76 |
|
|
const std::shared_ptr<crocoddyl::ActivationModelAbstract>& model = |
77 |
|
✗ |
factory.create(activation_type); |
78 |
|
|
|
79 |
|
|
// create the corresponding data object and set the cost to nan |
80 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstract>& data = |
81 |
|
✗ |
model->createData(); |
82 |
|
|
|
83 |
|
✗ |
crocoddyl::ActivationModelNumDiff model_num_diff(model); |
84 |
|
|
std::shared_ptr<crocoddyl::ActivationDataAbstract> data_num_diff = |
85 |
|
✗ |
model_num_diff.createData(); |
86 |
|
|
|
87 |
|
|
// Generating random values for the state and control |
88 |
|
✗ |
const Eigen::VectorXd r = Eigen::VectorXd::Random(model->get_nr()); |
89 |
|
|
|
90 |
|
|
// Computing the activation derivatives |
91 |
|
✗ |
model->calc(data, r); |
92 |
|
✗ |
model->calcDiff(data, r); |
93 |
|
✗ |
model_num_diff.calc(data_num_diff, r); |
94 |
|
✗ |
model_num_diff.calcDiff(data_num_diff, r); |
95 |
|
|
|
96 |
|
|
// Tolerance defined as in |
97 |
|
|
// http://www.it.uom.gr/teaching/linearalgebra/NumericalRecipiesInC/c5-7.pdf |
98 |
|
✗ |
double tol = std::pow(model_num_diff.get_disturbance(), 1. / 3.); |
99 |
|
✗ |
BOOST_CHECK(std::abs(data->a_value - data_num_diff->a_value) < tol); |
100 |
|
✗ |
BOOST_CHECK((data->Ar - data_num_diff->Ar).isZero(tol)); |
101 |
|
|
|
102 |
|
|
// numerical differentiation of the Hessian is not good enough to be tested. |
103 |
|
|
// BOOST_CHECK((data->Arr - data_num_diff->Arr).isMuchSmallerThan(1.0, tol)); |
104 |
|
|
|
105 |
|
|
// Checking that casted computation is the same |
106 |
|
|
const std::shared_ptr<crocoddyl::ActivationModelAbstractTpl<float>>& |
107 |
|
✗ |
casted_model = model->cast<float>(); |
108 |
|
|
const std::shared_ptr<crocoddyl::ActivationDataAbstractTpl<float>>& |
109 |
|
✗ |
casted_data = casted_model->createData(); |
110 |
|
✗ |
const Eigen::VectorXf r_f = r.cast<float>(); |
111 |
|
✗ |
casted_model->calc(casted_data, r_f); |
112 |
|
✗ |
casted_model->calcDiff(casted_data, r_f); |
113 |
|
|
float tol_f = |
114 |
|
✗ |
std::pow(model_num_diff.cast<float>().get_disturbance(), float(1. / 3.)); |
115 |
|
✗ |
BOOST_CHECK(std::abs(data->a_value - casted_data->a_value) < tol_f); |
116 |
|
✗ |
BOOST_CHECK((data->Ar.cast<float>() - casted_data->Ar).isZero(tol_f)); |
117 |
|
|
} |
118 |
|
|
|
119 |
|
✗ |
void test_activation_bounds_with_infinity() { |
120 |
|
✗ |
Eigen::VectorXd lb(1); |
121 |
|
✗ |
Eigen::VectorXd ub(1); |
122 |
|
|
double beta; |
123 |
|
✗ |
beta = 0.1; |
124 |
|
✗ |
lb[0] = 0; |
125 |
|
✗ |
ub[0] = std::numeric_limits<double>::infinity(); |
126 |
|
|
|
127 |
|
|
Eigen::VectorXd m = |
128 |
|
✗ |
0.5 * (lb + Eigen::VectorXd::Constant( |
129 |
|
✗ |
lb.size(), std::numeric_limits<double>::max())); |
130 |
|
|
Eigen::VectorXd d = |
131 |
|
✗ |
0.5 * (Eigen::VectorXd::Constant(lb.size(), |
132 |
|
✗ |
std::numeric_limits<double>::max()) - |
133 |
|
✗ |
lb); |
134 |
|
✗ |
crocoddyl::ActivationBounds bounds(lb, ub, beta); |
135 |
|
✗ |
BOOST_CHECK(bounds.lb != m - beta * d); |
136 |
|
|
|
137 |
|
|
// Checking that casted computation is the same |
138 |
|
✗ |
crocoddyl::ActivationBoundsTpl<float> casted_bounds = bounds.cast<float>(); |
139 |
|
✗ |
BOOST_CHECK(bounds.lb.cast<float>() == casted_bounds.lb); |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
//----------------------------------------------------------------------------// |
143 |
|
|
|
144 |
|
✗ |
void register_unit_tests(ActivationModelTypes::Type activation_type) { |
145 |
|
✗ |
boost::test_tools::output_test_stream test_name; |
146 |
|
✗ |
test_name << "test_" << activation_type; |
147 |
|
✗ |
std::cout << "Running " << test_name.str() << std::endl; |
148 |
|
✗ |
test_suite* ts = BOOST_TEST_SUITE(test_name.str()); |
149 |
|
✗ |
ts->add(BOOST_TEST_CASE(boost::bind(&test_construct_data, activation_type))); |
150 |
|
✗ |
ts->add(BOOST_TEST_CASE( |
151 |
|
|
boost::bind(&test_calc_returns_a_value, activation_type))); |
152 |
|
✗ |
ts->add(BOOST_TEST_CASE( |
153 |
|
|
boost::bind(&test_partial_derivatives_against_numdiff, activation_type))); |
154 |
|
✗ |
framework::master_test_suite().add(ts); |
155 |
|
|
} |
156 |
|
|
|
157 |
|
✗ |
bool register_bounds_unit_test() { |
158 |
|
✗ |
boost::test_tools::output_test_stream test_name; |
159 |
|
|
test_name << "test_" |
160 |
|
✗ |
<< "ActivationBoundsInfinity"; |
161 |
|
✗ |
std::cout << "Running " << test_name.str() << std::endl; |
162 |
|
✗ |
test_suite* ts = BOOST_TEST_SUITE(test_name.str()); |
163 |
|
✗ |
ts->add(BOOST_TEST_CASE(boost::bind(&test_activation_bounds_with_infinity))); |
164 |
|
✗ |
framework::master_test_suite().add(ts); |
165 |
|
✗ |
return true; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
✗ |
bool init_function() { |
169 |
|
✗ |
for (size_t i = 0; i < ActivationModelTypes::all.size(); ++i) { |
170 |
|
✗ |
register_unit_tests(ActivationModelTypes::all[i]); |
171 |
|
|
} |
172 |
|
✗ |
register_bounds_unit_test(); |
173 |
|
✗ |
return true; |
174 |
|
|
} |
175 |
|
|
|
176 |
|
✗ |
int main(int argc, char** argv) { |
177 |
|
✗ |
return ::boost::unit_test::unit_test_main(&init_function, argc, argv); |
178 |
|
|
} |
179 |
|
|
|