GCC Code Coverage Report


Directory: ./
File: include/crocoddyl/core/numdiff/action.hpp
Date: 2025-03-26 19:23:43
Exec Total Coverage
Lines: 21 22 95.5%
Branches: 44 86 51.2%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, New York University,
5 // Max Planck Gesellschaft, University of Edinburgh,
6 // Heriot-Watt University
7 // Copyright note valid unless otherwise stated in individual files.
8 // All rights reserved.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #ifndef CROCODDYL_CORE_NUMDIFF_ACTION_HPP_
12 #define CROCODDYL_CORE_NUMDIFF_ACTION_HPP_
13
14 #include <vector>
15
16 #include "crocoddyl/core/action-base.hpp"
17 #include "crocoddyl/core/fwd.hpp"
18
19 namespace crocoddyl {
20
21 /**
22 * @brief This class computes the numerical differentiation of an action model.
23 *
24 * It computes the Jacobian of the cost, its residual and dynamics via numerical
25 * differentiation. It considers that the action model owns a cost residual and
26 * the cost is the square of this residual, i.e.,
27 * \f$\ell(\mathbf{x},\mathbf{u})=\frac{1}{2}\|\mathbf{r}(\mathbf{x},\mathbf{u})\|^2\f$,
28 * where \f$\mathbf{r}(\mathbf{x},\mathbf{u})\f$ is the residual vector. The
29 * Hessian is computed only through the Gauss-Newton approximation, i.e.,
30 * \f{eqnarray*}{
31 * \mathbf{\ell}_\mathbf{xx} &=& \mathbf{R_x}^T\mathbf{R_x} \\
32 * \mathbf{\ell}_\mathbf{uu} &=& \mathbf{R_u}^T\mathbf{R_u} \\
33 * \mathbf{\ell}_\mathbf{xu} &=& \mathbf{R_x}^T\mathbf{R_u}
34 * \f}
35 * where the Jacobians of the cost residuals are denoted by \f$\mathbf{R_x}\f$
36 * and \f$\mathbf{R_u}\f$. Note that this approximation ignores the tensor
37 * products (e.g., \f$\mathbf{R_{xx}}\mathbf{r}\f$).
38 *
39 * Finally, in the case that the cost does not have a residual, we set the
40 * Hessian to zero, i.e., \f$\mathbf{L_{xx}} = \mathbf{L_{xu}} = \mathbf{L_{uu}}
41 * = \mathbf{0}\f$.
42 *
43 * \sa `ActionModelAbstractTpl()`, `calcDiff()`
44 */
45 template <typename _Scalar>
46 class ActionModelNumDiffTpl : public ActionModelAbstractTpl<_Scalar> {
47 public:
48 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
49 CROCODDYL_DERIVED_CAST(ActionModelBase, ActionModelNumDiffTpl)
50
51 typedef _Scalar Scalar;
52 typedef ActionDataAbstractTpl<Scalar> ActionDataAbstract;
53 typedef ActionModelAbstractTpl<Scalar> Base;
54 typedef ActionDataNumDiffTpl<Scalar> Data;
55 typedef MathBaseTpl<Scalar> MathBase;
56 typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
57 typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
58
59 /**
60 * @brief Initialize the numdiff action model
61 *
62 * @param[in] model Action model that we want to apply the
63 * numerical differentiation
64 * @param[in] with_gauss_approx True if we want to use the Gauss
65 * approximation for computing the Hessians
66 */
67 explicit ActionModelNumDiffTpl(std::shared_ptr<Base> model,
68 bool with_gauss_approx = false);
69 542 virtual ~ActionModelNumDiffTpl() = default;
70
71 /**
72 * @brief @copydoc Base::calc()
73 */
74 virtual void calc(const std::shared_ptr<ActionDataAbstract>& data,
75 const Eigen::Ref<const VectorXs>& x,
76 const Eigen::Ref<const VectorXs>& u) override;
77
78 /**
79 * @brief @copydoc Base::calc(const std::shared_ptr<ActionDataAbstract>&
80 * data, const Eigen::Ref<const VectorXs>& x)
81 */
82 virtual void calc(const std::shared_ptr<ActionDataAbstract>& data,
83 const Eigen::Ref<const VectorXs>& x) override;
84
85 /**
86 * @brief @copydoc Base::calcDiff()
87 */
88 virtual void calcDiff(const std::shared_ptr<ActionDataAbstract>& data,
89 const Eigen::Ref<const VectorXs>& x,
90 const Eigen::Ref<const VectorXs>& u) override;
91
92 /**
93 * @brief @copydoc Base::calcDiff(const std::shared_ptr<ActionDataAbstract>&
94 * data, const Eigen::Ref<const VectorXs>& x)
95 */
96 virtual void calcDiff(const std::shared_ptr<ActionDataAbstract>& data,
97 const Eigen::Ref<const VectorXs>& x) override;
98
99 /**
100 * @brief @copydoc Base::createData()
101 */
102 virtual std::shared_ptr<ActionDataAbstract> createData() override;
103
104 /**
105 * @brief @copydoc Base::quasiStatic()
106 */
107 virtual void quasiStatic(const std::shared_ptr<ActionDataAbstract>& data,
108 Eigen::Ref<VectorXs> u,
109 const Eigen::Ref<const VectorXs>& x,
110 const std::size_t maxiter = 100,
111 const Scalar tol = Scalar(1e-9)) override;
112
113 /**
114 * @brief Cast the action numdiff model to a different scalar type.
115 *
116 * It is useful for operations requiring different precision or scalar types.
117 *
118 * @tparam NewScalar The new scalar type to cast to.
119 * @return ActionModelNumDiffTpl<NewScalar> An action model with the new
120 * scalar type.
121 */
122 template <typename NewScalar>
123 ActionModelNumDiffTpl<NewScalar> cast() const;
124
125 /**
126 * @brief Return the acton model that we use to numerical differentiate
127 */
128 const std::shared_ptr<Base>& get_model() const;
129
130 /**
131 * @brief Return the disturbance constant used in the numerical
132 * differentiation routine
133 */
134 const Scalar get_disturbance() const;
135
136 /**
137 * @brief Modify the disturbance constant used in the numerical
138 * differentiation routine
139 */
140 void set_disturbance(const Scalar disturbance);
141
142 /**
143 * @brief Identify if the Gauss approximation is going to be used or not.
144 */
145 bool get_with_gauss_approx();
146
147 /**
148 * @brief Print relevant information of the diff-action numdiff model
149 *
150 * @param[out] os Output stream object
151 */
152 virtual void print(std::ostream& os) const override;
153
154 protected:
155 using Base::has_control_limits_; //!< Indicates whether any of the control
156 //!< limits
157 using Base::nr_; //!< Dimension of the cost residual
158 using Base::nu_; //!< Control dimension
159 using Base::state_; //!< Model of the state
160 using Base::u_lb_; //!< Lower control limits
161 using Base::u_ub_; //!< Upper control limits
162
163 private:
164 /**
165 * @brief Make sure that when we finite difference the Action Model, the user
166 * does not face unknown behaviour because of the finite differencing of a
167 * quaternion around pi. This behaviour might occur if CostModelState and
168 * FloatingInContact differential model are used together.
169 *
170 * For full discussions see issue
171 * https://gepgitlab.laas.fr/loco-3d/crocoddyl/issues/139
172 *
173 * @param x is the state at which the check is performed.
174 */
175 void assertStableStateFD(const Eigen::Ref<const VectorXs>& x);
176
177 std::shared_ptr<Base> model_; //!< Action model hat we want to apply the
178 //!< numerical differentiation
179 Scalar e_jac_; //!< Constant used for computing disturbances in Jacobian
180 //!< calculation
181 Scalar e_hess_; //!< Constant used for computing disturbances in Hessian
182 //!< calculation
183 bool with_gauss_approx_; //!< True if we want to use the Gauss approximation
184 //!< for computing the Hessians
185 };
186
187 template <typename _Scalar>
188 struct ActionDataNumDiffTpl : public ActionDataAbstractTpl<_Scalar> {
189 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
190
191 typedef _Scalar Scalar;
192 typedef MathBaseTpl<Scalar> MathBase;
193 typedef ActionDataAbstractTpl<Scalar> Base;
194 typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
195 typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
196
197 /**
198 * @brief Initialize the numdiff action data
199 *
200 * @tparam Model is the type of the `ActionModelAbstractTpl`.
201 * @param model is the object to compute the numerical differentiation from.
202 */
203 template <template <typename Scalar> class Model>
204 270 explicit ActionDataNumDiffTpl(Model<Scalar>* const model)
205 : Base(model),
206
2/4
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
270 Rx(model->get_model()->get_nr(),
207
3/6
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 270 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 270 times.
✗ Branch 10 not taken.
270 model->get_model()->get_state()->get_ndx()),
208
5/10
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 270 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 270 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 270 times.
✗ Branch 16 not taken.
270 Ru(model->get_model()->get_nr(), model->get_model()->get_nu()),
209
4/8
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 270 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 270 times.
✗ Branch 13 not taken.
270 dx(model->get_model()->get_state()->get_ndx()),
210
3/6
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 270 times.
✗ Branch 9 not taken.
270 du(model->get_model()->get_nu()),
211
5/10
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 270 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 270 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 270 times.
✗ Branch 17 not taken.
540 xp(model->get_model()->get_state()->get_nx()) {
212
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 Rx.setZero();
213
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 Ru.setZero();
214
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 dx.setZero();
215
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 du.setZero();
216
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 xp.setZero();
217
218
3/6
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 270 times.
✗ Branch 10 not taken.
270 const std::size_t ndx = model->get_model()->get_state()->get_ndx();
219
2/4
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
270 const std::size_t nu = model->get_model()->get_nu();
220
2/4
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
270 data_0 = model->get_model()->createData();
221
2/2
✓ Branch 0 taken 11303 times.
✓ Branch 1 taken 270 times.
11573 for (std::size_t i = 0; i < ndx; ++i) {
222
3/6
✓ Branch 1 taken 11303 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 11303 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 11303 times.
✗ Branch 9 not taken.
11303 data_x.push_back(model->get_model()->createData());
223 }
224
2/2
✓ Branch 0 taken 7278 times.
✓ Branch 1 taken 270 times.
7548 for (std::size_t i = 0; i < nu; ++i) {
225
3/6
✓ Branch 1 taken 7278 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 7278 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 7278 times.
✗ Branch 9 not taken.
7278 data_u.push_back(model->get_model()->createData());
226 }
227 270 }
228
229 using Base::cost;
230 using Base::Fu;
231 using Base::Fx;
232 using Base::Lu;
233 using Base::Luu;
234 using Base::Lx;
235 using Base::Lxu;
236 using Base::Lxx;
237 using Base::r;
238 using Base::xnext;
239
240 Scalar x_norm; //!< Norm of the state vector
241 Scalar
242 xh_jac; //!< Disturbance value used for computing \f$ \ell_\mathbf{x} \f$
243 Scalar
244 uh_jac; //!< Disturbance value used for computing \f$ \ell_\mathbf{u} \f$
245 Scalar xh_hess; //!< Disturbance value used for computing \f$
246 //!< \ell_\mathbf{xx} \f$
247 Scalar uh_hess; //!< Disturbance value used for computing \f$
248 //!< \ell_\mathbf{uu} \f$
249 Scalar xh_hess_pow2;
250 Scalar uh_hess_pow2;
251 Scalar xuh_hess_pow2;
252 MatrixXs Rx; //!< Cost residual jacobian: \f$ \frac{d r(x,u)}{dx} \f$
253 MatrixXs Ru; //!< Cost residual jacobian: \f$ \frac{d r(x,u)}{du} \f$
254 VectorXs dx; //!< State disturbance
255 VectorXs du; //!< Control disturbance
256 VectorXs xp; //!< The integrated state from the disturbance on one DoF "\f$
257 //!< \int x dx_i \f$"
258 std::shared_ptr<Base> data_0; //!< The data that contains the final results
259 std::vector<std::shared_ptr<Base> >
260 data_x; //!< The temporary data associated with the state variation
261 std::vector<std::shared_ptr<Base> >
262 data_u; //!< The temporary data associated with the control variation
263 };
264
265 } // namespace crocoddyl
266
267 /* --- Details -------------------------------------------------------------- */
268 /* --- Details -------------------------------------------------------------- */
269 /* --- Details -------------------------------------------------------------- */
270 #include "crocoddyl/core/numdiff/action.hxx"
271
272 CROCODDYL_DECLARE_EXTERN_TEMPLATE_CLASS(crocoddyl::ActionModelNumDiffTpl)
273 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(crocoddyl::ActionDataNumDiffTpl)
274
275 #endif // CROCODDYL_CORE_NUMDIFF_ACTION_HPP_
276