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")
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);
221 static void indexPattern2String(std::ostream& os,
222 const IndexPattern&
ip,
225 static void indexPattern2String(std::ostream& os,
226 const IndexPattern&
ip,
229 static inline void linearIndexPattern2String(std::ostream& os,
230 const LinearIndexPattern&
lip,
243 _currentLoops.clear();
244 _dependentIDs.clear();
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) {
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++) {
299 _code <<
" y" <<
i <<
" [label=\"";
300 if(node->
getName() ==
nullptr) {
312 _code <<
"\"]" << _endline;
315 _code <<
"}" << _endline;
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) {
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) {
370 }
else if (
op == CGOpCode::ArrayCreation) {
372 }
else if (
op == CGOpCode::SparseArrayCreation) {
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();
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) {
543 }
else if (
op == CGOpCode::SparseArrayCreation) {
546 }
else if (
op == CGOpCode::LoopIndexedDep) {
547 size_t pos =
var.getInfo()[0];
548 const IndexPattern*
ip = _info->loopDependentIndexPatterns[
pos];
551 }
else if (
op == CGOpCode::LoopIndexedIndep) {
552 size_t pos =
var.getInfo()[1];
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")
570 OperationNode<Base>*
tmpVar =
var.getArguments()[0].getOperation();
580 return *
var.getName();
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);
622 return "v" + std::to_string(node.getHandlerPosition());
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 =
"") {
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,
676 const std::string&
style =
"") {
677 const auto&
args = node.getArguments();
680 for (
size_t i = 0;
i <
args.size(); ++
i) {
684 for (
size_t i = 0;
i <
args.size(); ++
i) {
692 inline void printEdges(
const std::string& name,
694 const std::vector<std::string>&
args,
695 const std::string&
style =
"") {
696 size_t na = node.getArguments().size();
698 CPPADCG_ASSERT_UNKNOWN(
na >=
nna)
700 for (
size_t i = 0;
i <
na; ++
i) {
706 std::string
n = print(node.getArguments()[
i]);
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) {
717 size_t na = node.getArguments().size();
720 CPPADCG_ASSERT_UNKNOWN(
na >=
nna);
721 CPPADCG_ASSERT_UNKNOWN(
na >=
ns);
724 for (
size_t i = 0;
i <
args.size(); ++
i) {
732 std::string
n = print(node.getArguments()[
i]);
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 <<
"]";
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,
"'.");
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\""});
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();
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")
910 std::
string a0 = print(
op.getArguments()[0]);
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);
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);
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);
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);
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")
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)
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")
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:
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: