- 3.0.2 core module.
CGHelpers.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 #ifdef CPPADCG
9 
10 #include "SparsityPattern.h"
11 
12 namespace ct {
13 namespace core {
14 namespace internal {
15 
16 
18 class CGHelpers
19 {
20 public:
21  CGHelpers() = default;
22 
23  virtual ~CGHelpers() = default;
24 
26 
49  template <typename AD_SCALAR, typename SCALAR = double>
50  static std::string generateJacobianSource(CppAD::ADFun<AD_SCALAR>& f,
51  SparsityPattern& pattern,
52  const size_t jacDim,
53  size_t& maxTempVarCount,
54  bool useReverse = false,
55  bool ignoreZero = true,
56  std::string jacName = "jac",
57  std::string inputName = "x_in",
58  std::string tempName = "v_",
59  std::string scalarName = "double")
60  {
61  CppAD::cg::CodeHandler<SCALAR> codeHandler;
62 
63  size_t n = f.Domain();
64 
65  CppAD::vector<AD_SCALAR> input(n);
66  codeHandler.makeVariables(input);
67  for (size_t i = 0; i < n; i++)
68  {
69  // init to rand to avoid floating point problems in user's code
70  input[i].setValue(static_cast<double>(rand()) / static_cast<double>(RAND_MAX));
71  }
72 
73  CppAD::vector<AD_SCALAR> jac(jacDim);
74 
75  if (useReverse)
76  f.SparseJacobianReverse(
77  input, pattern.sparsity(), pattern.row(), pattern.col(), jac, pattern.workJacobian());
78  else
79  f.SparseJacobianForward(
80  input, pattern.sparsity(), pattern.row(), pattern.col(), jac, pattern.workJacobian());
81 
82  CppAD::cg::LanguageC<SCALAR> langC(scalarName, 4);
83  langC.setIgnoreZeroDepAssign(ignoreZero);
84  CppAD::cg::LangCDefaultVariableNameGenerator<SCALAR> nameGen(jacName, inputName, tempName);
85 
86  std::ostringstream code;
87  codeHandler.generateCode(code, langC, jac, nameGen);
88 
89  std::cout << "temporary variables: " << codeHandler.getTemporaryVariableCount() << std::endl;
90  maxTempVarCount = codeHandler.getTemporaryVariableCount();
91 
92  return code.str();
93  }
94 
96 
113  template <typename AD_SCALAR>
114  static std::string generateForwardZeroSource(CppAD::ADFun<AD_SCALAR>& f,
115  size_t& maxTempVarCount,
116  bool ignoreZero = true,
117  std::string jacName = "forwardZero",
118  std::string inputName = "x_in",
119  std::string tempName = "v_")
120  {
121  CppAD::cg::CodeHandler<double> codeHandler;
122 
123  // input vector, needs to be dynamic size
124  size_t n = f.Domain();
125 
126  CppAD::vector<AD_SCALAR> input(n);
127 
128  for (size_t i = 0; i < input.size(); i++)
129  {
130  // init to rand to avoid floating point problems in user's code
131  input[i].setValue(static_cast<double>(rand()) / static_cast<double>(RAND_MAX));
132  }
133 
134 
135  // mark independent as variables
136  codeHandler.makeVariables(input);
137 
138  CppAD::vector<AD_SCALAR> forwardZero = f.Forward(0, input);
139 
140  CppAD::cg::LanguageC<double> langC("double", 4);
141  langC.setIgnoreZeroDepAssign(ignoreZero);
142  CppAD::cg::LangCDefaultVariableNameGenerator<double> nameGen(jacName, inputName, tempName);
143 
144  std::ostringstream code;
145  codeHandler.generateCode(code, langC, forwardZero, nameGen);
146 
147  std::cout << "temporary variables: " << codeHandler.getTemporaryVariableCount() << std::endl;
148  maxTempVarCount = codeHandler.getTemporaryVariableCount();
149 
150  return code.str();
151  }
152 
154 
175  template <typename AD_SCALAR>
176  static std::string generateHessianSource(CppAD::ADFun<AD_SCALAR>& f,
177  SparsityPattern& pattern,
178  const size_t hesDim,
179  size_t& maxTempVarCount,
180  bool ignoreZero = true,
181  std::string jacName = "hes",
182  std::string inputName = "x_in",
183  std::string tempName = "v_")
184  {
185  CppAD::cg::CodeHandler<double> codeHandler;
186 
187  size_t m = f.Range();
188  size_t n = f.Domain();
189 
190  CppAD::vector<AD_SCALAR> input(n);
191  codeHandler.makeVariables(input);
192  // setting some typical values here.
193  for (size_t i = 0; i < input.size(); i++)
194  {
195  // init to rand to avoid floating point problems in user's code
196  input[i].setValue(static_cast<double>(rand()) / static_cast<double>(RAND_MAX));
197  }
198 
199  CppAD::vector<AD_SCALAR> weights(m);
200  codeHandler.makeVariables(weights);
201  // settings some typical values for the weights
202  for (size_t i = 0; i < m; ++i)
203  {
204  // init to rand to avoid floating point problems in user's code
205  weights[i].setValue(static_cast<double>(rand()) / static_cast<double>(RAND_MAX));
206  }
207 
208 
209  CppAD::vector<AD_SCALAR> hes(hesDim);
210  f.SparseHessian(input, weights, pattern.sparsity(), pattern.row(), pattern.col(), hes, pattern.workHessian());
211 
212  // make use of the symmetry of the hessian
213  for (size_t i = 0; i < n; i++)
214  for (size_t j = 0; j < i; j++)
215  hes[i * n + j] = hes[j * n + i];
216 
217  CppAD::cg::LanguageC<double> langC("double", 4);
218  langC.setIgnoreZeroDepAssign(ignoreZero);
219  CppAD::cg::LangCDefaultVariableNameGenerator<double> nameGenTmp(jacName, inputName, tempName);
220  CppAD::cg::LangCDefaultHessianVarNameGenerator<double> nameGen(&nameGenTmp, "w_in", m);
221 
222  std::ostringstream code;
223  codeHandler.generateCode(code, langC, hes, nameGen);
224 
225  std::cout << "temporary variables: " << codeHandler.getTemporaryVariableCount() << std::endl;
226  maxTempVarCount = codeHandler.getTemporaryVariableCount();
227 
228  return code.str();
229  }
230 
231 
233 
239  static void replaceAll(std::string& text, const std::string& placeholder, const std::string replaceWith)
240  {
241  size_t pos = text.find(placeholder);
242  while (pos != std::string::npos)
243  {
244  text.replace(pos, placeholder.length(), replaceWith);
245  pos = text.find(placeholder);
246  }
247  }
248 
250 
256  static void replaceOnce(std::string& text, const std::string& placeholder, const std::string replaceWith)
257  {
258  text.replace(text.find(placeholder), placeholder.length(), replaceWith);
259  }
260 
262 
267  static void writeFile(const std::string& outputFile, const std::string& content)
268  {
269  std::ofstream out(outputFile);
270 
271  if (!out.good())
272  {
273  std::cout << "Could not open output file for writing " << outputFile << std::endl;
274  out.close();
275  throw std::runtime_error("Code generation failed. Exiting.");
276  }
277 
278  std::cout << "Writing generated code to file... " << std::endl;
279 
280  out << content;
281  out.close();
282  }
283 
285 
290  static std::string parseFile(const std::string& filename)
291  {
292  std::ifstream t(filename);
293 
294  if (!t.good())
295  {
296  std::cout << "Could not open template file " << filename << std::endl;
297  std::cout << "Code generation failed. Exiting." << std::endl;
298  t.close();
299  throw std::runtime_error("Code generation failed. Exiting.");
300  }
301 
302  std::stringstream stream;
303  stream << t.rdbuf();
304 
305  std::string source(stream.str());
306 
307  t.close();
308 
309  return source;
310  }
311 
312 
320  template <typename SC = double>
321  static std::shared_ptr<CppAD::cg::DynamicLib<SC>> loadDynamicLibCppad(const std::string& libName)
322  {
323 #if CPPAD_CG_SYSTEM_LINUX
324  return std::shared_ptr<CppAD::cg::DynamicLib<SC>>(
325  new CppAD::cg::LinuxDynamicLib<SC>(libName + CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION));
326 #else
327  throw std::runtime_error("Loading dynamic Cppad codegen libraries only supported in Linux.");
328 #endif
329  }
330 };
331 
332 
333 } /* namespace internal */
334 } /* namespace core */
335 } /* namespace ct */
336 
337 #endif
clear all close all load ct GNMSLog0 mat reformat t
constexpr size_t n
Definition: MatrixInversionTest.cpp:14
for i