1 #ifndef CPPAD_CG_LANGUAGE_DOT_INCLUDED 2 #define CPPAD_CG_LANGUAGE_DOT_INCLUDED 30 static const std::string _C_STATIC_INDEX_ARRAY;
31 static const std::string _C_SPARSE_INDEX_ARRAY;
38 std::ostringstream _code;
42 std::ostringstream _ss;
44 size_t _independentSize;
46 size_t _minTemporaryVarID;
49 std::map<size_t, size_t> _dependentIDs;
53 bool _ignoreZeroDepAssign;
55 std::string _filename;
57 std::vector<const LoopStartOperationNode <Base>*> _currentLoops;
59 size_t _parameterPrecision;
61 bool _combineParameterNodes;
63 std::string _indepNodeStyle;
65 std::string _depNodeStyle;
67 std::vector<int> varIds_;
79 _minTemporaryVarID(0),
81 _ignoreZeroDepAssign(false),
82 _filename(
"algorithm"),
83 _parameterPrecision(
std::numeric_limits<Base>::digits10),
84 _combineParameterNodes(true),
91 inline bool isIgnoreZeroDepAssign()
const {
92 return _ignoreZeroDepAssign;
95 inline void setIgnoreZeroDepAssign(
bool ignore) {
96 _ignoreZeroDepAssign = ignore;
99 inline void setFilename(
const std::string& name) {
110 return _parameterPrecision;
120 _parameterPrecision = p;
127 _indepNodeStyle = indepNodeStyle;
134 return _indepNodeStyle;
141 _depNodeStyle = depNodeStyle;
148 return _depNodeStyle;
154 inline void setCombineParameterNodes(
bool combineParameterNodes) {
155 _combineParameterNodes = combineParameterNodes;
161 inline bool isCombineParameterNodes()
const {
162 return _combineParameterNodes;
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")
173 size_t infoSize = info.size();
174 for (
size_t e = 0; e < infoSize; e += 2) {
178 size_t min = info[e];
179 size_t max = info[e + 1];
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;
191 out << min <<
"==" << index <<
" or " << index <<
"==" << max;
193 out << min <<
"≤" << index <<
" and " << index <<
"≤" << max;
205 inline void printStaticIndexArray(std::ostringstream& os,
206 const std::string& name,
207 const std::vector<size_t>& values);
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);
216 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>& randomPatterns);
219 const std::set<RandomIndexPattern*>& randomPatterns);
221 static void indexPattern2String(std::ostream& os,
225 static void indexPattern2String(std::ostream& os,
229 static inline void linearIndexPattern2String(std::ostream& os,
243 _currentLoops.clear();
244 _dependentIDs.clear();
249 _independentSize = info->independent.size();
250 _dependent = &info->dependent;
251 _nameGen = &info->nameGen;
252 _minTemporaryVarID = info->minTemporaryVarID;
254 const std::vector<OperationNode<Base>*>& variableOrder = info->variableOrder;
256 varIds_.resize(_minTemporaryVarID + variableOrder.size());
257 std::fill(varIds_.begin(), varIds_.end(), 0);
259 _code <<
"digraph {" << _endline << _endline;
264 generateNames4RandomIndexPatterns(info->indexRandomPatterns);
270 _code <<
"subgraph indep {" << _endline;
271 _code <<
" rank=min" << _endline;
272 if(!_indepNodeStyle.empty()) {
273 _code <<
"node [" << _indepNodeStyle <<
"]" << _endline;
275 for (
size_t j = 0; j < _independentSize; j++) {
284 _code <<
"\"]" << _endline;
287 _code <<
"}" << _endline;
290 _code <<
"subgraph dep {" << _endline;
291 _code <<
" rank=max" << _endline;
292 if(!_depNodeStyle.empty()) {
293 _code <<
"node [" << _depNodeStyle <<
"]" << _endline;
295 for (
size_t i = 0; i < dependent.
size(); i++) {
299 _code <<
" y" << i <<
" [label=\"";
300 if(node->
getName() ==
nullptr) {
302 size_t pos = node->
getInfo()[0];
303 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
312 _code <<
"\"]" << _endline;
315 _code <<
"}" << _endline;
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")
338 std::set<size_t> dependentDuplicates;
340 for (
size_t i = 0; i < dependent.
size(); i++) {
342 if (node !=
nullptr) {
344 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
345 size_t varID = getVariableID(*node);
347 auto it2 = _dependentIDs.find(varID);
348 if (it2 == _dependentIDs.end()) {
349 _dependentIDs[getVariableID(*node)] = i;
352 dependentDuplicates.insert(i);
362 if (variableOrder.size() > 0) {
365 CGOpCode op = node->getOperationType();
366 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
368 if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
370 }
else if (op == CGOpCode::ArrayCreation) {
372 }
else if (op == CGOpCode::SparseArrayCreation) {
392 printExpressionNoVarCheck(node);
398 if (!dependentDuplicates.empty()) {
399 _code <<
"// variable duplicates: " << dependentDuplicates.size() << _endline;
401 for (
size_t index : dependentDuplicates) {
402 const CG<Base>& dep = dependent[index];
405 _code << makeNodeName(*depNode);
406 _code <<
" -> y" << index;
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;
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;
429 _code << makeNodeName(dependent[i].getValue());
430 _code <<
" -> y" << i;
433 }
else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
434 if (!commentWritten) {
435 _code <<
"// dependent variables without operations" << _endline;
436 commentWritten =
true;
439 _code << makeNodeName(*dependent[i].getOperationNode());
440 _code <<
" -> y" << i;
445 _code << _endline <<
"}" << _endline;
452 return _info->
varId[node];
456 size_t totalUseCount,
457 size_t opCount)
const override {
459 if (totalUseCount > 1) {
460 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
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;
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);
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;
524 bool requiresVariableArgument(
enum CGOpCode op,
size_t argIndex)
const override {
525 return op == CGOpCode::CondResult;
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)
539 if (var.
getName() ==
nullptr) {
540 if (op == CGOpCode::ArrayCreation) {
543 }
else if (op == CGOpCode::SparseArrayCreation) {
546 }
else if (op == CGOpCode::LoopIndexedDep) {
548 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
551 }
else if (op == CGOpCode::LoopIndexedIndep) {
553 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
556 }
else if (getVariableID(var) <= _independentSize) {
560 }
else if (getVariableID(var) < _minTemporaryVarID) {
562 auto it = _dependentIDs.find(getVariableID(var));
563 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
565 size_t index = it->second;
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")
571 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
572 return createVariableName(*tmpVar);
588 if (arg.getOperation() !=
nullptr) {
590 return printExpression(*arg.getOperation());
593 return printParameter(*arg.getParameter());
598 if (getVariableID(node) == 0) {
600 return printExpressionNoVarCheck(node);
602 return makeNodeName(node);
606 virtual std::string printParameter(
const Base& value) {
607 if(!_combineParameterNodes) {
608 std::string name = makeNodeName(value);
611 _code <<
" [label=\"";
612 _code << std::setprecision(_parameterPrecision) << value;
613 _code <<
"\"]" << _endline;
617 return makeNodeName(value);
626 if (arg.getOperation() !=
nullptr) {
628 return makeNodeName(*arg.getOperation());
631 return makeNodeName(*arg.getParameter());
635 inline virtual std::string makeNodeName(
const Base& value) {
636 if(_combineParameterNodes) {
639 _ss <<
"\"" << std::setprecision(_parameterPrecision) << value <<
"\"";
642 std::string name =
"p" + std::to_string(parIdx_);
649 const std::ostringstream& label,
650 const std::string& shape =
"") {
651 return printNodeDeclaration(op, label.str(), shape);
655 const std::string& label =
"",
656 const std::string& shape =
"") {
657 std::string name = makeNodeName(op);
659 _code << name <<
" [label=\"";
666 if (!shape.empty()) {
667 _code <<
", shape=" << shape;
669 _code <<
"]" << _endline;
674 inline void printEdges(
const std::string& name,
676 const std::string& style =
"") {
679 std::vector<std::string> aNames(args.size());
680 for (
size_t i = 0; i < args.size(); ++i) {
681 aNames[i] = print(args[i]);
684 for (
size_t i = 0; i < args.size(); ++i) {
687 printEdge(aNames[i], name, style);
692 inline void printEdges(
const std::string& name,
694 const std::vector<std::string>& args,
695 const std::string& style =
"") {
697 size_t nna = args.size();
698 CPPADCG_ASSERT_UNKNOWN(na >= nna)
700 for (
size_t i = 0; i < na; ++i) {
703 if(i < nna && !args[i].empty()) {
704 printEdge(args[i], name, style);
707 printEdge(n, name, style);
713 inline void printEdges(
const std::string& name,
715 const std::vector<std::string>& args,
716 const std::vector<std::string>& styles) {
718 size_t nna = args.size();
719 size_t ns = styles.size();
720 CPPADCG_ASSERT_UNKNOWN(na >= nna);
721 CPPADCG_ASSERT_UNKNOWN(na >= ns);
724 for (
size_t i = 0; i < args.size(); ++i) {
728 style = i < ns ? styles[i] :
"";
729 if(i < nna && !args[i].empty()) {
730 printEdge(args[i], name, style);
733 printEdge(n, name, style);
740 const std::string& to,
741 const std::string& style =
"") {
742 _code << makeNodeName(from);
743 _code <<
" -> " << to;
745 _code <<
"[" << style <<
"]";
748 inline void printEdge(
const std::string& from,
749 const std::string& to,
750 const std::string& style =
"") {
751 _code << from <<
" -> " << to;
753 _code <<
"[" << style <<
"]";
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);
782 #if CPPAD_USE_CPLUSPLUS_2011 785 case CGOpCode::Asinh:
786 case CGOpCode::Acosh:
787 case CGOpCode::Atanh:
788 case CGOpCode::Expm1:
789 case CGOpCode::Log1p:
791 return printUnaryFunction(node);
792 case CGOpCode::AtomicForward:
794 case CGOpCode::AtomicReverse:
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:
808 return printOperationDiv(node);
811 return makeNodeName(node);
813 return printOperationMul(node);
815 return printPowFunction(node);
818 return makeNodeName(node);
820 return printOperationMinus(node);
822 case CGOpCode::UnMinus:
823 return printOperationUnaryMinus(node);
825 case CGOpCode::DependentMultiAssign:
826 return printDependentMultiAssign(node);
828 case CGOpCode::Index:
829 return makeNodeName(node);
831 case CGOpCode::IndexAssign:
833 case CGOpCode::IndexDeclaration:
834 return makeNodeName(node);
836 case CGOpCode::LoopStart:
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:
846 return makeNodeName(node);
848 return printTmpVar(node);
849 case CGOpCode::LoopEnd:
850 return printLoopEnd(node);
851 case CGOpCode::IndexCondExpr:
852 return printIndexCondExprOp(node);
853 case CGOpCode::StartIf:
855 case CGOpCode::ElseIf:
859 case CGOpCode::EndIf:
860 return printEndIf(node);
861 case CGOpCode::CondResult:
862 return printCondResult(node);
864 throw CGException(
"Unknown operation code '", op,
"'.");
869 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for assign operation")
875 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for pow() function")
880 std::string name = printNodeDeclaration(op);
882 printEdges(name, op, std::vector<std::string>{a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
888 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for an unary function")
895 std::string label = _ss.str();
896 auto it = label.find(
'(');
897 if (it != std::string::npos) {
898 label = label.substr(0, it);
900 std::string name = printNodeDeclaration(op, label);
902 printEdges(name, op, std::vector<std::string> {a0});
908 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias")
912 std::string name = printNodeDeclaration(op);
914 printEdges(name, op, std::vector<std::string> {a0});
920 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for addition")
925 std::string a0 = print(left);
926 std::string a1 = print(right);
928 std::string name = printNodeDeclaration(op,
"+");
930 printEdges(name, op, std::vector<std::string> {a0, a1});
936 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for subtraction")
941 std::string a0 = print(left);
942 std::string a1 = print(right);
944 std::string name = printNodeDeclaration(op);
946 printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
952 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for division")
957 std::string a0 = print(left);
958 std::string a1 = print(right);
960 std::string name = printNodeDeclaration(op);
962 printEdges(name, op, std::vector<std::string> {a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
968 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication")
973 std::string a0 = print(left);
974 std::string a1 = print(right);
976 std::string name = printNodeDeclaration(op,
"×");
978 printEdges(name, op, std::vector<std::string> {a0, a1});
984 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary minus")
988 std::string a0 = print(arg);
990 std::string name = printNodeDeclaration(op);
992 printEdges(name, op, std::vector<std::string> {a0});
998 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1000 const std::vector<Argument<Base> >& args = node.
getArguments();
1006 std::string a0 = print(left);
1007 std::string a1 = print(right);
1008 std::string a2 = print(trueCase);
1009 std::string a3 = print(falseCase);
1011 std::string name = printNodeDeclaration(node,
"",
"diamond");
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\""});
1029 const size_t* indexes);
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];
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")
1041 size_t id = atomicFor.
getInfo()[0];
1043 std::string name = printNodeDeclaration(atomicFor, _info->
atomicFunctionId2Name.at(
id) +
".forward(" + std::to_string(q) +
", " + std::to_string(p) +
", tx, ty)");
1048 std::vector<std::string> args(opArgs.size());
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();
1055 args[0 * p1 + k] = print(*tx[k]);
1056 args[1 * p1 + k] = print(*ty[k]);
1059 for (
size_t k = 0; k < p1; k++) {
1060 printEdge(args[0 * p1 + k], name,
"label=\"tx" + std::to_string(k) +
"\"");
1063 printEdge(args[1 * p1 + k], name,
"label=\"ty" + std::to_string(k) +
"\"");
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")
1076 CPPADCG_ASSERT_KNOWN(atomicRev.
getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation")
1077 int p = atomicRev.
getInfo()[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")
1082 size_t id = atomicRev.
getInfo()[0];
1084 std::string name = printNodeDeclaration(atomicRev, _info->
atomicFunctionId2Name.at(
id) +
".reverse(" + std::to_string(p) +
", tx, px, py)");
1089 std::vector<std::string> args(opArgs.size());
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();
1097 args[0 * p1 + k] = print(*tx[k]);
1098 args[1 * p1 + k] = print(opArgs[1 * p1 + k]);
1099 args[2 * p1 + k] = print(*px[k]);
1100 args[3 * p1 + k] = print(*py[k]);
1103 for (
size_t k = 0; k < p1; k++) {
1104 printEdge(args[0 * p1 + k], name,
"label=\"tx" + std::to_string(k) +
"\"");
1107 printEdge(args[1 * p1 + k], name,
"label=\"ty" + std::to_string(k) +
"\"");
1110 printEdge(args[2 * p1 + k], name,
"label=\"px" + std::to_string(k) +
"\"");
1113 printEdge(args[3 * p1 + k], name,
"label=\"py" + std::to_string(k) +
"\"");
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")
1121 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
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")
1130 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type")
1131 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments")
1133 std::string name = printNodeDeclaration(node,
"+=");
1135 const std::vector<Argument<Base> >& args = node.
getArguments();
1136 for (
size_t a = 0; a < args.size(); a++) {
1137 bool useArg =
false;
1139 std::string aName = print(arg);
1141 if (arg.getParameter() !=
nullptr) {
1144 CGOpCode op = arg.getOperation()->getOperationType();
1145 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1149 printEdge(aName, name,
"label=\"+=\"");
1153 printEdge(aName, name,
"color=grey");
1162 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopStart,
"Invalid node type")
1165 _currentLoops.push_back(&lnode);
1170 const std::string& jj = *lnode.getIndex().getName();
1173 if (lnode.getIterationCountNode() !=
nullptr) {
1174 _ss <<
"for " << jj <<
" ∈ [0, " << lnode.getIterationCountNode()->getIndex().getName() <<
"-1]";
1176 _ss <<
"for " << jj <<
" ∈ [0, " << (lnode.getIterationCount() - 1) <<
"]";
1178 std::string name = printNodeDeclaration(node, _ss,
"parallelogram");
1183 if (lnode.getIterationCountNode() !=
nullptr) {
1185 printEdge(*lnode.getIterationCountNode(), name,
"label=\"" + (*lnode.getIterationCountNode()->getIndex().getName()) +
"\"");
1189 printEdge(lnode.getIndex(), name,
"label=\"index " + jj +
"\"");
1196 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopEnd,
"Invalid node type")
1198 std::string name = printNodeDeclaration(node);
1200 printEdges(name, node,
"color=grey");
1202 _currentLoops.pop_back();
1208 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed dependent operation")
1210 std::string name = printNodeDeclaration(node);
1213 printEdges(name, 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")
1222 size_t pos = node.
getInfo()[1];
1223 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1226 std::string name = printNodeDeclaration(node, _ss);
1228 printEdges(name, 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")
1237 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1239 std::string name = printNodeDeclaration(node);
1241 printEdges(name, 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")
1251 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1255 return makeNodeName(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")
1266 _ss << (*inode.getIndex().getName()) <<
" = ";
1267 indexPattern2String(_ss, ip, inode.getIndexPatternIndexes());
1269 std::string name = printNodeDeclaration(node, _ss);
1274 for (
const auto* idx: inode.getIndexPatternIndexes()) {
1275 printEdge(*idx, name);
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")
1289 const std::vector<size_t>& info = node.
getInfo();
1292 const std::string& index = *iterationIndexOp.getIndex().
getName();
1295 printIndexCondExpr(_ss, info, index);
1297 std::string name = printNodeDeclaration(node, _ss);
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")
1312 std::string name = printNodeDeclaration(node,
"",
"diamond");
1314 printEdges(name, node, std::vector<std::string>{},
1315 std::vector<std::string>{
"label=\"condition\""});
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")
1331 std::string name = printNodeDeclaration(node,
"",
"diamond");
1333 printEdges(name, node, std::vector<std::string>{},
1334 std::vector<std::string>{
"label=\"false\"",
"label=\"condition\""});
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")
1347 std::string name = printNodeDeclaration(node,
"",
"diamond");
1349 printEdges(name, node, std::vector<std::string>{},
1350 std::vector<std::string>{
"label=\"false\""});
1356 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation")
1358 std::string name = printNodeDeclaration(node,
"",
"diamond");
1360 printEdges(name, 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")
1374 std::string name = printNodeDeclaration(node,
"",
"diamond");
1376 printEdges(name, node);
1385 size_t id = getVariableID(arg);
1386 return id > _independentSize &&
id < _minTemporaryVarID;
1389 virtual void getComparison(std::ostream& os,
enum CGOpCode op)
const {
1391 case CGOpCode::ComLt:
1395 case CGOpCode::ComLe:
1399 case CGOpCode::ComEq:
1403 case CGOpCode::ComGe:
1407 case CGOpCode::ComGt:
1411 case CGOpCode::ComNe:
1416 CPPAD_ASSERT_UNKNOWN(0)
1419 throw CGException(
"Invalid comparison operator code");
1422 static bool isFunction(
enum CGOpCode op) {
1423 return isUnaryFunction(op) || op == CGOpCode::Pow;
1426 static bool isUnaryFunction(
enum CGOpCode op) {
1429 case CGOpCode::Acos:
1430 case CGOpCode::Asin:
1431 case CGOpCode::Atan:
1432 case CGOpCode::Cosh:
1436 case CGOpCode::Sign:
1437 case CGOpCode::Sinh:
1439 case CGOpCode::Sqrt:
1440 case CGOpCode::Tanh:
1442 #if CPPAD_USE_CPLUSPLUS_2011 1444 case CGOpCode::Erfc:
1445 case CGOpCode::Asinh:
1446 case CGOpCode::Acosh:
1447 case CGOpCode::Atanh:
1448 case CGOpCode::Expm1:
1449 case CGOpCode::Log1p:
1457 static bool isCondAssign(
enum CGOpCode 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:
1472 template<
class Base>
1475 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 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
size_t printArrayCreationUsingLoop(const std::string &arrayName, const OperationNode< Base > &array, size_t startj, const size_t *indexes)
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
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)
bool createsNewVariable(const OperationNode< Base > &var, size_t totalUseCount, size_t opCount) const override
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::set< RandomIndexPattern *> &randomPatterns)
virtual std::string generateDependent(size_t index)=0
bool requiresVariableDependencies() const override
const CodeHandlerVector< Base, size_t > & totalUseCount
CGOpCode getOperationType() const
virtual std::string printLoopStart(OperationNode< Base > &node)
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 void setParameterPrecision(size_t p)
size_t size() const noexcept
const std::vector< size_t > & getInfo() const