- 3.0.2 core module.
DerivativesCppadCG.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 #include <ct/core/templateDir.h>
10 
11 namespace ct {
12 namespace core {
13 
14 #ifdef CPPADCG
15 
17 
30 template <int IN_DIM, int OUT_DIM>
31 class DerivativesCppadCG
32 {
33 public:
34  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
35 
36  typedef ADCGScalar CG_SCALAR;
37  typedef ADCGValueType CG_VALUE_TYPE;
38 
39  typedef Eigen::Matrix<CG_SCALAR, IN_DIM, 1> IN_TYPE_CG;
40  typedef Eigen::Matrix<CG_SCALAR, OUT_DIM, 1> OUT_TYPE_CG;
41  typedef Eigen::Matrix<bool, IN_DIM, OUT_DIM> Sparsity;
42  typedef Eigen::Matrix<bool, IN_DIM, IN_DIM> HessianSparsity;
43 
44  typedef std::function<OUT_TYPE_CG(const IN_TYPE_CG&)> FUN_TYPE_CG;
45 
46 
59  DerivativesCppadCG(FUN_TYPE_CG& f, int inputDim = IN_DIM, int outputDim = OUT_DIM)
60  : cgStdFun_(f), inputDim_(inputDim), outputDim_(outputDim), tmpVarCount_(0)
61  {
62  if (outputDim > 0 && inputDim > 0)
63  this->recordCg();
64  }
65 
67  DerivativesCppadCG(const DerivativesCppadCG& arg)
68  : cgStdFun_(arg.cgStdFun_), inputDim_(arg.inputDim_), outputDim_(arg.outputDim_), tmpVarCount_(arg.tmpVarCount_)
69  {
70  }
71 
73  virtual ~DerivativesCppadCG() = default;
75  DerivativesCppadCG* clone() const { return new DerivativesCppadCG<IN_DIM, OUT_DIM>(*this); }
77 
92  void generateJacobianSource(const std::string& derivativeName,
93  const std::string& outputDir = ct::core::CODEGEN_OUTPUT_DIR,
94  const std::string& templateDir = ct::core::CODEGEN_TEMPLATE_DIR,
95  const std::string& ns1 = "core",
96  const std::string& ns2 = "generated",
97  const Sparsity& sparsity = Sparsity::Ones(),
98  bool useReverse = true,
99  bool ignoreZero = true)
100  {
101  internal::SparsityPattern pattern;
102  pattern.initPattern(sparsity);
103 
104  size_t jacDimension = IN_DIM * OUT_DIM;
105 
106  std::string codeJac = internal::CGHelpers::generateJacobianSource(
107  cgCppadFun_, pattern, jacDimension, tmpVarCount_, useReverse, ignoreZero);
108 
109  writeCodeFile(templateDir, "/Jacobian.tpl.h", "/Jacobian.tpl.cpp", outputDir, derivativeName, ns1, ns2, codeJac,
110  "AUTOGENERATED_CODE_PLACEHOLDER");
111  }
112 
114 
129  void generateForwardZeroSource(const std::string& forwardZeroName,
130  const std::string& outputDir = ct::core::CODEGEN_OUTPUT_DIR,
131  const std::string& templateDir = ct::core::CODEGEN_TEMPLATE_DIR,
132  const std::string& ns1 = "core",
133  const std::string& ns2 = "generated",
134  bool ignoreZero = true)
135  {
136  std::string codeJac = internal::CGHelpers::generateForwardZeroSource(cgCppadFun_, tmpVarCount_, ignoreZero);
137 
138  writeCodeFile(templateDir, "/ForwardZero.tpl.h", "/ForwardZero.tpl.cpp", outputDir, forwardZeroName, ns1, ns2,
139  codeJac, "AUTOGENERATED_CODE_PLACEHOLDER");
140  }
141 
143 
160  void generateHessianSource(const std::string& derivativeName,
161  const std::string& outputDir = ct::core::CODEGEN_OUTPUT_DIR,
162  const std::string& templateDir = ct::core::CODEGEN_TEMPLATE_DIR,
163  const std::string& ns1 = "core",
164  const std::string& ns2 = "generated",
165  const HessianSparsity& sparsity = HessianSparsity::Ones(),
166  bool useReverse = true,
167  bool ignoreZero = true)
168  {
169  internal::SparsityPattern pattern;
170  pattern.initPattern(sparsity);
171 
172  size_t hesDimension = IN_DIM * IN_DIM;
173 
174  std::string codeHes =
175  internal::CGHelpers::generateHessianSource(cgCppadFun_, pattern, hesDimension, tmpVarCount_, ignoreZero);
176 
177  writeCodeFile(templateDir, "/Hessian.tpl.h", "/Hessian.tpl.cpp", outputDir, derivativeName, ns1, ns2, codeHes,
178  "AUTOGENERATED_CODE_PLACEHOLDER");
179  }
180 
181 
182 private:
184  void recordCg()
185  {
186  // input vector, needs to be dynamic size
187  Eigen::Matrix<CG_SCALAR, Eigen::Dynamic, 1> x(inputDim_);
188  // init to rand to avoid floating point problems in user's code
189  x.setRandom();
190 
191  // declare x as independent
192  CppAD::Independent(x);
193 
194  // output vector, needs to be dynamic size
195  Eigen::Matrix<CG_SCALAR, Eigen::Dynamic, 1> y(outputDim_);
196 
197  y = cgStdFun_(x);
198 
199  // store operation sequence in f: x -> y and stop recording
200  CppAD::ADFun<CG_VALUE_TYPE> fCodeGen(x, y);
201 
202  fCodeGen.optimize();
203 
204  cgCppadFun_ = fCodeGen;
205  }
206 
208 
217  void writeCodeFile(const std::string& templateDir,
218  const std::string& tplHeaderName,
219  const std::string& tplSourceName,
220  const std::string& outputDir,
221  const std::string& derivativeName,
222  const std::string& ns1,
223  const std::string& ns2,
224  const std::string& codeJac,
225  const std::string& codePlaceholder)
226  {
227  std::cout << "Writing code of " + derivativeName + " to file..." << std::endl;
228 
229  std::string header = internal::CGHelpers::parseFile(templateDir + tplHeaderName);
230  std::string source = internal::CGHelpers::parseFile(templateDir + tplSourceName);
231 
232  replaceSizesAndNames(header, derivativeName, ns1, ns2);
233  replaceSizesAndNames(source, derivativeName, ns1, ns2);
234 
235  internal::CGHelpers::replaceOnce(header, "MAX_COUNT", std::to_string(tmpVarCount_));
236  internal::CGHelpers::replaceOnce(source, codePlaceholder, codeJac);
237 
238 
239  internal::CGHelpers::writeFile(outputDir + "/" + derivativeName + ".h", header);
240  internal::CGHelpers::writeFile(outputDir + "/" + derivativeName + ".cpp", source);
241 
242 
243  std::cout << "... Done! Successfully generated " + derivativeName << std::endl;
244  }
245 
246 
248 
255  void replaceSizesAndNames(std::string& file,
256  const std::string& systemName,
257  const std::string& ns1,
258  const std::string& ns2)
259  {
260  internal::CGHelpers::replaceAll(file, "DERIVATIVE_NAME", systemName);
261  internal::CGHelpers::replaceAll(file, "NS1", ns1);
262  internal::CGHelpers::replaceAll(file, "NS2", ns2);
263  internal::CGHelpers::replaceAll(file, "IN_DIM", std::to_string(IN_DIM));
264  internal::CGHelpers::replaceAll(file, "OUT_DIM", std::to_string(OUT_DIM));
265  }
266 
267  std::function<OUT_TYPE_CG(const IN_TYPE_CG&)> cgStdFun_;
268 
269  int inputDim_;
270  int outputDim_;
271 
272  CppAD::ADFun<CG_VALUE_TYPE> cgCppadFun_;
273 
274  size_t tmpVarCount_;
275 };
276 
277 #endif
278 
279 } /* namespace core */
280 } /* namespace ct */
ct::core::StateVector< state_dim > x