Crocoddyl
action-base.hpp
1 
3 // BSD 3-Clause License
4 //
5 // Copyright (C) 2019-2024, LAAS-CNRS, INRIA, University of Edinburgh,
6 // Heriot-Watt University
7 // Copyright note valid unless otherwise stated in individual files.
8 // All rights reserved.
10 
11 #ifndef CROCODDYL_CORE_CODEGEN_ACTION_BASE_HPP_
12 #define CROCODDYL_CORE_CODEGEN_ACTION_BASE_HPP_
13 
14 #include <functional>
15 
16 #include "crocoddyl/core/action-base.hpp"
17 #include "pinocchio/codegen/cppadcg.hpp"
18 
19 namespace crocoddyl {
20 
21 template <typename Scalar>
22 struct ActionDataCodeGenTpl;
23 
24 template <typename _Scalar>
26  public:
27  typedef _Scalar Scalar;
31  typedef typename MathBaseTpl<Scalar>::VectorXs VectorXs;
32  typedef typename MathBaseTpl<Scalar>::MatrixXs MatrixXs;
33 
34  typedef CppAD::cg::CG<Scalar> CGScalar;
35  typedef CppAD::AD<CGScalar> ADScalar;
39  typedef typename MathBaseTpl<ADScalar>::VectorXs ADVectorXs;
40  typedef typename MathBaseTpl<ADScalar>::MatrixXs ADMatrixXs;
41  typedef typename MathBaseTpl<ADScalar>::Vector3s ADVector3s;
42  typedef typename MathBaseTpl<ADScalar>::Matrix3s ADMatrix3s;
43 
44  typedef
45  typename PINOCCHIO_EIGEN_PLAIN_ROW_MAJOR_TYPE(ADMatrixXs) RowADMatrixXs;
46 
47  typedef CppAD::ADFun<CGScalar> ADFun;
48 
49  ActionModelCodeGenTpl(boost::shared_ptr<ADBase> admodel,
50  boost::shared_ptr<Base> model,
51  const std::string& library_name,
52  const std::size_t n_env = 0,
53  std::function<void(boost::shared_ptr<ADBase>,
54  const Eigen::Ref<const ADVectorXs>&)>
55  fn_record_env = empty_record_env,
56  const std::string& function_name_calc = "calc",
57  const std::string& function_name_calcDiff = "calcDiff")
58  : Base(model->get_state(), model->get_nu()),
59  model(model),
60  ad_model(admodel),
61  ad_data(ad_model->createData()),
63  function_name_calcDiff(function_name_calcDiff),
65  n_env(n_env),
67  ad_X(ad_model->get_state()->get_nx() + ad_model->get_nu() + n_env),
68  ad_X2(ad_model->get_state()->get_nx() + ad_model->get_nu() + n_env),
69  ad_calcout(ad_model->get_state()->get_nx() + 1) {
70  const std::size_t ndx = ad_model->get_state()->get_ndx();
71  const std::size_t nu = ad_model->get_nu();
72  ad_calcDiffout.resize(2 * ndx * ndx + 2 * ndx * nu + nu * nu + ndx + nu);
73  initLib();
74  loadLib();
75  }
76 
77  static void empty_record_env(boost::shared_ptr<ADBase>,
78  const Eigen::Ref<const ADVectorXs>&) {}
79 
80  void recordCalc() {
81  CppAD::Independent(ad_X);
82  const std::size_t nx = ad_model->get_state()->get_nx();
83  const std::size_t nu = ad_model->get_nu();
84 
85  fn_record_env(ad_model, ad_X.tail(n_env));
86 
87  ad_model->calc(ad_data, ad_X.head(nx), ad_X.segment(nx, nu));
88  collect_calcout();
89  // ad_calcout.template head<1>()[0] = ad_data->cost;
90  // ad_calcout.tail(ad_model->get_state()->get_nx()) = ad_data->xnext;
91  ad_calc.Dependent(ad_X, ad_calcout);
92  ad_calc.optimize("no_compare_op");
93  }
94 
95  void collect_calcout() {
96  ad_calcout[0] = ad_data->cost;
97  ad_calcout.tail(ad_model->get_state()->get_nx()) = ad_data->xnext;
98  }
99 
100  void collect_calcDiffout() {
101  ADVectorXs& ad_Y = ad_calcDiffout;
102 
103  const std::size_t ndx = ad_model->get_state()->get_ndx();
104  const std::size_t nu = ad_model->get_nu();
105  Eigen::DenseIndex it_Y = 0;
106  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, ndx) = ad_data->Fx;
107  it_Y += ndx * ndx;
108  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, nu) = ad_data->Fu;
109  it_Y += ndx * nu;
110  Eigen::Map<ADVectorXs>(ad_Y.data() + it_Y, ndx) = ad_data->Lx;
111  it_Y += ndx;
112  Eigen::Map<ADVectorXs>(ad_Y.data() + it_Y, nu) = ad_data->Lu;
113  it_Y += nu;
114  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, ndx) = ad_data->Lxx;
115  it_Y += ndx * ndx;
116  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, ndx, nu) = ad_data->Lxu;
117  it_Y += ndx * nu;
118  Eigen::Map<ADMatrixXs>(ad_Y.data() + it_Y, nu, nu) = ad_data->Luu;
119  }
120 
121  void recordCalcDiff() {
122  CppAD::Independent(ad_X2);
123  const std::size_t nx = ad_model->get_state()->get_nx();
124  const std::size_t nu = ad_model->get_nu();
125 
126  fn_record_env(ad_model, ad_X2.tail(n_env));
127 
128  ad_model->calc(ad_data, ad_X2.head(nx), ad_X2.segment(nx, nu));
129  ad_model->calcDiff(ad_data, ad_X2.head(nx), ad_X2.segment(nx, nu));
130 
131  collect_calcDiffout();
132  ad_calcDiff.Dependent(ad_X2, ad_calcDiffout);
133  ad_calcDiff.optimize("no_compare_op");
134  }
135 
136  void initLib() {
137  recordCalc();
138 
139  // generates source code
140  calcgen_ptr = std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> >(
141  new CppAD::cg::ModelCSourceGen<Scalar>(ad_calc, function_name_calc));
142  calcgen_ptr->setCreateForwardZero(true);
143  calcgen_ptr->setCreateJacobian(false);
144 
145  // generates source code
146  recordCalcDiff();
147  calcDiffgen_ptr = std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> >(
148  new CppAD::cg::ModelCSourceGen<Scalar>(ad_calcDiff,
149  function_name_calcDiff));
150  calcDiffgen_ptr->setCreateForwardZero(true);
151  calcDiffgen_ptr->setCreateJacobian(false);
152 
153  libcgen_ptr = std::unique_ptr<CppAD::cg::ModelLibraryCSourceGen<Scalar> >(
154  new CppAD::cg::ModelLibraryCSourceGen<Scalar>(*calcgen_ptr,
155  *calcDiffgen_ptr));
156 
157  dynamicLibManager_ptr =
158  std::unique_ptr<CppAD::cg::DynamicModelLibraryProcessor<Scalar> >(
159  new CppAD::cg::DynamicModelLibraryProcessor<Scalar>(*libcgen_ptr,
160  library_name));
161  }
162 
163  void compileLib() {
164  CppAD::cg::GccCompiler<Scalar> compiler;
165  std::vector<std::string> compile_options = compiler.getCompileFlags();
166  compile_options[0] = "-O3";
167  compiler.setCompileFlags(compile_options);
168  dynamicLibManager_ptr->createDynamicLibrary(compiler, false);
169  }
170 
171  bool existLib() const {
172  const std::string filename =
173  dynamicLibManager_ptr->getLibraryName() +
174  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION;
175  std::ifstream file(filename.c_str());
176  return file.good();
177  }
178 
179  void loadLib(const bool generate_if_not_exist = true) {
180  if (not existLib() && generate_if_not_exist) compileLib();
181 
182  const auto it = dynamicLibManager_ptr->getOptions().find("dlOpenMode");
183  if (it == dynamicLibManager_ptr->getOptions().end()) {
184  dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(
185  dynamicLibManager_ptr->getLibraryName() +
186  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION));
187  } else {
188  int dlOpenMode = std::stoi(it->second);
189  dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(
190  dynamicLibManager_ptr->getLibraryName() +
191  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION,
192  dlOpenMode));
193  }
194 
195  calcFun_ptr = dynamicLib_ptr->model(function_name_calc.c_str());
196  calcDiffFun_ptr = dynamicLib_ptr->model(function_name_calcDiff.c_str());
197  }
198 
199  void set_env(const boost::shared_ptr<ActionDataAbstract>& data,
200  const Eigen::Ref<const VectorXs>& env_val) const {
201  Data* d = static_cast<Data*>(data.get());
202  d->xu.tail(n_env) = env_val;
203  }
204 
205  void calc(const boost::shared_ptr<ActionDataAbstract>& data,
206  const Eigen::Ref<const VectorXs>& x,
207  const Eigen::Ref<const VectorXs>& u) {
208  Data* d = static_cast<Data*>(data.get());
209  const std::size_t nx = ad_model->get_state()->get_nx();
210  const std::size_t nu = ad_model->get_nu();
211 
212  d->xu.head(nx) = x;
213  d->xu.segment(nx, nu) = u;
214 
215  calcFun_ptr->ForwardZero(d->xu, d->calcout);
216  d->distribute_calcout();
217  }
218 
219  void calcDiff(const boost::shared_ptr<ActionDataAbstract>& data,
220  const Eigen::Ref<const VectorXs>& x,
221  const Eigen::Ref<const VectorXs>& u) {
222  Data* d = static_cast<Data*>(data.get());
223  const std::size_t nx = ad_model->get_state()->get_nx();
224  const std::size_t nu = ad_model->get_nu();
225 
226  d->xu.head(nx) = x;
227  d->xu.segment(nx, nu) = u;
228  calcDiffFun_ptr->ForwardZero(d->xu, d->calcDiffout);
229  d->distribute_calcDiffout();
230  }
231 
232  boost::shared_ptr<ActionDataAbstract> createData() {
233  return boost::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
234  }
235 
237  Eigen::DenseIndex getInputDimension() const { return ad_X.size(); }
238 
239  protected:
242  using Base::nr_;
243  using Base::nu_;
244  using Base::state_;
245  using Base::u_lb_;
246  using Base::u_ub_;
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.
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
< Upper control limits
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 .