1 #ifndef CPPAD_CG_LANGUAGE_LATEX_INCLUDED
2 #define CPPAD_CG_LANGUAGE_LATEX_INCLUDED
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),
179 _parameterPrecision(std::numeric_limits<Base>::digits10),
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;
548 _powBaseEnclose = enclose;
558 return _powBaseEnclose;
582 _multOpStr = multOpStr;
590 return _multValOpStr;
601 _multValOpStr = multValOpStr;
604 virtual void setMaxAssignmentsPerFunction(
size_t maxAssignmentsPerFunction,
605 std::map<std::string, std::string>* sources) {
606 _maxAssignmentsPerFile = maxAssignmentsPerFunction;
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")
620 size_t infoSize = info.size();
621 for (
size_t e = 0; e < infoSize; e += 2) {
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);
666 const std::string& identation,
667 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++) {
723 Node& op = *info->independent[j];
730 for (
size_t i = 0; i < dependent.
size(); i++) {
731 Node* node = dependent[i].getOperationNode();
734 size_t pos = node->
getInfo()[0];
735 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
747 const std::vector<FuncArgument>& indArg = _nameGen->
getIndependent();
748 const std::vector<FuncArgument>& depArg = _nameGen->
getDependent();
749 const std::vector<FuncArgument>& tmpArg = _nameGen->
getTemporary();
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";
761 std::set<size_t> dependentDuplicates;
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;
775 dependentDuplicates.insert(i);
783 std::vector<std::string> inputLatexFiles;
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;
828 size_t assignCount = 0;
829 for (
Node* it : variableOrder) {
831 if (assignCount >= _maxAssignmentsPerFile && multiFile && _currentLoops.empty()) {
833 saveLocalFunction(inputLatexFiles, inputLatexFiles.empty() && info->zeroDependents);
845 assignCount += printAssignment(node);
848 if (!inputLatexFiles.empty() && assignCount > 0) {
850 saveLocalFunction(inputLatexFiles,
false);
854 if (!inputLatexFiles.empty()) {
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);
861 for (
auto & inputLatexFile : inputLatexFiles) {
862 _code <<
"\\input{" << inputLatexFile <<
"}" << _endline;
864 printAlgorithmFileEnd(_code);
868 if (!dependentDuplicates.empty()) {
869 _code <<
"% variable duplicates: " << dependentDuplicates.size() << _endline;
871 checkEquationEnvStart();
872 for (
size_t index : dependentDuplicates) {
873 const CG<Base>& dep = (*_dependent)[index];
875 const std::string& origVarName = *dep.getOperationNode()->getName();
877 _code << _startAlgLine << _startEq
878 << _startDepVar << varName << _endDepVar
880 << _startDepVar << origVarName << _endDepVar;
881 printAssignmentEnd();
886 bool commentWritten =
false;
887 for (
size_t i = 0; i < dependent.
size(); i++) {
888 if (dependent[i].isParameter()) {
889 if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
890 if (!commentWritten) {
891 _code <<
"% dependent variables without operations" << _endline;
892 commentWritten =
true;
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) {
903 if (!commentWritten) {
904 _code <<
"% dependent variables without operations" << _endline;
905 commentWritten =
true;
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();
924 if (inputLatexFiles.empty()) {
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,
974 const Arg& nodeRhs) {
975 if (nodeRhs.getOperation() !=
nullptr) {
976 return printAssignment(nodeName, *nodeRhs.getOperation());
978 printAssignmentStart(nodeName);
979 printParameter(*nodeRhs.getParameter());
980 printAssignmentEnd(nodeName);
985 inline unsigned printAssignment(Node& nodeName,
989 printAssignmentStart(nodeName);
991 unsigned lines = printExpressionNoVarCheck(nodeRhs);
993 printAssignmentEnd(nodeRhs);
996 if (nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
997 Node* array = nodeRhs.getArguments()[0].getOperation();
998 size_t arrayId = getVariableID(*array);
999 size_t pos = nodeRhs.getInfo()[0];
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,
1043 bool zeroDependentArray) {
1044 _ss << _filename <<
"__part_" << (localFuncNames.size() + 1);
1045 std::string funcName = _ss.str();
1049 _nameGen->prepareCustomFunctionVariables(_ss);
1051 _nameGen->finalizeCustomFunctionVariables(_ss);
1053 (*_sources)[funcName +
".tex"] = _ss.str();
1054 localFuncNames.push_back(funcName);
1061 size_t totalUseCount,
1062 size_t opCount)
const override {
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);
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())
1170 size_t index = it->second;
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();
1176 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1177 return createVariableName(*tmpVar);
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;
1199 virtual
unsigned print(const Arg& arg) {
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")
1387 switch (op.getOperationType()) {
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")
1469 auto encloseInParentheses = [this](const Node* node) {
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());
1483 bool encloseBase = _powBaseEnclose || encloseInParentheses(op.getArguments()[0].getOperation());
1484 bool encloseExpo = encloseInParentheses(op.getArguments()[1].getOperation());
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")
1509 const Arg& left = op.getArguments()[0];
1510 const Arg& right = op.getArguments()[1];
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")
1527 const Arg& left = op.getArguments()[0];
1528 const Arg& right = op.getArguments()[1];
1530 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1531 bool encloseRight = encloseInParenthesesMul(right);
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")
1553 const Arg& left = op.getArguments()[0];
1554 const Arg& right = op.getArguments()[1];
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) {
1591 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments
for multiplication
")
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) {
1642 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments
for unary minus
")
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) {
1740 CPPADCG_ASSERT_KNOWN(atomicFor.getInfo().size() == 3, "Invalid number of information elements
for atomic forward operation
")
1741 int q = atomicFor.getInfo()[1];
1742 int p = atomicFor.getInfo()[2];
1744 const std::vector<Arg>& opArgs = atomicFor.getArguments();
1745 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments
for atomic forward operation
")
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) {
1779 CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements
for atomic reverse operation
")
1780 int p = atomicRev.getInfo()[1];
1782 const std::vector<Arg>& opArgs = atomicRev.getArguments();
1783 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4, "Invalid number of arguments
for atomic reverse operation
")
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) {
1881 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments
for loop indexed dependent operation
")
1884 print(node.getArguments()[0]);
1887 virtual void printLoopIndexedIndep(Node& node) {
1888 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type
")
1889 CPPADCG_ASSERT_KNOWN(node.getInfo().size() == 1, "Invalid number of information elements
for loop indexed independent operation
")
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
")
1899 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments
for loop indexed temporary operation
")
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
")
1908 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments
for temporary variable usage operation
")
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
")
1917 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments
for an index assignment operation
")
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
")
1932 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments
for an index condition expression operation
")
1933 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument
for an index condition expression operation
")
1934 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument
for an index condition expression operation
")
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
")
1952 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments
for an
'if start' operation
")
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
")
1975 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 2, "Invalid number of arguments
for an
'else if' operation
")
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
")
2008 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments
for an
'else' operation
")
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
")
2046 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments
for an assignment inside an
if/
else operation
")
2047 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument
for an an assignment inside an
if/
else operation
")
2048 CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument
for an an assignment inside an
if/
else operation
")
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
")
2058 throw CGException("Unable to generate Latex
for user custom operation nodes.
");
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)
2115 throw CGException("Invalid comparison
operator code
"); // should never get here
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:
2173 template<class Base>
2174 const std::string LanguageLatex<Base>::_COMP_OP_LT = "<
"; // NOLINT(cert-err58-cpp)
2175 template<class Base>
2176 const std::string LanguageLatex<Base>::_COMP_OP_LE = "\\le
"; // NOLINT(cert-err58-cpp)
2177 template<class Base>
2178 const std::string LanguageLatex<Base>::_COMP_OP_EQ = "==
"; // NOLINT(cert-err58-cpp)
2179 template<class Base>
2180 const std::string LanguageLatex<Base>::_COMP_OP_GE = "\\ge
"; // NOLINT(cert-err58-cpp)
2181 template<class Base>
2182 const std::string LanguageLatex<Base>::_COMP_OP_GT = ">
"; // NOLINT(cert-err58-cpp)
2183 template<class Base>
2184 const std::string LanguageLatex<Base>::_COMP_OP_NE = "\\ne
"; // NOLINT(cert-err58-cpp)
2186 template<class Base>
2187 const std::string LanguageLatex<Base>::_C_STATIC_INDEX_ARRAY = "index
"; // NOLINT(cert-err58-cpp)
2189 template<class Base>
2190 const std::string LanguageLatex<Base>::_C_SPARSE_INDEX_ARRAY = "idx
"; // NOLINT(cert-err58-cpp)
2192 template<class Base>
2193 const std::string LanguageLatex<Base>::_ATOMIC_TX = "atx
"; // NOLINT(cert-err58-cpp)
2195 template<class Base>
2196 const std::string LanguageLatex<Base>::_ATOMIC_TY = "aty
"; // NOLINT(cert-err58-cpp)
2198 template<class Base>
2199 const std::string LanguageLatex<Base>::_ATOMIC_PX = "apx
"; // NOLINT(cert-err58-cpp)
2201 template<class Base>
2202 const std::string LanguageLatex<Base>::_ATOMIC_PY = "apy
"; // NOLINT(cert-err58-cpp)
2204 } // END cg namespace
2205 } // END CppAD namespace
size_t size() const noexcept
const CodeHandlerVector< Base, size_t > & totalUseCount
const CodeHandlerVector< Base, size_t > & varId
const std::vector< Node * > & independent
virtual const std::string & getConditionEnvironmentEnd() const
virtual void printStartIf(Node &node)
virtual void setAgorithmFileEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getAgorithmFileEnvironmentEnd() const
virtual void setEquationBlockEnvironment(const std::string &begin, const std::string &end)
virtual bool isAlwaysEnclosePowBase() const
virtual const std::string & getDependentVarEnvironmentEnd() const
virtual void printElseIf(Node &node)
virtual bool directlyAssignsVariable(const Node &var) const
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
virtual const std::string & getElseIfEnvironmentEnd() const
virtual const std::string & getAgorithmFileEnvironmentStart() const
virtual const std::string & getIndependentVarEnvironmentStart() const
virtual void setForEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getEquationEnvironmentEnd() const
virtual const std::string & getConditionEnvironmentStart() const
virtual void printAtomicForwardOp(Node &atomicFor)
virtual void setAlgorithmLineEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getAlgorithmLineEnvironmentEnd() const
virtual const std::string & getIfEnvironmentEnd() const
virtual void setVariableEnvironment(const std::string &begin, const std::string &end)
virtual void setIndependentVarEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getEquationBlockEnvironmentEnd() const
virtual void setAlwaysEnclosePowBase(bool enclose)
virtual void setElseIfEnvironment(const std::string &begin, const std::string &end)
virtual void setElseEnvironment(const std::string &begin, const std::string &end)
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern * > &randomPatterns)
virtual void setIfEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getElseEnvironmentEnd() const
virtual const std::string & getAlgorithmLineEnvironmentStart() const
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
virtual const std::string & getEquationEnvironmentStart() const
void setMultiplicationOperator(const std::string &multOpStr)
const std::string & getMultiplicationConstParOperator() const
virtual void setEquationEnvironment(const std::string &begin, const std::string &end)
bool requiresVariableDependencies() const override
virtual const std::string & getEquationBlockEnvironmentStart() const
virtual void printElse(Node &node)
virtual const std::string & getElseIfEnvironmentStart() const
virtual const std::string & getVariableEnvironmentStart() const
virtual const std::string & getForEnvironmentEnd() const
virtual void setDependentVarEnvironment(const std::string &begin, const std::string &end)
virtual void setConditionEnvironment(const std::string &begin, const std::string &end)
const std::string & getMultiplicationOperator() const
virtual const std::string & getIndependentVarEnvironmentEnd() const
void setMultiplicationConstParOperator(const std::string &multValOpStr)
virtual const std::string & getVariableEnvironmentEnd() const
virtual void setParameterPrecision(size_t p)
virtual size_t getParameterPrecision() const
virtual const std::string & getElseEnvironmentStart() const
virtual const std::string & getIfEnvironmentStart() const
virtual void printAtomicReverseOp(Node &atomicRev)
virtual const std::string & getForEnvironmentStart() const
virtual const std::string & getDependentVarEnvironmentStart() const
const std::string * getName() const
void setName(const std::string &name)
const std::vector< size_t > & getInfo() const
CGOpCode getOperationType() const
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
virtual size_t getMaxTemporarySparseArrayVariableID() const =0
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getDependent() const
virtual const std::vector< FuncArgument > & getTemporary() const
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual size_t getMaxTemporaryArrayVariableID() const =0
virtual std::string generateDependent(size_t index)=0
virtual const std::vector< FuncArgument > & getIndependent() const