Directory: | ./ |
---|---|
File: | include/crocoddyl/core/numdiff/cost.hxx |
Date: | 2025-03-26 19:23:43 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 96 | 108 | 88.9% |
Branches: | 67 | 144 | 46.5% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | ||
2 | // BSD 3-Clause License | ||
3 | // | ||
4 | // Copyright (C) 2019-2025, University of Edinburgh, LAAS-CNRS, | ||
5 | // Heriot-Watt University | ||
6 | // Copyright note valid unless otherwise stated in individual files. | ||
7 | // All rights reserved. | ||
8 | /////////////////////////////////////////////////////////////////////////////// | ||
9 | |||
10 | #include "crocoddyl/core/numdiff/cost.hpp" | ||
11 | |||
12 | namespace crocoddyl { | ||
13 | |||
14 | template <typename Scalar> | ||
15 | 648 | CostModelNumDiffTpl<Scalar>::CostModelNumDiffTpl( | |
16 | const std::shared_ptr<Base>& model) | ||
17 | : Base(model->get_state(), model->get_activation(), model->get_nu()), | ||
18 | 648 | model_(model), | |
19 |
2/4✓ Branch 7 taken 648 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 648 times.
✗ Branch 12 not taken.
|
648 | e_jac_(sqrt(Scalar(2.0) * std::numeric_limits<Scalar>::epsilon())) {} |
20 | |||
21 | template <typename Scalar> | ||
22 | 648 | void CostModelNumDiffTpl<Scalar>::calc( | |
23 | const std::shared_ptr<CostDataAbstract>& data, | ||
24 | const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) { | ||
25 | 648 | Data* d = static_cast<Data*>(data.get()); | |
26 | 648 | d->data_0->cost = Scalar(0.); | |
27 | 648 | model_->calc(d->data_0, x, u); | |
28 | 648 | d->cost = d->data_0->cost; | |
29 | 648 | d->residual->r = d->data_0->residual->r; | |
30 | 648 | } | |
31 | |||
32 | template <typename Scalar> | ||
33 | 324 | void CostModelNumDiffTpl<Scalar>::calc( | |
34 | const std::shared_ptr<CostDataAbstract>& data, | ||
35 | const Eigen::Ref<const VectorXs>& x) { | ||
36 | 324 | Data* d = static_cast<Data*>(data.get()); | |
37 | 324 | d->data_0->cost = Scalar(0.); | |
38 | 324 | model_->calc(d->data_0, x); | |
39 | 324 | d->cost = d->data_0->cost; | |
40 | 324 | d->residual->r = d->data_0->residual->r; | |
41 | 324 | } | |
42 | |||
43 | template <typename Scalar> | ||
44 | 324 | void CostModelNumDiffTpl<Scalar>::calcDiff( | |
45 | const std::shared_ptr<CostDataAbstract>& data, | ||
46 | const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) { | ||
47 | 324 | Data* d = static_cast<Data*>(data.get()); | |
48 | |||
49 | 324 | const Scalar c0 = d->cost; | |
50 | 324 | const VectorXs& r0 = d->residual->r; | |
51 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | if (get_with_gauss_approx()) { |
52 |
1/2✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
|
324 | model_->get_activation()->calc(d->data_0->activation, r0); |
53 |
1/2✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
|
324 | model_->get_activation()->calcDiff(d->data_0->activation, r0); |
54 | } | ||
55 | 324 | d->du.setZero(); | |
56 | |||
57 | 324 | assertStableStateFD(x); | |
58 | |||
59 | // Computing the d cost(x,u) / dx | ||
60 |
4/8✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 324 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 324 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 324 times.
✗ Branch 17 not taken.
|
324 | model_->get_state()->diff(model_->get_state()->zero(), x, d->dx); |
61 | 324 | d->x_norm = d->dx.norm(); | |
62 | 324 | d->dx.setZero(); | |
63 | 324 | d->xh_jac = e_jac_ * std::max(Scalar(1.), d->x_norm); | |
64 |
2/2✓ Branch 2 taken 12978 times.
✓ Branch 3 taken 324 times.
|
13302 | for (std::size_t ix = 0; ix < state_->get_ndx(); ++ix) { |
65 | 12978 | d->dx(ix) = d->xh_jac; | |
66 |
2/4✓ Branch 5 taken 12978 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12978 times.
✗ Branch 9 not taken.
|
12978 | model_->get_state()->integrate(x, d->dx, d->xp); |
67 | // call the update function on the pinocchio data | ||
68 |
2/2✓ Branch 1 taken 13104 times.
✓ Branch 2 taken 12978 times.
|
26082 | for (size_t i = 0; i < reevals_.size(); ++i) { |
69 |
1/2✓ Branch 3 taken 13104 times.
✗ Branch 4 not taken.
|
13104 | reevals_[i](d->xp, u); |
70 | } | ||
71 |
1/2✓ Branch 4 taken 12978 times.
✗ Branch 5 not taken.
|
12978 | model_->calc(d->data_x[ix], d->xp, u); |
72 | 12978 | d->Lx(ix) = (d->data_x[ix]->cost - c0) / d->xh_jac; | |
73 |
1/2✓ Branch 1 taken 12978 times.
✗ Branch 2 not taken.
|
12978 | if (get_with_gauss_approx()) { |
74 |
3/6✓ Branch 5 taken 12978 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12978 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12978 times.
✗ Branch 13 not taken.
|
12978 | d->residual->Rx.col(ix) = (d->data_x[ix]->residual->r - r0) / d->xh_jac; |
75 | } | ||
76 | 12978 | d->dx(ix) = Scalar(0.); | |
77 | } | ||
78 | |||
79 | // Computing the d cost(x,u) / du | ||
80 | 324 | d->uh_jac = e_jac_ * std::max(Scalar(1.), u.norm()); | |
81 |
2/2✓ Branch 2 taken 6489 times.
✓ Branch 3 taken 324 times.
|
6813 | for (std::size_t iu = 0; iu < model_->get_nu(); ++iu) { |
82 | 6489 | d->du(iu) = d->uh_jac; | |
83 |
1/2✓ Branch 2 taken 6489 times.
✗ Branch 3 not taken.
|
6489 | d->up = u + d->du; |
84 | // call the update function | ||
85 |
2/2✓ Branch 1 taken 6552 times.
✓ Branch 2 taken 6489 times.
|
13041 | for (std::size_t i = 0; i < reevals_.size(); ++i) { |
86 |
1/2✓ Branch 3 taken 6552 times.
✗ Branch 4 not taken.
|
6552 | reevals_[i](x, d->up); |
87 | } | ||
88 |
1/2✓ Branch 4 taken 6489 times.
✗ Branch 5 not taken.
|
6489 | model_->calc(d->data_u[iu], x, d->up); |
89 | 6489 | d->Lu(iu) = (d->data_u[iu]->cost - c0) / d->uh_jac; | |
90 |
1/2✓ Branch 1 taken 6489 times.
✗ Branch 2 not taken.
|
6489 | if (get_with_gauss_approx()) { |
91 |
3/6✓ Branch 5 taken 6489 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 6489 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 6489 times.
✗ Branch 13 not taken.
|
6489 | d->residual->Ru.col(iu) = (d->data_u[iu]->residual->r - r0) / d->uh_jac; |
92 | } | ||
93 | 6489 | d->du(iu) = Scalar(0.); | |
94 | } | ||
95 | |||
96 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | if (get_with_gauss_approx()) { |
97 |
1/2✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
|
324 | const MatrixXs& Arr = d->data_0->activation->Arr; |
98 |
4/8✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 324 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
|
324 | d->Lxx = d->residual->Rx.transpose() * Arr * d->residual->Rx; |
99 |
4/8✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 324 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
|
324 | d->Lxu = d->residual->Rx.transpose() * Arr * d->residual->Ru; |
100 |
4/8✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 324 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
|
324 | d->Luu = d->residual->Ru.transpose() * Arr * d->residual->Ru; |
101 | 324 | } else { | |
102 | ✗ | d->Lxx.fill(Scalar(0.)); | |
103 | ✗ | d->Lxu.fill(Scalar(0.)); | |
104 | ✗ | d->Luu.fill(Scalar(0.)); | |
105 | } | ||
106 | 324 | } | |
107 | |||
108 | template <typename Scalar> | ||
109 | 324 | void CostModelNumDiffTpl<Scalar>::calcDiff( | |
110 | const std::shared_ptr<CostDataAbstract>& data, | ||
111 | const Eigen::Ref<const VectorXs>& x) { | ||
112 | 324 | Data* d = static_cast<Data*>(data.get()); | |
113 | |||
114 | 324 | const Scalar c0 = d->cost; | |
115 | 324 | const VectorXs& r0 = d->residual->r; | |
116 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | if (get_with_gauss_approx()) { |
117 |
1/2✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
|
324 | model_->get_activation()->calc(d->data_0->activation, r0); |
118 |
1/2✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
|
324 | model_->get_activation()->calcDiff(d->data_0->activation, r0); |
119 | } | ||
120 | 324 | d->dx.setZero(); | |
121 | |||
122 | 324 | assertStableStateFD(x); | |
123 | |||
124 | // Computing the d cost(x,u) / dx | ||
125 | 324 | d->xh_jac = e_jac_ * std::max(Scalar(1.), x.norm()); | |
126 |
2/2✓ Branch 2 taken 12978 times.
✓ Branch 3 taken 324 times.
|
13302 | for (std::size_t ix = 0; ix < state_->get_ndx(); ++ix) { |
127 | 12978 | d->dx(ix) = d->xh_jac; | |
128 |
2/4✓ Branch 5 taken 12978 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12978 times.
✗ Branch 9 not taken.
|
12978 | model_->get_state()->integrate(x, d->dx, d->xp); |
129 | // call the update function on the pinocchio data | ||
130 |
2/2✓ Branch 1 taken 13104 times.
✓ Branch 2 taken 12978 times.
|
26082 | for (size_t i = 0; i < reevals_.size(); ++i) { |
131 | 13104 | reevals_[i](d->xp, unone_); | |
132 | } | ||
133 |
1/2✓ Branch 4 taken 12978 times.
✗ Branch 5 not taken.
|
12978 | model_->calc(d->data_x[ix], d->xp); |
134 | 12978 | d->Lx(ix) = (d->data_x[ix]->cost - c0) / d->xh_jac; | |
135 |
1/2✓ Branch 1 taken 12978 times.
✗ Branch 2 not taken.
|
12978 | if (get_with_gauss_approx()) { |
136 |
3/6✓ Branch 5 taken 12978 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12978 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12978 times.
✗ Branch 13 not taken.
|
12978 | d->residual->Rx.col(ix) = (d->data_x[ix]->residual->r - r0) / d->xh_jac; |
137 | } | ||
138 | 12978 | d->dx(ix) = Scalar(0.); | |
139 | } | ||
140 | |||
141 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | if (get_with_gauss_approx()) { |
142 |
1/2✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
|
324 | const MatrixXs& Arr = d->data_0->activation->Arr; |
143 |
4/8✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 324 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
|
324 | d->Lxx = d->residual->Rx.transpose() * Arr * d->residual->Rx; |
144 | 324 | } else { | |
145 | ✗ | d->Lxx.fill(Scalar(0.)); | |
146 | } | ||
147 | 324 | } | |
148 | |||
149 | template <typename Scalar> | ||
150 | std::shared_ptr<CostDataAbstractTpl<Scalar> > | ||
151 | 648 | CostModelNumDiffTpl<Scalar>::createData(DataCollectorAbstract* const data) { | |
152 | ✗ | return std::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this, | |
153 |
1/2✓ Branch 2 taken 648 times.
✗ Branch 3 not taken.
|
648 | data); |
154 | } | ||
155 | |||
156 | template <typename Scalar> | ||
157 | template <typename NewScalar> | ||
158 | ✗ | CostModelNumDiffTpl<NewScalar> CostModelNumDiffTpl<Scalar>::cast() const { | |
159 | typedef CostModelNumDiffTpl<NewScalar> ReturnType; | ||
160 | ✗ | ReturnType res(model_->template cast<NewScalar>()); | |
161 | ✗ | return res; | |
162 | } | ||
163 | |||
164 | template <typename Scalar> | ||
165 | const std::shared_ptr<CostModelAbstractTpl<Scalar> >& | ||
166 | 40878 | CostModelNumDiffTpl<Scalar>::get_model() const { | |
167 | 40878 | return model_; | |
168 | } | ||
169 | |||
170 | template <typename Scalar> | ||
171 | 639 | const Scalar CostModelNumDiffTpl<Scalar>::get_disturbance() const { | |
172 | 639 | return e_jac_; | |
173 | } | ||
174 | |||
175 | template <typename Scalar> | ||
176 | ✗ | void CostModelNumDiffTpl<Scalar>::set_disturbance(const Scalar disturbance) { | |
177 | ✗ | if (disturbance < Scalar(0.)) { | |
178 | ✗ | throw_pretty("Invalid argument: " << "Disturbance constant is positive"); | |
179 | } | ||
180 | ✗ | e_jac_ = disturbance; | |
181 | } | ||
182 | |||
183 | template <typename Scalar> | ||
184 | 34389 | bool CostModelNumDiffTpl<Scalar>::get_with_gauss_approx() { | |
185 | 34389 | return activation_->get_nr() > 0; | |
186 | } | ||
187 | |||
188 | template <typename Scalar> | ||
189 | 324 | void CostModelNumDiffTpl<Scalar>::set_reevals( | |
190 | const std::vector<ReevaluationFunction>& reevals) { | ||
191 | 324 | reevals_ = reevals; | |
192 | 324 | } | |
193 | |||
194 | template <typename Scalar> | ||
195 | 648 | void CostModelNumDiffTpl<Scalar>::assertStableStateFD( | |
196 | const Eigen::Ref<const VectorXs>& /*x*/) { | ||
197 | // do nothing in the general case | ||
198 | 648 | } | |
199 | |||
200 | } // namespace crocoddyl | ||
201 |