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"),
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;
134 return _indepNodeStyle;
148 return _depNodeStyle;
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,
222 const IndexPattern& ip,
223 const OperationNode<Base>& index);
225 static void indexPattern2String(std::ostream& os,
226 const IndexPattern& ip,
227 const std::vector<
const OperationNode<Base>*>& indexes);
229 static inline void linearIndexPattern2String(std::ostream& os,
230 const LinearIndexPattern& lip,
231 const OperationNode<Base>& index);
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++) {
278 _code <<
" v" <<
op.getHandlerPosition() <<
" [label=\"";
279 if (
op.getName() ==
nullptr) {
280 _code << _nameGen->generateIndependent(
op, getVariableID(
op));
282 _code << *
op.getName();
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++) {
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];
304 _code << _nameGen->generateIndexedDependent(*node, getVariableID(*node), *
ip);
307 _code << _nameGen->generateDependent(
i);
310 _code << *node->getName();
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")
340 for (
size_t i = 0;
i < dependent.size();
i++) {
342 if (node !=
nullptr) {
343 CGOpCode
type = node->getOperationType();
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;
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) {
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)));
386 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
388 }
else if (node.getOperationType() == CGOpCode::TmpDcl) {
392 printExpressionNoVarCheck(node);
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;
421 for (
size_t i = 0;
i < dependent.size();
i++) {
422 if (dependent[
i].isParameter()) {
423 if (!_ignoreZeroDepAssign || !dependent[
i].isIdenticalZero()) {
425 _code <<
"// dependent variables without operations" << _endline;
429 _code << makeNodeName(dependent[
i].getValue());
430 _code <<
" -> y" <<
i;
433 }
else if (dependent[
i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
435 _code <<
"// dependent variables without operations" << _endline;
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 {
458 CGOpCode
op =
var.getOperationType();
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;
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);
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;
524 bool requiresVariableArgument(
enum CGOpCode
op,
size_t argIndex)
const override {
525 return op == CGOpCode::CondResult;
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)
539 if (
var.getName() ==
nullptr) {
540 if (
op == CGOpCode::ArrayCreation) {
541 var.setName(_nameGen->generateTemporaryArray(
var, getVariableID(
var)));
543 }
else if (op == CGOpCode::SparseArrayCreation) {
544 var.setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
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));
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));
556 }
else if (getVariableID(var) <= _independentSize) {
558 var.setName(_nameGen->generateIndependent(var, getVariableID(var)));
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;
566 var.setName(_nameGen->generateDependent(index));
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);
576 var.setName(_nameGen->generateTemporary(var, getVariableID(var)));
580 return *var.getName();
588 if (
arg.getOperation() !=
nullptr) {
590 return printExpression(*
arg.getOperation());
593 return printParameter(*
arg.getParameter());
597 virtual std::string printExpression(OperationNode<Base>& node) {
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);
621 inline virtual std::string makeNodeName(
const OperationNode<Base>& node) {
622 return "v" + std::to_string(node.getHandlerPosition());
625 inline std::string makeNodeName(
const Argument<Base>& arg) {
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_);
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);
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);
659 _code << name <<
" [label=\"";
663 _code << op.getOperationType();
666 if (!shape.empty()) {
667 _code <<
", shape=" << shape;
669 _code <<
"]" << _endline;
674 inline void printEdges(
const std::string& name,
675 const OperationNode<Base>& node,
676 const std::string& style =
"") {
677 const auto& args = node.getArguments();
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,
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)
700 for (
size_t i = 0; i < na; ++i) {
703 if(i < nna && !args[i].empty()) {
704 printEdge(args[i], name, style);
706 std::string n = print(node.getArguments()[i]);
707 printEdge(n, name, style);
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);
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);
732 std::string n = print(node.getArguments()[i]);
733 printEdge(n, name, style);
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;
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 <<
"]";
756 virtual std::string printExpressionNoVarCheck(OperationNode<Base>& node) {
757 CGOpCode op = node.getOperationType();
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,
"'.");
868 virtual std::string printAssignOp(OperationNode<Base>& node) {
869 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1,
"Invalid number of arguments for assign operation")
871 return print(node.getArguments()[0]);
874 virtual std::
string printPowFunction(OperationNode<Base>& op) {
875 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2,
"Invalid number of arguments for pow() function")
877 std::
string a0 = print(op.getArguments()[0]);
878 std::
string a1 = print(op.getArguments()[1]);
880 std::
string name = printNodeDeclaration(op);
882 printEdges(name, op, std::vector<std::
string>{a0, a1}, std::vector<std::string>{
"label=\"$1\"",
"label=\"$2\""});
887 virtual std::string printUnaryFunction(OperationNode<Base>& op) {
888 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1,
"Invalid number of arguments for an unary function")
890 std::
string a0 = print(op.getArguments()[0]);
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);
900 std::string name = printNodeDeclaration(op, label);
902 printEdges(name, op, std::vector<std::string> {a0});
907 virtual std::string printOperationAlias(OperationNode<Base>& op) {
908 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1,
"Invalid number of arguments for alias")
910 std::
string a0 = print(op.getArguments()[0]);
912 std::
string name = printNodeDeclaration(op);
914 printEdges(name, op, std::vector<std::
string> {a0});
919 virtual std::string printOperationAdd(OperationNode<Base>& op) {
920 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2,
"Invalid number of arguments for addition")
922 const Argument<Base>& left = op.getArguments()[0];
923 const Argument<Base>& right = op.getArguments()[1];
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});
935 virtual std::string printOperationMinus(OperationNode<Base>& op) {
936 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2,
"Invalid number of arguments for subtraction")
938 const Argument<Base>& left = op.getArguments()[0];
939 const Argument<Base>& right = op.getArguments()[1];
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\""});
951 virtual std::string printOperationDiv(OperationNode<Base>& op) {
952 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2,
"Invalid number of arguments for division")
954 const Argument<Base>& left = op.getArguments()[0];
955 const Argument<Base>& right = op.getArguments()[1];
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\""});
967 virtual std::string printOperationMul(OperationNode<Base>& op) {
968 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2,
"Invalid number of arguments for multiplication")
970 const Argument<Base>& left = op.getArguments()[0];
971 const Argument<Base>& right = op.getArguments()[1];
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});
983 virtual std::string printOperationUnaryMinus(OperationNode<Base>& op) {
984 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1,
"Invalid number of arguments for unary minus")
986 const Argument<Base>& arg = op.getArguments()[0];
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);
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")
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")
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++) {
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")
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")
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++) {
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, "+=");
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")
1222 size_t pos = node.getInfo()[1];
1224 _ss << _nameGen->generateIndexedIndependent(node, getVariableID(node), *
ip);
1226 std::
string name = printNodeDeclaration(node, _ss);
1228 printEdges(name, node);
1234 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type")
1239 std::
string name = printNodeDeclaration(node);
1241 printEdges(name, node);
1247 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp,
"Invalid node type")
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")
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")
1371 print(node.getArguments()[0]);
1372 print(node.getArguments()[1]);
1374 std::
string name = printNodeDeclaration(node, "", "
diamond");
1376 printEdges(name, node);
1382 if (
arg.getOperationType() == CGOpCode::LoopIndexedDep) {
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: