1 #ifndef CPPAD_CG_LANGUAGE_DOT_INCLUDED 2 #define CPPAD_CG_LANGUAGE_DOT_INCLUDED 29 static const std::string _C_STATIC_INDEX_ARRAY;
30 static const std::string _C_SPARSE_INDEX_ARRAY;
37 std::ostringstream _code;
41 std::ostringstream _ss;
43 size_t _independentSize;
45 size_t _minTemporaryVarID;
48 std::map<size_t, size_t> _dependentIDs;
52 bool _ignoreZeroDepAssign;
54 std::string _filename;
56 std::vector<const LoopStartOperationNode <Base>*> _currentLoops;
58 size_t _parameterPrecision;
60 bool _combineParameterNodes;
62 std::string _indepNodeStyle;
64 std::string _depNodeStyle;
66 std::vector<int> varIds_;
78 _minTemporaryVarID(0),
80 _ignoreZeroDepAssign(false),
81 _filename(
"algorithm"),
82 _parameterPrecision(
std::numeric_limits<Base>::digits10),
83 _combineParameterNodes(true),
90 inline bool isIgnoreZeroDepAssign()
const {
91 return _ignoreZeroDepAssign;
94 inline void setIgnoreZeroDepAssign(
bool ignore) {
95 _ignoreZeroDepAssign = ignore;
98 inline void setFilename(
const std::string& name) {
109 return _parameterPrecision;
119 _parameterPrecision = p;
126 _indepNodeStyle = indepNodeStyle;
133 return _indepNodeStyle;
140 _depNodeStyle = depNodeStyle;
147 return _depNodeStyle;
153 inline void setCombineParameterNodes(
bool combineParameterNodes) {
154 _combineParameterNodes = combineParameterNodes;
160 inline bool isCombineParameterNodes()
const {
161 return _combineParameterNodes;
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");
172 size_t infoSize = info.size();
173 for (
size_t e = 0; e < infoSize; e += 2) {
177 size_t min = info[e];
178 size_t max = info[e + 1];
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;
190 out << min <<
"==" << index <<
" or " << index <<
"==" << max;
192 out << min <<
"≤" << index <<
" and " << index <<
"≤" << max;
204 inline void printStaticIndexArray(std::ostringstream& os,
205 const std::string& name,
206 const std::vector<size_t>& values);
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);
215 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>& randomPatterns);
218 const std::set<RandomIndexPattern*>& randomPatterns);
220 static void indexPattern2String(std::ostream& os,
224 static void indexPattern2String(std::ostream& os,
228 static inline void linearIndexPattern2String(std::ostream& os,
242 _currentLoops.clear();
247 _independentSize = info->independent.size();
248 _dependent = &info->dependent;
249 _nameGen = &info->nameGen;
250 _minTemporaryVarID = info->minTemporaryVarID;
252 const std::vector<OperationNode<Base>*>& variableOrder = info->variableOrder;
254 varIds_.resize(_minTemporaryVarID + variableOrder.size());
255 std::fill(varIds_.begin(), varIds_.end(), 0);
257 _code <<
"digraph {" << _endline << _endline;
262 generateNames4RandomIndexPatterns(info->indexRandomPatterns);
268 _code <<
"subgraph indep {" << _endline;
269 _code <<
" rank=min" << _endline;
270 if(!_indepNodeStyle.empty()) {
271 _code <<
"node [" << _indepNodeStyle <<
"]" << _endline;
273 for (
size_t j = 0; j < _independentSize; j++) {
282 _code <<
"\"]" << _endline;
285 _code <<
"}" << _endline;
288 _code <<
"subgraph dep {" << _endline;
289 _code <<
" rank=max" << _endline;
290 if(!_depNodeStyle.empty()) {
291 _code <<
"node [" << _depNodeStyle <<
"]" << _endline;
293 for (
size_t i = 0; i < dependent.
size(); i++) {
297 _code <<
" y" << i <<
" [label=\"";
298 if(node->
getName() ==
nullptr) {
300 size_t pos = node->
getInfo()[0];
301 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
310 _code <<
"\"]" << _endline;
313 _code <<
"}" << _endline;
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");
336 std::set<size_t> dependentDuplicates;
338 for (
size_t i = 0; i < dependent.
size(); i++) {
340 if (node !=
nullptr) {
342 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
343 size_t varID = getVariableID(*node);
345 std::map<size_t, size_t>::const_iterator it2 = _dependentIDs.find(varID);
346 if (it2 == _dependentIDs.end()) {
347 _dependentIDs[getVariableID(*node)] = i;
350 dependentDuplicates.insert(i);
360 if (variableOrder.size() > 0) {
363 CGOpCode op = node->getOperationType();
364 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
366 if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
368 }
else if (op == CGOpCode::ArrayCreation) {
370 }
else if (op == CGOpCode::SparseArrayCreation) {
390 printExpressionNoVarCheck(node);
396 if (dependentDuplicates.size() > 0) {
397 _code <<
"// variable duplicates: " << dependentDuplicates.size() << _endline;
399 for (
size_t index : dependentDuplicates) {
400 const CG<Base>& dep = dependent[index];
403 _code << makeNodeName(*depNode);
404 _code <<
" -> y" << index;
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;
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;
427 _code << makeNodeName(dependent[i].getValue());
428 _code <<
" -> y" << i;
431 }
else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
432 if (!commentWritten) {
433 _code <<
"// dependent variables without operations" << _endline;
434 commentWritten =
true;
437 _code << makeNodeName(*dependent[i].getOperationNode());
438 _code <<
" -> y" << i;
443 _code << _endline <<
"}" << _endline;
450 return _info->
varId[node];
454 size_t totalUseCount)
const override {
456 if (totalUseCount > 1) {
457 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
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;
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);
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;
521 virtual bool requiresVariableArgument(
enum CGOpCode op,
size_t argIndex)
const override {
522 return op == CGOpCode::CondResult;
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);
536 if (var.
getName() ==
nullptr) {
537 if (op == CGOpCode::ArrayCreation) {
540 }
else if (op == CGOpCode::SparseArrayCreation) {
543 }
else if (op == CGOpCode::LoopIndexedDep) {
545 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
548 }
else if (op == CGOpCode::LoopIndexedIndep) {
550 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
553 }
else if (getVariableID(var) <= _independentSize) {
557 }
else if (getVariableID(var) < _minTemporaryVarID) {
559 std::map<size_t, size_t>::const_iterator it = _dependentIDs.find(getVariableID(var));
560 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
562 size_t index = it->second;
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");
568 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
569 return createVariableName(*tmpVar);
585 if (arg.getOperation() !=
nullptr) {
587 return printExpression(*arg.getOperation());
590 return printParameter(*arg.getParameter());
595 if (getVariableID(node) == 0) {
597 return printExpressionNoVarCheck(node);
599 return makeNodeName(node);
603 virtual std::string printParameter(
const Base& value) {
604 if(!_combineParameterNodes) {
605 std::string name = makeNodeName(value);
608 _code <<
" [label=\"";
609 _code << std::setprecision(_parameterPrecision) << value;
610 _code <<
"\"]" << _endline;
614 return makeNodeName(value);
623 if (arg.getOperation() !=
nullptr) {
625 return makeNodeName(*arg.getOperation());
628 return makeNodeName(*arg.getParameter());
632 inline virtual std::string makeNodeName(
const Base& value) {
633 if(_combineParameterNodes) {
636 _ss <<
"\"" << std::setprecision(_parameterPrecision) << value <<
"\"";
639 std::string name =
"p" + std::to_string(parIdx_);
646 const std::ostringstream& label,
647 const std::string& shape =
"") {
648 return printNodeDeclaration(op, label.str(), shape);
652 const std::string& label =
"",
653 const std::string& shape =
"") {
654 std::string name = makeNodeName(op);
656 _code << name <<
" [label=\"";
663 if (!shape.empty()) {
664 _code <<
", shape=" << shape;
666 _code <<
"]" << _endline;
671 inline void printEdges(
const std::string& name,
673 const std::string& style =
"") {
676 std::vector<std::string> aNames(args.size());
677 for (
size_t i = 0; i < args.size(); ++i) {
678 aNames[i] = print(args[i]);
681 for (
size_t i = 0; i < args.size(); ++i) {
684 printEdge(aNames[i], name, style);
689 inline void printEdges(
const std::string& name,
691 const std::vector<std::string>& args,
692 const std::string& style =
"") {
694 size_t nna = args.size();
695 CPPADCG_ASSERT_UNKNOWN(na >= nna);
697 for (
size_t i = 0; i < na; ++i) {
700 if(i < nna && !args[i].empty()) {
701 printEdge(args[i], name, style);
704 printEdge(n, name, style);
710 inline void printEdges(
const std::string& name,
712 const std::vector<std::string>& args,
713 const std::vector<std::string>& styles) {
715 size_t nna = args.size();
716 size_t ns = styles.size();
717 CPPADCG_ASSERT_UNKNOWN(na >= nna);
718 CPPADCG_ASSERT_UNKNOWN(na >= ns);
721 for (
size_t i = 0; i < args.size(); ++i) {
725 style = i < ns ? styles[i] :
"";
726 if(i < nna && !args[i].empty()) {
727 printEdge(args[i], name, style);
730 printEdge(n, name, style);
737 const std::string& to,
738 const std::string& style =
"") {
739 _code << makeNodeName(from);
740 _code <<
" -> " << to;
742 _code <<
"[" << style <<
"]";
745 inline void printEdge(
const std::string& from,
746 const std::string& to,
747 const std::string& style =
"") {
748 _code << from <<
" -> " << to;
750 _code <<
"[" << style <<
"]";
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);
779 return printUnaryFunction(node);
780 case CGOpCode::AtomicForward:
782 case CGOpCode::AtomicReverse:
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:
796 return printOperationDiv(node);
799 return makeNodeName(node);
801 return printOperationMul(node);
803 return printPowFunction(node);
806 return makeNodeName(node);
808 return printOperationMinus(node);
810 case CGOpCode::UnMinus:
811 return printOperationUnaryMinus(node);
813 case CGOpCode::DependentMultiAssign:
814 return printDependentMultiAssign(node);
816 case CGOpCode::Index:
817 return makeNodeName(node);
819 case CGOpCode::IndexAssign:
821 case CGOpCode::IndexDeclaration:
822 return makeNodeName(node);
824 case CGOpCode::LoopStart:
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:
834 return makeNodeName(node);
836 return printTmpVar(node);
837 case CGOpCode::LoopEnd:
838 return printLoopEnd(node);
839 case CGOpCode::IndexCondExpr:
840 return printIndexCondExprOp(node);
841 case CGOpCode::StartIf:
843 case CGOpCode::ElseIf:
847 case CGOpCode::EndIf:
848 return printEndIf(node);
849 case CGOpCode::CondResult:
850 return printCondResult(node);
852 throw CGException(
"Unknown operation code '", op,
"'.");
857 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for assign operation");
863 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for pow() function");
868 std::string name = printNodeDeclaration(op);
870 printEdges(name, op, std::vector<std::string>{a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
876 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for an unary function");
883 std::string label = _ss.str();
884 auto it = label.find(
'(');
885 if (it != std::string::npos) {
886 label = label.substr(0, it);
888 std::string name = printNodeDeclaration(op, label);
890 printEdges(name, op, std::vector<std::string> {a0});
896 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias");
900 std::string name = printNodeDeclaration(op);
902 printEdges(name, op, std::vector<std::string> {a0});
908 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for addition");
913 std::string a0 = print(left);
914 std::string a1 = print(right);
916 std::string name = printNodeDeclaration(op,
"+");
918 printEdges(name, op, std::vector<std::string> {a0, a1});
924 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for subtraction");
929 std::string a0 = print(left);
930 std::string a1 = print(right);
932 std::string name = printNodeDeclaration(op);
934 printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
940 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for division");
945 std::string a0 = print(left);
946 std::string a1 = print(right);
948 std::string name = printNodeDeclaration(op);
950 printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
956 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication");
961 std::string a0 = print(left);
962 std::string a1 = print(right);
964 std::string name = printNodeDeclaration(op,
"×");
966 printEdges(name, op, std::vector<std::string> {a0, a1});
972 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary minus");
976 std::string a0 = print(arg);
978 std::string name = printNodeDeclaration(op);
980 printEdges(name, op, std::vector<std::string> {a0});
986 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
988 const std::vector<Argument<Base> >& args = node.
getArguments();
994 std::string a0 = print(left);
995 std::string a1 = print(right);
996 std::string a2 = print(trueCase);
997 std::string a3 = print(falseCase);
999 std::string name = printNodeDeclaration(node,
"",
"diamond");
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\""});
1017 const size_t* indexes);
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];
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");
1029 size_t id = atomicFor.
getInfo()[0];
1031 std::string name = printNodeDeclaration(atomicFor, _info->
atomicFunctionId2Name.at(
id) +
".forward(" + std::to_string(q) +
", " + std::to_string(p) +
", tx, ty)");
1036 std::vector<std::string> args(opArgs.size());
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();
1043 args[0 * p1 + k] = print(*tx[k]);
1044 args[1 * p1 + k] = print(*ty[k]);
1047 for (
size_t k = 0; k < p1; k++) {
1048 printEdge(args[0 * p1 + k], name,
"label=\"tx" + std::to_string(k) +
"\"");
1051 printEdge(args[1 * p1 + k], name,
"label=\"ty" + std::to_string(k) +
"\"");
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");
1064 CPPADCG_ASSERT_KNOWN(atomicRev.
getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation");
1065 int p = atomicRev.
getInfo()[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");
1070 size_t id = atomicRev.
getInfo()[0];
1072 std::string name = printNodeDeclaration(atomicRev, _info->
atomicFunctionId2Name.at(
id) +
".reverse(" + std::to_string(p) +
", tx, px, py)");
1077 std::vector<std::string> args(opArgs.size());
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();
1085 args[0 * p1 + k] = print(*tx[k]);
1086 args[1 * p1 + k] = print(opArgs[1 * p1 + k]);
1087 args[2 * p1 + k] = print(*px[k]);
1088 args[3 * p1 + k] = print(*py[k]);
1091 for (
size_t k = 0; k < p1; k++) {
1092 printEdge(args[0 * p1 + k], name,
"label=\"tx" + std::to_string(k) +
"\"");
1095 printEdge(args[1 * p1 + k], name,
"label=\"ty" + std::to_string(k) +
"\"");
1098 printEdge(args[2 * p1 + k], name,
"label=\"px" + std::to_string(k) +
"\"");
1101 printEdge(args[3 * p1 + k], name,
"label=\"py" + std::to_string(k) +
"\"");
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");
1109 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
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");
1118 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type");
1119 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments");
1121 std::string name = printNodeDeclaration(node,
"+=");
1123 const std::vector<Argument<Base> >& args = node.
getArguments();
1124 for (
size_t a = 0; a < args.size(); a++) {
1125 bool useArg =
false;
1127 std::string aName = print(arg);
1129 if (arg.getParameter() !=
nullptr) {
1132 CGOpCode op = arg.getOperation()->getOperationType();
1133 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1137 printEdge(aName, name,
"label=\"+=\"");
1141 printEdge(aName, name,
"color=grey");
1150 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopStart,
"Invalid node type");
1153 _currentLoops.push_back(&lnode);
1158 const std::string& jj = *lnode.getIndex().getName();
1161 if (lnode.getIterationCountNode() !=
nullptr) {
1162 _ss <<
"for " << jj <<
" ∈ [0, " << lnode.getIterationCountNode()->getIndex().getName() <<
"-1]";
1164 _ss <<
"for " << jj <<
" ∈ [0, " << (lnode.getIterationCount() - 1) <<
"]";
1166 std::string name = printNodeDeclaration(node, _ss,
"parallelogram");
1171 if (lnode.getIterationCountNode() !=
nullptr) {
1173 printEdge(*lnode.getIterationCountNode(), name,
"label=\"" + (*lnode.getIterationCountNode()->getIndex().getName()) +
"\"");
1177 printEdge(lnode.getIndex(), name,
"label=\"index " + jj +
"\"");
1184 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopEnd,
"Invalid node type");
1186 std::string name = printNodeDeclaration(node);
1188 printEdges(name, node,
"color=grey");
1190 _currentLoops.pop_back();
1196 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed dependent operation");
1198 std::string name = printNodeDeclaration(node);
1201 printEdges(name, 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");
1210 size_t pos = node.
getInfo()[1];
1211 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1214 std::string name = printNodeDeclaration(node, _ss);
1216 printEdges(name, 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");
1225 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1227 std::string name = printNodeDeclaration(node);
1229 printEdges(name, 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");
1239 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1243 return makeNodeName(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");
1254 _ss << (*inode.getIndex().getName()) <<
" = ";
1255 indexPattern2String(_ss, ip, inode.getIndexPatternIndexes());
1257 std::string name = printNodeDeclaration(node, _ss);
1262 for (
const auto* idx: inode.getIndexPatternIndexes()) {
1263 printEdge(*idx, name);
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");
1277 const std::vector<size_t>& info = node.
getInfo();
1280 const std::string& index = *iterationIndexOp.getIndex().getName();
1283 printIndexCondExpr(_ss, info, index);
1285 std::string name = printNodeDeclaration(node, _ss);
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");
1300 std::string name = printNodeDeclaration(node,
"",
"diamond");
1302 printEdges(name, node, std::vector<std::string>{},
1303 std::vector<std::string>{
"label=\"condition\""});
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");
1319 std::string name = printNodeDeclaration(node,
"",
"diamond");
1321 printEdges(name, node, std::vector<std::string>{},
1322 std::vector<std::string>{
"label=\"false\"",
"label=\"condition\""});
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");
1335 std::string name = printNodeDeclaration(node,
"",
"diamond");
1337 printEdges(name, node, std::vector<std::string>{},
1338 std::vector<std::string>{
"label=\"false\""});
1344 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation");
1346 std::string name = printNodeDeclaration(node,
"",
"diamond");
1348 printEdges(name, 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");
1362 std::string name = printNodeDeclaration(node,
"",
"diamond");
1364 printEdges(name, node);
1373 size_t id = getVariableID(arg);
1374 return id > _independentSize &&
id < _minTemporaryVarID;
1377 virtual void getComparison(std::ostream& os,
enum CGOpCode op)
const {
1379 case CGOpCode::ComLt:
1383 case CGOpCode::ComLe:
1387 case CGOpCode::ComEq:
1391 case CGOpCode::ComGe:
1395 case CGOpCode::ComGt:
1399 case CGOpCode::ComNe:
1403 default: CPPAD_ASSERT_UNKNOWN(0);
1405 throw CGException(
"Invalid comparison operator code");
1408 static bool isFunction(
enum CGOpCode op) {
1409 return isUnaryFunction(op) || op == CGOpCode::Pow;
1412 static bool isUnaryFunction(
enum CGOpCode op) {
1415 case CGOpCode::Acos:
1416 case CGOpCode::Asin:
1417 case CGOpCode::Atan:
1418 case CGOpCode::Cosh:
1422 case CGOpCode::Sign:
1423 case CGOpCode::Sinh:
1425 case CGOpCode::Sqrt:
1426 case CGOpCode::Tanh:
1434 static bool isCondAssign(
enum CGOpCode 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:
1449 template<
class Base>
1452 template<
class Base>
const std::map< size_t, std::string > & atomicFunctionId2Name
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)
virtual std::string printConditionalAssignment(OperationNode< Base > &node)
size_t getHandlerPosition() const
virtual std::string printAtomicForwardOp(OperationNode< Base > &atomicFor)
const CodeHandlerVector< Base, size_t > & varId
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
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
const std::vector< size_t > & getInfo() const