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