GCC Code Coverage Report


Directory: ./
File: src/core/solver-base.cpp
Date: 2025-01-16 08:47:40
Exec Total Coverage
Lines: 159 273 58.2%
Branches: 67 507 13.2%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2024, LAAS-CNRS, University of Edinburgh,
5 // Heriot-Watt University, University of Oxford
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifdef CROCODDYL_WITH_MULTITHREADING
11 #include <omp.h>
12 #endif // CROCODDYL_WITH_MULTITHREADING
13
14 #include "crocoddyl/core/solver-base.hpp"
15 #include "crocoddyl/core/utils/exception.hpp"
16
17 namespace crocoddyl {
18
19 119 SolverAbstract::SolverAbstract(boost::shared_ptr<ShootingProblem> problem)
20 119 : problem_(problem),
21 119 is_feasible_(false),
22 119 was_feasible_(false),
23 119 cost_(0.),
24 119 merit_(0.),
25 119 stop_(0.),
26 119 dV_(0.),
27 119 dPhi_(0.),
28 119 dVexp_(0.),
29 119 dPhiexp_(0.),
30 119 dfeas_(0.),
31 119 feas_(0.),
32 119 ffeas_(0.),
33 119 gfeas_(0.),
34 119 hfeas_(0.),
35 119 ffeas_try_(0.),
36 119 gfeas_try_(0.),
37 119 hfeas_try_(0.),
38 119 preg_(0.),
39 119 dreg_(0.),
40 119 steplength_(1.),
41 119 th_acceptstep_(0.1),
42 119 th_stop_(1e-9),
43 119 th_gaptol_(1e-16),
44 119 feasnorm_(LInf),
45 119 iter_(0),
46
1/2
✓ Branch 6 taken 119 times.
✗ Branch 7 not taken.
119 tmp_feas_(0.) {
47 // Allocate common data
48 119 const std::size_t ndx = problem_->get_ndx();
49 119 const std::size_t T = problem_->get_T();
50
1/2
✓ Branch 4 taken 119 times.
✗ Branch 5 not taken.
119 const std::size_t ng_T = problem_->get_terminalModel()->get_ng_T();
51
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 xs_.resize(T + 1);
52
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 us_.resize(T);
53
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 fs_.resize(T + 1);
54
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 g_adj_.resize(T + 1);
55 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
56 119 problem_->get_runningModels();
57
2/2
✓ Branch 0 taken 1148 times.
✓ Branch 1 taken 119 times.
1267 for (std::size_t t = 0; t < T; ++t) {
58 1148 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
59 1148 const std::size_t nu = model->get_nu();
60
1/2
✓ Branch 2 taken 1148 times.
✗ Branch 3 not taken.
1148 const std::size_t ng = model->get_ng();
61
1/2
✓ Branch 4 taken 1148 times.
✗ Branch 5 not taken.
1148 xs_[t] = model->get_state()->zero();
62
2/4
✓ Branch 1 taken 1148 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1148 times.
✗ Branch 6 not taken.
1148 us_[t] = Eigen::VectorXd::Zero(nu);
63
2/4
✓ Branch 1 taken 1148 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1148 times.
✗ Branch 6 not taken.
1148 fs_[t] = Eigen::VectorXd::Zero(ndx);
64
2/4
✓ Branch 1 taken 1148 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1148 times.
✗ Branch 6 not taken.
1148 g_adj_[t] = Eigen::VectorXd::Zero(ng);
65 }
66
1/2
✓ Branch 6 taken 119 times.
✗ Branch 7 not taken.
119 xs_.back() = problem_->get_terminalModel()->get_state()->zero();
67
2/4
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 119 times.
✗ Branch 6 not taken.
119 fs_.back() = Eigen::VectorXd::Zero(ndx);
68
2/4
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 119 times.
✗ Branch 6 not taken.
119 g_adj_.back() = Eigen::VectorXd::Zero(ng_T);
69 119 }
70
71 266 SolverAbstract::~SolverAbstract() {}
72
73 void SolverAbstract::resizeData() {
74 START_PROFILER("SolverAbstract::resizeData");
75 const std::size_t T = problem_->get_T();
76 const std::size_t ng_T = problem_->get_terminalModel()->get_ng_T();
77 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
78 problem_->get_runningModels();
79 for (std::size_t t = 0; t < T; ++t) {
80 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
81 const std::size_t nu = model->get_nu();
82 const std::size_t ng = model->get_ng();
83 us_[t].conservativeResize(nu);
84 g_adj_[t].conservativeResize(ng);
85 }
86
87 g_adj_.back().conservativeResize(ng_T);
88
89 STOP_PROFILER("SolverAbstract::resizeData");
90 }
91
92 108 double SolverAbstract::computeDynamicFeasibility() {
93 108 tmp_feas_ = 0.;
94 108 const std::size_t T = problem_->get_T();
95 108 const Eigen::VectorXd& x0 = problem_->get_x0();
96 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
97 108 problem_->get_runningModels();
98 const std::vector<boost::shared_ptr<ActionDataAbstract> >& datas =
99 108 problem_->get_runningDatas();
100
101
3/6
✓ Branch 7 taken 108 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 108 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 108 times.
✗ Branch 15 not taken.
108 models[0]->get_state()->diff(xs_[0], x0, fs_[0]);
102 #ifdef CROCODDYL_WITH_MULTITHREADING
103 #pragma omp parallel for num_threads(problem_->get_nthreads())
104 #endif
105
2/2
✓ Branch 0 taken 1152 times.
✓ Branch 1 taken 108 times.
1260 for (std::size_t t = 0; t < T; ++t) {
106 1152 const boost::shared_ptr<ActionModelAbstract>& m = models[t];
107 1152 const boost::shared_ptr<ActionDataAbstract>& d = datas[t];
108
3/6
✓ Branch 7 taken 1152 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1152 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1152 times.
✗ Branch 15 not taken.
1152 m->get_state()->diff(xs_[t + 1], d->xnext, fs_[t + 1]);
109 }
110
1/3
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
108 switch (feasnorm_) {
111 108 case LInf:
112 108 tmp_feas_ = std::max(tmp_feas_, fs_[0].lpNorm<Eigen::Infinity>());
113
2/2
✓ Branch 0 taken 1152 times.
✓ Branch 1 taken 108 times.
1260 for (std::size_t t = 0; t < T; ++t) {
114 1152 tmp_feas_ = std::max(tmp_feas_, fs_[t + 1].lpNorm<Eigen::Infinity>());
115 }
116 108 break;
117 case L1:
118 tmp_feas_ = fs_[0].lpNorm<1>();
119 for (std::size_t t = 0; t < T; ++t) {
120 tmp_feas_ += fs_[t + 1].lpNorm<1>();
121 }
122 break;
123 }
124 108 return tmp_feas_;
125 }
126
127 108 double SolverAbstract::computeInequalityFeasibility() {
128 108 tmp_feas_ = 0.;
129 108 const std::size_t T = problem_->get_T();
130 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
131 108 problem_->get_runningModels();
132 const std::vector<boost::shared_ptr<ActionDataAbstract> >& datas =
133 108 problem_->get_runningDatas();
134
135
1/3
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
108 switch (feasnorm_) {
136 108 case LInf:
137
2/2
✓ Branch 0 taken 1152 times.
✓ Branch 1 taken 108 times.
1260 for (std::size_t t = 0; t < T; ++t) {
138
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1152 times.
1152 if (models[t]->get_ng() > 0) {
139 g_adj_[t] = datas[t]
140 ->g.cwiseMax(models[t]->get_g_lb())
141 .cwiseMin(models[t]->get_g_ub());
142 tmp_feas_ = std::max(
143 tmp_feas_, (datas[t]->g - g_adj_[t]).lpNorm<Eigen::Infinity>());
144 }
145 }
146
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
108 if (problem_->get_terminalModel()->get_ng_T() > 0) {
147 g_adj_.back() =
148 problem_->get_terminalData()
149 ->g.cwiseMax(problem_->get_terminalModel()->get_g_lb())
150 .cwiseMin(problem_->get_terminalModel()->get_g_ub());
151 tmp_feas_ += (problem_->get_terminalData()->g - g_adj_.back())
152 .lpNorm<Eigen::Infinity>();
153 }
154 108 break;
155 case L1:
156 for (std::size_t t = 0; t < T; ++t) {
157 if (models[t]->get_ng() > 0) {
158 g_adj_[t] = datas[t]
159 ->g.cwiseMax(models[t]->get_g_lb())
160 .cwiseMin(models[t]->get_g_ub());
161 tmp_feas_ =
162 std::max(tmp_feas_, (datas[t]->g - g_adj_[t]).lpNorm<1>());
163 }
164 }
165 if (problem_->get_terminalModel()->get_ng_T() > 0) {
166 g_adj_.back() =
167 problem_->get_terminalData()
168 ->g.cwiseMax(problem_->get_terminalModel()->get_g_lb())
169 .cwiseMin(problem_->get_terminalModel()->get_g_ub());
170 tmp_feas_ +=
171 (problem_->get_terminalData()->g - g_adj_.back()).lpNorm<1>();
172 }
173 break;
174 }
175 108 return tmp_feas_;
176 }
177
178 108 double SolverAbstract::computeEqualityFeasibility() {
179 108 tmp_feas_ = 0.;
180 108 const std::size_t T = problem_->get_T();
181 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
182 108 problem_->get_runningModels();
183 const std::vector<boost::shared_ptr<ActionDataAbstract> >& datas =
184 108 problem_->get_runningDatas();
185
1/3
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
108 switch (feasnorm_) {
186 108 case LInf:
187
2/2
✓ Branch 0 taken 1152 times.
✓ Branch 1 taken 108 times.
1260 for (std::size_t t = 0; t < T; ++t) {
188
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1152 times.
1152 if (models[t]->get_nh() > 0) {
189 tmp_feas_ =
190 std::max(tmp_feas_, datas[t]->h.lpNorm<Eigen::Infinity>());
191 }
192 }
193
2/2
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 100 times.
108 if (problem_->get_terminalModel()->get_nh_T() > 0) {
194 8 tmp_feas_ =
195 16 std::max(tmp_feas_,
196 8 problem_->get_terminalData()->h.lpNorm<Eigen::Infinity>());
197 }
198 108 break;
199 case L1:
200 for (std::size_t t = 0; t < T; ++t) {
201 if (models[t]->get_nh() > 0) {
202 tmp_feas_ += datas[t]->h.lpNorm<1>();
203 }
204 }
205 if (problem_->get_terminalModel()->get_nh_T() > 0) {
206 tmp_feas_ += problem_->get_terminalData()->h.lpNorm<1>();
207 }
208 break;
209 }
210 108 return tmp_feas_;
211 }
212
213 313 void SolverAbstract::setCandidate(const std::vector<Eigen::VectorXd>& xs_warm,
214 const std::vector<Eigen::VectorXd>& us_warm,
215 bool is_feasible) {
216 313 const std::size_t T = problem_->get_T();
217
218 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
219 313 problem_->get_runningModels();
220
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 273 times.
313 if (xs_warm.size() == 0) {
221
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 40 times.
400 for (std::size_t t = 0; t < T; ++t) {
222 360 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
223 360 xs_[t] = model->get_state()->zero();
224 }
225 40 xs_.back() = problem_->get_terminalModel()->get_state()->zero();
226 } else {
227
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
273 if (xs_warm.size() != T + 1) {
228 throw_pretty("Warm start state vector has wrong dimension, got "
229 << xs_warm.size() << " expecting " << (T + 1));
230 }
231
2/2
✓ Branch 0 taken 2922 times.
✓ Branch 1 taken 273 times.
3195 for (std::size_t t = 0; t < T; ++t) {
232 2922 const std::size_t nx = models[t]->get_state()->get_nx();
233
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2922 times.
2922 if (static_cast<std::size_t>(xs_warm[t].size()) != nx) {
234 throw_pretty("Invalid argument: "
235 << "xs_init[" + std::to_string(t) +
236 "] has wrong dimension ("
237 << xs_warm[t].size()
238 << " provided - it should be equal to " +
239 std::to_string(nx) + "). ActionModel: "
240 << *models[t]);
241 }
242 }
243 273 const std::size_t nx = problem_->get_terminalModel()->get_state()->get_nx();
244
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 273 times.
273 if (static_cast<std::size_t>(xs_warm[T].size()) != nx) {
245 throw_pretty("Invalid argument: "
246 << "xs_init[" + std::to_string(T) +
247 "] (terminal state) has wrong dimension ("
248 << xs_warm[T].size()
249 << " provided - it should be equal to " +
250 std::to_string(nx) + "). ActionModel: "
251 << *problem_->get_terminalModel());
252 }
253 273 std::copy(xs_warm.begin(), xs_warm.end(), xs_.begin());
254 }
255
256
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 273 times.
313 if (us_warm.size() == 0) {
257
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 40 times.
400 for (std::size_t t = 0; t < T; ++t) {
258 360 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
259 360 const std::size_t nu = model->get_nu();
260
1/2
✓ Branch 3 taken 360 times.
✗ Branch 4 not taken.
360 us_[t] = Eigen::VectorXd::Zero(nu);
261 }
262 } else {
263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
273 if (us_warm.size() != T) {
264 throw_pretty("Warm start control has wrong dimension, got "
265 << us_warm.size() << " expecting " << T);
266 }
267
2/2
✓ Branch 0 taken 2922 times.
✓ Branch 1 taken 273 times.
3195 for (std::size_t t = 0; t < T; ++t) {
268 2922 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
269 2922 const std::size_t nu = model->get_nu();
270
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2922 times.
2922 if (static_cast<std::size_t>(us_warm[t].size()) != nu) {
271 throw_pretty("Invalid argument: "
272 << "us_init[" + std::to_string(t) +
273 "] has wrong dimension ("
274 << us_warm[t].size()
275 << " provided - it should be equal to " +
276 std::to_string(nu) + "). ActionModel: "
277 << *model);
278 }
279 }
280 273 std::copy(us_warm.begin(), us_warm.end(), us_.begin());
281 }
282 313 is_feasible_ = is_feasible;
283 313 }
284
285 50 void SolverAbstract::setCallbacks(
286 const std::vector<boost::shared_ptr<CallbackAbstract> >& callbacks) {
287 50 callbacks_ = callbacks;
288 50 }
289
290 const std::vector<boost::shared_ptr<CallbackAbstract> >&
291 SolverAbstract::getCallbacks() const {
292 return callbacks_;
293 }
294
295 1769 const boost::shared_ptr<ShootingProblem>& SolverAbstract::get_problem() const {
296 1769 return problem_;
297 }
298
299 607 const std::vector<Eigen::VectorXd>& SolverAbstract::get_xs() const {
300 607 return xs_;
301 }
302
303 532 const std::vector<Eigen::VectorXd>& SolverAbstract::get_us() const {
304 532 return us_;
305 }
306
307 const std::vector<Eigen::VectorXd>& SolverAbstract::get_fs() const {
308 return fs_;
309 }
310
311 bool SolverAbstract::get_is_feasible() const { return is_feasible_; }
312
313 104 double SolverAbstract::get_cost() const { return cost_; }
314
315 104 double SolverAbstract::get_merit() const { return merit_; }
316
317 104 double SolverAbstract::get_stop() const { return stop_; }
318
319 104 const Eigen::Vector2d& SolverAbstract::get_d() const { return d_; }
320
321 104 double SolverAbstract::get_dV() const { return dV_; }
322
323 104 double SolverAbstract::get_dPhi() const { return dPhi_; }
324
325 104 double SolverAbstract::get_dVexp() const { return dVexp_; }
326
327 104 double SolverAbstract::get_dPhiexp() const { return dPhiexp_; }
328
329 double SolverAbstract::get_dfeas() const { return dfeas_; }
330
331 double SolverAbstract::get_feas() const { return feas_; }
332
333 104 double SolverAbstract::get_ffeas() const { return ffeas_; }
334
335 104 double SolverAbstract::get_gfeas() const { return gfeas_; }
336
337 104 double SolverAbstract::get_hfeas() const { return hfeas_; }
338
339 double SolverAbstract::get_ffeas_try() const { return ffeas_try_; }
340
341 double SolverAbstract::get_gfeas_try() const { return gfeas_try_; }
342
343 double SolverAbstract::get_hfeas_try() const { return hfeas_try_; }
344
345 3128 double SolverAbstract::get_preg() const { return preg_; }
346
347 104 double SolverAbstract::get_dreg() const { return dreg_; }
348
349 DEPRECATED(
350 "Use get_preg for gettting the primal-dual regularization",
351 double SolverAbstract::get_xreg() const { return preg_; })
352
353 DEPRECATED(
354 "Use get_preg for gettting the primal-dual regularization",
355 double SolverAbstract::get_ureg() const { return preg_; })
356
357 104 double SolverAbstract::get_steplength() const { return steplength_; }
358
359 44 double SolverAbstract::get_th_acceptstep() const { return th_acceptstep_; }
360
361 44 double SolverAbstract::get_th_stop() const { return th_stop_; }
362
363 double SolverAbstract::get_th_gaptol() const { return th_gaptol_; }
364
365 FeasibilityNorm SolverAbstract::get_feasnorm() const { return feasnorm_; }
366
367 208 std::size_t SolverAbstract::get_iter() const { return iter_; }
368
369 void SolverAbstract::set_xs(const std::vector<Eigen::VectorXd>& xs) {
370 const std::size_t T = problem_->get_T();
371 if (xs.size() != T + 1) {
372 throw_pretty("Invalid argument: " << "xs list has to be of length " +
373 std::to_string(T + 1));
374 }
375
376 const std::size_t nx = problem_->get_nx();
377 for (std::size_t t = 0; t < T; ++t) {
378 if (static_cast<std::size_t>(xs[t].size()) != nx) {
379 throw_pretty("Invalid argument: "
380 << "xs[" + std::to_string(t) + "] has wrong dimension ("
381 << xs[t].size()
382 << " provided - it should be " + std::to_string(nx) + ")")
383 }
384 }
385 if (static_cast<std::size_t>(xs[T].size()) != nx) {
386 throw_pretty("Invalid argument: "
387 << "xs[" + std::to_string(T) +
388 "] (terminal state) has wrong dimension ("
389 << xs[T].size()
390 << " provided - it should be " + std::to_string(nx) + ")")
391 }
392 xs_ = xs;
393 }
394
395 void SolverAbstract::set_us(const std::vector<Eigen::VectorXd>& us) {
396 const std::size_t T = problem_->get_T();
397 if (us.size() != T) {
398 throw_pretty("Invalid argument: " << "us list has to be of length " +
399 std::to_string(T));
400 }
401
402 const std::vector<boost::shared_ptr<ActionModelAbstract> >& models =
403 problem_->get_runningModels();
404 for (std::size_t t = 0; t < T; ++t) {
405 const boost::shared_ptr<ActionModelAbstract>& model = models[t];
406 const std::size_t nu = model->get_nu();
407 if (static_cast<std::size_t>(us[t].size()) != nu) {
408 throw_pretty("Invalid argument: "
409 << "us[" + std::to_string(t) + "] has wrong dimension ("
410 << us[t].size()
411 << " provided - it should be " + std::to_string(nu) + ")")
412 }
413 }
414 us_ = us;
415 }
416
417 148 void SolverAbstract::set_preg(const double preg) {
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (preg < 0.) {
419 throw_pretty("Invalid argument: " << "preg value has to be positive.");
420 }
421 148 preg_ = preg;
422 148 }
423
424 92 void SolverAbstract::set_dreg(const double dreg) {
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 if (dreg < 0.) {
426 throw_pretty("Invalid argument: " << "dreg value has to be positive.");
427 }
428 92 dreg_ = dreg;
429 92 }
430
431 DEPRECATED(
432 "Use set_preg for gettting the primal-variable regularization",
433 void SolverAbstract::set_xreg(const double xreg) {
434 if (xreg < 0.) {
435 throw_pretty("Invalid argument: " << "xreg value has to be positive.");
436 }
437 xreg_ = xreg;
438 preg_ = xreg;
439 })
440
441 DEPRECATED(
442 "Use set_preg for gettting the primal-variable regularization",
443 void SolverAbstract::set_ureg(const double ureg) {
444 if (ureg < 0.) {
445 throw_pretty("Invalid argument: " << "ureg value has to be positive.");
446 }
447 ureg_ = ureg;
448 preg_ = ureg;
449 })
450
451 void SolverAbstract::set_th_acceptstep(const double th_acceptstep) {
452 if (0. >= th_acceptstep || th_acceptstep > 1) {
453 throw_pretty(
454 "Invalid argument: " << "th_acceptstep value should between 0 and 1.");
455 }
456 th_acceptstep_ = th_acceptstep;
457 }
458
459 void SolverAbstract::set_th_stop(const double th_stop) {
460 if (th_stop <= 0.) {
461 throw_pretty("Invalid argument: " << "th_stop value has to higher than 0.");
462 }
463 th_stop_ = th_stop;
464 }
465
466 void SolverAbstract::set_th_gaptol(const double th_gaptol) {
467 if (0. > th_gaptol) {
468 throw_pretty("Invalid argument: " << "th_gaptol value has to be positive.");
469 }
470 th_gaptol_ = th_gaptol;
471 }
472
473 void SolverAbstract::set_feasnorm(const FeasibilityNorm feasnorm) {
474 feasnorm_ = feasnorm;
475 }
476
477 4728 bool raiseIfNaN(const double value) {
478
4/8
✓ Branch 1 taken 4728 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4728 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4728 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4728 times.
4728 if (std::isnan(value) || std::isinf(value) || value >= 1e30) {
479 return true;
480 } else {
481 4728 return false;
482 }
483 }
484
485 } // namespace crocoddyl
486