CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
language_dot.hpp
1 #ifndef CPPAD_CG_LANGUAGE_DOT_INCLUDED
2 #define CPPAD_CG_LANGUAGE_DOT_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2016 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 namespace CppAD {
19 namespace cg {
20 
26 template<class Base>
27 class LanguageDot : public Language<Base> {
28 protected:
29  static const std::string _C_STATIC_INDEX_ARRAY;
30  static const std::string _C_SPARSE_INDEX_ARRAY;
31 protected:
32  // information from the code handler (not owned)
34  // new line characters
35  std::string _endline;
36  // output stream for the generated source code
37  std::ostringstream _code;
38  // creates the variable names
40  // auxiliary string stream
41  std::ostringstream _ss;
42  //
43  size_t _independentSize;
44  //
45  size_t _minTemporaryVarID;
46  // maps the variable IDs to the their position in the dependent vector
47  // (some IDs may be the same as the independent variables when dep = indep)
48  std::map<size_t, size_t> _dependentIDs;
49  // the dependent variable vector
50  const ArrayView<CG<Base> >* _dependent;
51  // whether or not to ignore assignment of constant zero values to dependent variables
52  bool _ignoreZeroDepAssign;
53  // the name of the file to be created without the extension
54  std::string _filename;
55  //
56  std::vector<const LoopStartOperationNode <Base>*> _currentLoops;
57  // the maximum precision used to print values
58  size_t _parameterPrecision;
59  //
60  bool _combineParameterNodes;
61  //
62  std::string _indepNodeStyle;
63  //
64  std::string _depNodeStyle;
65 private:
66  std::vector<int> varIds_;
67  size_t parIdx_;
68 public:
69 
74  _info(nullptr),
75  _endline("\n"),
76  _nameGen(nullptr),
77  _independentSize(0), // not really required (but it avoids warnings)
78  _minTemporaryVarID(0), // not really required (but it avoids warnings)
79  _dependent(nullptr),
80  _ignoreZeroDepAssign(false),
81  _filename("algorithm"),
82  _parameterPrecision(std::numeric_limits<Base>::digits10),
83  _combineParameterNodes(true),
84  parIdx_(0) { // not really required (but it avoids warnings)
85  }
86 
87  inline virtual ~LanguageDot() {
88  }
89 
90  inline bool isIgnoreZeroDepAssign() const {
91  return _ignoreZeroDepAssign;
92  }
93 
94  inline void setIgnoreZeroDepAssign(bool ignore) {
95  _ignoreZeroDepAssign = ignore;
96  }
97 
98  inline void setFilename(const std::string& name) {
99  _filename = name;
100  }
101 
108  virtual size_t getParameterPrecision() const {
109  return _parameterPrecision;
110  }
111 
118  virtual void setParameterPrecision(size_t p) {
119  _parameterPrecision = p;
120  }
121 
125  inline void setIndepNodeStyle(const std::string& indepNodeStyle) {
126  _indepNodeStyle = indepNodeStyle;
127  }
128 
132  inline const std::string& getIndepNodeStyle() const {
133  return _indepNodeStyle;
134  }
135 
139  inline void setDepNodeStyle(const std::string& depNodeStyle) {
140  _depNodeStyle = depNodeStyle;
141  }
142 
146  inline const std::string& getDepNodeStyle() const {
147  return _depNodeStyle;
148  }
149 
153  inline void setCombineParameterNodes(bool combineParameterNodes) {
154  _combineParameterNodes = combineParameterNodes;
155  }
156 
160  inline bool isCombineParameterNodes() const {
161  return _combineParameterNodes;
162  }
163 
164  /***************************************************************************
165  * STATIC
166  **************************************************************************/
167  static inline void printIndexCondExpr(std::ostringstream& out,
168  const std::vector<size_t>& info,
169  const std::string& index) {
170  CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0, "Invalid number of information elements for an index condition expression operation");
171 
172  size_t infoSize = info.size();
173  for (size_t e = 0; e < infoSize; e += 2) {
174  if (e > 0) {
175  out << " or "; // or
176  }
177  size_t min = info[e];
178  size_t max = info[e + 1];
179  if (min == max) {
180  out << index << "==" << min;
181  } else if (min == 0) {
182  out << index << "≤" << max;
183  } else if (max == std::numeric_limits<size_t>::max()) {
184  out << min << "≤" << index;
185  } else {
186  if (infoSize != 2)
187  out << "(";
188 
189  if (max - min == 1)
190  out << min << "==" << index << " or " << index << "==" << max;
191  else
192  out << min << "≤" << index << " and " << index << "≤" << max;
193 
194  if (infoSize != 2)
195  out << ")";
196  }
197  }
198  }
199 
200  /***************************************************************************
201  *
202  **************************************************************************/
203 
204  inline void printStaticIndexArray(std::ostringstream& os,
205  const std::string& name,
206  const std::vector<size_t>& values);
207 
208  inline void printStaticIndexMatrix(std::ostringstream& os,
209  const std::string& name,
210  const std::map<size_t, std::map<size_t, size_t> >& values);
211 
212  /***************************************************************************
213  * index patterns
214  **************************************************************************/
215  static inline void generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns);
216 
217  inline void printRandomIndexPatternDeclaration(std::ostringstream& os,
218  const std::set<RandomIndexPattern*>& randomPatterns);
219 
220  static void indexPattern2String(std::ostream& os,
221  const IndexPattern& ip,
222  const OperationNode<Base>& index);
223 
224  static void indexPattern2String(std::ostream& os,
225  const IndexPattern& ip,
226  const std::vector<const OperationNode<Base>*>& indexes);
227 
228  static inline void linearIndexPattern2String(std::ostream& os,
229  const LinearIndexPattern& lip,
230  const OperationNode<Base>& index);
231 
232  /***************************************************************************
233  * protected
234  **************************************************************************/
235 protected:
236 
237  virtual void generateSourceCode(std::ostream& out,
238  const std::unique_ptr<LanguageGenerationData<Base> >& info) override {
239  // clean up
240  _code.str("");
241  _ss.str("");
242  _currentLoops.clear();
243  parIdx_ = 0;
244 
245  // save some info
246  _info = info.get();
247  _independentSize = info->independent.size();
248  _dependent = &info->dependent;
249  _nameGen = &info->nameGen;
250  _minTemporaryVarID = info->minTemporaryVarID;
251  const ArrayView<CG<Base> >& dependent = info->dependent;
252  const std::vector<OperationNode<Base>*>& variableOrder = info->variableOrder;
253 
254  varIds_.resize(_minTemporaryVarID + variableOrder.size());
255  std::fill(varIds_.begin(), varIds_.end(), 0);
256 
257  _code << "digraph {" << _endline << _endline;
258 
262  generateNames4RandomIndexPatterns(info->indexRandomPatterns);
263 
267  //generate names for the independent variables
268  _code << "subgraph indep {" << _endline;
269  _code << " rank=min" << _endline;
270  if(!_indepNodeStyle.empty()) {
271  _code << "node [" << _indepNodeStyle << "]" << _endline;
272  }
273  for (size_t j = 0; j < _independentSize; j++) {
274  OperationNode<Base>& op = *info->independent[j];
275 
276  _code << " v" << op.getHandlerPosition() << " [label=\"";
277  if (op.getName() == nullptr) {
278  _code << _nameGen->generateIndependent(op, getVariableID(op));
279  } else {
280  _code << *op.getName();
281  }
282  _code << "\"]" << _endline;
283 
284  }
285  _code << "}" << _endline;
286 
287  // generate names for the dependent variables (must be after naming independents)
288  _code << "subgraph dep {" << _endline;
289  _code << " rank=max" << _endline;
290  if(!_depNodeStyle.empty()) {
291  _code << "node [" << _depNodeStyle << "]" << _endline;
292  }
293  for (size_t i = 0; i < dependent.size(); i++) {
294 
295  OperationNode<Base>* node = dependent[i].getOperationNode();
296  if (node != nullptr && node->getOperationType() != CGOpCode::LoopEnd) {
297  _code << " y" << i << " [label=\"";
298  if(node->getName() == nullptr) {
299  if (node->getOperationType() == CGOpCode::LoopIndexedDep) {
300  size_t pos = node->getInfo()[0];
301  const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
302  _code << _nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip);
303 
304  } else {
305  _code << _nameGen->generateDependent(i);
306  }
307  } else {
308  _code << *node->getName();
309  }
310  _code << "\"]" << _endline;
311  }
312  }
313  _code << "}" << _endline;
314 
315 
319  printRandomIndexPatternDeclaration(_ss, _info->indexRandomPatterns);
320 
324  const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
325  const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
326  const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
327  CPPADCG_ASSERT_KNOWN(indArg.size() > 0 && depArg.size() > 0,
328  "There must be at least one dependent and one independent argument");
329  CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
330  "There must be three temporary variables");
331 
335  // dependent variables indexes that are copies of other dependent variables
336  std::set<size_t> dependentDuplicates;
337 
338  for (size_t i = 0; i < dependent.size(); i++) {
339  OperationNode<Base>* node = dependent[i].getOperationNode();
340  if (node != nullptr) {
341  CGOpCode type = node->getOperationType();
342  if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
343  size_t varID = getVariableID(*node);
344  if (varID > 0) {
345  std::map<size_t, size_t>::const_iterator it2 = _dependentIDs.find(varID);
346  if (it2 == _dependentIDs.end()) {
347  _dependentIDs[getVariableID(*node)] = i;
348  } else {
349  // there can be several dependent variables with the same ID
350  dependentDuplicates.insert(i);
351  }
352  }
353  }
354  }
355  }
356 
360  if (variableOrder.size() > 0) {
361  // generate names for temporary variables
362  for (OperationNode<Base>* node : variableOrder) {
363  CGOpCode op = node->getOperationType();
364  if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
365  // variable names for temporaries must always be created since they might have been used before with a different name/id
366  if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
367  node->setName(_nameGen->generateTemporary(*node, getVariableID(*node)));
368  } else if (op == CGOpCode::ArrayCreation) {
369  node->setName(_nameGen->generateTemporaryArray(*node, getVariableID(*node)));
370  } else if (op == CGOpCode::SparseArrayCreation) {
371  node->setName(_nameGen->generateTemporarySparseArray(*node, getVariableID(*node)));
372  }
373  }
374  }
375 
379  for (OperationNode<Base>* it : variableOrder) {
380  // check if a new function should start
381  OperationNode<Base>& node = *it;
382 
383  // a dependent variable assigned by a loop does require any source code (its done inside the loop)
384  if (node.getOperationType() == CGOpCode::DependentRefRhs) {
385  continue; // nothing to do (this operation is right hand side only)
386  } else if (node.getOperationType() == CGOpCode::TmpDcl) { // temporary variable declaration does not need any source code here
387  continue; // nothing to do (bogus operation)
388  }
389 
390  printExpressionNoVarCheck(node);
391  }
392 
393  }
394 
395  // dependent duplicates
396  if (dependentDuplicates.size() > 0) {
397  _code << "// variable duplicates: " << dependentDuplicates.size() << _endline;
398 
399  for (size_t index : dependentDuplicates) {
400  const CG<Base>& dep = dependent[index];
401  OperationNode<Base>* depNode = dep.getOperationNode();
402 
403  _code << makeNodeName(*depNode);
404  _code << " -> y" << index;
405  _code << _endline;
406  }
407  }
408 
409  for (size_t i = 0; i < dependent.size(); i++) {
410  if (!dependent[i].isParameter() && dependent[i].getOperationNode()->getOperationType() != CGOpCode::Inv) {
411  _code << makeNodeName(*dependent[i].getOperationNode());
412  _code << " -> y" << i;
413  _code << _endline;
414  }
415  }
416 
417  // constant dependent variables
418  bool commentWritten = false;
419  for (size_t i = 0; i < dependent.size(); i++) {
420  if (dependent[i].isParameter()) {
421  if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
422  if (!commentWritten) {
423  _code << "// dependent variables without operations" << _endline;
424  commentWritten = true;
425  }
426 
427  _code << makeNodeName(dependent[i].getValue());
428  _code << " -> y" << i;
429  _code << _endline;
430  }
431  } else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
432  if (!commentWritten) {
433  _code << "// dependent variables without operations" << _endline;
434  commentWritten = true;
435  }
436 
437  _code << makeNodeName(*dependent[i].getOperationNode());
438  _code << " -> y" << i;
439  _code << _endline;
440  }
441  }
442 
443  _code << _endline << "}" << _endline; // digraph
444 
445  // a single source file
446  out << _code.str();
447  }
448 
449  inline size_t getVariableID(const OperationNode<Base>& node) const {
450  return _info->varId[node];
451  }
452 
453  virtual bool createsNewVariable(const OperationNode<Base>& var,
454  size_t totalUseCount) const override {
455  CGOpCode op = var.getOperationType();
456  if (totalUseCount > 1) {
457  return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
458  } else {
459  return (op == CGOpCode::ArrayCreation ||
460  op == CGOpCode::SparseArrayCreation ||
461  op == CGOpCode::AtomicForward ||
462  op == CGOpCode::AtomicReverse ||
463  op == CGOpCode::ComLt ||
464  op == CGOpCode::ComLe ||
465  op == CGOpCode::ComEq ||
466  op == CGOpCode::ComGe ||
467  op == CGOpCode::ComGt ||
468  op == CGOpCode::ComNe ||
469  op == CGOpCode::LoopIndexedDep ||
470  op == CGOpCode::LoopIndexedTmp ||
471  op == CGOpCode::IndexAssign ||
472  op == CGOpCode::Assign) &&
473  op != CGOpCode::CondResult;
474  }
475  }
476 
477  virtual bool requiresVariableName(const OperationNode<Base>& var) const {
478  CGOpCode op = var.getOperationType();
479  return (_info->totalUseCount.get(var) > 1 &&
480  op != CGOpCode::AtomicForward &&
481  op != CGOpCode::AtomicReverse &&
482  op != CGOpCode::LoopStart &&
483  op != CGOpCode::LoopEnd &&
484  op != CGOpCode::Index &&
485  op != CGOpCode::IndexAssign &&
486  op != CGOpCode::StartIf &&
487  op != CGOpCode::ElseIf &&
488  op != CGOpCode::Else &&
489  op != CGOpCode::EndIf &&
490  op != CGOpCode::CondResult &&
491  op != CGOpCode::LoopIndexedTmp &&
492  op != CGOpCode::Tmp);
493  }
494 
502  virtual bool directlyAssignsVariable(const OperationNode<Base>& var) const {
503  CGOpCode op = var.getOperationType();
504  return isCondAssign(op) ||
505  op == CGOpCode::ArrayCreation ||
506  op == CGOpCode::SparseArrayCreation ||
507  op == CGOpCode::AtomicForward ||
508  op == CGOpCode::AtomicReverse ||
509  op == CGOpCode::DependentMultiAssign ||
510  op == CGOpCode::LoopStart ||
511  op == CGOpCode::LoopEnd ||
512  op == CGOpCode::IndexAssign ||
513  op == CGOpCode::StartIf ||
514  op == CGOpCode::ElseIf ||
515  op == CGOpCode::Else ||
516  op == CGOpCode::EndIf ||
517  op == CGOpCode::CondResult ||
518  op == CGOpCode::IndexDeclaration;
519  }
520 
521  virtual bool requiresVariableArgument(enum CGOpCode op, size_t argIndex) const override {
522  return op == CGOpCode::CondResult;
523  }
524 
525  inline const std::string& createVariableName(OperationNode<Base>& var) {
526  CGOpCode op = var.getOperationType();
527  CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0);
528  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward);
529  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse);
530  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart);
531  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd);
532  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index);
533  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign);
534  CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration);
535 
536  if (var.getName() == nullptr) {
537  if (op == CGOpCode::ArrayCreation) {
538  var.setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
539 
540  } else if (op == CGOpCode::SparseArrayCreation) {
541  var.setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
542 
543  } else if (op == CGOpCode::LoopIndexedDep) {
544  size_t pos = var.getInfo()[0];
545  const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
546  var.setName(_nameGen->generateIndexedDependent(var, getVariableID(var), *ip));
547 
548  } else if (op == CGOpCode::LoopIndexedIndep) {
549  size_t pos = var.getInfo()[1];
550  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
551  var.setName(_nameGen->generateIndexedIndependent(var, getVariableID(var), *ip));
552 
553  } else if (getVariableID(var) <= _independentSize) {
554  // independent variable
555  var.setName(_nameGen->generateIndependent(var, getVariableID(var)));
556 
557  } else if (getVariableID(var) < _minTemporaryVarID) {
558  // dependent variable
559  std::map<size_t, size_t>::const_iterator it = _dependentIDs.find(getVariableID(var));
560  CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
561 
562  size_t index = it->second;
563  var.setName(_nameGen->generateDependent(index));
564 
565  } else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
566  CPPADCG_ASSERT_KNOWN(var.getArguments().size() >= 1, "Invalid number of arguments for loop indexed temporary operation");
567  OperationNode<Base>* tmpVar = var.getArguments()[0].getOperation();
568  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
569  return createVariableName(*tmpVar);
570 
571  } else {
572  // temporary variable
573  var.setName(_nameGen->generateTemporary(var, getVariableID(var)));
574  }
575  }
576 
577  return *var.getName();
578  }
579 
580  virtual bool requiresVariableDependencies() const override {
581  return false;
582  }
583 
584  virtual std::string print(const Argument<Base>& arg) {
585  if (arg.getOperation() != nullptr) {
586  // expression
587  return printExpression(*arg.getOperation());
588  } else {
589  // parameter
590  return printParameter(*arg.getParameter());
591  }
592  }
593 
594  virtual std::string printExpression(OperationNode<Base>& node) {
595  if (getVariableID(node) == 0) {
596  // print expression code
597  return printExpressionNoVarCheck(node);
598  } else {
599  return makeNodeName(node);
600  }
601  }
602 
603  virtual std::string printParameter(const Base& value) {
604  if(!_combineParameterNodes) {
605  std::string name = makeNodeName(value);
606 
607  _code << name;
608  _code << " [label=\"";
609  _code << std::setprecision(_parameterPrecision) << value;
610  _code << "\"]" << _endline;
611 
612  return name;
613  } else {
614  return makeNodeName(value);
615  }
616  }
617 
618  inline virtual std::string makeNodeName(const OperationNode<Base>& node) {
619  return "v" + std::to_string(node.getHandlerPosition());
620  }
621 
622  inline std::string makeNodeName(const Argument<Base>& arg) {
623  if (arg.getOperation() != nullptr) {
624  // expression
625  return makeNodeName(*arg.getOperation());
626  } else {
627  // parameter
628  return makeNodeName(*arg.getParameter());
629  }
630  }
631 
632  inline virtual std::string makeNodeName(const Base& value) {
633  if(_combineParameterNodes) {
634  // node name for parameters which have the same node for the same value
635  _ss.str("");
636  _ss << "\"" << std::setprecision(_parameterPrecision) << value << "\"";
637  return _ss.str();
638  } else {
639  std::string name = "p" + std::to_string(parIdx_);
640  parIdx_++;
641  return name;
642  }
643  }
644 
645  inline std::string printNodeDeclaration(const OperationNode<Base>& op,
646  const std::ostringstream& label,
647  const std::string& shape = "") {
648  return printNodeDeclaration(op, label.str(), shape);
649  }
650 
651  virtual std::string printNodeDeclaration(const OperationNode<Base>& op,
652  const std::string& label = "",
653  const std::string& shape = "") {
654  std::string name = makeNodeName(op);
655 
656  _code << name << " [label=\"";
657  if(!label.empty()) {
658  _code << label;
659  } else {
660  _code << op.getOperationType();
661  }
662  _code << "\"";
663  if (!shape.empty()) {
664  _code << ", shape=" << shape;
665  }
666  _code << "]" << _endline;
667 
668  return name;
669  }
670 
671  inline void printEdges(const std::string& name,
672  const OperationNode<Base>& node,
673  const std::string& style = "") {
674  const auto& args = node.getArguments();
675 
676  std::vector<std::string> aNames(args.size());
677  for (size_t i = 0; i < args.size(); ++i) {
678  aNames[i] = print(args[i]);
679  }
680 
681  for (size_t i = 0; i < args.size(); ++i) {
682  if (i > 0)
683  _code << " ";
684  printEdge(aNames[i], name, style);
685  }
686  _code << _endline;
687  }
688 
689  inline void printEdges(const std::string& name,
690  const OperationNode<Base>& node,
691  const std::vector<std::string>& args,
692  const std::string& style = "") {
693  size_t na = node.getArguments().size();
694  size_t nna = args.size();
695  CPPADCG_ASSERT_UNKNOWN(na >= nna);
696 
697  for (size_t i = 0; i < na; ++i) {
698  if (i > 0)
699  _code << " ";
700  if(i < nna && !args[i].empty()) {
701  printEdge(args[i], name, style);
702  } else {
703  std::string n = print(node.getArguments()[i]);
704  printEdge(n, name, style);
705  }
706  }
707  _code << _endline;
708  }
709 
710  inline void printEdges(const std::string& name,
711  const OperationNode<Base>& node,
712  const std::vector<std::string>& args,
713  const std::vector<std::string>& styles) {
714  size_t na = node.getArguments().size();
715  size_t nna = args.size();
716  size_t ns = styles.size();
717  CPPADCG_ASSERT_UNKNOWN(na >= nna);
718  CPPADCG_ASSERT_UNKNOWN(na >= ns);
719 
720  std::string style;
721  for (size_t i = 0; i < args.size(); ++i) {
722  if (i > 0)
723  _code << " ";
724 
725  style = i < ns ? styles[i] : "";
726  if(i < nna && !args[i].empty()) {
727  printEdge(args[i], name, style);
728  } else {
729  std::string n = print(node.getArguments()[i]);
730  printEdge(n, name, style);
731  }
732  }
733  _code << _endline;
734  }
735 
736  inline void printEdge(const OperationNode<Base>& from,
737  const std::string& to,
738  const std::string& style = "") {
739  _code << makeNodeName(from);
740  _code << " -> " << to;
741  if (!style.empty())
742  _code << "[" << style << "]";
743  }
744 
745  inline void printEdge(const std::string& from,
746  const std::string& to,
747  const std::string& style = "") {
748  _code << from << " -> " << to;
749  if (!style.empty())
750  _code << "[" << style << "]";
751  }
752 
753  virtual std::string printExpressionNoVarCheck(OperationNode<Base>& node) {
754  CGOpCode op = node.getOperationType();
755  switch (op) {
756  case CGOpCode::ArrayCreation:
757  return printArrayCreationOp(node);
758  case CGOpCode::SparseArrayCreation:
759  return printSparseArrayCreationOp(node);
760  case CGOpCode::ArrayElement:
761  return printArrayElementOp(node);
762  case CGOpCode::Assign:
763  return printAssignOp(node);
764 
765  case CGOpCode::Abs:
766  case CGOpCode::Acos:
767  case CGOpCode::Asin:
768  case CGOpCode::Atan:
769  case CGOpCode::Cosh:
770  case CGOpCode::Cos:
771  case CGOpCode::Exp:
772  case CGOpCode::Log:
773  case CGOpCode::Sign:
774  case CGOpCode::Sinh:
775  case CGOpCode::Sin:
776  case CGOpCode::Sqrt:
777  case CGOpCode::Tanh:
778  case CGOpCode::Tan:
779  return printUnaryFunction(node);
780  case CGOpCode::AtomicForward: // atomicFunction.forward(q, p, vx, vy, tx, ty)
781  return printAtomicForwardOp(node);
782  case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
783  return printAtomicReverseOp(node);
784  case CGOpCode::Add:
785  return printOperationAdd(node);
786  case CGOpCode::Alias:
787  return printOperationAlias(node);
788  case CGOpCode::ComLt:
789  case CGOpCode::ComLe:
790  case CGOpCode::ComEq:
791  case CGOpCode::ComGe:
792  case CGOpCode::ComGt:
793  case CGOpCode::ComNe:
794  return printConditionalAssignment(node);
795  case CGOpCode::Div:
796  return printOperationDiv(node);
797  case CGOpCode::Inv:
798  // do nothing
799  return makeNodeName(node);
800  case CGOpCode::Mul:
801  return printOperationMul(node);
802  case CGOpCode::Pow:
803  return printPowFunction(node);
804  case CGOpCode::Pri:
805  // do nothing
806  return makeNodeName(node);
807  case CGOpCode::Sub:
808  return printOperationMinus(node);
809 
810  case CGOpCode::UnMinus:
811  return printOperationUnaryMinus(node);
812 
813  case CGOpCode::DependentMultiAssign:
814  return printDependentMultiAssign(node);
815 
816  case CGOpCode::Index:
817  return makeNodeName(node); // nothing to do
818 
819  case CGOpCode::IndexAssign:
820  return printIndexAssign(node);
821  case CGOpCode::IndexDeclaration:
822  return makeNodeName(node); // already done
823 
824  case CGOpCode::LoopStart:
825  return printLoopStart(node);
826  case CGOpCode::LoopIndexedIndep:
827  return printLoopIndexedIndep(node);
828  case CGOpCode::LoopIndexedDep:
829  return printLoopIndexedDep(node);
830  case CGOpCode::LoopIndexedTmp:
831  return printLoopIndexedTmp(node);
832  case CGOpCode::TmpDcl:
833  // nothing to do
834  return makeNodeName(node);
835  case CGOpCode::Tmp:
836  return printTmpVar(node);
837  case CGOpCode::LoopEnd:
838  return printLoopEnd(node);
839  case CGOpCode::IndexCondExpr:
840  return printIndexCondExprOp(node);
841  case CGOpCode::StartIf:
842  return printStartIf(node);
843  case CGOpCode::ElseIf:
844  return printElseIf(node);
845  case CGOpCode::Else:
846  return printElse(node);
847  case CGOpCode::EndIf:
848  return printEndIf(node);
849  case CGOpCode::CondResult:
850  return printCondResult(node);
851  default:
852  throw CGException("Unknown operation code '", op, "'.");
853  }
854  }
855 
856  virtual std::string printAssignOp(OperationNode<Base>& node) {
857  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for assign operation");
858 
859  return print(node.getArguments()[0]);
860  }
861 
862  virtual std::string printPowFunction(OperationNode<Base>& op) {
863  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for pow() function");
864 
865  std::string a0 = print(op.getArguments()[0]);
866  std::string a1 = print(op.getArguments()[1]);
867 
868  std::string name = printNodeDeclaration(op);
869 
870  printEdges(name, op, std::vector<std::string>{a0, a1}, std::vector<std::string>{"label=\"$1\"", "label=\"$2\""});
871 
872  return name;
873  }
874 
875  virtual std::string printUnaryFunction(OperationNode<Base>& op) {
876  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for an unary function");
877 
878  std::string a0 = print(op.getArguments()[0]);
879 
880  // TODO: improve this
881  _ss.str("");
882  _ss << op.getOperationType();
883  std::string label = _ss.str();
884  auto it = label.find('(');
885  if (it != std::string::npos) {
886  label = label.substr(0, it);
887  }
888  std::string name = printNodeDeclaration(op, label);
889 
890  printEdges(name, op, std::vector<std::string> {a0});
891 
892  return name;
893  }
894 
895  virtual std::string printOperationAlias(OperationNode<Base>& op) {
896  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for alias");
897 
898  std::string a0 = print(op.getArguments()[0]);
899 
900  std::string name = printNodeDeclaration(op);
901 
902  printEdges(name, op, std::vector<std::string> {a0});
903 
904  return name;
905  }
906 
907  virtual std::string printOperationAdd(OperationNode<Base>& op) {
908  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for addition");
909 
910  const Argument<Base>& left = op.getArguments()[0];
911  const Argument<Base>& right = op.getArguments()[1];
912 
913  std::string a0 = print(left);
914  std::string a1 = print(right);
915 
916  std::string name = printNodeDeclaration(op, "+");
917 
918  printEdges(name, op, std::vector<std::string> {a0, a1});
919 
920  return name;
921  }
922 
923  virtual std::string printOperationMinus(OperationNode<Base>& op) {
924  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for subtraction");
925 
926  const Argument<Base>& left = op.getArguments()[0];
927  const Argument<Base>& right = op.getArguments()[1];
928 
929  std::string a0 = print(left);
930  std::string a1 = print(right);
931 
932  std::string name = printNodeDeclaration(op);
933 
934  printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{"label=\"$1\"", "label=\"$2\""});
935 
936  return name;
937  }
938 
939  virtual std::string printOperationDiv(OperationNode<Base>& op) {
940  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for division");
941 
942  const Argument<Base>& left = op.getArguments()[0];
943  const Argument<Base>& right = op.getArguments()[1];
944 
945  std::string a0 = print(left);
946  std::string a1 = print(right);
947 
948  std::string name = printNodeDeclaration(op);
949 
950  printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{"label=\"$1\"", "label=\"$2\""});
951 
952  return name;
953  }
954 
955  virtual std::string printOperationMul(OperationNode<Base>& op) {
956  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for multiplication");
957 
958  const Argument<Base>& left = op.getArguments()[0];
959  const Argument<Base>& right = op.getArguments()[1];
960 
961  std::string a0 = print(left);
962  std::string a1 = print(right);
963 
964  std::string name = printNodeDeclaration(op, "×");
965 
966  printEdges(name, op, std::vector<std::string> {a0, a1});
967 
968  return name;
969  }
970 
971  virtual std::string printOperationUnaryMinus(OperationNode<Base>& op) {
972  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary minus");
973 
974  const Argument<Base>& arg = op.getArguments()[0];
975 
976  std::string a0 = print(arg);
977 
978  std::string name = printNodeDeclaration(op);
979 
980  printEdges(name, op, std::vector<std::string> {a0});
981 
982  return name;
983  }
984 
985  virtual std::string printConditionalAssignment(OperationNode<Base>& node) {
986  CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
987 
988  const std::vector<Argument<Base> >& args = node.getArguments();
989  const Argument<Base>& left = args[0];
990  const Argument<Base>& right = args[1];
991  const Argument<Base>& trueCase = args[2];
992  const Argument<Base>& falseCase = args[3];
993 
994  std::string a0 = print(left);
995  std::string a1 = print(right);
996  std::string a2 = print(trueCase);
997  std::string a3 = print(falseCase);
998 
999  std::string name = printNodeDeclaration(node, "", "diamond");
1000 
1004  printEdges(name, node, std::vector<std::string> {a0, a1, a2, a3},
1005  std::vector<std::string>{"label=\"left\"", "label=\"right\"", "label=\"true\"", "label=\"false\""});
1006 
1007  return name;
1008  }
1009 
1010  virtual std::string printArrayCreationOp(OperationNode<Base>& op);
1011 
1012  virtual std::string printSparseArrayCreationOp(OperationNode<Base>& op);
1013 
1014  inline size_t printArrayCreationUsingLoop(const std::string arrayName,
1015  const OperationNode<Base>& array,
1016  size_t startj,
1017  const size_t* indexes);
1018 
1019  virtual std::string printArrayElementOp(OperationNode<Base>& op);
1020 
1021  virtual std::string printAtomicForwardOp(OperationNode<Base>& atomicFor) {
1022  CPPADCG_ASSERT_KNOWN(atomicFor.getInfo().size() == 3, "Invalid number of information elements for atomic forward operation");
1023  int q = atomicFor.getInfo()[1];
1024  int p = atomicFor.getInfo()[2];
1025  size_t p1 = p + 1;
1026  const std::vector<Argument<Base> >& opArgs = atomicFor.getArguments();
1027  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments for atomic forward operation");
1028 
1029  size_t id = atomicFor.getInfo()[0];
1030 
1031  std::string name = printNodeDeclaration(atomicFor, _info->atomicFunctionId2Name.at(id) + ".forward(" + std::to_string(q) + ", " + std::to_string(p) + ", tx, ty)");
1032 
1036  std::vector<std::string> args(opArgs.size()); // argument node names
1037 
1038  std::vector<OperationNode<Base>*> tx(p1), ty(p1);
1039  for (size_t k = 0; k < p1; k++) {
1040  tx[k] = opArgs[0 * p1 + k].getOperation();
1041  ty[k] = opArgs[1 * p1 + k].getOperation();
1042 
1043  args[0 * p1 + k] = print(*tx[k]);
1044  args[1 * p1 + k] = print(*ty[k]);
1045  }
1046 
1047  for (size_t k = 0; k < p1; k++) {
1048  printEdge(args[0 * p1 + k], name, "label=\"tx" + std::to_string(k) + "\"");
1049  _code << " ";
1050 
1051  printEdge(args[1 * p1 + k], name, "label=\"ty" + std::to_string(k) + "\"");
1052  _code << " ";
1053  }
1054  _code << _endline;
1055 
1056  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1057  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1058  CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1059 
1060  return name;
1061  }
1062 
1063  virtual std::string printAtomicReverseOp(OperationNode<Base>& atomicRev) {
1064  CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements for atomic reverse operation");
1065  int p = atomicRev.getInfo()[1];
1066  size_t p1 = p + 1;
1067  const std::vector<Argument<Base> >& opArgs = atomicRev.getArguments();
1068  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4, "Invalid number of arguments for atomic reverse operation");
1069 
1070  size_t id = atomicRev.getInfo()[0];
1071 
1072  std::string name = printNodeDeclaration(atomicRev, _info->atomicFunctionId2Name.at(id) + ".reverse(" + std::to_string(p) + ", tx, px, py)");
1073 
1077  std::vector<std::string> args(opArgs.size()); // argument node names
1078 
1079  std::vector<OperationNode<Base>*> tx(p1), px(p1), py(p1);
1080  for (size_t k = 0; k < p1; k++) {
1081  tx[k] = opArgs[0 * p1 + k].getOperation();
1082  px[k] = opArgs[2 * p1 + k].getOperation();
1083  py[k] = opArgs[3 * p1 + k].getOperation();
1084 
1085  args[0 * p1 + k] = print(*tx[k]);
1086  args[1 * p1 + k] = print(opArgs[1 * p1 + k]); // todo: consider not showing this
1087  args[2 * p1 + k] = print(*px[k]);
1088  args[3 * p1 + k] = print(*py[k]);
1089  }
1090 
1091  for (size_t k = 0; k < p1; k++) {
1092  printEdge(args[0 * p1 + k], name, "label=\"tx" + std::to_string(k) + "\"");
1093  _code << " ";
1094 
1095  printEdge(args[1 * p1 + k], name, "label=\"ty" + std::to_string(k) + "\"");
1096  _code << " ";
1097 
1098  printEdge(args[2 * p1 + k], name, "label=\"px" + std::to_string(k) + "\"");
1099  _code << " ";
1100 
1101  printEdge(args[3 * p1 + k], name, "label=\"py" + std::to_string(k) + "\"");
1102  _code << " ";
1103  }
1104  _code << _endline;
1105 
1106  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1107  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1108 
1109  CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1110 
1111  CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1112  CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1113 
1114  return name;
1115  }
1116 
1117  virtual std::string printDependentMultiAssign(OperationNode<Base>& node) {
1118  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign, "Invalid node type");
1119  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments");
1120 
1121  std::string name = printNodeDeclaration(node, "+=");
1122 
1123  const std::vector<Argument<Base> >& args = node.getArguments();
1124  for (size_t a = 0; a < args.size(); a++) {
1125  bool useArg = false;
1126  const Argument<Base>& arg = args[a];
1127  std::string aName = print(arg);
1128 
1129  if (arg.getParameter() != nullptr) {
1130  useArg = true;
1131  } else {
1132  CGOpCode op = arg.getOperation()->getOperationType();
1133  useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1134  }
1135 
1136  if (useArg) {
1137  printEdge(aName, name, "label=\"+=\"");
1138  _code << _endline;
1139  break;
1140  } else {
1141  printEdge(aName, name, "color=grey");
1142  _code << _endline;
1143  }
1144  }
1145 
1146  return name;
1147  }
1148 
1149  virtual std::string printLoopStart(OperationNode<Base>& node) {
1150  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node type");
1151 
1152  LoopStartOperationNode<Base>& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1153  _currentLoops.push_back(&lnode);
1154 
1158  const std::string& jj = *lnode.getIndex().getName();
1159 
1160  _ss.str("");
1161  if (lnode.getIterationCountNode() != nullptr) {
1162  _ss << "for " << jj << " ∈ [0, " << lnode.getIterationCountNode()->getIndex().getName() << "-1]";
1163  } else {
1164  _ss << "for " << jj << " ∈ [0, " << (lnode.getIterationCount() - 1) << "]";
1165  }
1166  std::string name = printNodeDeclaration(node, _ss, "parallelogram");
1167 
1171  if (lnode.getIterationCountNode() != nullptr) {
1172  // is label ready necessary?
1173  printEdge(*lnode.getIterationCountNode(), name, "label=\"" + (*lnode.getIterationCountNode()->getIndex().getName()) + "\"");
1174  _code << _endline;
1175  }
1176 
1177  printEdge(lnode.getIndex(), name, "label=\"index " + jj + "\"");
1178  _code << _endline;
1179 
1180  return name;
1181  }
1182 
1183  virtual std::string printLoopEnd(OperationNode<Base>& node) {
1184  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node type");
1185 
1186  std::string name = printNodeDeclaration(node);
1187 
1188  printEdges(name, node, "color=grey");
1189 
1190  _currentLoops.pop_back();
1191 
1192  return name;
1193  }
1194 
1195  virtual std::string printLoopIndexedDep(OperationNode<Base>& node) {
1196  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for loop indexed dependent operation");
1197 
1198  std::string name = printNodeDeclaration(node);
1199 
1200  // LoopIndexedDep
1201  printEdges(name, node);
1202 
1203  return name;
1204  }
1205 
1206  virtual std::string printLoopIndexedIndep(OperationNode<Base>& node) {
1207  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type");
1208  CPPADCG_ASSERT_KNOWN(node.getInfo().size() == 1, "Invalid number of information elements for loop indexed independent operation");
1209 
1210  size_t pos = node.getInfo()[1];
1211  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1212  _ss << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1213 
1214  std::string name = printNodeDeclaration(node, _ss);
1215 
1216  printEdges(name, node);
1217 
1218  return name;
1219  }
1220 
1221  virtual std::string printLoopIndexedTmp(OperationNode<Base>& node) {
1222  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp, "Invalid node type");
1223  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for loop indexed temporary operation");
1224  OperationNode<Base>* tmpVar = node.getArguments()[0].getOperation();
1225  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1226 
1227  std::string name = printNodeDeclaration(node);
1228 
1229  printEdges(name, node);
1230 
1231  return name;
1232  }
1233 
1234  virtual std::string printTmpVar(OperationNode<Base>& node) {
1235  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp, "Invalid node type");
1236  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for temporary variable usage operation");
1237 #ifndef NDEBUG
1238  OperationNode<Base>* tmpVar = node.getArguments()[0].getOperation();
1239  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1240 #endif
1241  // do nothing
1242 
1243  return makeNodeName(node);
1244  }
1245 
1246  virtual std::string printIndexAssign(OperationNode<Base>& node) {
1247  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node type");
1248  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for an index assignment operation");
1249 
1250  IndexAssignOperationNode<Base>& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1251 
1252  const IndexPattern& ip = inode.getIndexPattern();
1253  _ss.str("");
1254  _ss << (*inode.getIndex().getName()) << " = ";
1255  indexPattern2String(_ss, ip, inode.getIndexPatternIndexes());
1256 
1257  std::string name = printNodeDeclaration(node, _ss);
1258 
1262  for (const auto* idx: inode.getIndexPatternIndexes()) {
1263  printEdge(*idx, name);
1264  _code << " ";
1265  }
1266  _code << _endline;
1267 
1268  return name;
1269  }
1270 
1271  virtual std::string printIndexCondExprOp(OperationNode<Base>& node) {
1272  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr, "Invalid node type");
1273  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for an index condition expression operation");
1274  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an index condition expression operation");
1275  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument for an index condition expression operation");
1276 
1277  const std::vector<size_t>& info = node.getInfo();
1278 
1279  IndexOperationNode<Base>& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1280  const std::string& index = *iterationIndexOp.getIndex().getName();
1281 
1282  _ss.str("");
1283  printIndexCondExpr(_ss, info, index);
1284 
1285  std::string name = printNodeDeclaration(node, _ss);
1286 
1287  return name;
1288  }
1289 
1290  virtual std::string printStartIf(OperationNode<Base>& node) {
1295  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf, "Invalid node type");
1296  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'if start' operation");
1297  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'if start' operation");
1298 
1299  //printIndexCondExprOp(*node.getArguments()[0].getOperation());
1300  std::string name = printNodeDeclaration(node, "", "diamond");
1301 
1302  printEdges(name, node, std::vector<std::string>{},
1303  std::vector<std::string>{"label=\"condition\""});
1304 
1305  return name;
1306  }
1307 
1308  virtual std::string printElseIf(OperationNode<Base>& node) {
1314  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ElseIf, "Invalid node type");
1315  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 2, "Invalid number of arguments for an 'else if' operation");
1316  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1317  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1318 
1319  std::string name = printNodeDeclaration(node, "", "diamond");
1320 
1321  printEdges(name, node, std::vector<std::string>{},
1322  std::vector<std::string>{"label=\"false\"", "label=\"condition\""});
1323 
1324  return name;
1325  }
1326 
1327  virtual std::string printElse(OperationNode<Base>& node) {
1332  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Else, "Invalid node type");
1333  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'else' operation");
1334 
1335  std::string name = printNodeDeclaration(node, "", "diamond");
1336 
1337  printEdges(name, node, std::vector<std::string>{},
1338  std::vector<std::string>{"label=\"false\""});
1339 
1340  return name;
1341  }
1342 
1343  virtual std::string printEndIf(OperationNode<Base>& node) {
1344  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node type for an 'end if' operation");
1345 
1346  std::string name = printNodeDeclaration(node, "", "diamond");
1347 
1348  printEdges(name, node);
1349 
1350  return name;
1351  }
1352 
1353  virtual std::string printCondResult(OperationNode<Base>& node) {
1354  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult, "Invalid node type");
1355  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for an assignment inside an if/else operation");
1356  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
1357  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
1358 
1359  print(node.getArguments()[0]); // condition start (e.g if or else if)
1360  print(node.getArguments()[1]); // temporary result
1361 
1362  std::string name = printNodeDeclaration(node, "", "diamond");
1363 
1364  printEdges(name, node);
1365 
1366  return name;
1367  }
1368 
1369  inline bool isDependent(const OperationNode<Base>& arg) const {
1370  if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
1371  return true;
1372  }
1373  size_t id = getVariableID(arg);
1374  return id > _independentSize && id < _minTemporaryVarID;
1375  }
1376 
1377  virtual void getComparison(std::ostream& os, enum CGOpCode op) const {
1378  switch (op) {
1379  case CGOpCode::ComLt:
1380  os << "<";
1381  return;
1382 
1383  case CGOpCode::ComLe:
1384  os << "≤";
1385  return;
1386 
1387  case CGOpCode::ComEq:
1388  os << "==";
1389  return;
1390 
1391  case CGOpCode::ComGe:
1392  os << "≥";
1393  return;
1394 
1395  case CGOpCode::ComGt:
1396  os << ">";
1397  return;
1398 
1399  case CGOpCode::ComNe:
1400  os << "≠";
1401  return;
1402 
1403  default: CPPAD_ASSERT_UNKNOWN(0);
1404  }
1405  throw CGException("Invalid comparison operator code"); // should never get here
1406  }
1407 
1408  static bool isFunction(enum CGOpCode op) {
1409  return isUnaryFunction(op) || op == CGOpCode::Pow;
1410  }
1411 
1412  static bool isUnaryFunction(enum CGOpCode op) {
1413  switch (op) {
1414  case CGOpCode::Abs:
1415  case CGOpCode::Acos:
1416  case CGOpCode::Asin:
1417  case CGOpCode::Atan:
1418  case CGOpCode::Cosh:
1419  case CGOpCode::Cos:
1420  case CGOpCode::Exp:
1421  case CGOpCode::Log:
1422  case CGOpCode::Sign:
1423  case CGOpCode::Sinh:
1424  case CGOpCode::Sin:
1425  case CGOpCode::Sqrt:
1426  case CGOpCode::Tanh:
1427  case CGOpCode::Tan:
1428  return true;
1429  default:
1430  return false;
1431  }
1432  }
1433 
1434  static bool isCondAssign(enum CGOpCode op) {
1435  switch (op) {
1436  case CGOpCode::ComLt:
1437  case CGOpCode::ComLe:
1438  case CGOpCode::ComEq:
1439  case CGOpCode::ComGe:
1440  case CGOpCode::ComGt:
1441  case CGOpCode::ComNe:
1442  return true;
1443  default:
1444  return false;
1445  }
1446  }
1447 };
1448 
1449 template<class Base>
1450 const std::string LanguageDot<Base>::_C_STATIC_INDEX_ARRAY = "index";
1451 
1452 template<class Base>
1453 const std::string LanguageDot<Base>::_C_SPARSE_INDEX_ARRAY = "idx";
1454 
1455 } // END cg namespace
1456 } // END CppAD namespace
1457 
1458 #endif
const std::map< size_t, std::string > & atomicFunctionId2Name
Definition: language.hpp:68
virtual std::string printAtomicReverseOp(OperationNode< Base > &atomicRev)
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
virtual bool createsNewVariable(const OperationNode< Base > &var, size_t totalUseCount) const override
virtual std::string printElse(OperationNode< Base > &node)
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
const std::string & getIndepNodeStyle() const
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
const std::string * getName() const
const std::vector< Argument< Base > > & getArguments() const
virtual const std::vector< FuncArgument > & getTemporary() const
void setIndepNodeStyle(const std::string &indepNodeStyle)
STL namespace.
virtual std::string printConditionalAssignment(OperationNode< Base > &node)
size_t getHandlerPosition() const
virtual std::string printAtomicForwardOp(OperationNode< Base > &atomicFor)
const CodeHandlerVector< Base, size_t > & varId
Definition: language.hpp:48
virtual std::string printStartIf(OperationNode< Base > &node)
void setDepNodeStyle(const std::string &depNodeStyle)
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::set< RandomIndexPattern *> &randomPatterns)
virtual std::string generateDependent(size_t index)=0
const CodeHandlerVector< Base, size_t > & totalUseCount
Definition: language.hpp:94
CGOpCode getOperationType() const
virtual std::string printLoopStart(OperationNode< Base > &node)
size_t printArrayCreationUsingLoop(const std::string arrayName, const OperationNode< Base > &array, size_t startj, const size_t *indexes)
virtual void generateSourceCode(std::ostream &out, const std::unique_ptr< LanguageGenerationData< Base > > &info) override
virtual bool directlyAssignsVariable(const OperationNode< Base > &var) const
const std::string & getDepNodeStyle() const
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getDependent() const
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getIndependent() const
virtual std::string printIndexAssign(OperationNode< Base > &node)
virtual std::string printElseIf(OperationNode< Base > &node)
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
void setName(const std::string &name)
virtual size_t getParameterPrecision() const
virtual bool requiresVariableDependencies() const override
virtual void setParameterPrecision(size_t p)
size_t size() const noexcept
Definition: array_view.hpp:202
const std::vector< size_t > & getInfo() const