GCC Code Coverage Report


Directory: ./
File: src/differentiable-function.cc
Date: 2025-05-05 12:19:30
Exec Total Coverage
Lines: 77 111 69.4%
Branches: 80 230 34.8%

Line Branch Exec Source
1 // Copyright (c) 2015, Joseph Mirabel
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // 1. Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 // DAMAGE.
28
29 #include <boost/serialization/string.hpp>
30 #include <hpp/constraints/differentiable-function.hh>
31 #include <hpp/pinocchio/configuration.hh>
32 #include <hpp/pinocchio/device.hh>
33 #include <hpp/pinocchio/joint-collection.hh>
34 #include <hpp/pinocchio/joint.hh>
35 #include <hpp/pinocchio/liegroup.hh>
36 #include <hpp/pinocchio/serialization.hh>
37 #include <hpp/util/serialization.hh>
38 #include <pinocchio/multibody/liegroup/liegroup.hpp>
39
40 BOOST_CLASS_EXPORT(hpp::constraints::DifferentiableFunction)
41
42 namespace hpp {
43 namespace constraints {
44 namespace {
45 using hpp::pinocchio::DefaultLieGroupMap;
46 typedef std::vector<pinocchio::JointIndex> JointIndexVector;
47
48 struct FiniteDiffRobotOp {
49 105 FiniteDiffRobotOp(const DevicePtr_t& r, const value_type& epsilon)
50 105 : robot(r),
51 105 model(robot->model()),
52 105 epsilon(epsilon),
53
1/2
✓ Branch 3 taken 105 times.
✗ Branch 4 not taken.
105 v(robot->numberDof()) {}
54
55 1250 inline value_type step(const size_type& i, const vector_t& x) const {
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1250 times.
1250 assert(i >= 0);
57 1250 value_type r = std::abs(x[i]);
58
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1250 times.
1250 if (r == 0)
60 return epsilon;
61 else
62 1250 return epsilon * r;
63 }
64
65 template <bool forward>
66 5000 inline void integrate(const vector_t& x, const vector_t& h,
67 const size_type& /*i*/, vector_t& result) const {
68 // Use only the joint corresponding to velocity index i
69 if (forward)
70
3/6
✓ Branch 2 taken 1250 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1250 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1250 times.
✗ Branch 9 not taken.
2500 hpp::pinocchio::integrate<false, DefaultLieGroupMap>(robot, x, h, result);
71 else
72
4/8
✓ Branch 2 taken 1250 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1250 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1250 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1250 times.
✗ Branch 12 not taken.
2500 hpp::pinocchio::integrate<false, DefaultLieGroupMap>(robot, x, -h,
73 result);
74 5000 }
75
76 inline value_type difference(const vector_t& x0, const vector_t& x1,
77 const size_type& i) const {
78 hpp::pinocchio::difference<DefaultLieGroupMap>(robot, x0, x1, v);
79 return v[i];
80 }
81
82 2500 inline void reset(const vector_t& x, const size_type& /*i*/,
83 vector_t& result) const {
84 // Use only the joint corresponding to velocity index i
85 2500 result = x;
86 2500 }
87
88 const DevicePtr_t& robot;
89 const pinocchio::Model& model;
90 const value_type& epsilon;
91 mutable vector_t v;
92 };
93
94 struct FiniteDiffVectorSpaceOp {
95 FiniteDiffVectorSpaceOp(const value_type& epsilon) : epsilon(epsilon) {}
96
97 inline value_type step(const size_type i, const vector_t& x) const {
98 const value_type r = std::abs(x[i]);
99
100 if (r == 0)
101 return epsilon;
102 else
103 return epsilon * r;
104 }
105
106 template <bool forward>
107 inline void integrate(const vector_t& x, const vector_t& h,
108 const size_type& i, vector_t& result) const {
109 result[i] = x[i] + (forward ? h[i] : -h[i]);
110 }
111
112 inline value_type difference(const vector_t& x0, const vector_t& x1,
113 const size_type& i) const {
114 return x0[i] - x1[i];
115 }
116
117 inline void reset(const vector_t& x, const size_type& i,
118 vector_t& result) const {
119 result[i] = x[i];
120 }
121
122 const value_type& epsilon;
123 };
124
125 template <typename FiniteDiffOp, typename Function>
126 210 void finiteDiffCentral(matrixOut_t jacobian, vectorIn_t x,
127 const FiniteDiffOp& op, const Function& f) {
128 210 size_type n = jacobian.cols();
129
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
210 vector_t x_pdx = x;
130
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
210 vector_t x_mdx = x;
131
2/4
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 105 times.
✗ Branch 6 not taken.
210 vector_t h = vector_t::Zero(jacobian.cols());
132
2/4
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 105 times.
✗ Branch 7 not taken.
420 LiegroupElement f_x_mdx(f.outputSpace()), f_x_pdx(f.outputSpace());
133 210 const ArrayXb& adp = f.activeDerivativeParameters();
134
135
2/2
✓ Branch 0 taken 3360 times.
✓ Branch 1 taken 105 times.
6930 for (size_type j = 0; j < n; ++j) {
136
3/4
✓ Branch 1 taken 3360 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2110 times.
✓ Branch 4 taken 1250 times.
6720 if (!adp[j]) {
137
2/4
✓ Branch 1 taken 2110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2110 times.
✗ Branch 5 not taken.
4220 jacobian.col(j).setZero();
138 4220 continue;
139 }
140
141
3/6
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1250 times.
✗ Branch 8 not taken.
2500 h[j] = op.step(j, x);
142
143
2/4
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
2500 op.template integrate<false>(x, h, j, x_mdx);
144
3/6
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1250 times.
✗ Branch 8 not taken.
2500 f.value(f_x_mdx, x_mdx);
145
146
2/4
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
2500 op.template integrate<true>(x, h, j, x_pdx);
147
3/6
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1250 times.
✗ Branch 8 not taken.
2500 f.value(f_x_pdx, x_pdx);
148
149
6/12
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1250 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1250 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1250 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1250 times.
✗ Branch 17 not taken.
2500 jacobian.col(j) = ((f_x_pdx - f_x_mdx) / h[j]) / 2;
150
151
2/4
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
2500 op.reset(x, j, x_mdx);
152
2/4
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250 times.
✗ Branch 5 not taken.
2500 op.reset(x, j, x_pdx);
153
1/2
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
2500 h[j] = 0;
154 }
155
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
210 if (jacobian.hasNaN()) {
156 hppDout(error, "Central finite difference: NaN");
157 }
158 }
159
160 template <typename FiniteDiffOp, typename Function>
161 void finiteDiffForward(matrixOut_t jacobian, vectorIn_t x,
162 const FiniteDiffOp& op, const Function& f) {
163 size_type n = jacobian.cols();
164 vector_t x_dx = x;
165 vector_t h = vector_t::Zero(jacobian.cols());
166 LiegroupElement f_x(f.outputSpace()), f_x_pdx(f.outputSpace());
167 const ArrayXb& adp = f.activeDerivativeParameters();
168
169 f.value(f_x, x);
170
171 for (size_type j = 0; j < n; ++j) {
172 if (!adp[j]) {
173 jacobian.col(j).setZero();
174 continue;
175 }
176
177 h[j] = op.step(j, x);
178
179 op.template integrate<true>(x, h, j, x_dx);
180 f.value(f_x_pdx, x_dx);
181
182 jacobian.col(j) = (f_x_pdx - f_x) / h[j];
183
184 op.reset(x, j, x_dx);
185 h[j] = 0;
186 }
187 if (jacobian.hasNaN()) {
188 hppDout(warning,
189 "Finite difference of \"" << f.name() << "\" has NaN values.");
190 }
191 }
192 } // namespace
193
194 void DifferentiableFunction::finiteDifferenceForward(matrixOut_t jacobian,
195 vectorIn_t x,
196 DevicePtr_t robot,
197 value_type eps) const {
198 if (robot)
199 finiteDiffForward(jacobian, x, FiniteDiffRobotOp(robot, eps), *this);
200 else
201 finiteDiffForward(jacobian, x, FiniteDiffVectorSpaceOp(eps), *this);
202 }
203
204 105 void DifferentiableFunction::finiteDifferenceCentral(matrixOut_t jacobian,
205 vectorIn_t x,
206 DevicePtr_t robot,
207 value_type eps) const {
208
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
105 if (robot)
209
3/6
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 105 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 105 times.
✗ Branch 9 not taken.
105 finiteDiffCentral(jacobian, x, FiniteDiffRobotOp(robot, eps), *this);
210 else
211 finiteDiffCentral(jacobian, x, FiniteDiffVectorSpaceOp(eps), *this);
212 105 }
213
214 19703 bool DifferentiableFunction::operator==(
215 DifferentiableFunction const& other) const {
216 try {
217
6/8
✓ Branch 1 taken 14658 times.
✓ Branch 2 taken 5045 times.
✓ Branch 3 taken 14630 times.
✓ Branch 4 taken 28 times.
✓ Branch 6 taken 14630 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14630 times.
✗ Branch 9 not taken.
19703 return isEqual(other) && other.isEqual(*this);
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5045 times.
5045 } catch (const std::bad_cast& exc) {
219 5045 return false;
220 5045 }
221 }
222 23 bool DifferentiableFunction::operator!=(DifferentiableFunction const& b) const {
223 23 return !(*this == b);
224 }
225
226 2084 DifferentiableFunction::DifferentiableFunction(size_type sizeInput,
227 size_type sizeInputDerivative,
228 size_type sizeOutput,
229 2084 std::string name)
230 2084 : inputSize_(sizeInput),
231 2084 inputDerivativeSize_(sizeInputDerivative),
232 2084 outputSpace_(LiegroupSpace::Rn(sizeOutput)),
233
2/4
✓ Branch 1 taken 2084 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2084 times.
✗ Branch 5 not taken.
2084 activeParameters_(ArrayXb::Constant(sizeInput, true)),
234
2/4
✓ Branch 1 taken 2084 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2084 times.
✗ Branch 5 not taken.
2084 activeDerivativeParameters_(ArrayXb::Constant(sizeInputDerivative, true)),
235
1/2
✓ Branch 2 taken 2084 times.
✗ Branch 3 not taken.
4168 name_(name) {}
236
237 1239 DifferentiableFunction::DifferentiableFunction(
238 size_type sizeInput, size_type sizeInputDerivative,
239 1239 const LiegroupSpacePtr_t& outputSpace, std::string name)
240 1239 : inputSize_(sizeInput),
241 1239 inputDerivativeSize_(sizeInputDerivative),
242 1239 outputSpace_(outputSpace),
243
2/4
✓ Branch 1 taken 1239 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1239 times.
✗ Branch 5 not taken.
1239 activeParameters_(ArrayXb::Constant(sizeInput, true)),
244
2/4
✓ Branch 1 taken 1239 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1239 times.
✗ Branch 5 not taken.
1239 activeDerivativeParameters_(ArrayXb::Constant(sizeInputDerivative, true)),
245
1/2
✓ Branch 1 taken 1239 times.
✗ Branch 2 not taken.
1239 name_(name),
246 2478 context_() {}
247
248 3 std::ostream& DifferentiableFunction::print(std::ostream& o) const {
249 3 return o << "Differentiable function: " << name();
250 }
251
252 template <class Archive>
253 52 void DifferentiableFunction::serialize(Archive& ar,
254 const unsigned int version) {
255 (void)version;
256
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 ar& BOOST_SERIALIZATION_NVP(inputSize_);
257
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 ar& BOOST_SERIALIZATION_NVP(inputDerivativeSize_);
258
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 ar& BOOST_SERIALIZATION_NVP(outputSpace_);
259
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
52 if (inputSize_ > 0) ar& BOOST_SERIALIZATION_NVP(activeParameters_);
260
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
52 if (inputDerivativeSize_ > 0)
261
1/2
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
48 ar& BOOST_SERIALIZATION_NVP(activeDerivativeParameters_);
262
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 ar& BOOST_SERIALIZATION_NVP(name_);
263
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 ar& BOOST_SERIALIZATION_NVP(context_);
264 }
265
266 HPP_SERIALIZATION_IMPLEMENT(DifferentiableFunction);
267 } // namespace constraints
268 } // namespace hpp
269