GCC Code Coverage Report


Directory: ./
File: include/crocoddyl/core/integrator/rk.hxx
Date: 2025-05-13 10:30:51
Exec Total Coverage
Lines: 0 275 0.0%
Branches: 0 792 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, University of Edinburgh, University of Trento,
5 // LAAS-CNRS, IRI: CSIC-UPC, Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 namespace crocoddyl {
11
12 template <typename Scalar>
13 IntegratedActionModelRKTpl<Scalar>::IntegratedActionModelRKTpl(
14 std::shared_ptr<DifferentialActionModelAbstract> model,
15 std::shared_ptr<ControlParametrizationModelAbstract> control,
16 const RKType rktype, const Scalar time_step, const bool with_cost_residual)
17 : Base(model, control, time_step, with_cost_residual), rk_type_(rktype) {
18 set_rk_type(rktype);
19 }
20
21 template <typename Scalar>
22 IntegratedActionModelRKTpl<Scalar>::IntegratedActionModelRKTpl(
23 std::shared_ptr<DifferentialActionModelAbstract> model, const RKType rktype,
24 const Scalar time_step, const bool with_cost_residual)
25 : Base(model, time_step, with_cost_residual), rk_type_(rktype) {
26 set_rk_type(rktype);
27 }
28
29 template <typename Scalar>
30 void IntegratedActionModelRKTpl<Scalar>::calc(
31 const std::shared_ptr<ActionDataAbstract>& data,
32 const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) {
33 if (static_cast<std::size_t>(x.size()) != state_->get_nx()) {
34 throw_pretty(
35 "Invalid argument: " << "x has wrong dimension (it should be " +
36 std::to_string(state_->get_nx()) + ")");
37 }
38 if (static_cast<std::size_t>(u.size()) != nu_) {
39 throw_pretty(
40 "Invalid argument: " << "u has wrong dimension (it should be " +
41 std::to_string(nu_) + ")");
42 }
43 const std::size_t nv = state_->get_nv();
44 Data* d = static_cast<Data*>(data.get());
45
46 const std::shared_ptr<DifferentialActionDataAbstract>& k0_data =
47 d->differential[0];
48 const std::shared_ptr<ControlParametrizationDataAbstract>& u0_data =
49 d->control[0];
50 control_->calc(u0_data, rk_c_[0], u);
51 d->ws[0] = u0_data->w;
52 differential_->calc(k0_data, x, d->ws[0]);
53 d->y[0] = x;
54 d->ki[0].head(nv) = d->y[0].tail(nv);
55 d->ki[0].tail(nv) = k0_data->xout;
56 d->integral[0] = k0_data->cost;
57 for (std::size_t i = 1; i < ni_; ++i) {
58 const std::shared_ptr<DifferentialActionDataAbstract>& ki_data =
59 d->differential[i];
60 const std::shared_ptr<ControlParametrizationDataAbstract>& ui_data =
61 d->control[i];
62 d->dx_rk[i].noalias() = time_step_ * rk_c_[i] * d->ki[i - 1];
63 state_->integrate(x, d->dx_rk[i], d->y[i]);
64 control_->calc(ui_data, rk_c_[i], u);
65 d->ws[i] = ui_data->w;
66 differential_->calc(ki_data, d->y[i], d->ws[i]);
67 d->ki[i].head(nv) = d->y[i].tail(nv);
68 d->ki[i].tail(nv) = ki_data->xout;
69 d->integral[i] = ki_data->cost;
70 }
71
72 if (ni_ == 2) {
73 d->dx = d->ki[1] * time_step_;
74 d->cost = d->integral[1] * time_step_;
75 } else if (ni_ == 3) {
76 d->dx = (d->ki[0] + Scalar(3.) * d->ki[2]) * time_step_ / Scalar(4.);
77 d->cost = (d->integral[0] + Scalar(3.) * d->integral[2]) * time_step_ /
78 Scalar(4.);
79 } else {
80 d->dx =
81 (d->ki[0] + Scalar(2.) * d->ki[1] + Scalar(2.) * d->ki[2] + d->ki[3]) *
82 time_step_ / Scalar(6.);
83 d->cost = (d->integral[0] + Scalar(2.) * d->integral[1] +
84 Scalar(2.) * d->integral[2] + d->integral[3]) *
85 time_step_ / Scalar(6.);
86 }
87 state_->integrate(x, d->dx, d->xnext);
88 d->g = k0_data->g;
89 d->h = k0_data->h;
90 if (with_cost_residual_) {
91 d->r = k0_data->r;
92 }
93 }
94
95 template <typename Scalar>
96 void IntegratedActionModelRKTpl<Scalar>::calc(
97 const std::shared_ptr<ActionDataAbstract>& data,
98 const Eigen::Ref<const VectorXs>& x) {
99 if (static_cast<std::size_t>(x.size()) != state_->get_nx()) {
100 throw_pretty(
101 "Invalid argument: " << "x has wrong dimension (it should be " +
102 std::to_string(state_->get_nx()) + ")");
103 }
104 Data* d = static_cast<Data*>(data.get());
105
106 const std::shared_ptr<DifferentialActionDataAbstract>& k0_data =
107 d->differential[0];
108 differential_->calc(k0_data, x);
109 d->dx.setZero();
110 d->xnext = x;
111 d->cost = k0_data->cost;
112 d->g = k0_data->g;
113 d->h = k0_data->h;
114 if (with_cost_residual_) {
115 d->r = k0_data->r;
116 }
117 }
118
119 template <typename Scalar>
120 void IntegratedActionModelRKTpl<Scalar>::calcDiff(
121 const std::shared_ptr<ActionDataAbstract>& data,
122 const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) {
123 if (static_cast<std::size_t>(x.size()) != state_->get_nx()) {
124 throw_pretty(
125 "Invalid argument: " << "x has wrong dimension (it should be " +
126 std::to_string(state_->get_nx()) + ")");
127 }
128 if (static_cast<std::size_t>(u.size()) != nu_) {
129 throw_pretty(
130 "Invalid argument: " << "u has wrong dimension (it should be " +
131 std::to_string(nu_) + ")");
132 }
133 const std::size_t nv = state_->get_nv();
134 const std::size_t nu = control_->get_nu();
135 Data* d = static_cast<Data*>(data.get());
136 assert_pretty(
137 MatrixXs(d->dyi_dx[0])
138 .isApprox(MatrixXs::Identity(state_->get_ndx(), state_->get_ndx())),
139 "you have changed dyi_dx[0] values that supposed to be constant.");
140 assert_pretty(
141 MatrixXs(d->dki_dx[0])
142 .topRightCorner(nv, nv)
143 .isApprox(MatrixXs::Identity(nv, nv)),
144 "you have changed dki_dx[0] values that supposed to be constant.");
145
146 for (std::size_t i = 0; i < ni_; ++i) {
147 differential_->calcDiff(d->differential[i], d->y[i], d->ws[i]);
148 }
149
150 const std::shared_ptr<DifferentialActionDataAbstract>& k0_data =
151 d->differential[0];
152 const std::shared_ptr<ControlParametrizationDataAbstract>& u0_data =
153 d->control[0];
154 d->dki_dx[0].bottomRows(nv) = k0_data->Fx;
155 control_->multiplyByJacobian(
156 u0_data, k0_data->Fu,
157 d->dki_du[0].bottomRows(nv)); // dki_du = dki_dw * dw_du
158
159 d->dli_dx[0] = k0_data->Lx;
160 control_->multiplyJacobianTransposeBy(
161 u0_data, k0_data->Lu,
162 d->dli_du[0]); // dli_du = dli_dw * dw_du
163
164 d->ddli_ddx[0] = k0_data->Lxx;
165 d->ddli_ddw[0] = k0_data->Luu;
166 control_->multiplyByJacobian(
167 u0_data, d->ddli_ddw[0],
168 d->ddli_dwdu[0]); // ddli_dwdu = ddli_ddw * dw_du
169 control_->multiplyJacobianTransposeBy(
170 u0_data, d->ddli_dwdu[0],
171 d->ddli_ddu[0]); // ddli_ddu = dw_du.T * ddli_dwdu
172 d->ddli_dxdw[0] = k0_data->Lxu;
173 control_->multiplyByJacobian(
174 u0_data, d->ddli_dxdw[0],
175 d->ddli_dxdu[0]); // ddli_dxdu = ddli_dxdw * dw_du
176
177 for (std::size_t i = 1; i < ni_; ++i) {
178 const std::shared_ptr<DifferentialActionDataAbstract>& ki_data =
179 d->differential[i];
180 const std::shared_ptr<ControlParametrizationDataAbstract>& ui_data =
181 d->control[i];
182 d->dyi_dx[i].noalias() = d->dki_dx[i - 1] * rk_c_[i] * time_step_;
183 d->dyi_du[i].noalias() = d->dki_du[i - 1] * rk_c_[i] * time_step_;
184 state_->JintegrateTransport(x, d->dx_rk[i], d->dyi_dx[i], second);
185 state_->Jintegrate(x, d->dx_rk[i], d->dyi_dx[i], d->dyi_dx[i], first,
186 addto);
187 state_->JintegrateTransport(x, d->dx_rk[i], d->dyi_du[i],
188 second); // dyi_du = Jintegrate * dyi_du
189
190 // Sparse matrix-matrix multiplication for computing:
191 Eigen::Block<MatrixXs> dkvi_dq = d->dki_dx[i].bottomLeftCorner(nv, nv);
192 Eigen::Block<MatrixXs> dkvi_dv = d->dki_dx[i].bottomRightCorner(nv, nv);
193 Eigen::Block<MatrixXs> dkqi_du = d->dki_du[i].topLeftCorner(nv, nu);
194 Eigen::Block<MatrixXs> dkvi_du = d->dki_du[i].bottomLeftCorner(nv, nu);
195 const Eigen::Block<MatrixXs> dki_dqi = ki_data->Fx.bottomLeftCorner(nv, nv);
196 const Eigen::Block<MatrixXs> dki_dvi =
197 ki_data->Fx.bottomRightCorner(nv, nv);
198 const Eigen::Block<MatrixXs> dqi_dq = d->dyi_dx[i].topLeftCorner(nv, nv);
199 const Eigen::Block<MatrixXs> dqi_dv = d->dyi_dx[i].topRightCorner(nv, nv);
200 const Eigen::Block<MatrixXs> dvi_dq = d->dyi_dx[i].bottomLeftCorner(nv, nv);
201 const Eigen::Block<MatrixXs> dvi_dv =
202 d->dyi_dx[i].bottomRightCorner(nv, nv);
203 const Eigen::Block<MatrixXs> dqi_du = d->dyi_du[i].topLeftCorner(nv, nu);
204 const Eigen::Block<MatrixXs> dvi_du = d->dyi_du[i].bottomLeftCorner(nv, nu);
205 // i. d->dki_dx[i].noalias() = d->dki_dy[i] * d->dyi_dx[i], where dki_dy
206 // is ki_data.Fx
207 d->dki_dx[i].topRows(nv) = d->dyi_dx[i].bottomRows(nv);
208 dkvi_dq.noalias() = dki_dqi * dqi_dq;
209 if (i == 1) {
210 dkvi_dv = time_step_ / Scalar(2.) * dki_dqi;
211 } else {
212 dkvi_dv.noalias() = dki_dqi * dqi_dv;
213 }
214 dkvi_dq.noalias() += dki_dvi * dvi_dq;
215 dkvi_dv.noalias() += dki_dvi * dvi_dv;
216 // ii. d->dki_du[i].noalias() = d->dki_dy[i] * d->dyi_du[i], where dki_dy
217 // is ki_data.Fx
218 dkqi_du = dvi_du;
219 dkvi_du.noalias() = dki_dqi * dqi_du;
220 dkvi_du.noalias() += dki_dvi * dvi_du;
221
222 control_->multiplyByJacobian(ui_data, ki_data->Fu,
223 d->dki_du[i].bottomRows(nv),
224 addto); // dfi_du = dki_dw * dw_du
225
226 d->dli_dx[i].noalias() = ki_data->Lx.transpose() * d->dyi_dx[i];
227 control_->multiplyJacobianTransposeBy(ui_data, ki_data->Lu,
228 d->dli_du[i]); // dli_du = Lu * dw_du
229 d->dli_du[i].noalias() += ki_data->Lx.transpose() * d->dyi_du[i];
230
231 d->Lxx_partialx[i].noalias() = ki_data->Lxx * d->dyi_dx[i];
232 d->ddli_ddx[i].noalias() = d->dyi_dx[i].transpose() * d->Lxx_partialx[i];
233
234 control_->multiplyByJacobian(ui_data, ki_data->Lxu,
235 d->Lxu_i[i]); // Lxu = Lxw * dw_du
236 d->Luu_partialx[i].noalias() = d->Lxu_i[i].transpose() * d->dyi_du[i];
237 d->Lxx_partialu[i].noalias() = ki_data->Lxx * d->dyi_du[i];
238 control_->multiplyByJacobian(
239 ui_data, ki_data->Luu,
240 d->ddli_dwdu[i]); // ddli_dwdu = ddli_ddw * dw_du
241 control_->multiplyJacobianTransposeBy(
242 ui_data, d->ddli_dwdu[i],
243 d->ddli_ddu[i]); // ddli_ddu = dw_du.T * ddli_dwdu
244 d->ddli_ddu[i].noalias() += d->Luu_partialx[i].transpose() +
245 d->Luu_partialx[i] +
246 d->dyi_du[i].transpose() * d->Lxx_partialu[i];
247
248 d->ddli_dxdw[i].noalias() = d->dyi_dx[i].transpose() * ki_data->Lxu;
249 control_->multiplyByJacobian(
250 ui_data, d->ddli_dxdw[i],
251 d->ddli_dxdu[i]); // ddli_dxdu = ddli_dxdw * dw_du
252 d->ddli_dxdu[i].noalias() += d->dyi_dx[i].transpose() * d->Lxx_partialu[i];
253 }
254
255 if (ni_ == 2) {
256 d->Fx.noalias() = time_step_ * d->dki_dx[1];
257 d->Fu.noalias() = time_step_ * d->dki_du[1];
258 d->Lx.noalias() = time_step_ * d->dli_dx[1];
259 d->Lu.noalias() = time_step_ * d->dli_du[1];
260 d->Lxx.noalias() = time_step_ * d->ddli_ddx[1];
261 d->Luu.noalias() = time_step_ * d->ddli_ddu[1];
262 d->Lxu.noalias() = time_step_ * d->ddli_dxdu[1];
263 } else if (ni_ == 3) {
264 d->Fx.noalias() =
265 time_step_ / Scalar(4.) * (d->dki_dx[0] + Scalar(3.) * d->dki_dx[2]);
266 d->Fu.noalias() =
267 time_step_ / Scalar(4.) * (d->dki_du[0] + Scalar(3.) * d->dki_du[2]);
268 d->Lx.noalias() =
269 time_step_ / Scalar(4.) * (d->dli_dx[0] + Scalar(3.) * d->dli_dx[2]);
270 d->Lu.noalias() =
271 time_step_ / Scalar(4.) * (d->dli_du[0] + Scalar(3.) * d->dli_du[2]);
272 d->Lxx.noalias() = time_step_ / Scalar(4.) *
273 (d->ddli_ddx[0] + Scalar(3.) * d->ddli_ddx[2]);
274 d->Luu.noalias() = time_step_ / Scalar(4.) *
275 (d->ddli_ddu[0] + Scalar(3.) * d->ddli_ddu[2]);
276 d->Lxu.noalias() = time_step_ / Scalar(4.) *
277 (d->ddli_dxdu[0] + Scalar(3.) * d->ddli_dxdu[2]);
278 } else {
279 d->Fx.noalias() = time_step_ / Scalar(6.) *
280 (d->dki_dx[0] + Scalar(2.) * d->dki_dx[1] +
281 Scalar(2.) * d->dki_dx[2] + d->dki_dx[3]);
282 d->Fu.noalias() = time_step_ / Scalar(6.) *
283 (d->dki_du[0] + Scalar(2.) * d->dki_du[1] +
284 Scalar(2.) * d->dki_du[2] + d->dki_du[3]);
285 d->Lx.noalias() = time_step_ / Scalar(6.) *
286 (d->dli_dx[0] + Scalar(2.) * d->dli_dx[1] +
287 Scalar(2.) * d->dli_dx[2] + d->dli_dx[3]);
288 d->Lu.noalias() = time_step_ / Scalar(6.) *
289 (d->dli_du[0] + Scalar(2.) * d->dli_du[1] +
290 Scalar(2.) * d->dli_du[2] + d->dli_du[3]);
291 d->Lxx.noalias() = time_step_ / Scalar(6.) *
292 (d->ddli_ddx[0] + Scalar(2.) * d->ddli_ddx[1] +
293 Scalar(2.) * d->ddli_ddx[2] + d->ddli_ddx[3]);
294 d->Luu.noalias() = time_step_ / Scalar(6.) *
295 (d->ddli_ddu[0] + Scalar(2.) * d->ddli_ddu[1] +
296 Scalar(2.) * d->ddli_ddu[2] + d->ddli_ddu[3]);
297 d->Lxu.noalias() = time_step_ / Scalar(6.) *
298 (d->ddli_dxdu[0] + Scalar(2.) * d->ddli_dxdu[1] +
299 Scalar(2.) * d->ddli_dxdu[2] + d->ddli_dxdu[3]);
300 }
301 d->Gx = k0_data->Gx;
302 d->Hx = k0_data->Hx;
303 d->Gu.conservativeResize(differential_->get_ng(), nu_);
304 d->Hu.conservativeResize(differential_->get_nh(), nu_);
305 control_->multiplyByJacobian(u0_data, k0_data->Gu, d->Gu);
306 control_->multiplyByJacobian(u0_data, k0_data->Hu, d->Hu);
307
308 state_->JintegrateTransport(x, d->dx, d->Fx, second);
309 state_->Jintegrate(x, d->dx, d->Fx, d->Fx, first, addto);
310 state_->JintegrateTransport(x, d->dx, d->Fu, second);
311 }
312
313 template <typename Scalar>
314 void IntegratedActionModelRKTpl<Scalar>::calcDiff(
315 const std::shared_ptr<ActionDataAbstract>& data,
316 const Eigen::Ref<const VectorXs>& x) {
317 if (static_cast<std::size_t>(x.size()) != state_->get_nx()) {
318 throw_pretty(
319 "Invalid argument: " << "x has wrong dimension (it should be " +
320 std::to_string(state_->get_nx()) + ")");
321 }
322 Data* d = static_cast<Data*>(data.get());
323
324 const std::shared_ptr<DifferentialActionDataAbstract>& k0_data =
325 d->differential[0];
326 differential_->calcDiff(k0_data, x);
327 d->Lx = k0_data->Lx;
328 d->Lxx = k0_data->Lxx;
329 d->Gx = k0_data->Gx;
330 d->Hx = k0_data->Hx;
331 }
332
333 template <typename Scalar>
334 std::shared_ptr<ActionDataAbstractTpl<Scalar> >
335 IntegratedActionModelRKTpl<Scalar>::createData() {
336 return std::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
337 }
338
339 template <typename Scalar>
340 template <typename NewScalar>
341 IntegratedActionModelRKTpl<NewScalar> IntegratedActionModelRKTpl<Scalar>::cast()
342 const {
343 typedef IntegratedActionModelRKTpl<NewScalar> ReturnType;
344 if (control_) {
345 ReturnType ret(differential_->template cast<NewScalar>(),
346 control_->template cast<NewScalar>(), rk_type_,
347 scalar_cast<NewScalar>(time_step_), with_cost_residual_);
348 return ret;
349 } else {
350 ReturnType ret(differential_->template cast<NewScalar>(), rk_type_,
351 scalar_cast<NewScalar>(time_step_), with_cost_residual_);
352 return ret;
353 }
354 }
355
356 template <typename Scalar>
357 bool IntegratedActionModelRKTpl<Scalar>::checkData(
358 const std::shared_ptr<ActionDataAbstract>& data) {
359 std::shared_ptr<Data> d = std::dynamic_pointer_cast<Data>(data);
360 if (data != NULL) {
361 for (std::size_t i = 0; i < ni_; ++i) {
362 if (!differential_->checkData(d->differential[i])) {
363 return false;
364 }
365 }
366 return true;
367 } else {
368 return false;
369 }
370 }
371
372 template <typename Scalar>
373 void IntegratedActionModelRKTpl<Scalar>::quasiStatic(
374 const std::shared_ptr<ActionDataAbstract>& data, Eigen::Ref<VectorXs> u,
375 const Eigen::Ref<const VectorXs>& x, const std::size_t maxiter,
376 const Scalar tol) {
377 if (static_cast<std::size_t>(u.size()) != nu_) {
378 throw_pretty(
379 "Invalid argument: " << "u has wrong dimension (it should be " +
380 std::to_string(nu_) + ")");
381 }
382 if (static_cast<std::size_t>(x.size()) != state_->get_nx()) {
383 throw_pretty(
384 "Invalid argument: " << "x has wrong dimension (it should be " +
385 std::to_string(state_->get_nx()) + ")");
386 }
387
388 Data* d = static_cast<Data*>(data.get());
389 const std::shared_ptr<ControlParametrizationDataAbstract>& u0_data =
390 d->control[0];
391 u0_data->w *= Scalar(0.);
392 differential_->quasiStatic(d->differential[0], u0_data->w, x, maxiter, tol);
393 control_->params(u0_data, Scalar(0.), u0_data->w);
394 u = u0_data->u;
395 }
396
397 template <typename Scalar>
398 std::size_t IntegratedActionModelRKTpl<Scalar>::get_ni() const {
399 return ni_;
400 }
401
402 template <typename Scalar>
403 void IntegratedActionModelRKTpl<Scalar>::print(std::ostream& os) const {
404 os << "IntegratedActionModelRK {dt=" << time_step_ << ", " << *differential_
405 << "}";
406 }
407
408 template <typename Scalar>
409 void IntegratedActionModelRKTpl<Scalar>::set_rk_type(const RKType rktype) {
410 switch (rktype) {
411 case two:
412 ni_ = 2;
413 rk_c_.resize(ni_);
414 rk_c_[0] = Scalar(0.);
415 rk_c_[1] = Scalar(0.5);
416 break;
417 case three:
418 ni_ = 3;
419 rk_c_.resize(ni_);
420 rk_c_[0] = Scalar(0.);
421 rk_c_[1] = Scalar(1. / 3.);
422 rk_c_[2] = Scalar(2. / 3.);
423 break;
424 case four:
425 ni_ = 4;
426 rk_c_.resize(ni_);
427 rk_c_[0] = Scalar(0.);
428 rk_c_[1] = Scalar(0.5);
429 rk_c_[2] = Scalar(0.5);
430 rk_c_[3] = Scalar(1.);
431 break;
432 }
433 }
434
435 } // namespace crocoddyl
436