35 static const std::string _C_STATIC_INDEX_ARRAY;
36 static const std::string _C_SPARSE_INDEX_ARRAY;
37 static const std::string _COMP_OP_LT;
38 static const std::string _COMP_OP_LE;
39 static const std::string _COMP_OP_EQ;
40 static const std::string _COMP_OP_GE;
41 static const std::string _COMP_OP_GT;
42 static const std::string _COMP_OP_NE;
43 static const std::string _ATOMIC_TX;
44 static const std::string _ATOMIC_TY;
45 static const std::string _ATOMIC_PX;
46 static const std::string _ATOMIC_PY;
51 size_t _indentationLevel;
53 std::string _startVar;
57 std::string _startDepVar;
59 std::string _endDepVar;
61 std::string _startIndepVar;
63 std::string _endIndepVar;
69 std::string _startAlgLine;
71 std::string _endAlgLine;
73 std::string _startEqBlock;
75 std::string _endEqBlock;
76 std::string _algFileStart;
77 std::string _algFileEnd;
78 std::string _forStart;
80 std::string _conditionStart;
81 std::string _conditionEnd;
84 std::string _elseIfStart;
85 std::string _elseIfEnd;
86 std::string _elseStart;
88 std::string _assignStr;
90 std::string _multOpStr;
92 std::string _multValOpStr;
96 std::ostringstream _code;
100 std::ostringstream _ss;
102 size_t _independentSize;
104 size_t _minTemporaryVarID;
107 std::map<size_t, size_t> _dependentIDs;
111 std::map<size_t, Node*> _temporary;
113 bool _ignoreZeroDepAssign;
115 std::string _filename;
117 size_t _maxAssignmentsPerFile;
119 std::map<std::string, std::string>* _sources;
121 std::vector<const Arg*> _tmpArrayValues;
123 std::vector<const Arg*> _tmpSparseArrayValues;
125 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
127 size_t _parameterPrecision;
131 bool _powBaseEnclose;
133 std::string auxArrayName_;
142 _indentationLevel(0),
143 _startVar(
"\\begin{CGVar}"),
144 _endVar(
"\\end{CGVar}"),
145 _startDepVar(
"\\begin{CGDepVar}"),
146 _endDepVar(
"\\end{CGDepVar}"),
147 _startIndepVar(
"\\begin{CGIndVar}"),
148 _endIndepVar(
"\\end{CGIndVar}"),
149 _startEq(
"\\begin{CGEq}"),
150 _endEq(
"\\end{CGEq}"),
151 _startAlgLine(
"\\begin{CGLine}"),
152 _endAlgLine(
"\\end{CGLine}"),
153 _startEqBlock(
"\\begin{CGEqBlock}"),
154 _endEqBlock(
"\\end{CGEqBlock}"),
155 _algFileStart(
"\\begin{CGAlgFile}"),
156 _algFileEnd(
"\\end{CGAlgFile}"),
157 _forStart(
"\\begin{CGFor}"),
158 _forEnd(
"\\end{CGFor}"),
159 _conditionStart(
"\\begin{CGCond}"),
160 _conditionEnd(
"\\end{CGCond}"),
161 _ifStart(
"\\begin{CGIf}"),
162 _ifEnd(
"\\end{CGIf}"),
163 _elseIfStart(
"\\begin{CGElseIf}"),
164 _elseIfEnd(
"\\end{CGElseIf}"),
165 _elseStart(
"\\begin{CGElse}"),
166 _elseEnd(
"\\end{CGElse}"),
169 _multValOpStr(
"\\times"),
173 _minTemporaryVarID(0),
175 _ignoreZeroDepAssign(
false),
176 _filename(
"algorithm"),
177 _maxAssignmentsPerFile(0),
180 _inEquationEnv(
false),
181 _powBaseEnclose(
false) {
184 inline const std::string& getAssignString()
const {
188 inline void setAssignString(
const std::string&
assign) {
192 inline bool isIgnoreZeroDepAssign()
const {
193 return _ignoreZeroDepAssign;
196 inline void setIgnoreZeroDepAssign(
bool ignore) {
197 _ignoreZeroDepAssign =
ignore;
200 virtual void setFilename(
const std::string& name) {
211 const std::string& end) {
237 const std::string& end) {
238 _startDepVar = begin;
263 const std::string& end) {
264 _startIndepVar = begin;
272 return _startIndepVar;
289 const std::string& end) {
315 const std::string& end) {
316 _startAlgLine = begin;
324 return _startAlgLine;
342 const std::string& end) {
343 _startEqBlock = begin;
352 return _startEqBlock;
370 const std::string& end) {
371 _algFileStart = begin;
379 return _algFileStart;
396 const std::string& end) {
422 const std::string& end) {
423 _conditionStart = begin;
431 return _conditionStart;
438 return _conditionEnd;
448 const std::string& end) {
474 const std::string& end) {
475 _elseIfStart = begin;
500 const std::string& end) {
526 return _parameterPrecision;
536 _parameterPrecision =
p;
558 return _powBaseEnclose;
590 return _multValOpStr;
605 std::map<std::string, std::string>*
sources) {
610 inline virtual ~LanguageLatex() =
default;
615 static inline void printIndexCondExpr(std::ostringstream&
out,
616 const std::vector<size_t>&
info,
617 const std::string& index) {
618 CPPADCG_ASSERT_KNOWN(
info.size() > 1 &&
info.size() % 2 == 0,
"Invalid number of information elements for an index condition expression operation")
625 size_t min =
info[
e];
626 size_t max =
info[
e + 1];
628 out << index <<
" == " << min;
629 }
else if (min == 0) {
630 out << index <<
" \\le " << max;
631 }
else if (max == (std::numeric_limits<size_t>::max)()) {
632 out << min <<
" \\le " << index;
638 out << min <<
" == " << index <<
" \\vee " << index <<
" == " << max;
640 out << min <<
" \\le " << index <<
" \\wedge" << index <<
" \\le " << max;
652 inline void printStaticIndexArray(std::ostringstream& os,
653 const std::string& name,
654 const std::vector<size_t>& values);
656 inline void printStaticIndexMatrix(std::ostringstream& os,
657 const std::string& name,
658 const std::map<
size_t, std::map<size_t, size_t> >& values);
663 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>&
randomPatterns);
669 static inline std::string indexPattern2String(
const IndexPattern&
ip,
672 static inline std::string indexPattern2String(
const IndexPattern&
ip,
673 const std::vector<const Node*>& indexes);
675 static inline std::string linearIndexPattern2String(
const LinearIndexPattern&
lip,
686 const bool multiFile = _maxAssignmentsPerFile > 0 && _sources !=
nullptr;
691 _indentationLevel = 0;
693 _inEquationEnv =
false;
695 _currentLoops.clear();
696 _dependentIDs.clear();
702 _dependent = &
info->dependent;
703 _nameGen = &
info->nameGen;
704 _minTemporaryVarID =
info->minTemporaryVarID;
706 const std::vector<Node*>& variableOrder =
info->variableOrder;
709 std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(),
nullptr);
711 std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(),
nullptr);
716 generateNames4RandomIndexPatterns(
info->indexRandomPatterns);
722 for (
size_t j = 0;
j < _independentSize;
j++) {
724 if (
op.getName() ==
nullptr) {
730 for (
size_t i = 0;
i < dependent.
size();
i++) {
731 Node* node = dependent[
i].getOperationNode();
750 CPPADCG_ASSERT_KNOWN(!
indArg.empty() && !
depArg.empty(),
751 "There must be at least one dependent and one independent argument")
752 CPPADCG_ASSERT_KNOWN(
tmpArg.size() == 3,
753 "There must be three temporary variables")
755 auxArrayName_ =
tmpArg[1].name +
"p";
763 for (
size_t i = 0;
i < dependent.
size();
i++) {
764 Node* node = dependent[
i].getOperationNode();
765 if (node !=
nullptr) {
767 if (
type != CGOpCode::Inv &&
type != CGOpCode::LoopEnd) {
768 size_t varID = getVariableID(*node);
770 auto it2 = _dependentIDs.find(
varID);
771 if (
it2 == _dependentIDs.end()) {
772 _dependentIDs[getVariableID(*node)] =
i;
785 inputLatexFiles.reserve(variableOrder.size() / _maxAssignmentsPerFile);
791 if (variableOrder.size() > 0) {
793 for (
Node* node : variableOrder) {
794 CGOpCode
op = node->getOperationType();
795 if (!isDependent(*node) &&
op != CGOpCode::IndexDeclaration) {
797 if (requiresVariableName(*node) &&
op != CGOpCode::ArrayCreation &&
op != CGOpCode::SparseArrayCreation) {
799 }
else if (
op == CGOpCode::ArrayCreation) {
801 }
else if (
op == CGOpCode::SparseArrayCreation) {
810 if (
info->zeroDependents) {
813 checkEquationEnvStart();
814 for (
size_t i = 0;
i <
depArg.size();
i++) {
815 _code << _startAlgLine << _startEq;
823 printParameter(Base(0.0));
824 _code << _endEq << _endAlgLine << _endline;
829 for (
Node*
it : variableOrder) {
858 CPPADCG_ASSERT_KNOWN(
tmpArg[0].array,
859 "The temporary variables must be saved in an array in order to generate multiple functions")
860 printAlgorithmFileStart(_code);
864 printAlgorithmFileEnd(_code);
871 checkEquationEnvStart();
875 const std::string&
origVarName = *
dep.getOperationNode()->getName();
877 _code << _startAlgLine << _startEq
878 << _startDepVar <<
varName << _endDepVar
881 printAssignmentEnd();
887 for (
size_t i = 0;
i < dependent.
size();
i++) {
888 if (dependent[
i].isParameter()) {
889 if (!_ignoreZeroDepAssign || !dependent[
i].isIdenticalZero()) {
891 _code <<
"% dependent variables without operations" << _endline;
894 checkEquationEnvStart();
897 _code << _startAlgLine << _startEq
898 << _startDepVar <<
varName << _endDepVar << _assignStr;
899 printParameter(dependent[
i].getValue());
900 printAssignmentEnd();
902 }
else if (dependent[
i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
904 _code <<
"% dependent variables without operations" << _endline;
907 checkEquationEnvStart();
910 const std::string&
indepName = *dependent[
i].getOperationNode()->getName();
911 _code << _startAlgLine << _startEq
912 << _startDepVar <<
varName << _endDepVar
914 << _startIndepVar <<
indepName << _endIndepVar;
915 printAssignmentEnd(*dependent[
i].getOperationNode());
919 checkEquationEnvEnd();
926 printAlgorithmFileStart(_ss);
928 printAlgorithmFileEnd(_ss);
932 if (_sources !=
nullptr) {
933 (*_sources)[_filename +
".tex"] = _ss.str();
937 (*_sources)[_filename +
".tex"] = _code.str();
942 inline size_t getVariableID(
const Node& node)
const {
943 return _info->
varId[node];
946 inline virtual void printAlgorithmFileStart(std::ostream&
out) {
947 out <<
"% Latex source file for '" << _filename <<
"' (automatically generated by CppADCodeGen)" << _endline;
948 out << _algFileStart << _endline;
951 inline virtual void printAlgorithmFileEnd(std::ostream&
out) {
955 inline virtual void checkEquationEnvStart() {
956 if (!_inEquationEnv) {
957 _code << _startEqBlock << _endline;
958 _inEquationEnv =
true;
962 inline virtual void checkEquationEnvEnd() {
963 if (_inEquationEnv) {
964 _code << _endEqBlock << _endline;
965 _inEquationEnv =
false;
969 inline unsigned printAssignment(Node& node) {
970 return printAssignment(node, node);
973 inline unsigned printAssignment(Node&
nodeName,
975 if (
nodeRhs.getOperation() !=
nullptr) {
979 printParameter(*
nodeRhs.getParameter());
985 inline unsigned printAssignment(Node&
nodeName,
996 if (
nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
997 Node* array =
nodeRhs.getArguments()[0].getOperation();
998 size_t arrayId = getVariableID(*array);
1000 if (array->getOperationType() == CGOpCode::ArrayCreation)
1001 _tmpArrayValues[
arrayId - 1 +
pos] =
nullptr;
1003 _tmpSparseArrayValues[
arrayId - 1 +
pos] =
nullptr;
1009 inline virtual void printAssignmentStart(Node&
op) {
1010 printAssignmentStart(
op, createVariableName(
op), isDependent(
op));
1013 inline virtual void printAssignmentStart(Node& node,
const std::string&
varName,
bool isDep) {
1015 _temporary[getVariableID(node)] = &node;
1018 checkEquationEnvStart();
1020 _code << _startAlgLine << _startEq;
1022 _code << _startDepVar <<
varName << _endDepVar;
1024 _code << _startVar <<
varName << _endVar;
1026 CGOpCode
op = node.getOperationType();
1027 if (
op == CGOpCode::DependentMultiAssign || (
op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
1030 _code << _assignStr;
1034 inline virtual void printAssignmentEnd() {
1035 _code << _endEq << _endAlgLine << _endline;
1038 inline virtual void printAssignmentEnd(Node&
op) {
1039 printAssignmentEnd();
1042 virtual void saveLocalFunction(std::vector<std::string>&
localFuncNames,
1049 _nameGen->prepareCustomFunctionVariables(_ss);
1051 _nameGen->finalizeCustomFunctionVariables(_ss);
1053 (*_sources)[
funcName +
".tex"] = _ss.str();
1061 size_t totalUseCount,
1062 size_t opCount)
const override {
1063 CGOpCode
op =
var.getOperationType();
1064 if (totalUseCount > 1) {
1065 return op != CGOpCode::ArrayElement &&
op != CGOpCode::Index &&
op != CGOpCode::IndexDeclaration &&
op != CGOpCode::Tmp;
1067 return (
op == CGOpCode::ArrayCreation ||
1068 op == CGOpCode::SparseArrayCreation ||
1069 op == CGOpCode::AtomicForward ||
1070 op == CGOpCode::AtomicReverse ||
1071 op == CGOpCode::ComLt ||
1072 op == CGOpCode::ComLe ||
1073 op == CGOpCode::ComEq ||
1074 op == CGOpCode::ComGe ||
1075 op == CGOpCode::ComGt ||
1076 op == CGOpCode::ComNe ||
1077 op == CGOpCode::LoopIndexedDep ||
1078 op == CGOpCode::LoopIndexedTmp ||
1079 op == CGOpCode::IndexAssign ||
1080 op == CGOpCode::Assign) &&
1081 op != CGOpCode::CondResult;
1085 virtual bool requiresVariableName(
const Node&
var)
const {
1086 CGOpCode
op =
var.getOperationType();
1088 op != CGOpCode::AtomicForward &&
1089 op != CGOpCode::AtomicReverse &&
1090 op != CGOpCode::LoopStart &&
1091 op != CGOpCode::LoopEnd &&
1092 op != CGOpCode::Index &&
1093 op != CGOpCode::IndexAssign &&
1094 op != CGOpCode::StartIf &&
1095 op != CGOpCode::ElseIf &&
1096 op != CGOpCode::Else &&
1097 op != CGOpCode::EndIf &&
1098 op != CGOpCode::CondResult &&
1099 op != CGOpCode::LoopIndexedTmp &&
1100 op != CGOpCode::Tmp);
1111 CGOpCode
op =
var.getOperationType();
1112 return isCondAssign(
op) ||
1113 op == CGOpCode::ArrayCreation ||
1114 op == CGOpCode::SparseArrayCreation ||
1115 op == CGOpCode::AtomicForward ||
1116 op == CGOpCode::AtomicReverse ||
1117 op == CGOpCode::DependentMultiAssign ||
1118 op == CGOpCode::LoopStart ||
1119 op == CGOpCode::LoopEnd ||
1120 op == CGOpCode::IndexAssign ||
1121 op == CGOpCode::StartIf ||
1122 op == CGOpCode::ElseIf ||
1123 op == CGOpCode::Else ||
1124 op == CGOpCode::EndIf ||
1125 op == CGOpCode::CondResult ||
1126 op == CGOpCode::IndexDeclaration;
1129 bool requiresVariableArgument(
enum CGOpCode
op,
size_t argIndex)
const override {
1130 return op == CGOpCode::CondResult;
1133 inline const std::string& createVariableName(Node&
var) {
1134 CGOpCode
op =
var.getOperationType();
1135 CPPADCG_ASSERT_UNKNOWN(getVariableID(
var) > 0)
1136 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::AtomicForward)
1137 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::AtomicReverse)
1138 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::LoopStart)
1139 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::LoopEnd)
1140 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::Index)
1141 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::IndexAssign)
1142 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::IndexDeclaration)
1144 if (
var.getName() ==
nullptr) {
1145 if (
op == CGOpCode::ArrayCreation) {
1148 }
else if (
op == CGOpCode::SparseArrayCreation) {
1151 }
else if (
op == CGOpCode::LoopIndexedDep) {
1152 size_t pos =
var.getInfo()[0];
1153 const IndexPattern*
ip = _info->loopDependentIndexPatterns[
pos];
1156 }
else if (
op == CGOpCode::LoopIndexedIndep) {
1157 size_t pos =
var.getInfo()[1];
1158 const IndexPattern*
ip = _info->loopIndependentIndexPatterns[
pos];
1161 }
else if (getVariableID(
var) <= _independentSize) {
1165 }
else if (getVariableID(
var) < _minTemporaryVarID) {
1167 auto it = _dependentIDs.find(getVariableID(
var));
1168 CPPADCG_ASSERT_UNKNOWN(
it != _dependentIDs.end())
1171 var.setName(_nameGen->generateDependent(index));
1173 }
else if (
op == CGOpCode::LoopIndexedTmp ||
op == CGOpCode::Tmp) {
1174 CPPADCG_ASSERT_KNOWN(
var.getArguments().size() >= 1,
"Invalid number of arguments for loop indexed temporary operation")
1175 Node*
tmpVar =
var.getArguments()[0].getOperation();
1186 return *
var.getName();
1193 virtual void printIndependentVariableName(Node&
op) {
1194 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 0,
"Invalid number of arguments for independent variable")
1196 _code << _startIndepVar << _nameGen->generateIndependent(
op, getVariableID(
op)) << _endIndepVar;
1200 if (
arg.getOperation() !=
nullptr) {
1202 return printExpression(*
arg.getOperation());
1205 printParameter(*
arg.getParameter());
1210 virtual unsigned printExpression(Node& node) {
1211 if (getVariableID(node) > 0) {
1212 const std::string& name = createVariableName(node);
1214 CGOpCode
op = node.getOperationType();
1215 if (getVariableID(node) >= _minTemporaryVarID ||
op == CGOpCode::ArrayCreation ||
op == CGOpCode::SparseArrayCreation ||
op == CGOpCode::LoopIndexedDep ||
op == CGOpCode::LoopIndexedIndep) {
1217 _code << _startVar << name << _endVar;
1219 }
else if (getVariableID(node) <= _independentSize) {
1221 _code << _startIndepVar << name << _endIndepVar;
1225 _code << _startDepVar << name << _endDepVar;
1232 return printExpressionNoVarCheck(node);
1236 virtual unsigned printExpressionNoVarCheck(Node& node) {
1237 CGOpCode
op = node.getOperationType();
1239 case CGOpCode::ArrayCreation:
1240 printArrayCreationOp(node);
1242 case CGOpCode::SparseArrayCreation:
1243 printSparseArrayCreationOp(node);
1245 case CGOpCode::ArrayElement:
1246 printArrayElementOp(node);
1248 case CGOpCode::Assign:
1249 return printAssignOp(node);
1252 case CGOpCode::Acos:
1253 case CGOpCode::Asin:
1254 case CGOpCode::Atan:
1255 case CGOpCode::Cosh:
1259 case CGOpCode::Sign:
1260 case CGOpCode::Sinh:
1262 case CGOpCode::Sqrt:
1263 case CGOpCode::Tanh:
1265#if CPPAD_USE_CPLUSPLUS_2011
1267 case CGOpCode::Erfc:
1268 case CGOpCode::Asinh:
1269 case CGOpCode::Acosh:
1270 case CGOpCode::Atanh:
1271 case CGOpCode::Expm1:
1272 case CGOpCode::Log1p:
1274 printUnaryFunction(node);
1276 case CGOpCode::AtomicForward:
1279 case CGOpCode::AtomicReverse:
1283 printOperationAdd(node);
1285 case CGOpCode::Alias:
1286 return printOperationAlias(node);
1288 case CGOpCode::ComLt:
1289 case CGOpCode::ComLe:
1290 case CGOpCode::ComEq:
1291 case CGOpCode::ComGe:
1292 case CGOpCode::ComGt:
1293 case CGOpCode::ComNe:
1294 printConditionalAssignment(node);
1297 printOperationDiv(node);
1300 printIndependentVariableName(node);
1303 printOperationMul(node);
1306 printPowFunction(node);
1312 printOperationMinus(node);
1315 case CGOpCode::UnMinus:
1316 printOperationUnaryMinus(node);
1319 case CGOpCode::DependentMultiAssign:
1320 return printDependentMultiAssign(node);
1322 case CGOpCode::Index:
1324 case CGOpCode::IndexAssign:
1325 printIndexAssign(node);
1327 case CGOpCode::IndexDeclaration:
1330 case CGOpCode::LoopStart:
1331 printLoopStart(node);
1333 case CGOpCode::LoopIndexedIndep:
1334 printLoopIndexedIndep(node);
1336 case CGOpCode::LoopIndexedDep:
1337 printLoopIndexedDep(node);
1339 case CGOpCode::LoopIndexedTmp:
1340 printLoopIndexedTmp(node);
1342 case CGOpCode::TmpDcl:
1348 case CGOpCode::LoopEnd:
1351 case CGOpCode::IndexCondExpr:
1352 printIndexCondExprOp(node);
1354 case CGOpCode::StartIf:
1357 case CGOpCode::ElseIf:
1360 case CGOpCode::Else:
1363 case CGOpCode::EndIf:
1366 case CGOpCode::CondResult:
1367 printCondResult(node);
1369 case CGOpCode::UserCustom:
1370 printUserCustom(node);
1373 throw CGException(
"Unknown operation code '",
op,
"'.");
1378 virtual unsigned printAssignOp(Node& node) {
1379 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1,
"Invalid number of arguments for assign operation")
1381 return print(node.getArguments()[0]);
1384 virtual void printUnaryFunction(Node&
op) {
1385 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 1,
"Invalid number of arguments for unary function")
1390 print(
op.getArguments()[0]);
1393 case CGOpCode::Acos:
1394 _code <<
"\\arccos";
1396 case CGOpCode::Asin:
1397 _code <<
"\\arcsin";
1399 case CGOpCode::Atan:
1400 _code <<
"\\arctan";
1402 case CGOpCode::Cosh:
1414 case CGOpCode::Sinh:
1417 case CGOpCode::Sign:
1418 _code <<
"\\operatorname{sgn}";
1423 case CGOpCode::Sqrt:
1425 print(
op.getArguments()[0]);
1428 case CGOpCode::Tanh:
1434#if CPPAD_USE_CPLUSPLUS_2011
1436 _code <<
"\\operatorname{erf}";
1438 case CGOpCode::Erfc:
1439 _code <<
"\\operatorname{erfc}";
1441 case CGOpCode::Asinh:
1442 _code <<
"\\operatorname{arcsinh}";
1444 case CGOpCode::Acosh:
1445 _code <<
"\\operatorname{arccosh}";
1447 case CGOpCode::Atanh:
1448 _code <<
"\\operatorname{arctanh}";
1450 case CGOpCode::Expm1:
1451 _code <<
"\\operatorname{expm1}";
1453 case CGOpCode::Log1p:
1454 _code <<
"\\operatorname{log1p}";
1458 throw CGException(
"Unknown function name for operation code '",
op.getOperationType(),
"'.");
1461 _code <<
"\\mathopen{}\\left(";
1462 print(
op.getArguments()[0]);
1463 _code <<
"\\right)\\mathclose{}";
1466 virtual void printPowFunction(Node&
op) {
1467 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for pow() function")
1470 while (node !=
nullptr) {
1471 if (getVariableID(*node) != 0)
1473 if (node->getOperationType() == CGOpCode::Alias)
1474 node = node->getArguments()[0].getOperation();
1478 return node !=
nullptr &&
1479 getVariableID(*node) == 0 &&
1480 !isFunction(node->getOperationType());
1489 print(
op.getArguments()[0]);
1491 _code <<
"\\right)";
1495 print(
op.getArguments()[1]);
1497 _code <<
"\\right)";
1501 virtual unsigned printOperationAlias(Node&
op) {
1502 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 1,
"Invalid number of arguments for alias")
1503 return print(
op.getArguments()[0]);
1506 virtual void printOperationAdd(Node&
op) {
1507 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for addition")
1512 if(
right.getParameter() ==
nullptr || (*
right.getParameter() >= 0)) {
1520 printParameter(-*
right.getParameter());
1524 virtual void printOperationMinus(Node&
op) {
1525 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for subtraction")
1530 if(
right.getParameter() ==
nullptr || (*
right.getParameter() >= 0)) {
1540 _code <<
"\\right)";
1546 printParameter(-*
right.getParameter());
1550 virtual void printOperationDiv(Node&
op) {
1551 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for division")
1565 inline bool encloseInParenthesesMul(const Arg& arg) const {
1566 if (arg.getParameter() != nullptr) {
1567 return ((*arg.getParameter()) < 0);
1569 return encloseInParenthesesMul(arg.getOperation());
1573 inline bool encloseInParenthesesMul(const Node* node) const {
1574 while (node != nullptr) {
1575 if (getVariableID(*node) != 0) {
1577 } else if (node->getOperationType() == CGOpCode::Alias) {
1578 node = node->getArguments()[0].getOperation();
1583 return node != nullptr &&
1584 getVariableID(*node) == 0 &&
1585 node->getOperationType() != CGOpCode::Div &&
1586 node->getOperationType() != CGOpCode::Mul &&
1587 !isFunction(node->getOperationType());
1590 virtual void printOperationMul(Node& op) {
1593 const Arg& left = op.getArguments()[0];
1594 const Arg& right = op.getArguments()[1];
1596 bool encloseLeft = encloseInParenthesesMul(left);
1597 bool encloseRight = encloseInParenthesesMul(right);
1599 auto isNumber = [this](const Node* node, int pos) -> bool {
1600 while (node != nullptr) {
1601 if(getVariableID(*node) != 0) {
1604 CGOpCode op = node->getOperationType();
1605 if (op == CGOpCode::Alias) {
1606 node = node->getArguments()[0].getOperation();
1608 } else if (op == CGOpCode::Mul) {
1609 node = node->getArguments()[pos].getOperation();
1610 } else if (pos == 0 && op == CGOpCode::Pow) {
1611 node = node->getArguments()[0].getOperation();
1616 return true; // a constant number
1624 _code << "\\
right)
";
1627 if (isNumber(left.getOperation(), 1) && isNumber(right.getOperation(), 0))
1628 _code << _multValOpStr; // numbers too close together are difficult to distinguish
1630 _code << _multOpStr; // e.g. invisible times
1637 _code << "\\
right)
";
1641 virtual void printOperationUnaryMinus(Node& op) {
1644 const Arg& arg = op.getArguments()[0];
1646 bool enclose = encloseInParenthesesMul(arg);
1654 _code << "\\
right)
";
1658 virtual void printConditionalAssignment(Node& node) {
1659 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1661 const std::vector<Arg>& args = node.getArguments();
1662 const Arg &left = args[0];
1663 const Arg &right = args[1];
1664 const Arg &trueCase = args[2];
1665 const Arg &falseCase = args[3];
1667 bool isDep = isDependent(node);
1668 const std::string& varName = createVariableName(node);
1670 if ((trueCase.getParameter() != nullptr && falseCase.getParameter() != nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1671 (trueCase.getOperation() != nullptr && falseCase.getOperation() != nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1672 // true and false cases are the same
1673 printAssignmentStart(node, varName, isDep);
1675 printAssignmentEnd(node);
1677 checkEquationEnvEnd();
1680 _code << _conditionStart;
1682 _code << " " << getComparison(node.getOperationType()) << " ";
1684 _code << _conditionEnd;
1686 //checkEquationEnvStart(); // no need
1687 printAssignmentStart(node, varName, isDep);
1689 printAssignmentEnd(node);
1690 checkEquationEnvEnd();
1691 _code << _ifEnd << _endline;
1692 _code << _elseStart << _endline; // else
1693 //checkEquationEnvStart(); // no need
1694 printAssignmentStart(node, varName, isDep);
1696 printAssignmentEnd(node);
1697 checkEquationEnvEnd();
1698 _code << _elseEnd << _endline; // end if
1702 inline bool isSameArgument(const Arg& newArg,
1703 const Arg* oldArg) {
1704 if (oldArg != nullptr) {
1705 if (oldArg->getParameter() != nullptr) {
1706 if (newArg.getParameter() != nullptr) {
1707 return (*newArg.getParameter() == *oldArg->getParameter());
1710 return (newArg.getOperation() == oldArg->getOperation());
1716 virtual void printArrayCreationOp(Node& op);
1718 virtual void printSparseArrayCreationOp(Node& op);
1720 inline void printArrayStructInit(const std::string& dataArrayName,
1722 const std::vector<Node*>& arrays,
1725 inline void printArrayStructInit(const std::string& dataArrayName,
1728 inline void markArrayChanged(Node& ty);
1730 inline size_t printArrayCreationUsingLoop(size_t startPos,
1733 std::vector<const Arg*>& tmpArrayValues);
1735 inline std::string getTempArrayName(const Node& op);
1737 virtual void printArrayElementOp(Node& op);
1739 virtual void printAtomicForwardOp(Node& atomicFor) {
1741 int q = atomicFor.getInfo()[1];
1742 int p = atomicFor.getInfo()[2];
1744 const std::vector<Arg>& opArgs = atomicFor.getArguments();
1747 size_t id = atomicFor.getInfo()[0];
1748 std::vector<Node*> tx(p1), ty(p1);
1749 for (size_t k = 0; k < p1; k++) {
1750 tx[k] = opArgs[0 * p1 + k].getOperation();
1751 ty[k] = opArgs[1 * p1 + k].getOperation();
1754 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array
type")
1755 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array
type")
1756 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array
type")
1759 for (size_t k = 0; k < p1; k++) {
1760 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1763 printArrayStructInit(_ATOMIC_TY, *ty[p]);
1766 _code << _startAlgLine << _startEq
1767 << _info->atomicFunctionId2Name.at(id) << ".forward(
"
1768 << q << ",
" << p << ",
"
1769 << _ATOMIC_TX << ", &
" << _ATOMIC_TY << ")
"
1770 << _endEq << _endAlgLine << _endline;
1775 markArrayChanged(*ty[p]);
1778 virtual void printAtomicReverseOp(Node& atomicRev) {
1780 int p = atomicRev.getInfo()[1];
1782 const std::vector<Arg>& opArgs = atomicRev.getArguments();
1785 size_t id = atomicRev.getInfo()[0];
1786 std::vector<Node*> tx(p1), px(p1), py(p1);
1787 for (size_t k = 0; k < p1; k++) {
1788 tx[k] = opArgs[0 * p1 + k].getOperation();
1789 px[k] = opArgs[2 * p1 + k].getOperation();
1790 py[k] = opArgs[3 * p1 + k].getOperation();
1793 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array
type")
1794 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array
type")
1796 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array
type")
1798 CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array
type")
1799 CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array
type")
1802 for (size_t k = 0; k < p1; k++) {
1803 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1806 for (size_t k = 0; k < p1; k++) {
1807 printArrayStructInit(_ATOMIC_PY, k, py, k);
1810 printArrayStructInit(_ATOMIC_PX, *px[0]);
1813 _code << _startAlgLine << _startEq
1814 << _info->atomicFunctionId2Name.at(id) << ".reverse(
"
1816 << _ATOMIC_TX << ", &
" << _ATOMIC_PX << ",
" << _ATOMIC_PY << ")
"
1817 << _endEq << _endAlgLine << _endline;
1822 markArrayChanged(*px[0]);
1825 virtual unsigned printDependentMultiAssign(Node& node) {
1826 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign, "
Invalid node
type")
1827 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments
")
1829 const std::vector<Arg>& args = node.getArguments();
1830 for (size_t a = 0; a < args.size(); a++) {
1831 bool useArg = false;
1832 const Arg& arg = args[a];
1833 if (arg.getParameter() != nullptr) {
1836 CGOpCode op = arg.getOperation()->getOperationType();
1837 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1841 printAssignment(node, arg); // ignore other arguments!
1848 virtual void printLoopStart(Node& node) {
1849 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node
type")
1851 auto& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1852 _currentLoops.push_back(&lnode);
1854 const std::string& jj = *lnode.getIndex().getName();
1856 if (lnode.getIterationCountNode() != nullptr) {
1857 lastIt = *lnode.getIterationCountNode()->getIndex().getName() + " - 1
";
1859 lastIt = std::to_string(lnode.getIterationCount() - 1);
1862 checkEquationEnvEnd();
1864 _code << _forStart << "{
$" << jj << "\\
in \\
left[0,
" << lastIt << "\\
right]
$}
" << _endline;
1865 _indentationLevel++;
1868 virtual void printLoopEnd(Node& node) {
1869 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node
type")
1871 checkEquationEnvEnd();
1873 _indentationLevel--;
1875 _code << _forEnd << _endline;
1877 _currentLoops.pop_back();
1880 virtual void printLoopIndexedDep(Node& node) {
1884 print(node.getArguments()[0]);
1887 virtual void printLoopIndexedIndep(Node& node) {
1888 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node
type")
1891 // CGLoopIndexedIndepOp
1892 size_t pos = node.getInfo()[1];
1893 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1894 _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1897 virtual void printLoopIndexedTmp(Node& node) {
1898 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp, "Invalid node
type")
1900 Node* tmpVar = node.getArguments()[0].getOperation();
1901 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments
for loop indexed
temporary operation")
1903 print(node.getArguments()[1]);
1906 virtual void printTmpVar(Node& node) {
1907 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp, "Invalid node
type")
1909 Node* tmpVar = node.getArguments()[0].getOperation();
1910 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments
for loop indexed
temporary operation")
1912 _code << _startVar << *tmpVar->getName() << _endVar;
1915 virtual void printIndexAssign(Node& node) {
1916 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node
type")
1919 auto& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1921 checkEquationEnvStart();
1923 const IndexPattern& ip = inode.getIndexPattern();
1924 _code << _startAlgLine << _startEq
1925 << (*inode.getIndex().getName())
1926 << _assignStr << indexPattern2String(ip, inode.getIndexPatternIndexes())
1927 << _endEq << _endAlgLine << _endline;
1930 virtual void printIndexCondExprOp(Node& node) {
1931 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr, "Invalid node
type")
1936 const std::vector<size_t>& info = node.getInfo();
1938 auto& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1939 const std::string& index = *iterationIndexOp.getIndex().getName();
1941 checkEquationEnvStart();
1943 printIndexCondExpr(_code, info, index);
1946 virtual void printStartIf(Node& node) {
1951 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf, "
Invalid node
type")
1953 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument
for an 'if start' operation")
1955 checkEquationEnvEnd();
1958 //checkEquationEnvStart(); // no need
1959 _code << _conditionStart;
1960 printIndexCondExprOp(*node.getArguments()[0].getOperation());
1961 checkEquationEnvEnd();
1962 _code << _conditionEnd;
1965 _indentationLevel++;
1968 virtual void printElseIf(Node& node) {
1974 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ElseIf, "
Invalid node
type")
1976 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument
for an 'else if' operation")
1977 CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument
for an 'else if' operation")
1979 checkEquationEnvEnd();
1980 _indentationLevel--;
1982 // close previous environment
1983 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
1984 if (nType == CGOpCode::StartIf) {
1985 _code << _ifEnd << _endline;
1986 } else if (nType == CGOpCode::ElseIf) {
1987 _code << _elseIfEnd << _endline;
1990 // start new else if
1991 _code << _elseIfStart;
1992 _code << _conditionStart;
1993 //checkEquationEnvStart(); // no need
1994 printIndexCondExprOp(*node.getArguments()[1].getOperation());
1995 checkEquationEnvEnd();
1996 _code << _conditionEnd;
1999 _indentationLevel++;
2002 virtual void printElse(Node& node) {
2007 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Else, "
Invalid node
type")
2010 checkEquationEnvEnd();
2011 _indentationLevel--;
2013 // close previous environment
2014 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
2015 if (nType == CGOpCode::StartIf) {
2016 _code << _ifEnd << _endline;
2017 } else if (nType == CGOpCode::ElseIf) {
2018 _code << _elseIfEnd << _endline;
2022 _code << _elseStart << _endline;
2024 _indentationLevel++;
2027 virtual void printEndIf(Node& node) {
2028 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node
type for an 'end if' operation")
2030 _indentationLevel--;
2032 // close previous environment
2033 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
2034 if (nType == CGOpCode::StartIf) {
2035 _code << _ifEnd << _endline;
2036 } else if (nType == CGOpCode::ElseIf) {
2037 _code << _elseIfEnd << _endline;
2039 assert(nType == CGOpCode::Else);
2040 _code << _elseEnd << _endline;
2044 virtual void printCondResult(Node& node) {
2045 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult, "Invalid node
type")
2050 // just follow the argument
2051 Node& nodeArg = *node.getArguments()[1].getOperation();
2052 printAssignment(nodeArg);
2055 virtual void printUserCustom(Node& node) {
2056 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom, "Invalid node
type")
2061 inline bool isDependent(const Node& arg) const {
2062 if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
2065 size_t id = getVariableID(arg);
2066 return id > _independentSize && id < _minTemporaryVarID;
2069 virtual void printParameter(const Base& value) {
2070 // make sure all digits of floating point values are printed
2071 std::ostringstream os;
2072 os << std::setprecision(_parameterPrecision) << value;
2074 std::string number = os.str();
2075 size_t pos = number.find('e');
2076 if (pos != std::string::npos) {
2077 std::string n = " \\
times 10^{
";
2078 number.replace(pos, 1, n);
2080 if (number[pos] == '-' || number[pos] == '+')
2082 while (number[pos] == '0')
2083 number.replace(pos, 1, ""); // remove zeros
2091 virtual const std::string& getComparison(enum CGOpCode op) const {
2093 case CGOpCode::ComLt:
2096 case CGOpCode::ComLe:
2099 case CGOpCode::ComEq:
2102 case CGOpCode::ComGe:
2105 case CGOpCode::ComGt:
2108 case CGOpCode::ComNe:
2112 CPPAD_ASSERT_UNKNOWN(0)
2118 inline const std::string& getPrintfBaseFormat() {
2119 static const std::string format; // empty string
2123 static bool isFunction(enum CGOpCode op) {
2124 return isUnaryFunction(op) || op == CGOpCode::Pow;
2127 static bool isUnaryFunction(enum CGOpCode op) {
2130 case CGOpCode::Acos:
2131 case CGOpCode::Asin:
2132 case CGOpCode::Atan:
2133 case CGOpCode::Cosh:
2137 case CGOpCode::Sign:
2138 case CGOpCode::Sinh:
2140#if CPPAD_USE_CPLUSPLUS_2011
2142 case CGOpCode::Erfc:
2143 case CGOpCode::Asinh:
2144 case CGOpCode::Acosh:
2145 case CGOpCode::Atanh:
2146 case CGOpCode::Expm1:
2147 case CGOpCode::Log1p:
2149 case CGOpCode::Sqrt:
2150 case CGOpCode::Tanh:
2158 static bool isCondAssign(enum CGOpCode op) {
2160 case CGOpCode::ComLt:
2161 case CGOpCode::ComLe:
2162 case CGOpCode::ComEq:
2163 case CGOpCode::ComGe:
2164 case CGOpCode::ComGt:
2165 case CGOpCode::ComNe: