GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/crocoddyl/core/numdiff/action.hpp Lines: 20 22 90.9 %
Date: 2024-02-13 11:12:33 Branches: 19 34 55.9 %

Line Branch Exec Source
1
///////////////////////////////////////////////////////////////////////////////
2
// BSD 3-Clause License
3
//
4
// Copyright (C) 2019-2024, 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
50
  typedef _Scalar Scalar;
51
  typedef ActionDataAbstractTpl<Scalar> ActionDataAbstract;
52
  typedef ActionModelAbstractTpl<Scalar> Base;
53
  typedef ActionDataNumDiffTpl<Scalar> Data;
54
  typedef MathBaseTpl<Scalar> MathBase;
55
  typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
56
  typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
57
58
  /**
59
   * @brief Initialize the numdiff action model
60
   *
61
   * @param[in] model              Action model that we want to apply the
62
   * numerical differentiation
63
   * @param[in] with_gauss_approx  True if we want to use the Gauss
64
   * approximation for computing the Hessians
65
   */
66
  explicit ActionModelNumDiffTpl(boost::shared_ptr<Base> model,
67
                                 bool with_gauss_approx = false);
68
  virtual ~ActionModelNumDiffTpl();
69
70
  /**
71
   * @brief @copydoc Base::calc()
72
   */
73
  virtual void calc(const boost::shared_ptr<ActionDataAbstract>& data,
74
                    const Eigen::Ref<const VectorXs>& x,
75
                    const Eigen::Ref<const VectorXs>& u);
76
77
  /**
78
   * @brief @copydoc Base::calc(const boost::shared_ptr<ActionDataAbstract>&
79
   * data, const Eigen::Ref<const VectorXs>& x)
80
   */
81
  virtual void calc(const boost::shared_ptr<ActionDataAbstract>& data,
82
                    const Eigen::Ref<const VectorXs>& x);
83
84
  /**
85
   * @brief @copydoc Base::calcDiff()
86
   */
87
  virtual void calcDiff(const boost::shared_ptr<ActionDataAbstract>& data,
88
                        const Eigen::Ref<const VectorXs>& x,
89
                        const Eigen::Ref<const VectorXs>& u);
90
91
  /**
92
   * @brief @copydoc Base::calcDiff(const boost::shared_ptr<ActionDataAbstract>&
93
   * data, const Eigen::Ref<const VectorXs>& x)
94
   */
95
  virtual void calcDiff(const boost::shared_ptr<ActionDataAbstract>& data,
96
                        const Eigen::Ref<const VectorXs>& x);
97
98
  /**
99
   * @brief @copydoc Base::createData()
100
   */
101
  virtual boost::shared_ptr<ActionDataAbstract> createData();
102
103
  /**
104
   * @brief @copydoc Base::quasiStatic()
105
   */
106
  virtual void quasiStatic(const boost::shared_ptr<ActionDataAbstract>& data,
107
                           Eigen::Ref<VectorXs> u,
108
                           const Eigen::Ref<const VectorXs>& x,
109
                           const std::size_t maxiter = 100,
110
                           const Scalar tol = Scalar(1e-9));
111
112
  /**
113
   * @brief Return the acton model that we use to numerical differentiate
114
   */
115
  const boost::shared_ptr<Base>& get_model() const;
116
117
  /**
118
   * @brief Return the disturbance constant used in the numerical
119
   * differentiation routine
120
   */
121
  const Scalar get_disturbance() const;
122
123
  /**
124
   * @brief Modify the disturbance constant used in the numerical
125
   * differentiation routine
126
   */
127
  void set_disturbance(const Scalar disturbance);
128
129
  /**
130
   * @brief Identify if the Gauss approximation is going to be used or not.
131
   */
132
  bool get_with_gauss_approx();
133
134
  /**
135
   * @brief Print relevant information of the diff-action numdiff model
136
   *
137
   * @param[out] os  Output stream object
138
   */
139
  virtual void print(std::ostream& os) const;
140
141
 protected:
142
  using Base::has_control_limits_;  //!< Indicates whether any of the control
143
                                    //!< limits
144
  using Base::nr_;                  //!< Dimension of the cost residual
145
  using Base::nu_;                  //!< Control dimension
146
  using Base::state_;               //!< Model of the state
147
  using Base::u_lb_;                //!< Lower control limits
148
  using Base::u_ub_;                //!< Upper control limits
149
150
 private:
151
  /**
152
   * @brief Make sure that when we finite difference the Action Model, the user
153
   * does not face unknown behaviour because of the finite differencing of a
154
   * quaternion around pi. This behaviour might occur if CostModelState and
155
   * FloatingInContact differential model are used together.
156
   *
157
   * For full discussions see issue
158
   * https://gepgitlab.laas.fr/loco-3d/crocoddyl/issues/139
159
   *
160
   * @param x is the state at which the check is performed.
161
   */
