CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
model_c_source_gen_jac.hpp
1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_JAC_INCLUDED
2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_JAC_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 namespace CppAD {
19 namespace cg {
20 
21 template<class Base>
22 void ModelCSourceGen<Base>::generateJacobianSource() {
23  using std::vector;
24 
25  const std::string jobName = "Jacobian";
26 
27  startingJob("'" + jobName + "'", JobTimer::GRAPH);
28 
29  CodeHandler<Base> handler;
30  handler.setJobTimer(_jobTimer);
31 
32  vector<CGBase> indVars(_fun.Domain());
33  handler.makeVariables(indVars);
34  if (_x.size() > 0) {
35  for (size_t i = 0; i < indVars.size(); i++) {
36  indVars[i].setValue(_x[i]);
37  }
38  }
39 
40  size_t m = _fun.Range();
41  size_t n = _fun.Domain();
42 
43  vector<CGBase> jac(n * m);
44  if (_jacMode == JacobianADMode::Automatic) {
45  jac = _fun.Jacobian(indVars);
46  } else if (_jacMode == JacobianADMode::Forward) {
47  JacobianFor(_fun, indVars, jac);
48  } else {
49  JacobianRev(_fun, indVars, jac);
50  }
51 
52  finishedJob();
53 
54  LanguageC<Base> langC(_baseTypeName);
55  langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
56  langC.setParameterPrecision(_parameterPrecision);
57  langC.setGenerateFunction(_name + "_" + FUNCTION_JACOBIAN);
58 
59  std::ostringstream code;
60  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("jac"));
61 
62  handler.generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
63 }
64 
65 template<class Base>
66 void ModelCSourceGen<Base>::generateSparseJacobianSource(MultiThreadingType multiThreadingType) {
67  size_t m = _fun.Range();
68  size_t n = _fun.Domain();
69 
73  determineJacobianSparsity();
74 
75  bool forwardMode;
76 
77  if (_jacMode == JacobianADMode::Automatic) {
78  if (_custom_jac.defined) {
79  forwardMode = estimateBestJacobianADMode(_jacSparsity.rows, _jacSparsity.cols);
80  } else {
81  forwardMode = n <= m;
82  }
83  } else {
84  forwardMode = _jacMode == JacobianADMode::Forward;
85  }
86 
90  if (_sparseJacobianReusesOne && _forwardOne && forwardMode) {
91  generateSparseJacobianForRevSource(true, multiThreadingType);
92  } else if (_sparseJacobianReusesOne && _reverseOne && !forwardMode) {
93  generateSparseJacobianForRevSource(false, multiThreadingType);
94  } else {
95  generateSparseJacobianSource(forwardMode);
96  }
97 }
98 
99 template<class Base>
101  using std::vector;
102 
103  const std::string jobName = "sparse Jacobian";
104 
105  //size_t m = _fun.Range();
106  size_t n = _fun.Domain();
107 
108  startingJob("'" + jobName + "'", JobTimer::GRAPH);
109 
110  CodeHandler<Base> handler;
111  handler.setJobTimer(_jobTimer);
112 
113  vector<CGBase> indVars(n);
114  handler.makeVariables(indVars);
115  if (_x.size() > 0) {
116  for (size_t i = 0; i < n; i++) {
117  indVars[i].setValue(_x[i]);
118  }
119  }
120 
121  vector<CGBase> jac(_jacSparsity.rows.size());
122  if (_loopTapes.empty()) {
123  //printSparsityPattern(_jacSparsity.sparsity, "jac sparsity");
124  CppAD::sparse_jacobian_work work;
125  if (forward) {
126  _fun.SparseJacobianForward(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
127  } else {
128  _fun.SparseJacobianReverse(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
129  }
130 
131  } else {
132  jac = prepareSparseJacobianWithLoops(handler, indVars, forward);
133  }
134 
135  finishedJob();
136 
137  LanguageC<Base> langC(_baseTypeName);
138  langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
139  langC.setParameterPrecision(_parameterPrecision);
140  langC.setGenerateFunction(_name + "_" + FUNCTION_SPARSE_JACOBIAN);
141 
142  std::ostringstream code;
143  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("jac"));
144 
145  handler.generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
146 }
147 
148 template<class Base>
150  MultiThreadingType multiThreadingType) {
151  //size_t m = _fun.Range();
152  //size_t n = _fun.Domain();
153  using namespace std;
154 
155  std::map<size_t, CompressedVectorInfo> jacInfo;
156  string functionRevFor, revForSuffix;
157  if (forward) {
158  // jacInfo[var].index{equations}
159  for (size_t e = 0; e < _jacSparsity.rows.size(); e++) {
160  jacInfo[_jacSparsity.cols[e]].indexes.push_back(_jacSparsity.rows[e]);
161  }
162  for (auto& it : jacInfo) {
163  size_t col = it.first;
164  it.second.locations = determineOrderByCol(col, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
165  }
166  _cache.str("");
167  _cache << _name << "_" << FUNCTION_SPARSE_FORWARD_ONE;
168  functionRevFor = _cache.str();
169  revForSuffix = "indep";
170  } else {
171  // jacInfo[equation].index{vars}
172  for (size_t e = 0; e < _jacSparsity.rows.size(); e++) {
173  jacInfo[_jacSparsity.rows[e]].indexes.push_back(_jacSparsity.cols[e]);
174  }
175  for (auto& it : jacInfo) {
176  size_t row = it.first;
177  it.second.locations = determineOrderByRow(row, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
178  }
179  _cache.str("");
180  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE;
181  functionRevFor = _cache.str();
182  revForSuffix = "dep";
183  }
184 
185 
190  for (auto& it : jacInfo) {
191  const std::vector<size_t>& els = it.second.indexes;
192  const std::vector<set<size_t> >& location = it.second.locations;
193  CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
194  CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
195 
196  bool passed = true;
197  size_t jacArrayStart = *location[0].begin();
198  for (size_t e = 0; e < els.size(); e++) {
199  if (location[e].size() > 1) {
200  passed = false; // too many elements
201  break;
202  }
203  if (*location[e].begin() != jacArrayStart + e) {
204  passed = false; // wrong order
205  break;
206  }
207  }
208  it.second.ordered = passed;
209  }
210 
211  size_t maxCompressedSize = 0;
212  map<size_t, bool>::const_iterator itOrd;
213  map<size_t, std::vector<size_t> >::const_iterator it;
214  for (const auto& it : jacInfo) {
215  if (it.second.indexes.size() > maxCompressedSize && !it.second.ordered)
216  maxCompressedSize = it.second.indexes.size();
217  }
218 
219  if (!_loopTapes.empty()) {
223  if (forward) {
224  generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
225  FUNCTION_SPARSE_FORWARD_ONE, "indep", "jcol",
226  _nonLoopFor1Elements, _loopFor1Groups,
227  generateFunctionNameLoopFor1);
228  } else {
229  generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
230  FUNCTION_SPARSE_REVERSE_ONE, "dep", "jrow",
231  _nonLoopRev1Elements, _loopRev1Groups,
232  generateFunctionNameLoopRev1);
233  }
234  return;
235  }
236 
237  _cache.str("");
238  _cache << _name << "_" << FUNCTION_SPARSE_JACOBIAN;
239  string functionName(_cache.str());
240 
241  if(!_multiThreading || multiThreadingType == MultiThreadingType::NONE) {
242  _sources[functionName + ".c"] = generateSparseJacobianForRevSingleThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward);
243  } else {
244  _sources[functionName + ".c"] = generateSparseJacobianForRevMultiThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward, multiThreadingType);
245  }
246 
247  _cache.str("");
248 }
249 
250 template<class Base>
251 std::string ModelCSourceGen<Base>::generateSparseJacobianForRevSingleThreadSource(const std::string& functionName,
252  std::map<size_t, CompressedVectorInfo> jacInfo,
253  size_t maxCompressedSize,
254  const std::string& functionRevFor,
255  const std::string& revForSuffix,
256  bool forward) {
257 
258  LanguageC<Base> langC(_baseTypeName);
259  std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
260  std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
261 
262  _cache.str("");
263  _cache << "#include <stdlib.h>\n"
264  "\n"
266  generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
267  _cache << "\n";
268  LanguageC<Base>::printFunctionDeclaration(_cache, "void", functionName, argsDcl2);
269  _cache << " {\n"
270  " " << _baseTypeName << " const * inLocal[2];\n"
271  " " << _baseTypeName << " inLocal1 = 1;\n"
272  " " << _baseTypeName << " * outLocal[1];\n"
273  " " << _baseTypeName << " compressed[" << maxCompressedSize << "];\n"
274  " " << _baseTypeName << " * jac = out[0];\n"
275  "\n"
276  " inLocal[0] = in[0];\n"
277  " inLocal[1] = &inLocal1;\n"
278  " outLocal[0] = compressed;\n";
279 
280  langC.setArgumentIn("inLocal");
281  langC.setArgumentOut("outLocal");
282  std::string argsLocal = langC.generateDefaultFunctionArguments();
283 
284  bool previousCompressed = true;
285  for (const auto& it : jacInfo) {
286  size_t index = it.first;
287  const std::vector<size_t>& els = it.second.indexes;
288  const std::vector<std::set<size_t> >& location = it.second.locations;
289  CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
290 
291  _cache << "\n";
292  bool compressed = !it.second.ordered;
293  if (!compressed) {
294  _cache << " outLocal[0] = &jac[" << *location[0].begin() << "];\n";
295  } else if (!previousCompressed) {
296  _cache << " outLocal[0] = compressed;\n";
297  }
298  _cache << " " << functionRevFor << "_" << revForSuffix << index << "(" << argsLocal << ");\n";
299  if (compressed) {
300  for (size_t e = 0; e < els.size(); e++) {
301  _cache << " ";
302  for (size_t itl : location[e]) {
303  _cache << "jac[" << (itl) << "] = ";
304  }
305  _cache << "compressed[" << e << "];\n";
306  }
307  }
308  previousCompressed = compressed;
309  }
310 
311  _cache << "\n"
312  "}\n";
313 
314  return _cache.str();
315 }
316 
317 template<class Base>
319  std::map<size_t, CompressedVectorInfo> jacInfo,
320  size_t maxCompressedSize,
321  const std::string& functionRevFor,
322  const std::string& revForSuffix,
323  bool forward,
324  MultiThreadingType multiThreadingType) {
325  LanguageC<Base> langC(_baseTypeName);
326  std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
327  std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
328 
329  _cache.str("");
330  _cache << "#include <stdlib.h>\n"
331  "\n"
333  generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
334 
335  langC.setArgumentIn("inLocal");
336  langC.setArgumentOut("outLocal");
337  std::string argsLocal = langC.generateDefaultFunctionArguments();
338 
342  for (const auto& it : jacInfo) {
343  size_t index = it.first;
344  const std::vector<size_t>& els = it.second.indexes;
345  const std::vector<std::set<size_t> >& location = it.second.locations;
346  CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
347 
348  bool compressed = !it.second.ordered;
349  if (!compressed) {
350  continue;
351  }
352 
353  std::string functionNameWrap = functionRevFor + "_" + revForSuffix + std::to_string(index) + "_wrap";
354  LanguageC<Base>::printFunctionDeclaration(_cache, "void", functionNameWrap, argsDcl2);
355  _cache << " {\n"
356  " " << _baseTypeName << " const * inLocal[2];\n"
357  " " << _baseTypeName << " inLocal1 = 1;\n"
358  " " << _baseTypeName << " * outLocal[1];\n"
359  " " << _baseTypeName << " compressed[" << it.second.indexes.size() << "];\n"
360  " " << _baseTypeName << " * jac = out[0];\n"
361  "\n"
362  " inLocal[0] = in[0];\n"
363  " inLocal[1] = &inLocal1;\n"
364  " outLocal[0] = compressed;\n";
365 
366  _cache << " " << functionRevFor << "_" << revForSuffix << index << "(" << argsLocal << ");\n";
367  for (size_t e = 0; e < els.size(); e++) {
368  _cache << " ";
369  for (size_t itl : location[e]) {
370  _cache << "jac[" << (itl) << "] = ";
371  }
372  _cache << "compressed[" << e << "];\n";
373  }
374  _cache << "}\n";
375  }
376 
377  _cache << "\n"
378  "typedef void (*cppadcg_function_type) (" << argsDcl << ");\n";
379 
383  if(multiThreadingType == MultiThreadingType::OPENMP) {
384  _cache << "\n";
385  printFileStartOpenMP(_cache);
386  _cache << "\n";
387 
388  } else {
389  assert(multiThreadingType == MultiThreadingType::PTHREADS);
390 
391  printFileStartPThreads(_cache, _baseTypeName);
392  }
393 
397  _cache << "\n"
398  "void " << functionName << "(" << argsDcl << ") {\n"
399  " static const cppadcg_function_type p[" << jacInfo.size() << "] = {";
400  for (const auto& it : jacInfo) {
401  size_t index = it.first;
402  if (index != jacInfo.begin()->first) _cache << ", ";
403  if (it.second.ordered) {
404  _cache << functionRevFor << "_" << revForSuffix << index;
405  } else {
406  _cache << functionRevFor << "_" << revForSuffix << index << "_wrap";
407  }
408  }
409  _cache << "};\n"
410  " static const long offset["<< jacInfo.size() <<"] = {";
411  for (const auto& it : jacInfo) {
412  if (it.first != jacInfo.begin()->first) _cache << ", ";
413  if (it.second.ordered) {
414  _cache << *it.second.locations[0].begin();
415  } else {
416  _cache << "0";
417  }
418  }
419  _cache << "};\n"
420  " " << _baseTypeName << " inLocal1 = 1;\n"
421  " " << _baseTypeName << " const * inLocal[2] = {in[0], &inLocal1};\n"
422  " " << _baseTypeName << " * outLocal[1];\n"
423  " " << _baseTypeName << " * jac = out[0];\n"
424  " long i;\n"
425  "\n";
426 
427  if(multiThreadingType == MultiThreadingType::OPENMP) {
428  printFunctionStartOpenMP(_cache, jacInfo.size());
429  _cache << "\n";
430  printLoopStartOpenMP(_cache, jacInfo.size());
431  _cache << " outLocal[0] = &jac[offset[i]];\n"
432  " (*p[i])(" << argsLocal << ");\n";
433  printLoopEndOpenMP(_cache, jacInfo.size());
434  _cache << "\n";
435 
436  } else {
437  assert(multiThreadingType == MultiThreadingType::PTHREADS);
438 
439  printFunctionStartPThreads(_cache, jacInfo.size());
440  _cache << "\n"
441  " for(i = 0; i < " << jacInfo.size() << "; ++i) {\n"
442  " args[i] = (ExecArgStruct*) malloc(sizeof(ExecArgStruct));\n"
443  " args[i]->func = p[i];\n"
444  " args[i]->in = inLocal;\n"
445  " args[i]->out[0] = &jac[offset[i]];\n"
446  " args[i]->atomicFun = " << langC.getArgumentAtomic() << ";\n"
447  " }\n"
448  "\n";
449  printFunctionEndPThreads(_cache, jacInfo.size());
450  }
451 
452  _cache << "\n"
453  "}\n";
454 
455  return _cache.str();
456 }
457 
458 template<class Base>
460  if (_jacSparsity.sparsity.size() > 0) {
461  return;
462  }
463 
467  _jacSparsity.sparsity = jacobianSparsitySet<SparsitySetType, CGBase> (_fun);
468 
469  if (!_custom_jac.defined) {
470  generateSparsityIndexes(_jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols);
471 
472  } else {
473  _jacSparsity.rows = _custom_jac.row;
474  _jacSparsity.cols = _custom_jac.col;
475  }
476 }
477 
478 template<class Base>
480  determineJacobianSparsity();
481 
482  generateSparsity2DSource(_name + "_" + FUNCTION_JACOBIAN_SPARSITY, _jacSparsity);
483  _sources[_name + "_" + FUNCTION_JACOBIAN_SPARSITY + ".c"] = _cache.str();
484  _cache.str("");
485 }
486 
487 } // END cg namespace
488 } // END CppAD namespace
489 
490 #endif
virtual void generateSparseJacobianSource(MultiThreadingType multiThreadingType)
STL namespace.
static void printFunctionDeclaration(std::ostringstream &out, const std::string &returnType, const std::string &functionName, const std::vector< std::string > &arguments, const std::vector< std::string > &arguments2={})
Definition: language_c.hpp:489
virtual std::string generateSparseJacobianForRevMultiThreadSource(const std::string &functionName, std::map< size_t, CompressedVectorInfo > jacInfo, size_t maxCompressedSize, const std::string &functionRevFor, const std::string &revForSuffix, bool forward, MultiThreadingType multiThreadingType)
void makeVariables(VectorCG &variables)
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:219
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
virtual void generateSparseJacobianForRevSource(bool forward, MultiThreadingType multiThreadingType)