CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
language_c.hpp
1 #ifndef CPPAD_CG_LANGUAGE_C_INCLUDED
2 #define CPPAD_CG_LANGUAGE_C_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  * Copyright (C) 2018 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 
19 #define CPPAD_CG_C_LANG_FUNCNAME(fn) \
20 inline virtual const std::string& fn ## FuncName() {\
21  static const std::string name(#fn);\
22  return name;\
23 }
24 
25 namespace CppAD {
26 namespace cg {
27 
33 template<class Base>
34 class LanguageC : public Language<Base> {
35 public:
36  using Node = OperationNode<Base>;
37  using Arg = Argument<Base>;
38 public:
39  static const std::string U_INDEX_TYPE;
40  static const std::string ATOMICFUN_STRUCT_DEFINITION;
41 protected:
42  static const std::string _C_COMP_OP_LT;
43  static const std::string _C_COMP_OP_LE;
44  static const std::string _C_COMP_OP_EQ;
45  static const std::string _C_COMP_OP_GE;
46  static const std::string _C_COMP_OP_GT;
47  static const std::string _C_COMP_OP_NE;
48  static const std::string _C_STATIC_INDEX_ARRAY;
49  static const std::string _C_SPARSE_INDEX_ARRAY;
50  static const std::string _ATOMIC_TX;
51  static const std::string _ATOMIC_TY;
52  static const std::string _ATOMIC_PX;
53  static const std::string _ATOMIC_PY;
54 private:
55  class AtomicFuncArray; //forward declaration
56 protected:
57  // the type name of the Base class (e.g. "double")
58  const std::string _baseTypeName;
59  // spaces for 1 level indentation
60  const std::string _spaces;
61  // information from the code handler (not owned)
62  LanguageGenerationData<Base>* _info;
63  // current indentation
64  std::string _indentation;
65  // variable name used for the inlet variable
66  std::string _inArgName;
67  // variable name used for the outlet variable
68  std::string _outArgName;
69  // variable name used for the atomic functions array
70  std::string _atomicArgName;
71  // output stream for the generated source code
72  std::ostringstream _code;
73  // creates the variable names
74  VariableNameGenerator<Base>* _nameGen;
75  // auxiliary string stream
76  std::ostringstream _ss;
77  //
78  size_t _independentSize;
79  //
80  size_t _minTemporaryVarID;
81  // maps the variable IDs to the their position in the dependent vector
82  // (some IDs may be the same as the independent variables when dep = indep)
83  std::map<size_t, size_t> _dependentIDs;
84  // the dependent variable vector
85  const ArrayView<CG<Base> >* _dependent;
86  // the temporary variables that may require a declaration
87  std::map<size_t, Node*> _temporary;
88  // the operator used for assignment of dependent variables
89  std::string _depAssignOperation;
90  // whether or not to ignore assignment of constant zero values to dependent variables
91  bool _ignoreZeroDepAssign;
92  // the name of the function to be created (if the string is empty no function is created)
93  std::string _functionName;
94  // the arguments provided to local functions called by the main function
95  std::string _localFunctionArguments;
96  // the maximum number of assignment (~lines) per local function
97  size_t _maxAssigmentsPerFunction;
98  //
99  std::map<std::string, std::string>* _sources;
100  // the values in the temporary array
101  std::vector<const Arg*> _tmpArrayValues;
102  // the values in the temporary sparse array
103  std::vector<const Arg*> _tmpSparseArrayValues;
104  // the current state of Array structures used by atomic functions
105  std::map<std::string, AtomicFuncArray> _atomicFuncArrays;
106  // indexes defined as function arguments
107  std::vector<const Node*> _funcArgIndexes;
108  std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
109  // the maximum precision used to print values
110  size_t _parameterPrecision;
111 private:
112  std::vector<std::string> funcArgDcl_;
113  std::vector<std::string> localFuncArgDcl_;
114  std::string localFuncArgs_;
115  std::string auxArrayName_;
116 
117 public:
118 
125  LanguageC(const std::string& varTypeName,
126  size_t spaces = 3) :
127  _baseTypeName(varTypeName),
128  _spaces(spaces, ' '),
129  _info(nullptr),
130  _inArgName("in"),
131  _outArgName("out"),
132  _atomicArgName("atomicFun"),
133  _nameGen(nullptr),
134  _independentSize(0), // not really required (but it avoids warnings)
135  _minTemporaryVarID(0), // not really required (but it avoids warnings)
136  _dependent(nullptr),
137  _depAssignOperation("="),
138  _ignoreZeroDepAssign(false),
139  _maxAssigmentsPerFunction(0),
140  _sources(nullptr),
141  _parameterPrecision(std::numeric_limits<Base>::digits10) {
142  }
143 
144  inline virtual ~LanguageC() = default;
145 
146  inline const std::string& getArgumentIn() const {
147  return _inArgName;
148  }
149 
150  inline void setArgumentIn(const std::string& inArgName) {
151  _inArgName = inArgName;
152  }
153 
154  inline const std::string& getArgumentOut() const {
155  return _outArgName;
156  }
157 
158  inline void setArgumentOut(const std::string& outArgName) {
159  _outArgName = outArgName;
160  }
161 
162  inline const std::string& getArgumentAtomic() const {
163  return _atomicArgName;
164  }
165 
166  inline void setArgumentAtomic(const std::string& atomicArgName) {
167  _atomicArgName = atomicArgName;
168  }
169 
170  inline const std::string& getDependentAssignOperation() const {
171  return _depAssignOperation;
172  }
173 
174  inline void setDependentAssignOperation(const std::string& depAssignOperation) {
175  _depAssignOperation = depAssignOperation;
176  }
177 
178  inline bool isIgnoreZeroDepAssign() const {
179  return _ignoreZeroDepAssign;
180  }
181 
182  inline void setIgnoreZeroDepAssign(bool ignore) {
183  _ignoreZeroDepAssign = ignore;
184  }
185 
186  virtual void setGenerateFunction(const std::string& functionName) {
187  _functionName = functionName;
188  }
189 
190  virtual void setFunctionIndexArgument(const Node& funcArgIndex) {
191  _funcArgIndexes.resize(1);
192  _funcArgIndexes[0] = &funcArgIndex;
193  }
194 
195  virtual void setFunctionIndexArguments(const std::vector<const Node*>& funcArgIndexes) {
196  _funcArgIndexes = funcArgIndexes;
197  }
198 
199  virtual const std::vector<const Node*>& getFunctionIndexArguments() const {
200  return _funcArgIndexes;
201  }
202 
209  virtual size_t getParameterPrecision() const {
210  return _parameterPrecision;
211  }
212 
219  virtual void setParameterPrecision(size_t p) {
220  _parameterPrecision = p;
221  }
222 
223  virtual void setMaxAssigmentsPerFunction(size_t maxAssigmentsPerFunction,
224  std::map<std::string, std::string>* sources) {
225  _maxAssigmentsPerFunction = maxAssigmentsPerFunction;
226  _sources = sources;
227  }
228 
229  inline std::string generateTemporaryVariableDeclaration(bool isWrapperFunction,
230  bool zeroArrayDependents,
231  const std::vector<int>& atomicMaxForward,
232  const std::vector<int>& atomicMaxReverse) {
233  int maxForward = -1;
234  if (!atomicMaxForward.empty())
235  maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
236 
237  int maxReverse = -1;
238  if (!atomicMaxReverse.empty())
239  maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
240 
241  return generateTemporaryVariableDeclaration(isWrapperFunction, zeroArrayDependents,
242  maxForward, maxReverse);
243  }
244 
260  virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction = false,
261  bool zeroArrayDependents = false,
262  int maxForwardOrder = -1,
263  int maxReverseOrder = -1) {
264  CPPADCG_ASSERT_UNKNOWN(_nameGen != nullptr);
265 
266  // declare variables
267  const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
268 
269  CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
270  "There must be two temporary variables");
271 
272  _ss << _spaces << "// auxiliary variables\n";
276  if (tmpArg[0].array) {
277  size_t size = _nameGen->getMaxTemporaryVariableID() + 1 - _nameGen->getMinTemporaryVariableID();
278  if (size > 0 || isWrapperFunction) {
279  _ss << _spaces << _baseTypeName << " " << tmpArg[0].name << "[" << size << "];\n";
280  }
281  } else if (_temporary.size() > 0) {
282  for (const std::pair<size_t, Node*>& p : _temporary) {
283  Node* var = p.second;
284  if (var->getName() == nullptr) {
285  var->setName(_nameGen->generateTemporary(*var, getVariableID(*var)));
286  }
287  }
288 
289  Node* var1 = _temporary.begin()->second;
290  const std::string& varName1 = *var1->getName();
291  _ss << _spaces << _baseTypeName << " " << varName1;
292 
293  typename std::map<size_t, Node*>::const_iterator it = _temporary.begin();
294  for (it++; it != _temporary.end(); ++it) {
295  _ss << ", " << *it->second->getName();
296  }
297  _ss << ";\n";
298  }
299 
303  size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
304  if (arraySize > 0 || isWrapperFunction) {
305  _ss << _spaces << _baseTypeName << " " << tmpArg[1].name << "[" << arraySize << "];\n";
306  }
307 
311  size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
312  if (sArraySize > 0 || isWrapperFunction) {
313  _ss << _spaces << _baseTypeName << " " << tmpArg[2].name << "[" << sArraySize << "];\n";
314  _ss << _spaces << U_INDEX_TYPE << " " << _C_SPARSE_INDEX_ARRAY << "[" << sArraySize << "];\n";
315  }
316 
317  if (!isWrapperFunction) {
318  generateArrayContainersDeclaration(_ss, maxForwardOrder, maxReverseOrder);
319  }
320 
321  //
322  if (!isWrapperFunction && (arraySize > 0 || sArraySize > 0)) {
323  _ss << _spaces << _baseTypeName << "* " << auxArrayName_ << ";\n";
324  }
325 
326  if ((isWrapperFunction && zeroArrayDependents) ||
327  (!isWrapperFunction && (arraySize > 0 || sArraySize > 0 || zeroArrayDependents))) {
328  _ss << _spaces << U_INDEX_TYPE << " i;\n";
329  }
330 
331  // loop indexes
332  createIndexDeclaration();
333 
334  // clean-up
335  std::string code = _ss.str();
336  _ss.str("");
337 
338  return code;
339  }
340 
341  inline void generateArrayContainersDeclaration(std::ostringstream& ss,
342  const std::vector<int>& atomicMaxForward,
343  const std::vector<int>& atomicMaxReverse) {
344  int maxForward = -1;
345  if (!atomicMaxForward.empty())
346  maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
347 
348  int maxReverse = -1;
349  if (!atomicMaxReverse.empty())
350  maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
351 
352  generateArrayContainersDeclaration(ss, maxForward, maxReverse);
353  }
354 
355  virtual void generateArrayContainersDeclaration(std::ostringstream& ss,
356  int maxForwardOrder = -1,
357  int maxReverseOrder = -1) {
358  if (maxForwardOrder >= 0 || maxReverseOrder >= 0) {
359  ss << _spaces << "Array " << _ATOMIC_TX << "[" << (std::max(maxForwardOrder, maxReverseOrder) + 1) << "];\n";
360  if (maxForwardOrder >= 0)
361  ss << _spaces << "Array " << _ATOMIC_TY << ";\n";
362  if (maxReverseOrder >= 0) {
363  ss << _spaces << "Array " << _ATOMIC_PX << ";\n";
364  ss << _spaces << "Array " << _ATOMIC_PY << "[" << (maxReverseOrder + 1) << "];\n";
365  }
366  }
367  }
368 
369  virtual std::string generateDependentVariableDeclaration() {
370  const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
371  CPPADCG_ASSERT_KNOWN(depArg.size() > 0,
372  "There must be at least one dependent argument");
373 
374  _ss << _spaces << "//dependent variables\n";
375  for (size_t i = 0; i < depArg.size(); i++) {
376  _ss << _spaces << argumentDeclaration(depArg[i]) << " = " << _outArgName << "[" << i << "];\n";
377  }
378 
379  std::string code = _ss.str();
380  _ss.str("");
381  return code;
382  }
383 
384  virtual std::string generateIndependentVariableDeclaration() {
385  const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
386  CPPADCG_ASSERT_KNOWN(indArg.size() > 0,
387  "There must be at least one independent argument");
388 
389  _ss << _spaces << "//independent variables\n";
390  for (size_t i = 0; i < indArg.size(); i++) {
391  _ss << _spaces << "const " << argumentDeclaration(indArg[i]) << " = " << _inArgName << "[" << i << "];\n";
392  }
393 
394  std::string code = _ss.str();
395  _ss.str("");
396  return code;
397  }
398 
399  inline std::string generateArgumentAtomicDcl() const {
400  return "struct LangCAtomicFun " + _atomicArgName;
401  }
402 
403  virtual std::string generateFunctionArgumentsDcl() const {
404  std::string args = generateFunctionIndexArgumentsDcl();
405  if (!args.empty())
406  args += ", ";
407  args += generateDefaultFunctionArgumentsDcl();
408 
409  return args;
410  }
411 
412  virtual std::vector<std::string> generateFunctionArgumentsDcl2() const {
413  std::vector<std::string> args = generateFunctionIndexArgumentsDcl2();
414  std::vector<std::string> dArgs = generateDefaultFunctionArgumentsDcl2();
415  args.insert(args.end(), dArgs.begin(), dArgs.end());
416  return args;
417  }
418 
419  virtual std::string generateDefaultFunctionArgumentsDcl() const {
420  return implode(generateDefaultFunctionArgumentsDcl2(), ", ");
421  }
422 
423  virtual std::vector<std::string> generateDefaultFunctionArgumentsDcl2() const {
424  return std::vector<std::string> {_baseTypeName + " const *const * " + _inArgName,
425  _baseTypeName + "*const * " + _outArgName,
426  generateArgumentAtomicDcl()};
427  }
428 
429  virtual std::string generateFunctionIndexArgumentsDcl() const {
430  return implode(generateFunctionIndexArgumentsDcl2(), ", ");
431  }
432 
433  virtual std::vector<std::string> generateFunctionIndexArgumentsDcl2() const {
434  std::vector<std::string> argtxt(_funcArgIndexes.size());
435  for (size_t a = 0; a < _funcArgIndexes.size(); a++) {
436  argtxt[a] = U_INDEX_TYPE + " " + *_funcArgIndexes[a]->getName();
437  }
438  return argtxt;
439  }
440 
441  virtual std::string generateDefaultFunctionArguments() const {
442  return _inArgName + ", " + _outArgName + ", " + _atomicArgName;
443  }
444 
445  virtual std::string generateFunctionIndexArguments() const {
446  std::string argtxt;
447  for (size_t a = 0; a < _funcArgIndexes.size(); a++) {
448  if (a > 0) argtxt += ", ";
449  argtxt += *_funcArgIndexes[a]->getName();
450  }
451  return argtxt;
452  }
453 
454  inline void createIndexDeclaration();
455 
456  CPPAD_CG_C_LANG_FUNCNAME(abs)
457  CPPAD_CG_C_LANG_FUNCNAME(acos)
458  CPPAD_CG_C_LANG_FUNCNAME(asin)
459  CPPAD_CG_C_LANG_FUNCNAME(atan)
460  CPPAD_CG_C_LANG_FUNCNAME(cosh)
461  CPPAD_CG_C_LANG_FUNCNAME(cos)
462  CPPAD_CG_C_LANG_FUNCNAME(exp)
463  CPPAD_CG_C_LANG_FUNCNAME(log)
464  CPPAD_CG_C_LANG_FUNCNAME(sinh)
465  CPPAD_CG_C_LANG_FUNCNAME(sin)
466  CPPAD_CG_C_LANG_FUNCNAME(sqrt)
467  CPPAD_CG_C_LANG_FUNCNAME(tanh)
468  CPPAD_CG_C_LANG_FUNCNAME(tan)
469  CPPAD_CG_C_LANG_FUNCNAME(pow)
470 
471 #if CPPAD_USE_CPLUSPLUS_2011
472  CPPAD_CG_C_LANG_FUNCNAME(erf)
473  CPPAD_CG_C_LANG_FUNCNAME(asinh)
474  CPPAD_CG_C_LANG_FUNCNAME(acosh)
475  CPPAD_CG_C_LANG_FUNCNAME(atanh)
476  CPPAD_CG_C_LANG_FUNCNAME(expm1)
477  CPPAD_CG_C_LANG_FUNCNAME(log1p)
478 #endif
479 
489  static inline void printFunctionDeclaration(std::ostringstream& out,
490  const std::string& returnType,
491  const std::string& functionName,
492  const std::vector<std::string>& arguments,
493  const std::vector<std::string>& arguments2 = {}) {
494  out << returnType << " " << functionName << "(";
495  size_t i = 0;
496  size_t offset = returnType.size() + 1 + functionName.size() + 1;
497  for (const std::string& a : arguments) {
498  if (i > 0) {
499  out << ",\n" << std::setw(offset) << " ";
500  }
501  out << a;
502  ++i;
503  }
504  for (const std::string& a : arguments2) {
505  if (i > 0) {
506  out << ",\n" << std::setw(offset) << " ";
507  }
508  out << a;
509  ++i;
510  }
511  out << ")";
512  }
513 
514  static inline void printIndexCondExpr(std::ostringstream& out,
515  const std::vector<size_t>& info,
516  const std::string& index) {
517  CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0, "Invalid number of information elements for an index condition expression operation");
518 
519  size_t infoSize = info.size();
520  for (size_t e = 0; e < infoSize; e += 2) {
521  if (e > 0) {
522  out << " || ";
523  }
524  size_t min = info[e];
525  size_t max = info[e + 1];
526  if (min == max) {
527  out << index << " == " << min;
528  } else if (min == 0) {
529  out << index << " <= " << max;
530  } else if (max == std::numeric_limits<size_t>::max()) {
531  out << min << " <= " << index;
532  } else {
533  if (infoSize != 2)
534  out << "(";
535 
536  if (max - min == 1)
537  out << min << " == " << index << " || " << index << " == " << max;
538  else
539  out << min << " <= " << index << " && " << index << " <= " << max;
540 
541  if (infoSize != 2)
542  out << ")";
543  }
544  }
545  }
546 
547  /***********************************************************************
548  *
549  **********************************************************************/
550 
551  static inline void printStaticIndexArray(std::ostringstream& os,
552  const std::string& name,
553  const std::vector<size_t>& values);
554 
555  static inline void printStaticIndexMatrix(std::ostringstream& os,
556  const std::string& name,
557  const std::map<size_t, std::map<size_t, size_t> >& values);
558 
559  /***********************************************************************
560  * index patterns
561  **********************************************************************/
562  static inline void generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns);
563 
564  static inline void printRandomIndexPatternDeclaration(std::ostringstream& os,
565  const std::string& identation,
566  const std::set<RandomIndexPattern*>& randomPatterns);
567 
568  static inline std::string indexPattern2String(const IndexPattern& ip,
569  const Node& index);
570 
571  static inline std::string indexPattern2String(const IndexPattern& ip,
572  const std::string& index);
573 
574  static inline std::string indexPattern2String(const IndexPattern& ip,
575  const std::vector<const Node*>& indexes);
576 
577  static inline std::string indexPattern2String(const IndexPattern& ip,
578  const std::vector<const std::string*>& indexes);
579 
580  static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
581  const Node& index);
582 
583  static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
584  const std::string& index);
585 
586  static inline bool isOffsetBy(const IndexPattern* ip,
587  const IndexPattern* refIp,
588  long offset);
589 
590  static inline bool isOffsetBy(const LinearIndexPattern* lIp,
591  const LinearIndexPattern* refLIp,
592  long offset);
593 
594  static inline bool isOffsetBy(const LinearIndexPattern& lIp,
595  const LinearIndexPattern& refLIp,
596  long offset);
597 
598 
599  static inline bool isOffsetBy(const SectionedIndexPattern* sIp,
600  const SectionedIndexPattern* refSecp,
601  long offset);
602 
603  static inline bool isOffsetBy(const SectionedIndexPattern& lIp,
604  const SectionedIndexPattern& refSecp,
605  long offset);
606 
607  static inline Plane2DIndexPattern* encapsulateIndexPattern(const LinearIndexPattern& refLIp,
608  size_t starti);
609 
610  static inline Plane2DIndexPattern* encapsulateIndexPattern(const SectionedIndexPattern& refSecp,
611  size_t starti);
612 protected:
613 
614  void generateSourceCode(std::ostream& out,
615  const std::unique_ptr<LanguageGenerationData<Base> >& info) override {
616 
617  const bool createFunction = !_functionName.empty();
618  const bool multiFunction = createFunction && _maxAssigmentsPerFunction > 0 && _sources != nullptr;
619 
620  // clean up
621  _code.str("");
622  _ss.str("");
623  _temporary.clear();
624  _indentation = _spaces;
625  funcArgDcl_.clear();
626  localFuncArgDcl_.clear();
627  localFuncArgs_ = "";
628  auxArrayName_ = "";
629  _currentLoops.clear();
630  _atomicFuncArrays.clear();
631 
632  // save some info
633  _info = info.get();
634  _independentSize = info->independent.size();
635  _dependent = &info->dependent;
636  _nameGen = &info->nameGen;
637  _minTemporaryVarID = info->minTemporaryVarID;
638  const ArrayView<CG<Base> >& dependent = info->dependent;
639  const std::vector<Node*>& variableOrder = info->variableOrder;
640 
641  _tmpArrayValues.resize(_nameGen->getMaxTemporaryArrayVariableID());
642  std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(), nullptr);
643  _tmpSparseArrayValues.resize(_nameGen->getMaxTemporarySparseArrayVariableID());
644  std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(), nullptr);
645 
649  generateNames4RandomIndexPatterns(info->indexRandomPatterns);
650 
654  //generate names for the independent variables
655  for (size_t j = 0; j < _independentSize; j++) {
656  Node& op = *info->independent[j];
657  if (op.getName() == nullptr) {
658  op.setName(_nameGen->generateIndependent(op, getVariableID(op)));
659  }
660  }
661 
662  // generate names for the dependent variables (must be after naming independents)
663  for (size_t i = 0; i < dependent.size(); i++) {
664  Node* node = dependent[i].getOperationNode();
665  if (node != nullptr && node->getOperationType() != CGOpCode::LoopEnd && node->getName() == nullptr) {
666  if (node->getOperationType() == CGOpCode::LoopIndexedDep) {
667  size_t pos = node->getInfo()[0];
668  const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
669  node->setName(_nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip));
670 
671  } else {
672  node->setName(_nameGen->generateDependent(i));
673  }
674  }
675  }
676 
680  const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
681  const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
682  const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
683  CPPADCG_ASSERT_KNOWN(indArg.size() > 0 && depArg.size() > 0,
684  "There must be at least one dependent and one independent argument");
685  CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
686  "There must be three temporary variables");
687 
688  if (createFunction) {
689  funcArgDcl_ = generateFunctionArgumentsDcl2();
690 
691  localFuncArgDcl_.reserve(funcArgDcl_.size() + 4);
692  localFuncArgDcl_ = funcArgDcl_;
693  localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[0]));
694  localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[1]));
695  localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[2]));
696  localFuncArgDcl_.push_back(U_INDEX_TYPE + "* " + _C_SPARSE_INDEX_ARRAY);
697 
698  localFuncArgs_ = generateDefaultFunctionArguments() + ", "
699  + tmpArg[0].name + ", "
700  + tmpArg[1].name + ", "
701  + tmpArg[2].name + ", "
702  + _C_SPARSE_INDEX_ARRAY;
703  }
704 
705  auxArrayName_ = tmpArg[1].name + "p";
706 
710  // dependent variables indexes that are copies of other dependent variables
711  std::set<size_t> dependentDuplicates;
712 
713  for (size_t i = 0; i < dependent.size(); i++) {
714  Node* node = dependent[i].getOperationNode();
715  if (node != nullptr) {
716  CGOpCode type = node->getOperationType();
717  if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
718  size_t varID = getVariableID(*node);
719  if (varID > 0) {
720  std::map<size_t, size_t>::const_iterator it2 = _dependentIDs.find(varID);
721  if (it2 == _dependentIDs.end()) {
722  _dependentIDs[getVariableID(*node)] = i;
723  } else {
724  // there can be several dependent variables with the same ID
725  dependentDuplicates.insert(i);
726  }
727  }
728  }
729  }
730  }
731 
732  // the names of local functions
733  std::vector<std::string> localFuncNames;
734  if (multiFunction) {
735  localFuncNames.reserve(variableOrder.size() / _maxAssigmentsPerFunction);
736  }
737 
741  if (variableOrder.size() > 0) {
742  // generate names for temporary variables
743  for (Node* node : variableOrder) {
744  CGOpCode op = node->getOperationType();
745  if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
746  // variable names for temporaries must always be created since they might have been used before with a different name/id
747  if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
748  node->setName(_nameGen->generateTemporary(*node, getVariableID(*node)));
749  } else if (op == CGOpCode::ArrayCreation) {
750  node->setName(_nameGen->generateTemporaryArray(*node, getVariableID(*node)));
751  } else if (op == CGOpCode::SparseArrayCreation) {
752  node->setName(_nameGen->generateTemporarySparseArray(*node, getVariableID(*node)));
753  }
754  }
755  }
756 
760  if (info->zeroDependents) {
761  // zero initial values
762  const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
763  for (size_t i = 0; i < depArg.size(); i++) {
764  const FuncArgument& a = depArg[i];
765  if (a.array) {
766  _code << _indentation << "for(i = 0; i < " << _dependent->size() << "; i++) " << a.name << "[i]";
767  } else {
768  _code << _indentation << _nameGen->generateDependent(i);
769  }
770  _code << " = ";
771  printParameter(Base(0.0));
772  _code << ";\n";
773  }
774  }
775 
776  size_t assignCount = 0;
777  for (size_t i = 0; i < variableOrder.size(); ++i) {
778  Node* it = variableOrder[i];
779 
780  // check if a new function should start
781  if (assignCount >= _maxAssigmentsPerFunction && multiFunction && _currentLoops.empty()) {
782  assignCount = 0;
783  saveLocalFunction(localFuncNames, localFuncNames.empty() && info->zeroDependents);
784  }
785 
786  Node& node = *it;
787 
788  // a dependent variable assigned by a loop does require any source code (its done inside the loop)
789  if (node.getOperationType() == CGOpCode::DependentRefRhs) {
790  continue; // nothing to do (this operation is right hand side only)
791  } else if (node.getOperationType() == CGOpCode::TmpDcl) { // temporary variable declaration does not need any source code here
792  continue; // nothing to do (bogus operation)
793  } else if (node.getOperationType() == CGOpCode::LoopIndexedDep) {
794  // try to detect a pattern and use a loop instead of individual assignments
795  i = printLoopIndexDeps(variableOrder, i);
796  continue;
797  }
798 
799  assignCount += printAssignment(node);
800  }
801 
802  if (localFuncNames.size() > 0 && assignCount > 0) {
803  assignCount = 0;
804  saveLocalFunction(localFuncNames, false);
805  }
806  }
807 
808  if (localFuncNames.size() > 0) {
812  CPPADCG_ASSERT_KNOWN(tmpArg[0].array,
813  "The temporary variables must be saved in an array in order to generate multiple functions");
814 
815  _code << ATOMICFUN_STRUCT_DEFINITION << "\n\n";
816  // forward declarations
817  std::string localFuncArgDcl2 = implode(localFuncArgDcl_, ", ");
818  for (size_t i = 0; i < localFuncNames.size(); i++) {
819  _code << "void " << localFuncNames[i] << "(" << localFuncArgDcl2 << ");\n";
820  }
821  _code << "\n";
822  printFunctionDeclaration(_code, "void", _functionName, funcArgDcl_);
823  _code << " {\n";
824  _nameGen->customFunctionVariableDeclarations(_code);
825  _code << generateIndependentVariableDeclaration() << "\n";
826  _code << generateDependentVariableDeclaration() << "\n";
827  _code << generateTemporaryVariableDeclaration(true, false,
828  info->atomicFunctionsMaxForward,
829  info->atomicFunctionsMaxReverse) << "\n";
830  _nameGen->prepareCustomFunctionVariables(_code);
831  for (size_t i = 0; i < localFuncNames.size(); i++) {
832  _code << _spaces << localFuncNames[i] << "(" << localFuncArgs_ << ");\n";
833  }
834  }
835 
836  // dependent duplicates
837  if (dependentDuplicates.size() > 0) {
838  _code << _spaces << "// variable duplicates: " << dependentDuplicates.size() << "\n";
839  for (size_t index : dependentDuplicates) {
840  const CG<Base>& dep = (*_dependent)[index];
841  std::string varName = _nameGen->generateDependent(index);
842  const std::string& origVarName = *dep.getOperationNode()->getName();
843 
844  _code << _spaces << varName << " " << _depAssignOperation << " " << origVarName << ";\n";
845  }
846  }
847 
848  // constant dependent variables
849  bool commentWritten = false;
850  for (size_t i = 0; i < dependent.size(); i++) {
851  if (dependent[i].isParameter()) {
852  if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
853  if (!commentWritten) {
854  _code << _spaces << "// dependent variables without operations\n";
855  commentWritten = true;
856  }
857  std::string varName = _nameGen->generateDependent(i);
858  _code << _spaces << varName << " " << _depAssignOperation << " ";
859  printParameter(dependent[i].getValue());
860  _code << ";\n";
861  }
862  } else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
863  if (!commentWritten) {
864  _code << _spaces << "// dependent variables without operations\n";
865  commentWritten = true;
866  }
867  std::string varName = _nameGen->generateDependent(i);
868  const std::string& indepName = *dependent[i].getOperationNode()->getName();
869  _code << _spaces << varName << " " << _depAssignOperation << " " << indepName << ";\n";
870  }
871  }
872 
876  if (createFunction) {
877  if (localFuncNames.empty()) {
878  _ss << "#include <math.h>\n"
879  "#include <stdio.h>\n\n"
880  << ATOMICFUN_STRUCT_DEFINITION << "\n\n";
881  printFunctionDeclaration(_ss, "void", _functionName, funcArgDcl_);
882  _ss << " {\n";
883  _nameGen->customFunctionVariableDeclarations(_ss);
884  _ss << generateIndependentVariableDeclaration() << "\n";
885  _ss << generateDependentVariableDeclaration() << "\n";
886  _ss << generateTemporaryVariableDeclaration(false, info->zeroDependents,
887  info->atomicFunctionsMaxForward,
888  info->atomicFunctionsMaxReverse) << "\n";
889  _nameGen->prepareCustomFunctionVariables(_ss);
890  _ss << _code.str();
891  _nameGen->finalizeCustomFunctionVariables(_ss);
892  _ss << "}\n\n";
893 
894  out << _ss.str();
895 
896  if (_sources != nullptr) {
897  (*_sources)[_functionName + ".c"] = _ss.str();
898  }
899  } else {
900  _nameGen->finalizeCustomFunctionVariables(_code);
901  _code << "}\n\n";
902 
903  (*_sources)[_functionName + ".c"] = _code.str();
904  }
905  } else {
906  out << _code.str();
907  }
908  }
909 
910  inline size_t getVariableID(const Node& node) const {
911  return _info->varId[node];
912  }
913 
914  inline unsigned printAssignment(Node& node) {
915  return printAssignment(node, node);
916  }
917 
918  inline unsigned printAssignment(Node& nodeName,
919  const Arg& nodeRhs) {
920  if (nodeRhs.getOperation() != nullptr) {
921  return printAssignment(nodeName, *nodeRhs.getOperation());
922  } else {
923  printAssignmentStart(nodeName);
924  printParameter(*nodeRhs.getParameter());
925  printAssignmentEnd(nodeName);
926  return 1;
927  }
928  }
929 
930  inline unsigned printAssignment(Node& nodeName,
931  Node& nodeRhs) {
932  bool createsVar = directlyAssignsVariable(nodeRhs); // do we need to do the assignment here?
933  if (!createsVar) {
934  printAssignmentStart(nodeName);
935  }
936  unsigned lines = printExpressionNoVarCheck(nodeRhs);
937  if (!createsVar) {
938  printAssignmentEnd(nodeRhs);
939  }
940 
941  if (nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
942  Node* array = nodeRhs.getArguments()[0].getOperation();
943  size_t arrayId = getVariableID(*array);
944  size_t pos = nodeRhs.getInfo()[0];
945  if (array->getOperationType() == CGOpCode::ArrayCreation)
946  _tmpArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
947  else
948  _tmpSparseArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
949  }
950 
951  return lines;
952  }
953 
954  inline virtual void printAssignmentStart(Node& op) {
955  printAssignmentStart(op, createVariableName(op), isDependent(op));
956  }
957 
958  inline virtual void printAssignmentStart(Node& node,
959  const std::string& varName,
960  bool isDep) {
961  if (!isDep) {
962  _temporary[getVariableID(node)] = &node;
963  }
964 
965  _code << _indentation << varName << " ";
966  if (isDep) {
967  CGOpCode op = node.getOperationType();
968  if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
969  _code << "+=";
970  } else {
971  _code << _depAssignOperation;
972  }
973  } else {
974  _code << "=";
975  }
976  _code << " ";
977  }
978 
979  inline virtual void printAssignmentEnd(Node& op) {
980  _code << ";\n";
981  }
982 
983  virtual std::string argumentDeclaration(const FuncArgument& funcArg) const {
984  std::string dcl = _baseTypeName;
985  if (funcArg.array) {
986  dcl += "*";
987  }
988  return dcl + " " + funcArg.name;
989  }
990 
991  virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
992  bool zeroDependentArray) {
993  _ss << _functionName << "__" << (localFuncNames.size() + 1);
994  std::string funcName = _ss.str();
995  _ss.str("");
996 
997  _ss << "#include <math.h>\n"
998  "#include <stdio.h>\n\n"
999  << ATOMICFUN_STRUCT_DEFINITION << "\n\n";
1000  printFunctionDeclaration(_ss, "void", funcName, localFuncArgDcl_);
1001  _ss << " {\n";
1002  _nameGen->customFunctionVariableDeclarations(_ss);
1003  _ss << generateIndependentVariableDeclaration() << "\n";
1004  _ss << generateDependentVariableDeclaration() << "\n";
1005  size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
1006  size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
1007  if (arraySize > 0 || sArraySize > 0) {
1008  _ss << _spaces << _baseTypeName << "* " << auxArrayName_ << ";\n";
1009  }
1010 
1011  generateArrayContainersDeclaration(_ss,
1012  _info->atomicFunctionsMaxForward,
1013  _info->atomicFunctionsMaxReverse);
1014 
1015  if (arraySize > 0 || sArraySize > 0 || zeroDependentArray) {
1016  _ss << _spaces << U_INDEX_TYPE << " i;\n";
1017  }
1018 
1019  // loop indexes
1020  createIndexDeclaration();
1021 
1022  _nameGen->prepareCustomFunctionVariables(_ss);
1023  _ss << _code.str();
1024  _nameGen->finalizeCustomFunctionVariables(_ss);
1025  _ss << "}\n\n";
1026 
1027  (*_sources)[funcName + ".c"] = _ss.str();
1028  localFuncNames.push_back(funcName);
1029 
1030  _code.str("");
1031  _ss.str("");
1032  }
1033 
1034  bool createsNewVariable(const Node& var,
1035  size_t totalUseCount) const override {
1036  CGOpCode op = var.getOperationType();
1037  if (totalUseCount > 1) {
1038  return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1039  } else {
1040  return ( op == CGOpCode::ArrayCreation ||
1041  op == CGOpCode::SparseArrayCreation ||
1042  op == CGOpCode::AtomicForward ||
1043  op == CGOpCode::AtomicReverse ||
1044  op == CGOpCode::ComLt ||
1045  op == CGOpCode::ComLe ||
1046  op == CGOpCode::ComEq ||
1047  op == CGOpCode::ComGe ||
1048  op == CGOpCode::ComGt ||
1049  op == CGOpCode::ComNe ||
1050  op == CGOpCode::LoopIndexedDep ||
1051  op == CGOpCode::LoopIndexedTmp ||
1052  op == CGOpCode::IndexAssign ||
1053  op == CGOpCode::Assign) &&
1054  op != CGOpCode::CondResult;
1055  }
1056  }
1057 
1058  virtual bool requiresVariableName(const Node& var) const {
1059  CGOpCode op = var.getOperationType();
1060  if (_info->totalUseCount.get(var) > 1) {
1061  return (op != CGOpCode::Pri &&
1062  op != CGOpCode::AtomicForward &&
1063  op != CGOpCode::AtomicReverse &&
1064  op != CGOpCode::LoopStart &&
1065  op != CGOpCode::LoopEnd &&
1066  op != CGOpCode::Index &&
1067  op != CGOpCode::IndexAssign &&
1068  op != CGOpCode::StartIf &&
1069  op != CGOpCode::ElseIf &&
1070  op != CGOpCode::Else &&
1071  op != CGOpCode::EndIf &&
1072  op != CGOpCode::CondResult &&
1073  op != CGOpCode::LoopIndexedTmp &&
1074  op != CGOpCode::Tmp);
1075  } else {
1076  return isCondAssign(op);
1077  }
1078  }
1079 
1087  virtual bool directlyAssignsVariable(const Node& var) const {
1088  CGOpCode op = var.getOperationType();
1089  return isCondAssign(op) ||
1090  op == CGOpCode::Pri ||
1091  op == CGOpCode::ArrayCreation ||
1092  op == CGOpCode::SparseArrayCreation ||
1093  op == CGOpCode::AtomicForward ||
1094  op == CGOpCode::AtomicReverse ||
1095  op == CGOpCode::DependentMultiAssign ||
1096  op == CGOpCode::LoopStart ||
1097  op == CGOpCode::LoopEnd ||
1098  op == CGOpCode::IndexAssign ||
1099  op == CGOpCode::StartIf ||
1100  op == CGOpCode::ElseIf ||
1101  op == CGOpCode::Else ||
1102  op == CGOpCode::EndIf ||
1103  op == CGOpCode::CondResult ||
1104  op == CGOpCode::IndexDeclaration;
1105  }
1106 
1107  bool requiresVariableArgument(enum CGOpCode op, size_t argIndex) const override {
1108  return op == CGOpCode::Sign || op == CGOpCode::CondResult || op == CGOpCode::Pri;
1109  }
1110 
1111  inline const std::string& createVariableName(Node& var) {
1112  CGOpCode op = var.getOperationType();
1113  CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0);
1114  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward);
1115  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse);
1116  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart);
1117  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd);
1118  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index);
1119  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign);
1120  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration);
1121 
1122  if (var.getName() == nullptr) {
1123  if (op == CGOpCode::ArrayCreation) {
1124  var.setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
1125 
1126  } else if (op == CGOpCode::SparseArrayCreation) {
1127  var.setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
1128 
1129  } else if (op == CGOpCode::LoopIndexedDep) {
1130  size_t pos = var.getInfo()[0];
1131  const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
1132  var.setName(_nameGen->generateIndexedDependent(var, getVariableID(var), *ip));
1133 
1134  } else if (op == CGOpCode::LoopIndexedIndep) {
1135  size_t pos = var.getInfo()[1];
1136  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1137  var.setName(_nameGen->generateIndexedIndependent(var, getVariableID(var), *ip));
1138 
1139  } else if (getVariableID(var) <= _independentSize) {
1140  // independent variable
1141  var.setName(_nameGen->generateIndependent(var, getVariableID(var)));
1142 
1143  } else if (getVariableID(var) < _minTemporaryVarID) {
1144  // dependent variable
1145  std::map<size_t, size_t>::const_iterator it = _dependentIDs.find(getVariableID(var));
1146  CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
1147 
1148  size_t index = it->second;
1149  var.setName(_nameGen->generateDependent(index));
1150  } else if (op == CGOpCode::Pri) {
1151  CPPADCG_ASSERT_KNOWN(var.getArguments().size() == 1, "Invalid number of arguments for print operation");
1152  Node* tmpVar = var.getArguments()[0].getOperation();
1153  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr, "Invalid argument for print operation");
1154  return createVariableName(*tmpVar);
1155 
1156  } else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
1157  CPPADCG_ASSERT_KNOWN(var.getArguments().size() >= 1, "Invalid number of arguments for loop indexed temporary operation");
1158  Node* tmpVar = var.getArguments()[0].getOperation();
1159  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1160  return createVariableName(*tmpVar);
1161 
1162  } else {
1163  // temporary variable
1164  var.setName(_nameGen->generateTemporary(var, getVariableID(var)));
1165  }
1166  }
1167 
1168 
1169  return *var.getName();
1170  }
1171 
1172  bool requiresVariableDependencies() const override {
1173  return false;
1174  }
1175 
1176  virtual void printIndependentVariableName(Node& op) {
1177  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 0, "Invalid number of arguments for independent variable");
1178 
1179  _code << _nameGen->generateIndependent(op, getVariableID(op));
1180  }
1181 
1182  virtual unsigned print(const Arg& arg) {
1183  if (arg.getOperation() != nullptr) {
1184  // expression
1185  return printExpression(*arg.getOperation());
1186  } else {
1187  // parameter
1188  printParameter(*arg.getParameter());
1189  return 1;
1190  }
1191  }
1192 
1193  virtual unsigned printExpression(Node& op) {
1194  if (getVariableID(op) > 0) {
1195  // use variable name
1196  _code << createVariableName(op);
1197  return 1;
1198  } else {
1199  // print expression code
1200  return printExpressionNoVarCheck(op);
1201  }
1202  }
1203 
1204  virtual unsigned printExpressionNoVarCheck(Node& node) {
1205  CGOpCode op = node.getOperationType();
1206  switch (op) {
1207  case CGOpCode::ArrayCreation:
1208  printArrayCreationOp(node);
1209  break;
1210  case CGOpCode::SparseArrayCreation:
1211  printSparseArrayCreationOp(node);
1212  break;
1213  case CGOpCode::ArrayElement:
1214  printArrayElementOp(node);
1215  break;
1216  case CGOpCode::Assign:
1217  return printAssignOp(node);
1218 
1219  case CGOpCode::Abs:
1220  case CGOpCode::Acos:
1221  case CGOpCode::Asin:
1222  case CGOpCode::Atan:
1223  case CGOpCode::Cosh:
1224  case CGOpCode::Cos:
1225  case CGOpCode::Exp:
1226  case CGOpCode::Log:
1227  case CGOpCode::Sinh:
1228  case CGOpCode::Sin:
1229  case CGOpCode::Sqrt:
1230  case CGOpCode::Tanh:
1231  case CGOpCode::Tan:
1232 #if CPPAD_USE_CPLUSPLUS_2011
1233  case CGOpCode::Erf:
1234  case CGOpCode::Asinh:
1235  case CGOpCode::Acosh:
1236  case CGOpCode::Atanh:
1237  case CGOpCode::Expm1:
1238  case CGOpCode::Log1p:
1239 #endif
1240  printUnaryFunction(node);
1241  break;
1242  case CGOpCode::AtomicForward: // atomicFunction.forward(q, p, vx, vy, tx, ty)
1243  printAtomicForwardOp(node);
1244  break;
1245  case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
1246  printAtomicReverseOp(node);
1247  break;
1248  case CGOpCode::Add:
1249  printOperationAdd(node);
1250  break;
1251  case CGOpCode::Alias:
1252  return printOperationAlias(node);
1253 
1254  case CGOpCode::ComLt:
1255  case CGOpCode::ComLe:
1256  case CGOpCode::ComEq:
1257  case CGOpCode::ComGe:
1258  case CGOpCode::ComGt:
1259  case CGOpCode::ComNe:
1260  printConditionalAssignment(node);
1261  break;
1262  case CGOpCode::Div:
1263  printOperationDiv(node);
1264  break;
1265  case CGOpCode::Inv:
1266  printIndependentVariableName(node);
1267  break;
1268  case CGOpCode::Mul:
1269  printOperationMul(node);
1270  break;
1271  case CGOpCode::Pow:
1272  printPowFunction(node);
1273  break;
1274  case CGOpCode::Pri:
1275  printPrintOperation(node);
1276  break;
1277  case CGOpCode::Sign:
1278  printSignFunction(node);
1279  break;
1280  case CGOpCode::Sub:
1281  printOperationMinus(node);
1282  break;
1283 
1284  case CGOpCode::UnMinus:
1285  printOperationUnaryMinus(node);
1286  break;
1287 
1288  case CGOpCode::DependentMultiAssign:
1289  return printDependentMultiAssign(node);
1290 
1291  case CGOpCode::Index:
1292  return 0; // nothing to do
1293  case CGOpCode::IndexAssign:
1294  printIndexAssign(node);
1295  break;
1296  case CGOpCode::IndexDeclaration:
1297  return 0; // already done
1298 
1299  case CGOpCode::LoopStart:
1300  printLoopStart(node);
1301  break;
1302  case CGOpCode::LoopIndexedIndep:
1303  printLoopIndexedIndep(node);
1304  break;
1305  case CGOpCode::LoopIndexedDep:
1306  printLoopIndexedDep(node);
1307  break;
1308  case CGOpCode::LoopIndexedTmp:
1309  printLoopIndexedTmp(node);
1310  break;
1311  case CGOpCode::TmpDcl:
1312  // nothing to do
1313  return 0;
1314  case CGOpCode::Tmp:
1315  printTmpVar(node);
1316  break;
1317  case CGOpCode::LoopEnd:
1318  printLoopEnd(node);
1319  break;
1320  case CGOpCode::IndexCondExpr:
1321  printIndexCondExprOp(node);
1322  break;
1323  case CGOpCode::StartIf:
1324  printStartIf(node);
1325  break;
1326  case CGOpCode::ElseIf:
1327  printElseIf(node);
1328  break;
1329  case CGOpCode::Else:
1330  printElse(node);
1331  break;
1332  case CGOpCode::EndIf:
1333  printEndIf(node);
1334  break;
1335  case CGOpCode::CondResult:
1336  printCondResult(node);
1337  break;
1338  case CGOpCode::UserCustom:
1339  printUserCustom(node);
1340  break;
1341  default:
1342  throw CGException("Unknown operation code '", op, "'.");
1343  }
1344  return 1;
1345  }
1346 
1347  virtual unsigned printAssignOp(Node& node) {
1348  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for assign operation");
1349 
1350  return print(node.getArguments()[0]);
1351  }
1352 
1353  virtual void printUnaryFunction(Node& op) {
1354  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary function");
1355 
1356  switch (op.getOperationType()) {
1357  case CGOpCode::Abs:
1358  _code << absFuncName();
1359  break;
1360  case CGOpCode::Acos:
1361  _code << acosFuncName();
1362  break;
1363  case CGOpCode::Asin:
1364  _code << asinFuncName();
1365  break;
1366  case CGOpCode::Atan:
1367  _code << atanFuncName();
1368  break;
1369  case CGOpCode::Cosh:
1370  _code << coshFuncName();
1371  break;
1372  case CGOpCode::Cos:
1373  _code << cosFuncName();
1374  break;
1375  case CGOpCode::Exp:
1376  _code << expFuncName();
1377  break;
1378  case CGOpCode::Log:
1379  _code << logFuncName();
1380  break;
1381  case CGOpCode::Sinh:
1382  _code << sinhFuncName();
1383  break;
1384  case CGOpCode::Sin:
1385  _code << sinFuncName();
1386  break;
1387  case CGOpCode::Sqrt:
1388  _code << sqrtFuncName();
1389  break;
1390  case CGOpCode::Tanh:
1391  _code << tanhFuncName();
1392  break;
1393  case CGOpCode::Tan:
1394  _code << tanFuncName();
1395  break;
1396 #if CPPAD_USE_CPLUSPLUS_2011
1397  case CGOpCode::Erf:
1398  _code << erfFuncName();
1399  break;
1400  case CGOpCode::Asinh:
1401  _code << asinhFuncName();
1402  break;
1403  case CGOpCode::Acosh:
1404  _code << acoshFuncName();
1405  break;
1406  case CGOpCode::Atanh:
1407  _code << atanhFuncName();
1408  break;
1409  case CGOpCode::Expm1:
1410  _code << expm1FuncName();
1411  break;
1412  case CGOpCode::Log1p:
1413  _code << log1pFuncName();
1414  break;
1415 #endif
1416  default:
1417  throw CGException("Unknown function name for operation code '", op.getOperationType(), "'.");
1418  }
1419 
1420  _code << "(";
1421  print(op.getArguments()[0]);
1422  _code << ")";
1423  }
1424 
1425  virtual void printPowFunction(Node& op) {
1426  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for pow() function");
1427 
1428  _code << powFuncName() << "(";
1429  print(op.getArguments()[0]);
1430  _code << ", ";
1431  print(op.getArguments()[1]);
1432  _code << ")";
1433  }
1434 
1435  virtual void printSignFunction(Node& op) {
1436  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for sign() function");
1437  CPPADCG_ASSERT_UNKNOWN(op.getArguments()[0].getOperation() != nullptr);
1438  CPPADCG_ASSERT_UNKNOWN(getVariableID(*op.getArguments()[0].getOperation()) > 0);
1439 
1440  Node& arg = *op.getArguments()[0].getOperation();
1441 
1442  const std::string& argName = createVariableName(arg);
1443 
1444  _code << "(" << argName << " " << _C_COMP_OP_GT << " ";
1445  printParameter(Base(0.0));
1446  _code << "?";
1447  printParameter(Base(1.0));
1448  _code << ":(" << argName << " " << _C_COMP_OP_LT << " ";
1449  printParameter(Base(0.0));
1450  _code << "?";
1451  printParameter(Base(-1.0));
1452  _code << ":";
1453  printParameter(Base(0.0));
1454  _code << "))";
1455  }
1456 
1457  virtual unsigned printOperationAlias(Node& op) {
1458  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for alias");
1459  return print(op.getArguments()[0]);
1460  }
1461 
1462  virtual void printOperationAdd(Node& op) {
1463  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for addition");
1464 
1465  const Arg& left = op.getArguments()[0];
1466  const Arg& right = op.getArguments()[1];
1467 
1468  if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1469  print(left);
1470  _code << " + ";
1471  print(right);
1472  } else {
1473  // right has a negative parameter so we would get v0 + -v1
1474  print(left);
1475  _code << " - ";
1476  printParameter(-*right.getParameter()); // make it positive
1477  }
1478  }
1479 
1480  virtual void printOperationMinus(Node& op) {
1481  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for subtraction");
1482 
1483  const Arg& left = op.getArguments()[0];
1484  const Arg& right = op.getArguments()[1];
1485 
1486  if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1487  bool encloseRight = encloseInParenthesesMul(right.getOperation());
1488 
1489  print(left);
1490  _code << " - ";
1491  if (encloseRight) {
1492  _code << "(";
1493  }
1494  print(right);
1495  if (encloseRight) {
1496  _code << ")";
1497  }
1498  } else {
1499  // right has a negative parameter so we would get v0 - -v1
1500  print(left);
1501  _code << " + ";
1502  printParameter(-*right.getParameter()); // make it positive
1503  }
1504  }
1505 
1506  inline bool encloseInParenthesesDiv(const Node* node) const {
1507  while (node != nullptr) {
1508  if (getVariableID(*node) != 0)
1509  return false;
1510  if (node->getOperationType() == CGOpCode::Alias)
1511  node = node->getArguments()[0].getOperation();
1512  else
1513  break;
1514  }
1515  return node != nullptr &&
1516  getVariableID(*node) == 0 &&
1517  !isFunction(node->getOperationType());
1518  }
1519 
1520  virtual void printOperationDiv(Node& op) {
1521  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for division");
1522 
1523  const Arg& left = op.getArguments()[0];
1524  const Arg& right = op.getArguments()[1];
1525 
1526  bool encloseLeft = encloseInParenthesesDiv(left.getOperation());
1527  bool encloseRight = encloseInParenthesesDiv(right.getOperation());
1528 
1529  if (encloseLeft) {
1530  _code << "(";
1531  }
1532  print(left);
1533  if (encloseLeft) {
1534  _code << ")";
1535  }
1536  _code << " / ";
1537  if (encloseRight) {
1538  _code << "(";
1539  }
1540  print(right);
1541  if (encloseRight) {
1542  _code << ")";
1543  }
1544  }
1545 
1546  inline bool encloseInParenthesesMul(const Node* node) const {
1547  while (node != nullptr) {
1548  if (getVariableID(*node) != 0)
1549  return false;
1550  else if (node->getOperationType() == CGOpCode::Alias)
1551  node = node->getArguments()[0].getOperation();
1552  else
1553  break;
1554  }
1555  return node != nullptr &&
1556  getVariableID(*node) == 0 &&
1557  node->getOperationType() != CGOpCode::Div &&
1558  node->getOperationType() != CGOpCode::Mul &&
1559  !isFunction(node->getOperationType());
1560  }
1561 
1562  virtual void printOperationMul(Node& op) {
1563  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for multiplication");
1564 
1565  const Arg& left = op.getArguments()[0];
1566  const Arg& right = op.getArguments()[1];
1567 
1568  bool encloseLeft = encloseInParenthesesMul(left.getOperation());
1569  bool encloseRight = encloseInParenthesesMul(right.getOperation());
1570 
1571  if (encloseLeft) {
1572  _code << "(";
1573  }
1574  print(left);
1575  if (encloseLeft) {
1576  _code << ")";
1577  }
1578  _code << " * ";
1579  if (encloseRight) {
1580  _code << "(";
1581  }
1582  print(right);
1583  if (encloseRight) {
1584  _code << ")";
1585  }
1586  }
1587 
1588  virtual void printOperationUnaryMinus(Node& op) {
1589  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary minus");
1590 
1591  const Arg& arg = op.getArguments()[0];
1592 
1593  bool enclose = encloseInParenthesesMul(arg.getOperation());
1594 
1595  _code << "-";
1596  if (enclose) {
1597  _code << "(";
1598  } else {
1599  _code << " "; // there may be several - together -> space required
1600  }
1601  print(arg);
1602  if (enclose) {
1603  _code << ")";
1604  }
1605  }
1606 
1607  virtual void printPrintOperation(const Node& node) {
1608  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Pri, "Invalid node type");
1609  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for print operation");
1610 
1611  const PrintOperationNode<Base>& pnode = static_cast<const PrintOperationNode<Base>&> (node);
1612  std::string before = pnode.getBeforeString();
1613  replaceString(before, "\n", "\\n");
1614  replaceString(before, "\"", "\\\"");
1615  std::string after = pnode.getAfterString();
1616  replaceString(after, "\n", "\\n");
1617  replaceString(after, "\"", "\\\"");
1618 
1619  _code << _indentation << "fprintf(stderr, \"" << before << getPrintfBaseFormat() << after << "\"";
1620  const std::vector<Arg>& args = pnode.getArguments();
1621  for (size_t a = 0; a < args.size(); a++) {
1622  _code << ", ";
1623  print(args[a]);
1624  }
1625  _code << ");\n";
1626  }
1627 
1628  virtual void printConditionalAssignment(Node& node) {
1629  CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
1630 
1631  const std::vector<Arg>& args = node.getArguments();
1632  const Arg &left = args[0];
1633  const Arg &right = args[1];
1634  const Arg &trueCase = args[2];
1635  const Arg &falseCase = args[3];
1636 
1637  bool isDep = isDependent(node);
1638  const std::string& varName = createVariableName(node);
1639 
1640  if ((trueCase.getParameter() != nullptr && falseCase.getParameter() != nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1641  (trueCase.getOperation() != nullptr && falseCase.getOperation() != nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1642  // true and false cases are the same
1643  printAssignmentStart(node, varName, isDep);
1644  print(trueCase);
1645  printAssignmentEnd(node);
1646  } else {
1647  _code << _indentation << "if( ";
1648  print(left);
1649  _code << " " << getComparison(node.getOperationType()) << " ";
1650  print(right);
1651  _code << " ) {\n";
1652  _code << _spaces;
1653  printAssignmentStart(node, varName, isDep);
1654  print(trueCase);
1655  printAssignmentEnd(node);
1656  _code << _indentation << "} else {\n";
1657  _code << _spaces;
1658  printAssignmentStart(node, varName, isDep);
1659  print(falseCase);
1660  printAssignmentEnd(node);
1661  _code << _indentation << "}\n";
1662  }
1663  }
1664 
1665  inline bool isSameArgument(const Arg& newArg,
1666  const Arg* oldArg) {
1667  if (oldArg != nullptr) {
1668  if (oldArg->getParameter() != nullptr) {
1669  if (newArg.getParameter() != nullptr) {
1670  return (*newArg.getParameter() == *oldArg->getParameter());
1671  }
1672  } else {
1673  return (newArg.getOperation() == oldArg->getOperation());
1674  }
1675  }
1676  return false;
1677  }
1678 
1679  virtual void printArrayCreationOp(Node& op);
1680 
1681  virtual void printSparseArrayCreationOp(Node& op);
1682 
1683  inline void printArrayStructInit(const std::string& dataArrayName,
1684  size_t pos,
1685  const std::vector<Node*>& arrays,
1686  size_t k);
1687 
1688  inline void printArrayStructInit(const std::string& dataArrayName,
1689  Node& array);
1690 
1691  inline void markArrayChanged(Node& ty);
1692 
1693  inline size_t printArrayCreationUsingLoop(size_t startPos,
1694  Node& array,
1695  size_t startj,
1696  std::vector<const Arg*>& tmpArrayValues);
1697 
1698  inline std::string getTempArrayName(const Node& op);
1699 
1700  virtual void printArrayElementOp(Node& op);
1701 
1702  virtual void printAtomicForwardOp(Node& atomicFor) {
1703  CPPADCG_ASSERT_KNOWN(atomicFor.getInfo().size() == 3, "Invalid number of information elements for atomic forward operation");
1704  int q = atomicFor.getInfo()[1];
1705  int p = atomicFor.getInfo()[2];
1706  size_t p1 = p + 1;
1707  const std::vector<Arg>& opArgs = atomicFor.getArguments();
1708  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments for atomic forward operation");
1709 
1710  size_t id = atomicFor.getInfo()[0];
1711  size_t atomicIndex = _info->atomicFunctionId2Index.at(id);
1712 
1713  std::vector<Node*> tx(p1), ty(p1);
1714  for (size_t k = 0; k < p1; k++) {
1715  tx[k] = opArgs[0 * p1 + k].getOperation();
1716  ty[k] = opArgs[1 * p1 + k].getOperation();
1717  }
1718 
1719  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1720  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1721 
1722  CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1723 
1724  // tx
1725  for (size_t k = 0; k < p1; k++) {
1726  printArrayStructInit(_ATOMIC_TX, k, tx, k); // also does indentation
1727  }
1728  // ty
1729  printArrayStructInit(_ATOMIC_TY, *ty[p]); // also does indentation
1730  _ss.str("");
1731 
1732  _code << _indentation << "atomicFun.forward(atomicFun.libModel, "
1733  << atomicIndex << ", " << q << ", " << p << ", "
1734  << _ATOMIC_TX << ", &" << _ATOMIC_TY << "); // "
1735  << _info->atomicFunctionId2Name.at(id)
1736  << "\n";
1737 
1741  markArrayChanged(*ty[p]);
1742  }
1743 
1744  virtual void printAtomicReverseOp(Node& atomicRev) {
1745  CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements for atomic reverse operation");
1746  int p = atomicRev.getInfo()[1];
1747  size_t p1 = p + 1;
1748  const std::vector<Arg>& opArgs = atomicRev.getArguments();
1749  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4, "Invalid number of arguments for atomic reverse operation");
1750 
1751  size_t id = atomicRev.getInfo()[0];
1752  size_t atomicIndex = _info->atomicFunctionId2Index.at(id);
1753  std::vector<Node*> tx(p1), px(p1), py(p1);
1754  for (size_t k = 0; k < p1; k++) {
1755  tx[k] = opArgs[0 * p1 + k].getOperation();
1756  px[k] = opArgs[2 * p1 + k].getOperation();
1757  py[k] = opArgs[3 * p1 + k].getOperation();
1758  }
1759 
1760  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1761  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1762 
1763  CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1764 
1765  CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1766  CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1767 
1768  // tx
1769  for (size_t k = 0; k < p1; k++) {
1770  printArrayStructInit(_ATOMIC_TX, k, tx, k); // also does indentation
1771  }
1772  // py
1773  for (size_t k = 0; k < p1; k++) {
1774  printArrayStructInit(_ATOMIC_PY, k, py, k); // also does indentation
1775  }
1776  // px
1777  printArrayStructInit(_ATOMIC_PX, *px[0]); // also does indentation
1778  _ss.str("");
1779 
1780  _code << _indentation << "atomicFun.reverse(atomicFun.libModel, "
1781  << atomicIndex << ", " << p << ", "
1782  << _ATOMIC_TX << ", &" << _ATOMIC_PX << ", " << _ATOMIC_PY << "); // "
1783  << _info->atomicFunctionId2Name.at(id)
1784  << "\n";
1785 
1789  markArrayChanged(*px[0]);
1790  }
1791 
1792  virtual unsigned printDependentMultiAssign(Node& node) {
1793  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign, "Invalid node type");
1794  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments");
1795 
1796  const std::vector<Arg>& args = node.getArguments();
1797  for (size_t a = 0; a < args.size(); a++) {
1798  bool useArg = false;
1799  const Arg& arg = args[a];
1800  if (arg.getParameter() != nullptr) {
1801  useArg = true;
1802  } else {
1803  CGOpCode op = arg.getOperation()->getOperationType();
1804  useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1805  }
1806 
1807  if (useArg) {
1808  printAssignment(node, arg); // ignore other arguments!
1809  return 1;
1810  }
1811  }
1812  return 0;
1813  }
1814 
1815  virtual void printLoopStart(Node& node) {
1816  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node type");
1817 
1818  LoopStartOperationNode<Base>& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1819  _currentLoops.push_back(&lnode);
1820 
1821  const std::string& jj = *lnode.getIndex().getName();
1822  std::string iterationCount;
1823  if (lnode.getIterationCountNode() != nullptr) {
1824  iterationCount = *lnode.getIterationCountNode()->getIndex().getName();
1825  } else {
1826  std::ostringstream oss;
1827  oss << lnode.getIterationCount();
1828  iterationCount = oss.str();
1829  }
1830 
1831  _code << _spaces << "for("
1832  << jj << " = 0; "
1833  << jj << " < " << iterationCount << "; "
1834  << jj << "++) {\n";
1835  _indentation += _spaces;
1836  }
1837 
1838  virtual void printLoopEnd(Node& node) {
1839  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node type");
1840 
1841  _indentation.resize(_indentation.size() - _spaces.size());
1842 
1843  _code << _indentation << "}\n";
1844 
1845  _currentLoops.pop_back();
1846  }
1847 
1848 
1849  virtual size_t printLoopIndexDeps(const std::vector<Node*>& variableOrder,
1850  size_t pos);
1851 
1852  virtual size_t printLoopIndexedDepsUsingLoop(const std::vector<Node*>& variableOrder,
1853  size_t starti);
1854 
1855  virtual void printLoopIndexedDep(Node& node);
1856 
1857  virtual void printLoopIndexedIndep(Node& node) {
1858  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type");
1859  CPPADCG_ASSERT_KNOWN(node.getInfo().size() == 1, "Invalid number of information elements for loop indexed independent operation");
1860 
1861  // CGLoopIndexedIndepOp
1862  size_t pos = node.getInfo()[1];
1863  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1864  _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1865  }
1866 
1867  virtual void printLoopIndexedTmp(Node& node) {
1868  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp, "Invalid node type");
1869  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for loop indexed temporary operation");
1870  Node* tmpVar = node.getArguments()[0].getOperation();
1871  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1872 
1873  print(node.getArguments()[1]);
1874  }
1875 
1876  virtual void printTmpVar(Node& node) {
1877  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp, "Invalid node type");
1878  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for temporary variable usage operation");
1879  Node* tmpVar = node.getArguments()[0].getOperation();
1880  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1881 
1882  _code << *tmpVar->getName();
1883  }
1884 
1885  virtual void printIndexAssign(Node& node) {
1886  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node type");
1887  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for an index assignment operation");
1888 
1889  IndexAssignOperationNode<Base>& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1890 
1891  const IndexPattern& ip = inode.getIndexPattern();
1892  _code << _indentation << (*inode.getIndex().getName())
1893  << " = " << indexPattern2String(ip, inode.getIndexPatternIndexes()) << ";\n";
1894  }
1895 
1896  virtual void printIndexCondExprOp(Node& node) {
1897  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr, "Invalid node type");
1898  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for an index condition expression operation");
1899  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an index condition expression operation");
1900  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument for an index condition expression operation");
1901 
1902  const std::vector<size_t>& info = node.getInfo();
1903 
1904  IndexOperationNode<Base>& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1905  const std::string& index = *iterationIndexOp.getIndex().getName();
1906 
1907  printIndexCondExpr(_code, info, index);
1908  }
1909 
1910  virtual void printStartIf(Node& node) {
1915  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf, "Invalid node type");
1916  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'if start' operation");
1917  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'if start' operation");
1918 
1919  _code << _indentation << "if(";
1920  printIndexCondExprOp(*node.getArguments()[0].getOperation());
1921  _code << ") {\n";
1922 
1923  _indentation += _spaces;
1924  }
1925 
1926  virtual void printElseIf(Node& node) {
1932  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ElseIf, "Invalid node type");
1933  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 2, "Invalid number of arguments for an 'else if' operation");
1934  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1935  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1936 
1937  _indentation.resize(_indentation.size() - _spaces.size());
1938 
1939  _code << _indentation << "} else if(";
1940  printIndexCondExprOp(*node.getArguments()[1].getOperation());
1941  _code << ") {\n";
1942 
1943  _indentation += _spaces;
1944  }
1945 
1946  virtual void printElse(Node& node) {
1951  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Else, "Invalid node type");
1952  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'else' operation");
1953 
1954  _indentation.resize(_indentation.size() - _spaces.size());
1955 
1956  _code << _indentation << "} else {\n";
1957 
1958  _indentation += _spaces;
1959  }
1960 
1961  virtual void printEndIf(Node& node) {
1962  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node type for an 'end if' operation");
1963 
1964  _indentation.resize(_indentation.size() - _spaces.size());
1965 
1966  _code << _indentation << "}\n";
1967  }
1968 
1969  virtual void printCondResult(Node& node) {
1970  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult, "Invalid node type");
1971  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for an assignment inside an if/else operation");
1972  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
1973  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
1974 
1975  // just follow the argument
1976  Node& nodeArg = *node.getArguments()[1].getOperation();
1977  printAssignment(nodeArg);
1978  }
1979 
1980  virtual void printUserCustom(Node& node) {
1981  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom, "Invalid node type");
1982 
1983  throw CGException("Unable to generate C source code for user custom operation nodes.");
1984  }
1985 
1986  inline bool isDependent(const Node& arg) const {
1987  if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
1988  return true;
1989  }
1990  size_t id = getVariableID(arg);
1991  return id > _independentSize && id < _minTemporaryVarID;
1992  }
1993 
1994  virtual void printParameter(const Base& value) {
1995  // make sure all digits of floating point values are printed
1996  std::ostringstream os;
1997  os << std::setprecision(_parameterPrecision) << value;
1998 
1999  std::string number = os.str();
2000  _code << number;
2001 
2002  if (std::abs(value) > Base(0) && value != Base(1) && value != Base(-1)) {
2003  if (number.find('.') == std::string::npos && number.find('e') == std::string::npos) {
2004  // also make sure there is always a '.' after the number in
2005  // order to avoid integer overflows
2006  _code << '.';
2007  }
2008  }
2009  }
2010 
2011  virtual const std::string& getComparison(enum CGOpCode op) const {
2012  switch (op) {
2013  case CGOpCode::ComLt:
2014  return _C_COMP_OP_LT;
2015 
2016  case CGOpCode::ComLe:
2017  return _C_COMP_OP_LE;
2018 
2019  case CGOpCode::ComEq:
2020  return _C_COMP_OP_EQ;
2021 
2022  case CGOpCode::ComGe:
2023  return _C_COMP_OP_GE;
2024 
2025  case CGOpCode::ComGt:
2026  return _C_COMP_OP_GT;
2027 
2028  case CGOpCode::ComNe:
2029  return _C_COMP_OP_NE;
2030 
2031  default:
2032  CPPAD_ASSERT_UNKNOWN(0);
2033  }
2034  throw CGException("Invalid comparison operator code"); // should never get here
2035  }
2036 
2037  inline const std::string& getPrintfBaseFormat() {
2038  static const std::string format; // empty string
2039  return format;
2040  }
2041 
2042  static bool isFunction(enum CGOpCode op) {
2043  return isUnaryFunction(op) || op == CGOpCode::Pow;
2044  }
2045 
2046  static bool isUnaryFunction(enum CGOpCode op) {
2047  switch (op) {
2048  case CGOpCode::Abs:
2049  case CGOpCode::Acos:
2050  case CGOpCode::Asin:
2051  case CGOpCode::Atan:
2052  case CGOpCode::Cosh:
2053  case CGOpCode::Cos:
2054  case CGOpCode::Exp:
2055  case CGOpCode::Log:
2056  case CGOpCode::Sinh:
2057  case CGOpCode::Sin:
2058  case CGOpCode::Sqrt:
2059  case CGOpCode::Tanh:
2060  case CGOpCode::Tan:
2061 #if CPPAD_USE_CPLUSPLUS_2011
2062  case CGOpCode::Erf:
2063  case CGOpCode::Asinh:
2064  case CGOpCode::Acosh:
2065  case CGOpCode::Atanh:
2066  case CGOpCode::Expm1:
2067  case CGOpCode::Log1p:
2068 #endif
2069  return true;
2070  default:
2071  return false;
2072  }
2073  }
2074 
2075  inline static bool isCondAssign(enum CGOpCode op) {
2076  switch (op) {
2077  case CGOpCode::ComLt:
2078  case CGOpCode::ComLe:
2079  case CGOpCode::ComEq:
2080  case CGOpCode::ComGe:
2081  case CGOpCode::ComGt:
2082  case CGOpCode::ComNe:
2083  return true;
2084  default:
2085  return false;
2086  }
2087  }
2088 private:
2089 
2090  class AtomicFuncArray {
2091  public:
2092  std::string data;
2093  unsigned long size;
2094  bool sparse;
2095  size_t idx_id;
2096  unsigned long nnz;
2097  unsigned short scope;
2098  };
2099 };
2100 template<class Base>
2101 const std::string LanguageC<Base>::U_INDEX_TYPE = "unsigned long";
2102 
2103 template<class Base>
2104 const std::string LanguageC<Base>::_C_COMP_OP_LT = "<";
2105 template<class Base>
2106 const std::string LanguageC<Base>::_C_COMP_OP_LE = "<=";
2107 template<class Base>
2108 const std::string LanguageC<Base>::_C_COMP_OP_EQ = "==";
2109 template<class Base>
2110 const std::string LanguageC<Base>::_C_COMP_OP_GE = ">=";
2111 template<class Base>
2112 const std::string LanguageC<Base>::_C_COMP_OP_GT = ">";
2113 template<class Base>
2114 const std::string LanguageC<Base>::_C_COMP_OP_NE = "!=";
2115 
2116 template<class Base>
2117 const std::string LanguageC<Base>::_C_STATIC_INDEX_ARRAY = "index";
2118 
2119 template<class Base>
2120 const std::string LanguageC<Base>::_C_SPARSE_INDEX_ARRAY = "idx";
2121 
2122 template<class Base>
2123 const std::string LanguageC<Base>::_ATOMIC_TX = "atx";
2124 
2125 template<class Base>
2126 const std::string LanguageC<Base>::_ATOMIC_TY = "aty";
2127 
2128 template<class Base>
2129 const std::string LanguageC<Base>::_ATOMIC_PX = "apx";
2130 
2131 template<class Base>
2132 const std::string LanguageC<Base>::_ATOMIC_PY = "apy";
2133 
2134 template<class Base>
2136 "typedef struct Array {\n"
2137 " void* data;\n"
2138 " " + U_INDEX_TYPE + " size;\n"
2139 " int sparse;\n"
2140 " const " + U_INDEX_TYPE + "* idx;\n"
2141 " " + U_INDEX_TYPE + " nnz;\n"
2142 "} Array;\n"
2143 "\n"
2144 "struct LangCAtomicFun {\n"
2145 " void* libModel;\n"
2146 " int (*forward)(void* libModel,\n"
2147 " int atomicIndex,\n"
2148 " int q,\n"
2149 " int p,\n"
2150 " const Array tx[],\n"
2151 " Array* ty);\n"
2152 " int (*reverse)(void* libModel,\n"
2153 " int atomicIndex,\n"
2154 " int p,\n"
2155 " const Array tx[],\n"
2156 " Array* px,\n"
2157 " const Array py[]);\n"
2158 "};";
2159 
2160 } // END cg namespace
2161 } // END CppAD namespace
2162 
2163 #endif
virtual void printElseIf(Node &node)
LanguageC(const std::string &varTypeName, size_t spaces=3)
Definition: language_c.hpp:125
virtual bool directlyAssignsVariable(const Node &var) const
const std::string * getName() const
const std::vector< Argument< Base > > & getArguments() const
bool createsNewVariable(const Node &var, size_t totalUseCount) const override
virtual void printAtomicForwardOp(Node &atomicFor)
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
cg::CG< Base > pow(const cg::CG< Base > &x, const cg::CG< Base > &y)
Definition: math_other.hpp:21
virtual size_t getParameterPrecision() const
Definition: language_c.hpp:209
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
CGOpCode getOperationType() const
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg *> &tmpArrayValues)
virtual void printElse(Node &node)
bool requiresVariableDependencies() const override
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:219
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node *> &variableOrder, size_t starti)
virtual void printStartIf(Node &node)
void setName(const std::string &name)
virtual void printAtomicReverseOp(Node &atomicRev)
void generateSourceCode(std::ostream &out, const std::unique_ptr< LanguageGenerationData< Base > > &info) override
Definition: language_c.hpp:614
size_t size() const noexcept
Definition: array_view.hpp:202
virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction=false, bool zeroArrayDependents=false, int maxForwardOrder=-1, int maxReverseOrder=-1)
Definition: language_c.hpp:260
const std::vector< size_t > & getInfo() const