GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/crocoddyl/core/solvers/ddp.hpp Lines: 0 1 0.0 %
Date: 2024-02-13 11:12:33 Branches: 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
#ifndef CROCODDYL_CORE_SOLVERS_DDP_HPP_
11
#define CROCODDYL_CORE_SOLVERS_DDP_HPP_
12
13
#include <Eigen/Cholesky>
14
#include <vector>
15
16
#include "crocoddyl/core/mathbase.hpp"
17
#include "crocoddyl/core/solver-base.hpp"
18
#include "crocoddyl/core/utils/deprecate.hpp"
19
20
namespace crocoddyl {
21
22
/**
23
 * @brief Differential Dynamic Programming (DDP) solver
24
 *
25
 * The DDP solver computes an optimal trajectory and control commands by
26
 * iterates running `backwardPass()` and `forwardPass()`. The backward-pass
27
 * updates locally the quadratic approximation of the problem and computes
28
 * descent direction. If the warm-start is feasible, then it computes the gaps
29
 * \f$\mathbf{f}_s\f$ and run a modified Riccati sweep: \f{eqnarray*}
30
 *   \mathbf{Q}_{\mathbf{x}_k} &=& \mathbf{l}_{\mathbf{x}_k} +
31
 * \mathbf{f}^\top_{\mathbf{x}_k} (V_{\mathbf{x}_{k+1}} +
32
 * V_{\mathbf{xx}_{k+1}}\mathbf{\bar{f}}_{k+1}),\\
33
 *   \mathbf{Q}_{\mathbf{u}_k} &=& \mathbf{l}_{\mathbf{u}_k} +
34
 * \mathbf{f}^\top_{\mathbf{u}_k} (V_{\mathbf{x}_{k+1}} +
35
 * V_{\mathbf{xx}_{k+1}}\mathbf{\bar{f}}_{k+1}),\\
36
 *   \mathbf{Q}_{\mathbf{xx}_k} &=& \mathbf{l}_{\mathbf{xx}_k} +
37
 * \mathbf{f}^\top_{\mathbf{x}_k} V_{\mathbf{xx}_{k+1}}
38
 * \mathbf{f}_{\mathbf{x}_k},\\
39
 *   \mathbf{Q}_{\mathbf{xu}_k} &=& \mathbf{l}_{\mathbf{xu}_k} +
40
 * \mathbf{f}^\top_{\mathbf{x}_k} V_{\mathbf{xx}_{k+1}}
41
 * \mathbf{f}_{\mathbf{u}_k},\\
42
 *   \mathbf{Q}_{\mathbf{uu}_k} &=& \mathbf{l}_{\mathbf{uu}_k} +
43
 * \mathbf{f}^\top_{\mathbf{u}_k} V_{\mathbf{xx}_{k+1}}
44
 * \mathbf{f}_{\mathbf{u}_k}.
45
 * \f}
46
 * Then, the forward-pass rollouts this new policy by integrating the system
47
 * dynamics along a tuple of optimized control commands \f$\mathbf{u}^*_s\f$,
48
 * i.e. \f{eqnarray}
49
 *   \mathbf{\hat{x}}_0 &=& \mathbf{\tilde{x}}_0,\\
50
 *   \mathbf{\hat{u}}_k &=& \mathbf{u}_k + \alpha\mathbf{k}_k +
51
 * \mathbf{K}_k(\mathbf{\hat{x}}_k-\mathbf{x}_k),\\ \mathbf{\hat{x}}_{k+1} &=&
52
 * \mathbf{f}_k(\mathbf{\hat{x}}_k,\mathbf{\hat{u}}_k). \f}
53
 *
54
 * \sa SolverAbstract(), `backwardPass()` and `forwardPass()`
55
 */
56
class SolverDDP : public SolverAbstract {
57
 public:
58
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
59
60
  typedef typename MathBaseTpl<double>::MatrixXsRowMajor MatrixXdRowMajor;
61
62
  /**
63
   * @brief Initialize the DDP solver
64
   *
65
   * @param[in] problem  shooting problem
66
   */
67
  explicit SolverDDP(boost::shared_ptr<ShootingProblem> problem);
68
  virtual ~SolverDDP();
69
70
  virtual bool solve(
71
      const std::vector<Eigen::VectorXd>& init_xs = DEFAULT_VECTOR,
72
      const std::vector<Eigen::VectorXd>& init_us = DEFAULT_VECTOR,
73
      const std::size_t maxiter = 100, const bool is_feasible = false,
74
      const double init_reg = NAN);
75
  virtual void computeDirection(const bool recalc = true);
76
  virtual double tryStep(const double steplength = 1);
77
  virtual double stoppingCriteria();
78
  virtual const Eigen::Vector2d& expectedImprovement();
79
  virtual void resizeData();
80
81
  /**
82
   * @brief Update the Jacobian, Hessian and feasibility of the optimal control
83
   * problem
84
   *
85
   * These derivatives are computed around the guess state and control
86
   * trajectory. These trajectory can be set by using `setCandidate()`.
87
   *
88
   * @return the total cost around the guess trajectory
89
   */
90
  virtual double calcDiff();
91
92
  /**
93
   * @brief Run the backward pass (Riccati sweep)
94
   *
95
   * It assumes that the Jacobian and Hessians of the optimal control problem
96
   * have been compute (i.e., `calcDiff()`). The backward pass handles
97
   * infeasible guess through a modified Riccati sweep: \f{eqnarray*}
98
   *   \mathbf{Q}_{\mathbf{x}_k} &=& \mathbf{l}_{\mathbf{x}_k} +
99
   * \mathbf{f}^\top_{\mathbf{x}_k} (V_{\mathbf{x}_{k+1}}
100
   * +
101
   * V_{\mathbf{xx}_{k+1}}\mathbf{\bar{f}}_{k+1}),\\
102
   *   \mathbf{Q}_{\mathbf{u}_k} &=& \mathbf{l}_{\mathbf{u}_k} +
103
   * \mathbf{f}^\top_{\mathbf{u}_k} (V_{\mathbf{x}_{k+1}}
104
   * +
105
   * V_{\mathbf{xx}_{k+1}}\mathbf{\bar{f}}_{k+1}),\\
106
   *   \mathbf{Q}_{\mathbf{xx}_k} &=& \mathbf{l}_{\mathbf{xx}_k} +
107
   * \mathbf{f}^\top_{\mathbf{x}_k} V_{\mathbf{xx}_{k+1}}
108
   * \mathbf{f}_{\mathbf{x}_k},\\
109
   *   \mathbf{Q}_{\mathbf{xu}_k} &=& \mathbf{l}_{\mathbf{xu}_k} +
110
   * \mathbf{f}^\top_{\mathbf{x}_k} V_{\mathbf{xx}_{k+1}}
111
   * \mathbf{f}_{\mathbf{u}_k},\\
112
   *   \mathbf{Q}_{\mathbf{uu}_k} &=& \mathbf{l}_{\mathbf{uu}_k} +
113
   * \mathbf{f}^\top_{\mathbf{u}_k} V_{\mathbf{xx}_{k+1}}
114
   * \mathbf{f}_{\mathbf{u}_k}, \f} where
115
   * \f$\mathbf{l}_{\mathbf{x}_k}\f$,\f$\mathbf{l}_{\mathbf{u}_k}\f$,\f$\mathbf{f}_{\mathbf{x}_k}\f$
116
   * and \f$\mathbf{f}_{\mathbf{u}_k}\f$ are the Jacobians of the cost function
117
   * and dynamics,
118
   * \f$\mathbf{l}_{\mathbf{xx}_k}\f$,\f$\mathbf{l}_{\mathbf{xu}_k}\f$ and
119
   * \f$\mathbf{l}_{\mathbf{uu}_k}\f$ are the Hessians of the cost function,
120
   * \f$V_{\mathbf{x}_{k+1}}\f$ and \f$V_{\mathbf{xx}_{k+1}}\f$ defines the
121
   * linear-quadratic approximation of the Value function, and
122
   * \f$\mathbf{\bar{f}}_{k+1}\f$ describes the gaps of the dynamics.
123
   */
124
  virtual void backwardPass();
125
126
  /**
127
   * @brief Run the forward pass or rollout
128
   *
129
   * It rollouts the action model given the computed policy (feedforward terns
130
   * and feedback gains) by the `backwardPass()`: \f{eqnarray}
131
   *   \mathbf{\hat{x}}_0 &=& \mathbf{\tilde{x}}_0,\\
132
   *   \mathbf{\hat{u}}_k &=& \mathbf{u}_k + \alpha\mathbf{k}_k +
133
   * \mathbf{K}_k(\mathbf{\hat{x}}_k-\mathbf{x}_k),\\ \mathbf{\hat{x}}_{k+1} &=&
134
   * \mathbf{f}_k(\mathbf{\hat{x}}_k,\mathbf{\hat{u}}_k). \f} We can define
135
   * different step lengths \f$\alpha\f$.
136
   *
137
   * @param stepLength  applied step length (\f$0\leq\alpha\leq1\f$)
138
   */
139
  virtual void forwardPass(const double stepLength);
140
141
  /**
142
   * @brief Compute the linear-quadratic approximation of the control
143
   * Hamiltonian function
144
   *
145
   * @param[in] t      Time instance
146
   * @param[in] model  Action model in the given time instance
147
   * @param[in] data   Action data in the given time instance
148
   */
149
  virtual void computeActionValueFunction(
150
      const std::size_t t, const boost::shared_ptr<ActionModelAbstract>& model,
151
      const boost::shared_ptr<ActionDataAbstract>& data);
152
153
  /**
154
   * @brief Compute the linear-quadratic approximation of the Value function
155
   *
156
   * This function is called in the backward pass after updating the local
157
   * Hamiltonian.
158
   *
159
   * @param[in] t      Time instance
160
   * @param[in] model  Action model in the given time instance
161
   */
162
  virtual void computeValueFunction(
163
      const std::size_t t, const boost::shared_ptr<ActionModelAbstract>& model);
164
165
  /**
166
   * @brief Compute the feedforward and feedback terms using a Cholesky
167
   * decomposition
168
   *
169
   * To compute the feedforward \f$\mathbf{k}_k\f$ and feedback
170
   * \f$\mathbf{K}_k\f$ terms, we use a Cholesky decomposition to solve
171
   * \f$\mathbf{Q}_{\mathbf{uu}_k}^{-1}\f$ term: \f{eqnarray}
172
   * \mathbf{k}_k &=& \mathbf{Q}_{\mathbf{uu}_k}^{-1}\mathbf{Q}_{\mathbf{u}},\\
173
   * \mathbf{K}_k &=& \mathbf{Q}_{\mathbf{uu}_k}^{-1}\mathbf{Q}_{\mathbf{ux}}.
174
   * \f}
175
   *
176
   * Note that if the Cholesky decomposition fails, then we re-start the
177
   * backward pass and increase the state and control regularization values.
178
   */
179
  virtual void computeGains(const std::size_t t);
180
181
  /**
182
   * @brief Increase the state and control regularization values by a
183
   * `regfactor_` factor
184
   */
185
  void increaseRegularization();
186
187
  /**
188
   * @brief Decrease the state and control regularization values by a
189
   * `regfactor_` factor
190
   */
191
  void decreaseRegularization();
192
193
  /**
194
   * @brief Allocate all the internal data needed for the solver
195
   */
196
  virtual void allocateData();
197
198
  /**
199
   * @brief Return the regularization factor used to increase the damping value
200
   */
201
  double get_reg_incfactor() const;
202
203
  /**
204
   * @brief Return the regularization factor used to decrease the damping value
205
   */
206
  double get_reg_decfactor() const;
207
208
  /**
209
   * @brief Return the regularization factor used to decrease / increase it
210
   */
211
  DEPRECATED("Use get_reg_incfactor() or get_reg_decfactor()",
212
             double get_regfactor() const;)
213
214
  /**
215
   * @brief Return the minimum regularization value
216
   */
217
  double get_reg_min() const;
218
  DEPRECATED("Use get_reg_min()", double get_regmin() const);
219
220
  /**
221
   * @brief Return the maximum regularization value
222
   */
223
  double get_reg_max() const;
224
  DEPRECATED("Use get_reg_max()", double get_regmax() const);
225
226
  /**
227
   * @brief Return the set of step lengths using by the line-search procedure
228
   */
229
  const std::vector<double>& get_alphas() const;
230
231
  /**
232
   * @brief Return the step-length threshold used to decrease regularization
233
   */
234
  double get_th_stepdec() const;
235
236
  /**
237
   * @brief Return the step-length threshold used to increase regularization
238
   */
239
  double get_th_stepinc() const;
240
241
  /**
242
   * @brief Return the tolerance of the expected gradient used for testing the
243
   * step
244
   */
245
  double get_th_grad() const;
246
247
  /**
248
   * @brief Return the Hessian of the Value function \f$V_{\mathbf{xx}_s}\f$
249
   */
250
  const std::vector<Eigen::MatrixXd>& get_Vxx() const;
251
252
  /**
253
   * @brief Return the Hessian of the Value function \f$V_{\mathbf{x}_s}\f$
254
   */
255
  const std::vector<Eigen::VectorXd>& get_Vx() const;
256
257
  /**
258
   * @brief Return the Hessian of the Hamiltonian function
259
   * \f$\mathbf{Q}_{\mathbf{xx}_s}\f$
260
   */
261
  const std::vector<Eigen::MatrixXd>& get_Qxx() const;
262
263
  /**
264
   * @brief Return the Hessian of the Hamiltonian function
265
   * \f$\mathbf{Q}_{\mathbf{xu}_s}\f$
266
   */
267
  const std::vector<Eigen::MatrixXd>& get_Qxu() const;
268
269
  /**
270
   * @brief Return the Hessian of the Hamiltonian function
271
   * \f$\mathbf{Q}_{\mathbf{uu}_s}\f$
272
   */
273
  const std::vector<Eigen::MatrixXd>& get_Quu() const;
274
275
  /**
276
   * @brief Return the Jacobian of the Hamiltonian function
277
   * \f$\mathbf{Q}_{\mathbf{x}_s}\f$
278
   */
279
  const std::vector<Eigen::VectorXd>& get_Qx() const;
280
281
  /**
282
   * @brief Return the Jacobian of the Hamiltonian function
283
   * \f$\mathbf{Q}_{\mathbf{u}_s}\f$
284
   */
285
  const std::vector<Eigen::VectorXd>& get_Qu() const;
286
287
  /**
288
   * @brief Return the feedback gains \f$\mathbf{K}_{s}\f$
289
   */
290
  const std::vector<MatrixXdRowMajor>& get_K() const;
291
292
  /**
293
   * @brief Return the feedforward gains \f$\mathbf{k}_{s}\f$
294
   */
295
  const std::vector<Eigen::VectorXd>& get_k() const;
296
297
  /**
298
   * @brief Modify the regularization factor used to increase the damping value
299
   */
300
  void set_reg_incfactor(const double reg_factor);
301
302
  /**
303
   * @brief Modify the regularization factor used to decrease the damping value
304
   */
305
  void set_reg_decfactor(const double reg_factor);
306
307
  /**
308
   * @brief Modify the regularization factor used to decrease / increase it
309
   */
310
  DEPRECATED("Use set_reg_incfactor() or set_reg_decfactor()",
311
             void set_regfactor(const double reg_factor);)
312
313
  /**
314
   * @brief Modify the minimum regularization value
315
   */
316
  void set_reg_min(const double regmin);
317
  DEPRECATED("Use set_reg_min()", void set_regmin(const double regmin));
318
319
  /**
320
   * @brief Modify the maximum regularization value
321
   */
322
  void set_reg_max(const double regmax);
323
  DEPRECATED("Use set_reg_max()", void set_regmax(const double regmax));
324
325
  /**
326
   * @brief Modify the set of step lengths using by the line-search procedure
327
   */
328
  void set_alphas(const std::vector<double>& alphas);
329
330
  /**
331
   * @brief Modify the step-length threshold used to decrease regularization
332
   */
333
  void set_th_stepdec(const double th_step);
334
335
  /**
336
   * @brief Modify the step-length threshold used to increase regularization
337
   */
338
  void set_th_stepinc(const double th_step);
339
340
  /**
341
   * @brief Modify the tolerance of the expected gradient used for testing the
342
   * step
343
   */
344
  void set_th_grad(const double th_grad);
345
346
 protected:
347
  double reg_incfactor_;  //!< Regularization factor used to increase the
348
                          //!< damping value
349
  double reg_decfactor_;  //!< Regularization factor used to decrease the
350
                          //!< damping value
351
  double reg_min_;        //!< Minimum allowed regularization value
352
  double reg_max_;        //!< Maximum allowed regularization value
353
354
  double cost_try_;  //!< Total cost computed by line-search procedure
355
  std::vector<Eigen::VectorXd>
356
      xs_try_;  //!< State trajectory computed by line-search procedure
357
  std::vector<Eigen::VectorXd>
358
      us_try_;  //!< Control trajectory computed by line-search procedure
359
  std::vector<Eigen::VectorXd>
360
      dx_;  //!< State error during the roll-out/forward-pass (size T)
361
362
  // allocate data
363
  std::vector<Eigen::MatrixXd>
364
      Vxx_;  //!< Hessian of the Value function \f$\mathbf{V_{xx}}\f$
365
  Eigen::MatrixXd
366
      Vxx_tmp_;  //!< Temporary variable for ensuring symmetry of Vxx
367
  std::vector<Eigen::VectorXd>
368
      Vx_;  //!< Gradient of the Value function \f$\mathbf{V_x}\f$
369
  std::vector<Eigen::MatrixXd>
370
      Qxx_;  //!< Hessian of the Hamiltonian \f$\mathbf{Q_{xx}}\f$
371
  std::vector<Eigen::MatrixXd>
372
      Qxu_;  //!< Hessian of the Hamiltonian \f$\mathbf{Q_{xu}}\f$
373
  std::vector<Eigen::MatrixXd>
374
      Quu_;  //!< Hessian of the Hamiltonian \f$\mathbf{Q_{uu}}\f$
375
  std::vector<Eigen::VectorXd>
376
      Qx_;  //!< Gradient of the Hamiltonian \f$\mathbf{Q_x}\f$
377
  std::vector<Eigen::VectorXd>
378
      Qu_;  //!< Gradient of the Hamiltonian \f$\mathbf{Q_u}\f$
379
  std::vector<MatrixXdRowMajor> K_;  //!< Feedback gains \f$\mathbf{K}\f$
380
  std::vector<Eigen::VectorXd> k_;   //!< Feed-forward terms \f$\mathbf{l}\f$
381
382
  Eigen::VectorXd xnext_;      //!< Next state \f$\mathbf{x}^{'}\f$
383
  MatrixXdRowMajor FxTVxx_p_;  //!< Store the value of
384
                               //!< \f$\mathbf{f_x}^T\mathbf{V_{xx}}^{'}\f$
385
  std::vector<MatrixXdRowMajor>
386
      FuTVxx_p_;             //!< Store the values of
387
                             //!< \f$\mathbf{f_u}^T\mathbf{V_{xx}}^{'}\f$
388
                             //!< per each running node
389
  Eigen::VectorXd fTVxx_p_;  //!< Store the value of
390
                             //!< \f$\mathbf{\bar{f}}^T\mathbf{V_{xx}}^{'}\f$
391
  std::vector<Eigen::LLT<Eigen::MatrixXd> > Quu_llt_;  //!< Cholesky LLT solver
392
  std::vector<Eigen::VectorXd>
393
      Quuk_;  //!< Store the values of \f$\mathbf{Q_{uu}\mathbf{k}} per each
394
              //!< running node
395
  std::vector<double>
396
      alphas_;      //!< Set of step lengths using by the line-search procedure
397
  double th_grad_;  //!< Tolerance of the expected gradient used for testing the
398
                    //!< step
399
  double
400
      th_stepdec_;  //!< Step-length threshold used to decrease regularization
401
  double
402
      th_stepinc_;  //!< Step-length threshold used to increase regularization
403
};
404
405
}  // namespace crocoddyl
406
407
#endif  // CROCODDYL_CORE_SOLVERS_DDP_HPP_