GCC Code Coverage Report


Directory: ./
File: src/core/solvers/ddp.cpp
Date: 2025-06-03 08:14:12
Exec Total Coverage
Lines: 0 407 0.0%
Functions: 0 48 0.0%
Branches: 0 1292 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh,
5 // University of Oxford, Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "crocoddyl/core/solvers/ddp.hpp"
11
12 namespace crocoddyl {
13
14 ✗ SolverDDP::SolverDDP(std::shared_ptr<ShootingProblem> problem)
15 : SolverAbstract(problem),
16 ✗ reg_incfactor_(10.),
17 ✗ reg_decfactor_(10.),
18 ✗ reg_min_(1e-9),
19 ✗ reg_max_(1e9),
20 ✗ cost_try_(0.),
21 ✗ th_grad_(1e-12),
22 ✗ th_stepdec_(0.5),
23 ✗ th_stepinc_(0.01) {
24 ✗ allocateData();
25
26 ✗ const std::size_t n_alphas = 10;
27 ✗ alphas_.resize(n_alphas);
28 ✗ for (std::size_t n = 0; n < n_alphas; ++n) {
29 ✗ alphas_[n] = 1. / pow(2., static_cast<double>(n));
30 }
31 ✗ if (th_stepinc_ < alphas_[n_alphas - 1]) {
32 ✗ th_stepinc_ = alphas_[n_alphas - 1];
33 std::cerr << "Warning: th_stepinc has higher value than lowest alpha "
34 "value, set to "
35 ✗ << std::to_string(alphas_[n_alphas - 1]) << std::endl;
36 }
37 ✗ }
38
39 ✗ SolverDDP::~SolverDDP() {}
40
41 ✗ bool SolverDDP::solve(const std::vector<Eigen::VectorXd>& init_xs,
42 const std::vector<Eigen::VectorXd>& init_us,
43 const std::size_t maxiter, const bool is_feasible,
44 const double init_reg) {
45 ✗ START_PROFILER("SolverDDP::solve");
46 ✗ if (problem_->is_updated()) {
47 ✗ resizeData();
48 }
49 ✗ xs_try_[0] =
50 ✗ problem_->get_x0(); // it is needed in case that init_xs[0] is infeasible
51 ✗ setCandidate(init_xs, init_us, is_feasible);
52
53 ✗ if (std::isnan(init_reg)) {
54 ✗ preg_ = reg_min_;
55 ✗ dreg_ = reg_min_;
56 } else {
57 ✗ preg_ = init_reg;
58 ✗ dreg_ = init_reg;
59 }
60 ✗ was_feasible_ = false;
61
62 ✗ bool recalcDiff = true;
63 ✗ for (iter_ = 0; iter_ < maxiter; ++iter_) {
64 while (true) {
65 try {
66 ✗ computeDirection(recalcDiff);
67 ✗ } catch (std::exception& e) {
68 ✗ recalcDiff = false;
69 ✗ increaseRegularization();
70 ✗ if (preg_ == reg_max_) {
71 ✗ return false;
72 } else {
73 ✗ continue;
74 }
75 ✗ }
76 ✗ break;
77 ✗ }
78 ✗ expectedImprovement();
79
80 // We need to recalculate the derivatives when the step length passes
81 ✗ recalcDiff = false;
82 ✗ for (std::vector<double>::const_iterator it = alphas_.begin();
83 ✗ it != alphas_.end(); ++it) {
84 ✗ steplength_ = *it;
85
86 try {
87 ✗ dV_ = tryStep(steplength_);
88 ✗ } catch (std::exception& e) {
89 ✗ continue;
90 ✗ }
91 ✗ dVexp_ = steplength_ * (d_[0] + 0.5 * steplength_ * d_[1]);
92
93 ✗ if (dVexp_ >= 0) { // descend direction
94 ✗ if (std::abs(d_[0]) < th_grad_ || !is_feasible_ ||
95 ✗ dV_ > th_acceptstep_ * dVexp_) {
96 ✗ was_feasible_ = is_feasible_;
97 ✗ setCandidate(xs_try_, us_try_, true);
98 ✗ cost_ = cost_try_;
99 ✗ recalcDiff = true;
100 ✗ break;
101 }
102 }
103 }
104
105 ✗ if (steplength_ > th_stepdec_) {
106 ✗ decreaseRegularization();
107 }
108 ✗ if (steplength_ <= th_stepinc_) {
109 ✗ increaseRegularization();
110 ✗ if (preg_ == reg_max_) {
111 ✗ STOP_PROFILER("SolverDDP::solve");
112 ✗ return false;
113 }
114 }
115 ✗ stoppingCriteria();
116
117 ✗ const std::size_t n_callbacks = callbacks_.size();
118 ✗ for (std::size_t c = 0; c < n_callbacks; ++c) {
119 ✗ CallbackAbstract& callback = *callbacks_[c];
120 ✗ callback(*this);
121 }
122
123 ✗ if (was_feasible_ && stop_ < th_stop_) {
124 ✗ STOP_PROFILER("SolverDDP::solve");
125 ✗ return true;
126 }
127 }
128 ✗ STOP_PROFILER("SolverDDP::solve");
129 ✗ return false;
130 }
131
132 ✗ void SolverDDP::computeDirection(const bool recalcDiff) {
133 ✗ START_PROFILER("SolverDDP::computeDirection");
134 ✗ if (recalcDiff) {
135 ✗ calcDiff();
136 }
137 ✗ backwardPass();
138 ✗ STOP_PROFILER("SolverDDP::computeDirection");
139 ✗ }
140
141 ✗ double SolverDDP::tryStep(const double steplength) {
142 ✗ START_PROFILER("SolverDDP::tryStep");
143 ✗ forwardPass(steplength);
144 ✗ STOP_PROFILER("SolverDDP::tryStep");
145 ✗ return cost_ - cost_try_;
146 }
147
148 ✗ double SolverDDP::stoppingCriteria() {
149 // This stopping criteria represents the expected reduction in the value
150 // function. If this reduction is less than a certain threshold, then the
151 // algorithm reaches the local minimum. For more details, see C. Mastalli et
152 // al. "Inverse-dynamics MPC via Nullspace Resolution".
153 ✗ stop_ = std::abs(d_[0] + 0.5 * d_[1]);
154 ✗ return stop_;
155 }
156
157 ✗ const Eigen::Vector2d& SolverDDP::expectedImprovement() {
158 ✗ d_.fill(0);
159 ✗ const std::size_t T = this->problem_->get_T();
160 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
161 ✗ problem_->get_runningModels();
162 ✗ for (std::size_t t = 0; t < T; ++t) {
163 ✗ const std::size_t nu = models[t]->get_nu();
164 ✗ if (nu != 0) {
165 ✗ d_[0] += Qu_[t].dot(k_[t]);
166 ✗ d_[1] -= k_[t].dot(Quuk_[t]);
167 }
168 }
169 ✗ return d_;
170 }
171
172 ✗ void SolverDDP::resizeData() {
173 ✗ START_PROFILER("SolverDDP::resizeData");
174 ✗ SolverAbstract::resizeData();
175
176 ✗ const std::size_t T = problem_->get_T();
177 ✗ const std::size_t ndx = problem_->get_ndx();
178 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
179 ✗ problem_->get_runningModels();
180 ✗ for (std::size_t t = 0; t < T; ++t) {
181 ✗ const std::shared_ptr<ActionModelAbstract>& model = models[t];
182 ✗ const std::size_t nu = model->get_nu();
183 ✗ Qxu_[t].conservativeResize(ndx, nu);
184 ✗ Quu_[t].conservativeResize(nu, nu);
185 ✗ Qu_[t].conservativeResize(nu);
186 ✗ K_[t].conservativeResize(nu, ndx);
187 ✗ k_[t].conservativeResize(nu);
188 ✗ us_try_[t].conservativeResize(nu);
189 ✗ FuTVxx_p_[t].conservativeResize(nu, ndx);
190 ✗ Quuk_[t].conservativeResize(nu);
191 ✗ if (nu != 0) {
192 ✗ FuTVxx_p_[t].setZero();
193 }
194 }
195 ✗ STOP_PROFILER("SolverDDP::resizeData");
196 ✗ }
197
198 ✗ double SolverDDP::calcDiff() {
199 ✗ START_PROFILER("SolverDDP::calcDiff");
200 ✗ if (iter_ == 0) {
201 ✗ problem_->calc(xs_, us_);
202 }
203 ✗ cost_ = problem_->calcDiff(xs_, us_);
204
205 ✗ ffeas_ = computeDynamicFeasibility();
206 ✗ gfeas_ = computeInequalityFeasibility();
207 ✗ hfeas_ = computeEqualityFeasibility();
208 ✗ STOP_PROFILER("SolverDDP::calcDiff");
209 ✗ return cost_;
210 }
211
212 ✗ void SolverDDP::backwardPass() {
213 ✗ START_PROFILER("SolverDDP::backwardPass");
214 ✗ const std::shared_ptr<ActionDataAbstract>& d_T = problem_->get_terminalData();
215 ✗ Vxx_.back() = d_T->Lxx;
216 ✗ Vx_.back() = d_T->Lx;
217
218 ✗ if (!std::isnan(preg_)) {
219 ✗ Vxx_.back().diagonal().array() += preg_;
220 }
221
222 ✗ if (!is_feasible_) {
223 ✗ Vx_.back().noalias() += Vxx_.back() * fs_.back();
224 }
225 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
226 ✗ problem_->get_runningModels();
227 const std::vector<std::shared_ptr<ActionDataAbstract> >& datas =
228 ✗ problem_->get_runningDatas();
229 ✗ for (int t = static_cast<int>(problem_->get_T()) - 1; t >= 0; --t) {
230 ✗ const std::shared_ptr<ActionModelAbstract>& m = models[t];
231 ✗ const std::shared_ptr<ActionDataAbstract>& d = datas[t];
232
233 // Compute the linear-quadratic approximation of the control Hamiltonian
234 // function
235 ✗ computeActionValueFunction(t, m, d);
236
237 // Compute the feedforward and feedback gains
238 ✗ computeGains(t);
239
240 // Compute the linear-quadratic approximation of the Value function
241 ✗ computeValueFunction(t, m);
242
243 ✗ if (raiseIfNaN(Vx_[t].lpNorm<Eigen::Infinity>())) {
244 ✗ throw_pretty("backward_error");
245 }
246 ✗ if (raiseIfNaN(Vxx_[t].lpNorm<Eigen::Infinity>())) {
247 ✗ throw_pretty("backward_error");
248 }
249 }
250 ✗ STOP_PROFILER("SolverDDP::backwardPass");
251 ✗ }
252
253 ✗ void SolverDDP::forwardPass(const double steplength) {
254 ✗ if (steplength > 1. || steplength < 0.) {
255 ✗ throw_pretty("Invalid argument: "
256 << "invalid step length, value is between 0. to 1.");
257 }
258 ✗ START_PROFILER("SolverDDP::forwardPass");
259 ✗ cost_try_ = 0.;
260 ✗ const std::size_t T = problem_->get_T();
261 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
262 ✗ problem_->get_runningModels();
263 const std::vector<std::shared_ptr<ActionDataAbstract> >& datas =
264 ✗ problem_->get_runningDatas();
265 ✗ for (std::size_t t = 0; t < T; ++t) {
266 ✗ const std::shared_ptr<ActionModelAbstract>& m = models[t];
267 ✗ const std::shared_ptr<ActionDataAbstract>& d = datas[t];
268
269 ✗ m->get_state()->diff(xs_[t], xs_try_[t], dx_[t]);
270 ✗ if (m->get_nu() != 0) {
271 ✗ us_try_[t].noalias() = us_[t];
272 ✗ us_try_[t].noalias() -= k_[t] * steplength;
273 ✗ us_try_[t].noalias() -= K_[t] * dx_[t];
274 ✗ m->calc(d, xs_try_[t], us_try_[t]);
275 } else {
276 ✗ m->calc(d, xs_try_[t]);
277 }
278 ✗ xs_try_[t + 1] = d->xnext;
279 ✗ cost_try_ += d->cost;
280
281 ✗ if (raiseIfNaN(cost_try_)) {
282 ✗ STOP_PROFILER("SolverDDP::forwardPass");
283 ✗ throw_pretty("forward_error");
284 }
285 ✗ if (raiseIfNaN(xs_try_[t + 1].lpNorm<Eigen::Infinity>())) {
286 ✗ STOP_PROFILER("SolverDDP::forwardPass");
287 ✗ throw_pretty("forward_error");
288 }
289 }
290
291 ✗ const std::shared_ptr<ActionModelAbstract>& m = problem_->get_terminalModel();
292 ✗ const std::shared_ptr<ActionDataAbstract>& d = problem_->get_terminalData();
293 ✗ m->calc(d, xs_try_.back());
294 ✗ cost_try_ += d->cost;
295
296 ✗ if (raiseIfNaN(cost_try_)) {
297 ✗ STOP_PROFILER("SolverDDP::forwardPass");
298 ✗ throw_pretty("forward_error");
299 }
300 ✗ STOP_PROFILER("SolverDDP::forwardPass");
301 ✗ }
302
303 ✗ void SolverDDP::computeActionValueFunction(
304 const std::size_t t, const std::shared_ptr<ActionModelAbstract>& model,
305 const std::shared_ptr<ActionDataAbstract>& data) {
306 ✗ assert_pretty(t < problem_->get_T(),
307 "Invalid argument: t should be between 0 and " +
308 std::to_string(problem_->get_T()););
309 ✗ const std::size_t nu = model->get_nu();
310 ✗ const Eigen::MatrixXd& Vxx_p = Vxx_[t + 1];
311 ✗ const Eigen::VectorXd& Vx_p = Vx_[t + 1];
312
313 ✗ FxTVxx_p_.noalias() = data->Fx.transpose() * Vxx_p;
314 ✗ START_PROFILER("SolverDDP::Qx");
315 ✗ Qx_[t] = data->Lx;
316 ✗ Qx_[t].noalias() += data->Fx.transpose() * Vx_p;
317 ✗ STOP_PROFILER("SolverDDP::Qx");
318 ✗ START_PROFILER("SolverDDP::Qxx");
319 ✗ Qxx_[t] = data->Lxx;
320 ✗ Qxx_[t].noalias() += FxTVxx_p_ * data->Fx;
321 ✗ STOP_PROFILER("SolverDDP::Qxx");
322 ✗ if (nu != 0) {
323 ✗ FuTVxx_p_[t].noalias() = data->Fu.transpose() * Vxx_p;
324 ✗ START_PROFILER("SolverDDP::Qu");
325 ✗ Qu_[t] = data->Lu;
326 ✗ Qu_[t].noalias() += data->Fu.transpose() * Vx_p;
327 ✗ STOP_PROFILER("SolverDDP::Qu");
328 ✗ START_PROFILER("SolverDDP::Quu");
329 ✗ Quu_[t] = data->Luu;
330 ✗ Quu_[t].noalias() += FuTVxx_p_[t] * data->Fu;
331 ✗ STOP_PROFILER("SolverDDP::Quu");
332 ✗ START_PROFILER("SolverDDP::Qxu");
333 ✗ Qxu_[t] = data->Lxu;
334 ✗ Qxu_[t].noalias() += FxTVxx_p_ * data->Fu;
335 ✗ STOP_PROFILER("SolverDDP::Qxu");
336 ✗ if (!std::isnan(preg_)) {
337 ✗ Quu_[t].diagonal().array() += preg_;
338 }
339 }
340 ✗ }
341
342 ✗ void SolverDDP::computeValueFunction(
343 const std::size_t t, const std::shared_ptr<ActionModelAbstract>& model) {
344 ✗ assert_pretty(t < problem_->get_T(),
345 "Invalid argument: t should be between 0 and " +
346 std::to_string(problem_->get_T()););
347 ✗ const std::size_t nu = model->get_nu();
348 ✗ Vx_[t] = Qx_[t];
349 ✗ Vxx_[t] = Qxx_[t];
350 ✗ if (nu != 0) {
351 ✗ START_PROFILER("SolverDDP::Vx");
352 ✗ Quuk_[t].noalias() = Quu_[t] * k_[t];
353 ✗ Vx_[t].noalias() -= K_[t].transpose() * Qu_[t];
354 ✗ STOP_PROFILER("SolverDDP::Vx");
355 ✗ START_PROFILER("SolverDDP::Vxx");
356 ✗ Vxx_[t].noalias() -= Qxu_[t] * K_[t];
357 ✗ STOP_PROFILER("SolverDDP::Vxx");
358 }
359 ✗ Vxx_tmp_ = 0.5 * (Vxx_[t] + Vxx_[t].transpose());
360 ✗ Vxx_[t] = Vxx_tmp_;
361
362 ✗ if (!std::isnan(preg_)) {
363 ✗ Vxx_[t].diagonal().array() += preg_;
364 }
365
366 // Compute and store the Vx gradient at end of the interval (rollout state)
367 ✗ if (!is_feasible_) {
368 ✗ Vx_[t].noalias() += Vxx_[t] * fs_[t];
369 }
370 ✗ }
371
372 ✗ void SolverDDP::computeGains(const std::size_t t) {
373 ✗ assert_pretty(t < problem_->get_T(),
374 "Invalid argument: t should be between 0 and " +
375 std::to_string(problem_->get_T()));
376 ✗ START_PROFILER("SolverDDP::computeGains");
377 ✗ const std::size_t nu = problem_->get_runningModels()[t]->get_nu();
378 ✗ if (nu > 0) {
379 ✗ START_PROFILER("SolverDDP::Quu_inv");
380 ✗ Quu_llt_[t].compute(Quu_[t]);
381 ✗ STOP_PROFILER("SolverDDP::Quu_inv");
382 ✗ const Eigen::ComputationInfo& info = Quu_llt_[t].info();
383 ✗ if (info != Eigen::Success) {
384 ✗ STOP_PROFILER("SolverDDP::computeGains");
385 ✗ throw_pretty("backward_error");
386 }
387 ✗ K_[t] = Qxu_[t].transpose();
388
389 ✗ START_PROFILER("SolverDDP::Quu_inv_Qux");
390 ✗ Quu_llt_[t].solveInPlace(K_[t]);
391 ✗ STOP_PROFILER("SolverDDP::Quu_inv_Qux");
392 ✗ k_[t] = Qu_[t];
393 ✗ Quu_llt_[t].solveInPlace(k_[t]);
394 }
395 ✗ STOP_PROFILER("SolverDDP::computeGains");
396 ✗ }
397
398 ✗ void SolverDDP::increaseRegularization() {
399 ✗ preg_ *= reg_incfactor_;
400 ✗ if (preg_ > reg_max_) {
401 ✗ preg_ = reg_max_;
402 }
403 ✗ dreg_ = preg_;
404 ✗ }
405
406 ✗ void SolverDDP::decreaseRegularization() {
407 ✗ preg_ /= reg_decfactor_;
408 ✗ if (preg_ < reg_min_) {
409 ✗ preg_ = reg_min_;
410 }
411 ✗ dreg_ = preg_;
412 ✗ }
413
414 ✗ void SolverDDP::allocateData() {
415 ✗ const std::size_t T = problem_->get_T();
416 ✗ Vxx_.resize(T + 1);
417 ✗ Vx_.resize(T + 1);
418 ✗ Qxx_.resize(T);
419 ✗ Qxu_.resize(T);
420 ✗ Quu_.resize(T);
421 ✗ Qx_.resize(T);
422 ✗ Qu_.resize(T);
423 ✗ K_.resize(T);
424 ✗ k_.resize(T);
425
426 ✗ xs_try_.resize(T + 1);
427 ✗ us_try_.resize(T);
428 ✗ dx_.resize(T);
429
430 ✗ FuTVxx_p_.resize(T);
431 ✗ Quu_llt_.resize(T);
432 ✗ Quuk_.resize(T);
433
434 ✗ const std::size_t ndx = problem_->get_ndx();
435 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
436 ✗ problem_->get_runningModels();
437 ✗ for (std::size_t t = 0; t < T; ++t) {
438 ✗ const std::shared_ptr<ActionModelAbstract>& model = models[t];
439 ✗ const std::size_t nu = model->get_nu();
440 ✗ Vxx_[t] = Eigen::MatrixXd::Zero(ndx, ndx);
441 ✗ Vx_[t] = Eigen::VectorXd::Zero(ndx);
442 ✗ Qxx_[t] = Eigen::MatrixXd::Zero(ndx, ndx);
443 ✗ Qxu_[t] = Eigen::MatrixXd::Zero(ndx, nu);
444 ✗ Quu_[t] = Eigen::MatrixXd::Zero(nu, nu);
445 ✗ Qx_[t] = Eigen::VectorXd::Zero(ndx);
446 ✗ Qu_[t] = Eigen::VectorXd::Zero(nu);
447 ✗ K_[t] = MatrixXdRowMajor::Zero(nu, ndx);
448 ✗ k_[t] = Eigen::VectorXd::Zero(nu);
449
450 ✗ if (t == 0) {
451 ✗ xs_try_[t] = problem_->get_x0();
452 } else {
453 ✗ xs_try_[t] = model->get_state()->zero();
454 }
455 ✗ us_try_[t] = Eigen::VectorXd::Zero(nu);
456 ✗ dx_[t] = Eigen::VectorXd::Zero(ndx);
457
458 ✗ FuTVxx_p_[t] = MatrixXdRowMajor::Zero(nu, ndx);
459 ✗ Quu_llt_[t] = Eigen::LLT<Eigen::MatrixXd>(nu);
460 ✗ Quuk_[t] = Eigen::VectorXd(nu);
461 }
462 ✗ Vxx_.back() = Eigen::MatrixXd::Zero(ndx, ndx);
463 ✗ Vxx_tmp_ = Eigen::MatrixXd::Zero(ndx, ndx);
464 ✗ Vx_.back() = Eigen::VectorXd::Zero(ndx);
465 ✗ xs_try_.back() = problem_->get_terminalModel()->get_state()->zero();
466
467 ✗ FxTVxx_p_ = MatrixXdRowMajor::Zero(ndx, ndx);
468 ✗ fTVxx_p_ = Eigen::VectorXd::Zero(ndx);
469 ✗ }
470
471 ✗ double SolverDDP::get_reg_incfactor() const { return reg_incfactor_; }
472
473 ✗ double SolverDDP::get_reg_decfactor() const { return reg_decfactor_; }
474
475 ✗ double SolverDDP::get_regfactor() const { return reg_incfactor_; }
476
477 ✗ double SolverDDP::get_reg_min() const { return reg_min_; }
478
479 ✗ double SolverDDP::get_regmin() const { return reg_min_; }
480
481 ✗ double SolverDDP::get_reg_max() const { return reg_max_; }
482
483 ✗ double SolverDDP::get_regmax() const { return reg_max_; }
484
485 ✗ const std::vector<double>& SolverDDP::get_alphas() const { return alphas_; }
486
487 ✗ double SolverDDP::get_th_stepdec() const { return th_stepdec_; }
488
489 ✗ double SolverDDP::get_th_stepinc() const { return th_stepinc_; }
490
491 ✗ double SolverDDP::get_th_grad() const { return th_grad_; }
492
493 ✗ const std::vector<Eigen::MatrixXd>& SolverDDP::get_Vxx() const { return Vxx_; }
494
495 ✗ const std::vector<Eigen::VectorXd>& SolverDDP::get_Vx() const { return Vx_; }
496
497 ✗ const std::vector<Eigen::MatrixXd>& SolverDDP::get_Qxx() const { return Qxx_; }
498
499 ✗ const std::vector<Eigen::MatrixXd>& SolverDDP::get_Qxu() const { return Qxu_; }
500
501 ✗ const std::vector<Eigen::MatrixXd>& SolverDDP::get_Quu() const { return Quu_; }
502
503 ✗ const std::vector<Eigen::VectorXd>& SolverDDP::get_Qx() const { return Qx_; }
504
505 ✗ const std::vector<Eigen::VectorXd>& SolverDDP::get_Qu() const { return Qu_; }
506
507 const std::vector<typename MathBaseTpl<double>::MatrixXsRowMajor>&
508 ✗ SolverDDP::get_K() const {
509 ✗ return K_;
510 }
511
512 ✗ const std::vector<Eigen::VectorXd>& SolverDDP::get_k() const { return k_; }
513
514 ✗ void SolverDDP::set_reg_incfactor(const double regfactor) {
515 ✗ if (regfactor <= 1.) {
516 ✗ throw_pretty(
517 "Invalid argument: " << "reg_incfactor value is higher than 1.");
518 }
519 ✗ reg_incfactor_ = regfactor;
520 ✗ }
521
522 ✗ void SolverDDP::set_reg_decfactor(const double regfactor) {
523 ✗ if (regfactor <= 1.) {
524 ✗ throw_pretty(
525 "Invalid argument: " << "reg_decfactor value is higher than 1.");
526 }
527 ✗ reg_decfactor_ = regfactor;
528 ✗ }
529
530 ✗ void SolverDDP::set_regfactor(const double regfactor) {
531 ✗ if (regfactor <= 1.) {
532 ✗ throw_pretty("Invalid argument: " << "regfactor value is higher than 1.");
533 }
534 ✗ set_reg_incfactor(regfactor);
535 ✗ set_reg_decfactor(regfactor);
536 ✗ }
537
538 ✗ void SolverDDP::set_reg_min(const double regmin) {
539 ✗ if (0. > regmin) {
540 ✗ throw_pretty("Invalid argument: " << "regmin value has to be positive.");
541 }
542 ✗ reg_min_ = regmin;
543 ✗ }
544
545 ✗ void SolverDDP::set_regmin(const double regmin) {
546 ✗ if (0. > regmin) {
547 ✗ throw_pretty("Invalid argument: " << "regmin value has to be positive.");
548 }
549 ✗ reg_min_ = regmin;
550 ✗ }
551
552 ✗ void SolverDDP::set_reg_max(const double regmax) {
553 ✗ if (0. > regmax) {
554 ✗ throw_pretty("Invalid argument: " << "regmax value has to be positive.");
555 }
556 ✗ reg_max_ = regmax;
557 ✗ }
558
559 ✗ void SolverDDP::set_regmax(const double regmax) {
560 ✗ if (0. > regmax) {
561 ✗ throw_pretty("Invalid argument: " << "regmax value has to be positive.");
562 }
563 ✗ reg_max_ = regmax;
564 ✗ }
565
566 ✗ void SolverDDP::set_alphas(const std::vector<double>& alphas) {
567 ✗ double prev_alpha = alphas[0];
568 ✗ if (prev_alpha != 1.) {
569 ✗ std::cerr << "Warning: alpha[0] should be 1" << std::endl;
570 }
571 ✗ for (std::size_t i = 1; i < alphas.size(); ++i) {
572 ✗ double alpha = alphas[i];
573 ✗ if (0. >= alpha) {
574 ✗ throw_pretty("Invalid argument: " << "alpha values has to be positive.");
575 }
576 ✗ if (alpha >= prev_alpha) {
577 ✗ throw_pretty(
578 "Invalid argument: " << "alpha values are monotonously decreasing.");
579 }
580 ✗ prev_alpha = alpha;
581 }
582 ✗ alphas_ = alphas;
583 ✗ }
584
585 ✗ void SolverDDP::set_th_stepdec(const double th_stepdec) {
586 ✗ if (0. >= th_stepdec || th_stepdec > 1.) {
587 ✗ throw_pretty(
588 "Invalid argument: " << "th_stepdec value should between 0 and 1.");
589 }
590 ✗ th_stepdec_ = th_stepdec;
591 ✗ }
592
593 ✗ void SolverDDP::set_th_stepinc(const double th_stepinc) {
594 ✗ if (0. >= th_stepinc || th_stepinc > 1.) {
595 ✗ throw_pretty(
596 "Invalid argument: " << "th_stepinc value should between 0 and 1.");
597 }
598 ✗ th_stepinc_ = th_stepinc;
599 ✗ }
600
601 ✗ void SolverDDP::set_th_grad(const double th_grad) {
602 ✗ if (0. > th_grad) {
603 ✗ throw_pretty("Invalid argument: " << "th_grad value has to be positive.");
604 }
605 ✗ th_grad_ = th_grad;
606 ✗ }
607
608 } // namespace crocoddyl
609