162
  void assertStableStateFD(const Eigen::Ref<const VectorXs>& x);
163
164
  boost::shared_ptr<Base> model_;  //!< Action model hat we want to apply the
165
                                   //!< numerical differentiation
166
  Scalar e_jac_;   //!< Constant used for computing disturbances in Jacobian
167
                   //!< calculation
168
  Scalar e_hess_;  //!< Constant used for computing disturbances in Hessian
169
                   //!< calculation
170
  bool with_gauss_approx_;  //!< True if we want to use the Gauss approximation
171
                            //!< for computing the Hessians
172
};
173
174
template <typename _Scalar>
175
struct ActionDataNumDiffTpl : public ActionDataAbstractTpl<_Scalar> {
176
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
177
178
  typedef _Scalar Scalar;
179
  typedef MathBaseTpl<Scalar> MathBase;
180
  typedef ActionDataAbstractTpl<Scalar> Base;
181
  typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
182
  typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
183
184
  /**
185
   * @brief Initialize the numdiff action data
186
   *
187
   * @tparam Model is the type of the `ActionModelAbstractTpl`.
188
   * @param model is the object to compute the numerical differentiation from.
189
   */
190
  template <template <typename Scalar> class Model>
191
259
  explicit ActionDataNumDiffTpl(Model<Scalar>* const model)
192
      : Base(model),
193
259
        Rx(model->get_model()->get_nr(),
194
259
           model->get_model()->get_state()->get_ndx()),
195
518
        Ru(model->get_model()->get_nr(), model->get_model()->get_nu()),
196
259
        dx(model->get_model()->get_state()->get_ndx()),
197
259
        du(model->get_model()->get_nu()),
198


777
        xp(model->get_model()->get_state()->get_nx()) {
199
259
    Rx.setZero();
200
259
    Ru.setZero();
201
259
    dx.setZero();
202
259
    du.setZero();
203
259
    xp.setZero();
204
205
259
    const std::size_t ndx = model->get_model()->get_state()->get_ndx();
206
259
    const std::size_t nu = model->get_model()->get_nu();
207
259
    data_0 = model->get_model()->createData();
208
10826
    for (std::size_t i = 0; i < ndx; ++i) {
209

10567
      data_x.push_back(model->get_model()->createData());
210
    }
211
6893
    for (std::size_t i = 0; i < nu; ++i) {
212

6634
      data_u.push_back(model->get_model()->createData());
213
    }
214
259
  }
215
216
  using Base::cost;
217
  using Base::Fu;
218
  using Base::Fx;
219
  using Base::Lu;
220
  using Base::Luu;
221
  using Base::Lx;
222
  using Base::Lxu;
223
  using Base::Lxx;
224
  using Base::r;
225
  using Base::xnext;
226
227
  Scalar x_norm;  //!< Norm of the state vector
228
  Scalar
229
      xh_jac;  //!< Disturbance value used for computing \f$ \ell_\mathbf{x} \f$
230
  Scalar
231
      uh_jac;  //!< Disturbance value used for computing \f$ \ell_\mathbf{u} \f$
232
  Scalar xh_hess;  //!< Disturbance value used for computing \f$
233
                   //!< \ell_\mathbf{xx} \f$
234
  Scalar uh_hess;  //!< Disturbance value used for computing \f$
235
                   //!< \ell_\mathbf{uu} \f$
236
  Scalar xh_hess_pow2;
237
  Scalar uh_hess_pow2;
238
  Scalar xuh_hess_pow2;
239
  MatrixXs Rx;  //!< Cost residual jacobian: \f$ \frac{d r(x,u)}{dx} \f$
240
  MatrixXs Ru;  //!< Cost residual jacobian: \f$ \frac{d r(x,u)}{du} \f$
241
  VectorXs dx;  //!< State disturbance
242
  VectorXs du;  //!< Control disturbance
243
  VectorXs xp;  //!< The integrated state from the disturbance on one DoF "\f$
244
                //!< \int x dx_i \f$"
245
  boost::shared_ptr<Base> data_0;  //!< The data that contains the final results
246
  std::vector<boost::shared_ptr<Base> >
247
      data_x;  //!< The temporary data associated with the state variation
248
  std::vector<boost::shared_ptr<Base> >
249
      data_u;  //!< The temporary data associated with the control variation
250
};
251
252
}  // namespace crocoddyl
253
254
/* --- Details -------------------------------------------------------------- */
255
/* --- Details -------------------------------------------------------------- */
256
/* --- Details -------------------------------------------------------------- */
257
#include "crocoddyl/core/numdiff/action.hxx"
258
259
#endif  // CROCODDYL_CORE_NUMDIFF_ACTION_HPP_