Crocoddyl
action-base.hpp
1 
3 // BSD 3-Clause License
4 //
5 // Copyright (C) 2019-2020, LAAS-CNRS, INRIA, University of Edinburgh
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
9 
10 #ifndef CROCODDYL_CORE_CODEGEN_ACTION_BASE_HPP_
11 #define CROCODDYL_CORE_CODEGEN_ACTION_BASE_HPP_
12 
13 #include <functional>
14 
15 #include "crocoddyl/core/action-base.hpp"
16 #include "pinocchio/codegen/cppadcg.hpp"
17 
18 namespace crocoddyl {
19 
20 template <typename Scalar>
21 struct ActionDataCodeGenTpl;
22 
23 template <typename _Scalar>
25  public:
26  typedef _Scalar Scalar;
30  typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
31  typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
32 
33  typedef CppAD::cg::CG<Scalar> CGScalar;
34  typedef CppAD::AD<CGScalar> ADScalar;
38  typedef typename MathBaseTpl<ADScalar>::VectorXs ADVectorXs;
39  typedef typename MathBaseTpl<ADScalar>::MatrixXs ADMatrixXs;
40  typedef typename MathBaseTpl<ADScalar>::Vector3s ADVector3s;
41  typedef typename MathBaseTpl<ADScalar>::Matrix3s ADMatrix3s;
42 
43  typedef
44  typename PINOCCHIO_EIGEN_PLAIN_ROW_MAJOR_TYPE(ADMatrixXs) RowADMatrixXs;
45 
46  typedef CppAD::ADFun<CGScalar> ADFun;
47 
48  ActionModelCodeGenTpl(boost::shared_ptr<ADBase> admodel,
49  boost::shared_ptr<Base> model,
50  const std::string& library_name,
51  const std::size_t n_env = 0,
52  std::function<void(boost::shared_ptr<ADBase>,
53  const Eigen::Ref<const ADVectorXs>&)>
54  fn_record_env = empty_record_env,
55  const std::string& function_name_calc = "calc",
56  const std::string& function_name_calcDiff = "calcDiff")
57  : Base(model->get_state(), model->get_nu()),
58  model(model),
59  ad_model(admodel),
60  ad_data(ad_model->createData()),
62  function_name_calcDiff(function_name_calcDiff),
64  n_env(n_env),
66  ad_X(ad_model->get_state()->get_nx() + ad_model->get_nu() + n_env),
67  ad_X2(ad_model->get_state()->get_nx() + ad_model->get_nu() + n_env),
68  ad_calcout(ad_model->get_state()->get_nx() + 1) {
69  const std::size_t ndx = ad_model->get_state()->get_ndx();
70  const std::size_t nu = ad_model->get_nu();
71  ad_calcDiffout.resize(2 * ndx * ndx + 2 * ndx * nu + nu * nu + ndx + nu);
72  initLib();
73  loadLib();
74  }
75 
76  static void empty_record_env(boost::shared_ptr<ADBase>,
77  const Eigen::Ref<const ADVectorXs>&) {}
78 
79  void recordCalc() {
80  CppAD::Independent(ad_X);
81  const std::size_t nx = ad_model->get_state()->get_nx();
82  const std::size_t nu = ad_model->get_nu();
83 
84  fn_record_env(ad_model, ad_X.tail(n_env));
85 
86  ad_model->calc(ad_data, ad_X.head(nx), ad_X.segment(nx, nu));
87  collect_calcout();
88  // ad_calcout.template head<1>()[0] = ad_data->cost;
89  // ad_calcout.tail(ad_model->get_state()->get_nx()) = ad_data->xnext;
90  ad_calc.Dependent(ad_X, ad_calcout);
91  ad_calc.optimize("no_compare_op");
92  }
93 
94  void collect_calcout() {
95  ad_calcout[0] = ad_data->cost;
96  ad_calcout.tail(ad_model->get_state()->get_nx()) = ad_data->xnext;
97  }
98 
99  void collect_calcDiffout() {
100  ADVectorXs& ad_Y = ad_calcDiffout;
101 
102  const std::size_t ndx = ad_model->get_state()->get_ndx();
103  const std::size_t nu = ad_model->get_nu();
104  Eigen::DenseIndex it_Y = 0;
105  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, ndx) = ad_data->Fx;
106  it_Y += ndx * ndx;
107  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, nu) = ad_data->Fu;
108  it_Y += ndx * nu;
109  Eigen::Map<ADVectorXs>(ad_Y.data() + it_Y, ndx) = ad_data->Lx;
110  it_Y += ndx;
111  Eigen::Map<ADVectorXs>(ad_Y.data() + it_Y, nu) = ad_data->Lu;
112  it_Y += nu;
113  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, ndx) = ad_data->Lxx;
114  it_Y += ndx * ndx;
115  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, nu) = ad_data->Lxu;
116  it_Y += ndx * nu;
117  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, nu, nu) = ad_data->Luu;
118  }
119 
120  void recordCalcDiff() {
121  CppAD::Independent(ad_X2);
122  const std::size_t nx = ad_model->get_state()->get_nx();
123  const std::size_t nu = ad_model->get_nu();
124 
125  fn_record_env(ad_model, ad_X2.tail(n_env));
126 
127  ad_model->calc(ad_data, ad_X2.head(nx), ad_X2.segment(nx, nu));
128  ad_model->calcDiff(ad_data, ad_X2.head(nx), ad_X2.segment(nx, nu));
129 
130  collect_calcDiffout();
131  ad_calcDiff.Dependent(ad_X2, ad_calcDiffout);
132  ad_calcDiff.optimize("no_compare_op");
133  }
134 
135  void initLib() {
136  recordCalc();
137 
138  // generates source code
139  calcgen_ptr = std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> >(
140  new CppAD::cg::ModelCSourceGen<Scalar>(ad_calc, function_name_calc));
141  calcgen_ptr->setCreateForwardZero(true);
142  calcgen_ptr->setCreateJacobian(false);
143 
144  // generates source code
145  recordCalcDiff();
146  calcDiffgen_ptr = std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> >(
147  new CppAD::cg::ModelCSourceGen<Scalar>(ad_calcDiff,
148  function_name_calcDiff));
149  calcDiffgen_ptr->setCreateForwardZero(true);
150  calcDiffgen_ptr->setCreateJacobian(false);
151 
152  libcgen_ptr = std::unique_ptr<CppAD::cg::ModelLibraryCSourceGen<Scalar> >(
153  new CppAD::cg::ModelLibraryCSourceGen<Scalar>(*calcgen_ptr,
154  *calcDiffgen_ptr));
155 
156  dynamicLibManager_ptr =
157  std::unique_ptr<CppAD::cg::DynamicModelLibraryProcessor<Scalar> >(
158  new CppAD::cg::DynamicModelLibraryProcessor<Scalar>(*libcgen_ptr,
159  library_name));
160  }
161 
162  void compileLib() {
163  CppAD::cg::GccCompiler<Scalar> compiler;
164  std::vector<std::string> compile_options = compiler.getCompileFlags();
165  compile_options[0] = "-O3";
166  compiler.setCompileFlags(compile_options);
167  dynamicLibManager_ptr->createDynamicLibrary(compiler, false);
168  }
169 
170  bool existLib() const {
171  const std::string filename =
172  dynamicLibManager_ptr->getLibraryName() +
173  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION;
174  std::ifstream file(filename.c_str());
175  return file.good();
176  }
177 
178  void loadLib(const bool generate_if_not_exist = true) {
179  if (not existLib() && generate_if_not_exist) compileLib();
180 
181  const auto it = dynamicLibManager_ptr->getOptions().find("dlOpenMode");
182  if (it == dynamicLibManager_ptr->getOptions().end()) {
183  dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(
184  dynamicLibManager_ptr->getLibraryName() +
185  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION));
186  } else {
187  int dlOpenMode = std::stoi(it->second);
188  dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(
189  dynamicLibManager_ptr->getLibraryName() +
190  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION,
191  dlOpenMode));
192  }
193 
194  calcFun_ptr = dynamicLib_ptr->model(function_name_calc.c_str());
195  calcDiffFun_ptr = dynamicLib_ptr->model(function_name_calcDiff.c_str());
196  }
197 
198  void set_env(const boost::shared_ptr<ActionDataAbstract>& data,
199  const Eigen::Ref<const VectorXs>& env_val) const {
200  Data* d = static_cast<Data*>(data.get());
201  d->xu.tail(n_env) = env_val;
202  }
203 
204  void calc(const boost::shared_ptr<ActionDataAbstract>& data,
205  const Eigen::Ref<const VectorXs>& x,
206  const Eigen::Ref<const VectorXs>& u) {
207  Data* d = static_cast<Data*>(data.get());
208  const std::size_t nx = ad_model->get_state()->get_nx();
209  const std::size_t nu = ad_model->get_nu();
210 
211  d->xu.head(nx) = x;
212  d->xu.segment(nx, nu) = u;
213 
214  calcFun_ptr->ForwardZero(d->xu, d->calcout);
215  d->distribute_calcout();
216  }
217 
218  void calcDiff(const boost::shared_ptr<ActionDataAbstract>& data,
219  const Eigen::Ref<const VectorXs>& x,
220  const Eigen::Ref<const VectorXs>& u) {
221  Data* d = static_cast<Data*>(data.get());
222  const std::size_t nx = ad_model->get_state()->get_nx();
223  const std::size_t nu = ad_model->get_nu();
224 
225  d->xu.head(nx) = x;
226  d->xu.segment(nx, nu) = u;
227  calcDiffFun_ptr->ForwardZero(d->xu, d->calcDiffout);
228  d->distribute_calcDiffout();
229  }
230 
231  boost::shared_ptr<ActionDataAbstract> createData() {
232  return boost::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
233  }
234 
236  Eigen::DenseIndex getInputDimension() const { return ad_X.size(); }
237 
238  protected:
241  using Base::nr_;
242  using Base::nu_;
243  using Base::state_;
244  using Base::u_lb_;
245  using Base::u_ub_;
246  using Base::unone_;
247 
248  boost::shared_ptr<Base> model;
249  boost::shared_ptr<ADBase> ad_model;
250  boost::shared_ptr<ADActionDataAbstract> ad_data;
251 
253  const std::string function_name_calc, function_name_calcDiff;
254 
256  const std::string library_name;
257 
259  const std::size_t n_env;
260 
263  std::function<void(boost::shared_ptr<ADBase>,
264  const Eigen::Ref<const ADVectorXs>&)>
266 
270 
271  ADVectorXs ad_X, ad_X2;
272 
273  ADVectorXs ad_calcout;
274  ADVectorXs ad_calcDiffout;
275 
276  ADFun ad_calc, ad_calcDiff;
277 
278  std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> > calcgen_ptr,
279  calcDiffgen_ptr;
280  std::unique_ptr<CppAD::cg::ModelLibraryCSourceGen<Scalar> > libcgen_ptr;
281  std::unique_ptr<CppAD::cg::DynamicModelLibraryProcessor<Scalar> >
282  dynamicLibManager_ptr;
283  std::unique_ptr<CppAD::cg::DynamicLib<Scalar> > dynamicLib_ptr;
284  std::unique_ptr<CppAD::cg::GenericModel<Scalar> > calcFun_ptr,
285  calcDiffFun_ptr;
286 
287 }; // struct CodeGenBase
288 
289 template <typename _Scalar>
290 struct ActionDataCodeGenTpl : public ActionDataAbstractTpl<_Scalar> {
291  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
292 
293  typedef _Scalar Scalar;
296  typedef typename MathBase::VectorXs VectorXs;
297  typedef typename MathBase::MatrixXs MatrixXs;
298 
299  using Base::cost;
300  using Base::Fu;
301  using Base::Fx;
302  using Base::Lu;
303  using Base::Luu;
304  using Base::Lx;
305  using Base::Lxu;
306  using Base::Lxx;
307  using Base::r;
308  using Base::xnext;
309 
310  VectorXs xu, calcout;
311 
312  VectorXs calcDiffout;
313 
314  void distribute_calcout() {
315  cost = calcout[0];
316  xnext = calcout.tail(xnext.size());
317  }
318 
319  void distribute_calcDiffout() {
320  VectorXs& Y = calcDiffout;
321  const std::size_t ndx = Fx.rows();
322  const std::size_t nu = Fu.cols();
323 
324  Eigen::DenseIndex it_Y = 0;
325  Fx = Eigen::Map<MatrixXs>(Y.data() + it_Y, ndx, ndx);
326  it_Y += ndx * ndx;
327  Fu = Eigen::Map<MatrixXs>(Y.data() + it_Y, ndx, nu);
328  it_Y += ndx * nu;
329  Lx = Eigen::Map<VectorXs>(Y.data() + it_Y, ndx);
330  it_Y += ndx;
331  Lu = Eigen::Map<VectorXs>(Y.data() + it_Y, nu);
332  it_Y += nu;
333  Lxx = Eigen::Map<MatrixXs>(Y.data() + it_Y, ndx, ndx);
334  it_Y += ndx * ndx;
335  Lxu = Eigen::Map<MatrixXs>(Y.data() + it_Y, ndx, nu);
336  it_Y += ndx * nu;
337  Luu = Eigen::Map<MatrixXs>(Y.data() + it_Y, nu, nu);
338  }
339 
340  template <template <typename Scalar> class Model>
341  explicit ActionDataCodeGenTpl(Model<Scalar>* const model)
342  : Base(model), calcout(model->get_state()->get_nx() + 1) {
344  static_cast<ActionModelCodeGenTpl<Scalar>*>(model);
345  xu.resize(m->getInputDimension());
346  xu.setZero();
347  calcout.setZero();
348  const std::size_t ndx = model->get_state()->get_ndx();
349  const std::size_t nu = model->get_nu();
350  calcDiffout.resize(2 * ndx * ndx + 2 * ndx * nu + nu * nu + ndx + nu);
351  calcDiffout.setZero();
352  }
353 };
354 
355 } // namespace crocoddyl
356 
357 #endif // ifndef CROCODDYL_CORE_CODEGEN_ACTION_BASE_HPP_
Abstract class for action model.
Definition: action-base.hpp:95
const boost::shared_ptr< StateAbstract > & get_state() const
Return the state.
VectorXs u_lb_
Lower control limits.
VectorXs u_ub_
Upper control limits.
boost::shared_ptr< StateAbstract > state_
Model of the state.
std::size_t nu_
Control dimension.
VectorXs unone_
Neutral state.
std::size_t nr_
Dimension of the cost residual.
std::function< void(boost::shared_ptr< ADBase >, const Eigen::Ref< const ADVectorXs > &)> fn_record_env
A function that updates the environment variables before starting record.
Eigen::DenseIndex getInputDimension() const
Dimension of the input vector.
boost::shared_ptr< ActionDataAbstract > createData()
Create the action data.
const std::string function_name_calc
Name of the function.
boost::shared_ptr< Base > model
< Neutral state
const std::size_t n_env
Size of the environment variables.
void calc(const boost::shared_ptr< ActionDataAbstract > &data, const Eigen::Ref< const VectorXs > &x, const Eigen::Ref< const VectorXs > &u)
Compute the next state and cost value.
bool build_forward
Options to generate or not the source code for the evaluation function.
void calcDiff(const boost::shared_ptr< ActionDataAbstract > &data, const Eigen::Ref< const VectorXs > &x, const Eigen::Ref< const VectorXs > &u)
Compute the derivatives of the dynamics and cost functions.
const std::string library_name
Name of the library.
VectorXs xnext
evolution state
MatrixXs Fx
Jacobian of the dynamics w.r.t. the state .
MatrixXs Fu
Jacobian of the dynamics w.r.t. the control .
MatrixXs Luu
Hessian of the cost w.r.t. the control .
VectorXs Lx
Jacobian of the cost w.r.t. the state .
MatrixXs Lxx
Hessian of the cost w.r.t. the state .
VectorXs Lu
Jacobian of the cost w.r.t. the control .
VectorXs r
Cost residual.
VectorXs xnext
evolution state
MatrixXs Fx
Jacobian of the dynamics w.r.t. the state .
MatrixXs Fu
Jacobian of the dynamics w.r.t. the control .
MatrixXs Luu
Hessian of the cost w.r.t. the control .
VectorXs Lx
Jacobian of the cost w.r.t. the state .
MatrixXs Lxx
Hessian of the cost w.r.t. the state .
VectorXs Lu
Jacobian of the cost w.r.t. the control .