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