33 static const std::string _C_STATIC_INDEX_ARRAY;
34 static const std::string _C_SPARSE_INDEX_ARRAY;
35 static const std::string _ATOMIC_TX;
36 static const std::string _ATOMIC_TY;
37 static const std::string _ATOMIC_PX;
38 static const std::string _ATOMIC_PY;
43 size_t _indentationLevel;
47 std::string _javascript;
49 std::string _headExtra;
52 std::string _forStart;
54 std::string _forBodyStart;
55 std::string _forBodyEnd;
58 std::string _elseIfStart;
59 std::string _elseIfEnd;
60 std::string _elseStart;
62 std::string _condBodyStart;
63 std::string _condBodyEnd;
64 std::string _assignStr;
65 std::string _assignAddStr;
67 std::string _multOpStr;
69 std::string _multValOpStr;
73 std::ostringstream _code;
77 std::ostringstream _ss;
79 size_t _independentSize;
81 size_t _minTemporaryVarID;
84 std::map<size_t, size_t> _dependentIDs;
88 bool _ignoreZeroDepAssign;
90 std::string _filename;
92 size_t _maxAssignmentsPerFile;
94 std::map<std::string, std::string>* _sources;
96 std::vector<const Arg*> _tmpArrayValues;
98 std::vector<const Arg*> _tmpSparseArrayValues;
100 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
102 size_t _parameterPrecision;
104 bool _powBaseEnclose;
106 bool _saveVariableRelations;
108 std::string auxArrayName_;
109 std::vector<int> varIds_;
110 std::vector<std::string> depConstIds_;
111 std::vector<std::string> depIsIndepIds_;
119 _indentationLevel(0),
121 ".loopBody{padding-left: 2em;}\n"
125 ".condBody{padding-left: 2em;}\n"
126 ".dep{color:#600;}\n"
127 ".indep{color:#060;}\n"
128 ".tmp{color:#006;}\n"
129 ".index{color:#00f;}\n"),
130 _startEq(R
"(<math display="block" class="equation">)"),
132 _forStart(
"<div class='loop'>"),
134 _forBodyStart(
"<div class='loopBody'>"),
135 _forBodyEnd(
"</div>"),
136 _ifStart(
"<div class='condIf'>"),
138 _elseIfStart(
"<div class='condElseIf'>"),
139 _elseIfEnd(
"</div>"),
140 _elseStart(
"<div class='condElse'>"),
142 _condBodyStart(
"<div class='condBody'>"),
143 _condBodyEnd(
"</div>"),
144 _assignStr(
"<mo>=</mo>"),
145 _assignAddStr(
"<mo>+=</mo>"),
146 _multOpStr(
"<mo>⁢</mo>"),
147 _multValOpStr(
"<mo>×</mo>"),
151 _minTemporaryVarID(0),
153 _ignoreZeroDepAssign(
false),
154 _filename(
"algorithm"),
155 _maxAssignmentsPerFile(0),
158 _powBaseEnclose(
false),
159 _saveVariableRelations(
false) {
164 inline const std::string& getAssignMarkup()
const {
168 inline void setAssignMarkup(
const std::string&
assign) {
172 inline const std::string& getAddAssignMarkup()
const {
173 return _assignAddStr;
176 inline void setAddAssignMarkup(
const std::string&
assignAdd) {
209 return _multValOpStr;
224 inline bool isIgnoreZeroDepAssign()
const {
225 return _ignoreZeroDepAssign;
228 inline void setIgnoreZeroDepAssign(
bool ignore) {
229 _ignoreZeroDepAssign =
ignore;
232 void setFilename(
const std::string& name) {
245 const std::string& getStyle()
const {
258 const std::string& getJavascript()
const {
271 const std::string& getHeadExtraMarkup()
const {
282 const std::string& end) {
308 const std::string& end) {
334 const std::string& end) {
360 const std::string& end) {
361 _elseIfStart = begin;
386 const std::string& end) {
412 return _parameterPrecision;
422 _parameterPrecision =
p;
444 return _powBaseEnclose;
448 std::map<std::string, std::string>*
sources) {
453 inline void setSaveVariableRelations(
bool save) {
454 _saveVariableRelations =
save;
458 return _saveVariableRelations;
464 static inline void printIndexCondExpr(std::ostringstream&
out,
465 const std::vector<size_t>&
info,
466 const std::string& index) {
467 CPPADCG_ASSERT_KNOWN(
info.size() > 1 &&
info.size() % 2 == 0,
"Invalid number of information elements for an index condition expression operation")
472 out <<
"<mo>∨</mo>";
474 size_t min =
info[
e];
475 size_t max =
info[
e + 1];
477 out <<
"<mi class='index'>" << index <<
"</mi><mo>==</mo><mn>" << min <<
"</nm>";
478 }
else if (min == 0) {
479 out <<
"<mi class='index'>" << index <<
"</mi><mo>≤</mo><mn>" << max <<
"</mn>";
480 }
else if (max == (std::numeric_limits<size_t>::max)()) {
481 out <<
"<mn>" << min <<
"</mn><mo>≤</mo><mi class='index'>" << index <<
"</mi>";
484 out <<
"<mfenced><mrow>";
487 out <<
"<mn>" << min <<
"</mn><mo>==</mo><mi class='index'>" << index <<
"</mi><mo>∨</mo><mi class='index'>" << index <<
"</mi><mo>==</mo><mn>" << max <<
"</mn>";
489 out <<
"<mn>" << min <<
"</mn><mo>≤</mo><mi class='index'>" << index <<
"</mi><mo>∧</mo><mi class='index'>" << index <<
"</mi><mo>≤</mo><mn>" << max <<
"</mn";
492 out <<
"</mrow></mfenced>";
501 inline void printStaticIndexArray(std::ostringstream& os,
502 const std::string& name,
503 const std::vector<size_t>& values);
506 const std::string& name,
507 const std::map<
size_t, std::map<size_t, size_t> >& values);
512 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>&
randomPatterns);
518 static void indexPattern2String(std::ostream& os,
519 const IndexPattern&
ip,
522 static void indexPattern2String(std::ostream& os,
523 const IndexPattern&
ip,
524 const std::vector<const Node*>& indexes);
526 static inline void linearIndexPattern2String(std::ostream& os,
527 const LinearIndexPattern&
lip,
538 const bool multiFile = _maxAssignmentsPerFile > 0 && _sources !=
nullptr;
543 _indentationLevel = 0;
545 _currentLoops.clear();
546 depConstIds_.clear();
547 depIsIndepIds_.clear();
548 _dependentIDs.clear();
554 _dependent = &
info->dependent;
555 _nameGen = &
info->nameGen;
556 _minTemporaryVarID =
info->minTemporaryVarID;
558 const std::vector<Node*>& variableOrder =
info->variableOrder;
561 std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(),
nullptr);
563 std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(),
nullptr);
565 varIds_.resize(_minTemporaryVarID + variableOrder.size());
566 std::fill(varIds_.begin(), varIds_.end(), 0);
571 generateNames4RandomIndexPatterns(
info->indexRandomPatterns);
577 for (
size_t j = 0;
j < _independentSize;
j++) {
579 if (
op.getName() ==
nullptr) {
585 for (
size_t i = 0;
i < dependent.
size();
i++) {
586 Node* node = dependent[
i].getOperationNode();
605 CPPADCG_ASSERT_KNOWN(!
indArg.empty() && !
depArg.empty(),
606 "There must be at least one dependent and one independent argument")
607 CPPADCG_ASSERT_KNOWN(
tmpArg.size() == 3,
608 "There must be three temporary variables")
610 auxArrayName_ =
tmpArg[1].name +
"p";
618 for (
size_t i = 0;
i < dependent.
size();
i++) {
619 Node* node = dependent[
i].getOperationNode();
620 if (node !=
nullptr) {
622 if (
type != CGOpCode::Inv &&
type != CGOpCode::LoopEnd) {
623 size_t varID = getVariableID(*node);
625 auto it2 = _dependentIDs.find(
varID);
626 if (
it2 == _dependentIDs.end()) {
627 _dependentIDs[getVariableID(*node)] =
i;
640 mathMLFiles.reserve(variableOrder.size() / _maxAssignmentsPerFile);
646 if (variableOrder.size() > 0) {
648 for (
Node* node : variableOrder) {
649 CGOpCode
op = node->getOperationType();
650 if (!isDependent(*node) &&
op != CGOpCode::IndexDeclaration) {
652 if (requiresVariableName(*node) &&
op != CGOpCode::ArrayCreation &&
op != CGOpCode::SparseArrayCreation) {
654 }
else if (
op == CGOpCode::ArrayCreation) {
656 }
else if (
op == CGOpCode::SparseArrayCreation) {
665 if (
info->zeroDependents) {
668 for (
size_t i = 0;
i <
depArg.size();
i++) {
677 printParameter(Base(0.0));
678 _code << _endEq << _endline;
683 for (
Node*
it : variableOrder) {
712 CPPADCG_ASSERT_KNOWN(
tmpArg[0].array,
713 "The temporary variables must be saved in an array in order to generate multiple functions")
714 printAlgorithmFileStart(_code);
716 _code <<
"<a href='" <<
mathMLFiles[
i] <<
".html'>part " << (
i + 1) <<
"</a><br/>" << _endline;
718 printAlgorithmFileEnd(_code);
735 printAssignmentEnd();
741 for (
size_t i = 0;
i < dependent.
size();
i++) {
742 if (dependent[
i].isParameter()) {
743 if (!_ignoreZeroDepAssign || !dependent[
i].isIdenticalZero()) {
745 _code <<
"<!-- dependent variables without operations -->" << _endline;
749 std::string
depId =
"d" + std::to_string(
i);
750 if (_saveVariableRelations) {
751 depConstIds_.push_back(
depId);
756 <<
"<mrow id='" <<
depId <<
"' class='dep'>" <<
varName <<
"</mrow>" << _assignStr;
757 printParameter(dependent[
i].getValue());
758 printAssignmentEnd();
760 }
else if (dependent[
i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
762 _code <<
"<!-- dependent variables without operations -->" << _endline;
767 const std::string&
indepName = *dependent[
i].getOperationNode()->getName();
769 if (_saveVariableRelations) {
770 depIsIndepIds_.push_back(
depId);
773 <<
"<mrow id='" <<
depId <<
"' class='dep'>" <<
varName <<
"</mrow>"
775 <<
"<mrow id='" <<
createHtmlID(dependent[
i].getOperationNode()) <<
"' class='indep'>" <<
indepName <<
"</mrow>";
776 printAssignmentEnd(*dependent[
i].getOperationNode());
785 printAlgorithmFileStart(_ss);
787 printAlgorithmFileEnd(_ss);
791 if (_sources !=
nullptr) {
792 (*_sources)[_filename +
".html"] = _ss.str();
796 (*_sources)[_filename +
".html"] = _code.str();
801 inline size_t getVariableID(
const Node& node)
const {
802 return _info->
varId[node];
805 inline virtual void printAlgorithmFileStart(std::ostream&
out) {
806 out <<
"<!DOCTYPE html>" << _endline <<
807 "<html lang=\"en\">" << _endline <<
808 "<head>" << _endline <<
809 "<meta charset=\"utf-8\">" << _endline <<
810 "<title>" << _filename <<
"</title>" << _endline;
812 if (!_headExtra.empty()) {
813 out << _headExtra << _endline;
816 if (!_style.empty()) {
817 out <<
"<style>" << _endline
818 << _style << _endline
819 <<
"</style>" << _endline;
822 if (_saveVariableRelations) {
830 const auto& varDeps = _info->variableDependencies;
831 const auto& varOrder = _info->variableOrder;
833 for (size_t i = 0; i < varDeps.size(); ++i) {
834 if (!varDeps[i].empty()) {
838 out << ",
" << _endline;
848 out << _endline <<
" };" << _endline;
851 out <<
" var dep2var = {" << _endline;
853 std::map<size_t, std::set<size_t> >
deps2Var;
863 if (pair.first !=
deps2Var.begin()->first) {
864 out <<
"," << _endline;
866 out <<
" \"" << pair.first <<
"\": [";
868 if (
j != *pair.second.begin())
out <<
", ";
873 out << _endline <<
" };" << _endline;
875 out <<
"</script>" << _endline;
878 if (!_javascript.empty()) {
879 out <<
"<script type=\"text/javascript\">" << _endline <<
880 _javascript << _endline
881 <<
"</script>" << _endline;
884 out <<
"</head>" << _endline <<
886 "<body>" << _endline <<
887 "<!-- source file for '" << _filename <<
"' (automatically generated by CppADCodeGen) -->" << _endline <<
888 "<div id='algorithm'>" << _endline;
891 inline virtual void printAlgorithmFileEnd(std::ostream&
out) {
893 if(_saveVariableRelations) {
894 out <<
"<script type=\"text/javascript\">" << _endline;
895 out <<
" depConst = [";
897 for (
const auto&
d: depConstIds_) {
902 out <<
"\'" <<
d <<
"\'";
904 out <<
"];" << _endline;
905 out <<
" depIsVar = [";
907 for (
const auto&
d: depIsIndepIds_) {
912 out <<
"\'" <<
d <<
"\'";
914 out <<
"];" << _endline;
915 out <<
"</script>" << _endline;
918 out <<
"</div>" << _endline <<
919 "</body>" << _endline <<
923 inline unsigned printAssignment(Node& node) {
924 return printAssignment(node, node);
927 inline unsigned printAssignment(Node&
nodeName,
929 if (
nodeRhs.getOperation() !=
nullptr) {
933 printParameter(*
nodeRhs.getParameter());
939 inline unsigned printAssignment(Node&
nodeName,
950 if (
nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
951 Node* array =
nodeRhs.getArguments()[0].getOperation();
952 size_t arrayId = getVariableID(*array);
954 if (array->getOperationType() == CGOpCode::ArrayCreation)
957 _tmpSparseArrayValues[
arrayId - 1 +
pos] =
nullptr;
963 inline virtual void printAssignmentStart(Node&
op) {
964 printAssignmentStart(
op, createVariableName(
op), isDependent(
op));
967 inline virtual void printAssignmentStart(Node& node,
const std::string&
varName,
bool isDep) {
969 _code <<
"<mrow id='" << createHtmlID(node) <<
"' class='" << (
isDep ?
"dep" :
"tmp") <<
"'>" <<
varName <<
"</mrow>";
971 CGOpCode
op = node.getOperationType();
972 if (
op == CGOpCode::DependentMultiAssign || (
op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
973 _code << _assignAddStr;
979 inline virtual void printAssignmentEnd() {
980 _code << _endEq << _endline;
983 inline virtual void printAssignmentEnd(Node&
op) {
984 printAssignmentEnd();
987 virtual void saveLocalFunction(std::vector<std::string>&
localFuncNames,
994 _nameGen->prepareCustomFunctionVariables(_ss);
996 _nameGen->finalizeCustomFunctionVariables(_ss);
998 (*_sources)[
funcName +
".html"] = _ss.str();
1006 size_t totalUseCount,
1007 size_t opCount)
const override {
1008 CGOpCode
op =
var.getOperationType();
1009 if (totalUseCount > 1) {
1010 return op != CGOpCode::ArrayElement &&
op != CGOpCode::Index &&
op != CGOpCode::IndexDeclaration &&
op != CGOpCode::Tmp;
1012 return (
op == CGOpCode::ArrayCreation ||
1013 op == CGOpCode::SparseArrayCreation ||
1014 op == CGOpCode::AtomicForward ||
1015 op == CGOpCode::AtomicReverse ||
1016 op == CGOpCode::ComLt ||
1017 op == CGOpCode::ComLe ||
1018 op == CGOpCode::ComEq ||
1019 op == CGOpCode::ComGe ||
1020 op == CGOpCode::ComGt ||
1021 op == CGOpCode::ComNe ||
1022 op == CGOpCode::LoopIndexedDep ||
1023 op == CGOpCode::LoopIndexedTmp ||
1024 op == CGOpCode::IndexAssign ||
1025 op == CGOpCode::Assign) &&
1026 op != CGOpCode::CondResult;
1030 virtual bool requiresVariableName(
const Node&
var)
const {
1031 CGOpCode
op =
var.getOperationType();
1033 op != CGOpCode::AtomicForward &&
1034 op != CGOpCode::AtomicReverse &&
1035 op != CGOpCode::LoopStart &&
1036 op != CGOpCode::LoopEnd &&
1037 op != CGOpCode::Index &&
1038 op != CGOpCode::IndexAssign &&
1039 op != CGOpCode::StartIf &&
1040 op != CGOpCode::ElseIf &&
1041 op != CGOpCode::Else &&
1042 op != CGOpCode::EndIf &&
1043 op != CGOpCode::CondResult &&
1044 op != CGOpCode::LoopIndexedTmp &&
1045 op != CGOpCode::Tmp);
1056 CGOpCode
op =
var.getOperationType();
1057 return isCondAssign(
op) ||
1058 op == CGOpCode::ArrayCreation ||
1059 op == CGOpCode::SparseArrayCreation ||
1060 op == CGOpCode::AtomicForward ||
1061 op == CGOpCode::AtomicReverse ||
1062 op == CGOpCode::DependentMultiAssign ||
1063 op == CGOpCode::LoopStart ||
1064 op == CGOpCode::LoopEnd ||
1065 op == CGOpCode::IndexAssign ||
1066 op == CGOpCode::StartIf ||
1067 op == CGOpCode::ElseIf ||
1068 op == CGOpCode::Else ||
1069 op == CGOpCode::EndIf ||
1070 op == CGOpCode::CondResult ||
1071 op == CGOpCode::IndexDeclaration;
1074 bool requiresVariableArgument(
enum CGOpCode
op,
size_t argIndex)
const override {
1075 return op == CGOpCode::CondResult;
1078 inline const std::string& createVariableName(Node&
var) {
1079 CGOpCode
op =
var.getOperationType();
1080 CPPADCG_ASSERT_UNKNOWN(getVariableID(
var) > 0)
1081 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::AtomicForward)
1082 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::AtomicReverse)
1083 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::LoopStart)
1084 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::LoopEnd)
1085 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::Index)
1086 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::IndexAssign)
1087 CPPADCG_ASSERT_UNKNOWN(
op != CGOpCode::IndexDeclaration)
1089 if (
var.getName() ==
nullptr) {
1090 if (
op == CGOpCode::ArrayCreation) {
1093 }
else if (
op == CGOpCode::SparseArrayCreation) {
1096 }
else if (
op == CGOpCode::LoopIndexedDep) {
1097 size_t pos =
var.getInfo()[0];
1098 const IndexPattern*
ip = _info->loopDependentIndexPatterns[
pos];
1101 }
else if (
op == CGOpCode::LoopIndexedIndep) {
1102 size_t pos =
var.getInfo()[1];
1103 const IndexPattern*
ip = _info->loopIndependentIndexPatterns[
pos];
1106 }
else if (getVariableID(
var) <= _independentSize) {
1110 }
else if (getVariableID(
var) < _minTemporaryVarID) {
1112 auto it = _dependentIDs.find(getVariableID(
var));
1113 CPPADCG_ASSERT_UNKNOWN(
it != _dependentIDs.end())
1116 var.setName(_nameGen->generateDependent(index));
1118 }
else if (
op == CGOpCode::LoopIndexedTmp ||
op == CGOpCode::Tmp) {
1119 CPPADCG_ASSERT_KNOWN(
var.getArguments().size() >= 1,
"Invalid number of arguments for loop indexed temporary operation")
1120 Node*
tmpVar =
var.getArguments()[0].getOperation();
1131 return *
var.getName();
1138 return var.getHandlerPosition();
1145 return createHtmlID(*
var);
1152 size_t id = getHtmlID(
var);
1153 if (varIds_.size() <=
id) {
1154 varIds_.resize(
id + 1 + varIds_.size() * 3 / 2, 0);
1157 int n = varIds_[
id];
1161 return "v" + std::to_string(
id);
1163 return "v" + std::to_string(
id) +
"_" + std::to_string(
n);
1166 virtual void printIndependentVariableName(Node&
op) {
1167 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 0,
"Invalid number of arguments for independent variable")
1168 _code << "<
mrow id='" << createHtmlID(
op) << "'
class='
indep'>" << _nameGen->generateIndependent(
op, getVariableID(
op)) << "</
mrow>";
1172 if (
arg.getOperation() !=
nullptr) {
1174 return printExpression(*
arg.getOperation());
1177 printParameter(*
arg.getParameter());
1182 virtual unsigned printExpression(Node& node) {
1183 if (getVariableID(node) > 0) {
1184 const std::string& name = createVariableName(node);
1186 CGOpCode
op = node.getOperationType();
1187 if (getVariableID(node) >= _minTemporaryVarID ||
op == CGOpCode::ArrayCreation ||
op == CGOpCode::SparseArrayCreation ||
op == CGOpCode::LoopIndexedDep ||
op == CGOpCode::LoopIndexedIndep) {
1189 _code <<
"<mrow id='" << createHtmlID(node) <<
"' class='tmp'>" << name <<
"</mrow>";
1191 }
else if (getVariableID(node) <= _independentSize) {
1193 _code <<
"<mrow id='" << createHtmlID(node) <<
"' class='indep'>" << name <<
"</mrow>";
1197 _code <<
"<mrow id='" << createHtmlID(node) <<
"' class='dep'>" << name <<
"</mrow>";
1204 return printExpressionNoVarCheck(node);
1208 virtual unsigned printExpressionNoVarCheck(Node& node) {
1209 CGOpCode
op = node.getOperationType();
1211 case CGOpCode::ArrayCreation:
1212 printArrayCreationOp(node);
1214 case CGOpCode::SparseArrayCreation:
1215 printSparseArrayCreationOp(node);
1217 case CGOpCode::ArrayElement:
1218 printArrayElementOp(node);
1220 case CGOpCode::Assign:
1221 return printAssignOp(node);
1224 case CGOpCode::Acos:
1225 case CGOpCode::Asin:
1226 case CGOpCode::Atan:
1227 case CGOpCode::Cosh:
1231 case CGOpCode::Sign:
1232 case CGOpCode::Sinh:
1234 case CGOpCode::Sqrt:
1235 case CGOpCode::Tanh:
1237#if CPPAD_USE_CPLUSPLUS_2011
1239 case CGOpCode::Erfc:
1240 case CGOpCode::Asinh:
1241 case CGOpCode::Acosh:
1242 case CGOpCode::Atanh:
1243 case CGOpCode::Expm1:
1244 case CGOpCode::Log1p:
1246 printUnaryFunction(node);
1248 case CGOpCode::AtomicForward:
1249 printAtomicForwardOp(node);
1251 case CGOpCode::AtomicReverse:
1252 printAtomicReverseOp(node);
1255 printOperationAdd(node);
1257 case CGOpCode::Alias:
1258 return printOperationAlias(node);
1260 case CGOpCode::ComLt:
1261 case CGOpCode::ComLe:
1262 case CGOpCode::ComEq:
1263 case CGOpCode::ComGe:
1264 case CGOpCode::ComGt:
1265 case CGOpCode::ComNe:
1266 printConditionalAssignment(node);
1269 printOperationDiv(node);
1272 printIndependentVariableName(node);
1275 printOperationMul(node);
1278 printPowFunction(node);
1284 printOperationMinus(node);
1287 case CGOpCode::UnMinus:
1288 printOperationUnaryMinus(node);
1291 case CGOpCode::DependentMultiAssign:
1292 return printDependentMultiAssign(node);
1294 case CGOpCode::Index:
1296 case CGOpCode::IndexAssign:
1297 printIndexAssign(node);
1299 case CGOpCode::IndexDeclaration:
1302 case CGOpCode::LoopStart:
1303 printLoopStart(node);
1305 case CGOpCode::LoopIndexedIndep:
1306 printLoopIndexedIndep(node);
1308 case CGOpCode::LoopIndexedDep:
1309 printLoopIndexedDep(node);
1311 case CGOpCode::LoopIndexedTmp:
1312 printLoopIndexedTmp(node);
1314 case CGOpCode::TmpDcl:
1320 case CGOpCode::LoopEnd:
1323 case CGOpCode::IndexCondExpr:
1324 printIndexCondExprOp(node);
1326 case CGOpCode::StartIf:
1329 case CGOpCode::ElseIf:
1332 case CGOpCode::Else:
1335 case CGOpCode::EndIf:
1338 case CGOpCode::CondResult:
1339 printCondResult(node);
1341 case CGOpCode::UserCustom:
1342 printUserCustom(node);
1345 throw CGException(
"Unknown operation code '",
op,
"'.");
1350 virtual unsigned printAssignOp(Node& node) {
1351 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1,
"Invalid number of arguments for assign operation")
1353 return print(node.getArguments()[0]);
1356 virtual void printUnaryFunction(Node&
op) {
1357 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 1,
"Invalid number of arguments for unary function")
1361 _code <<
"<mi>abs</mi>";
1363 case CGOpCode::Acos:
1364 _code <<
"<mi>arccos</mi>";
1366 case CGOpCode::Asin:
1367 _code <<
"<mi>arcsin</mi>";
1369 case CGOpCode::Atan:
1370 _code <<
"<mi>arctan</mi>";
1372 case CGOpCode::Cosh:
1373 _code <<
"<mi>cosh</mi>";
1376 _code <<
"<mi>cos</mi>";
1379 _code <<
"<mi>exp</mi>";
1382 _code <<
"<mi>ln</mi>";
1384 case CGOpCode::Sinh:
1385 _code <<
"<mi>sinh</mi>";
1387 case CGOpCode::Sign:
1388 _code <<
"<mi>sgn</mi>";
1391 _code <<
"<mi>sin</mi>";
1393 case CGOpCode::Sqrt:
1394 _code <<
"<msqrt><mrow>";
1395 print(
op.getArguments()[0]);
1396 _code <<
"</mrow></msqrt>";
1398 case CGOpCode::Tanh:
1399 _code <<
"<mi>tanh</mi>";
1402 _code <<
"<mi>tan</mi>";
1404#if CPPAD_USE_CPLUSPLUS_2011
1406 _code <<
"<mi>erf</mi>";
1408 case CGOpCode::Erfc:
1409 _code <<
"<mi>erfc</mi>";
1411 case CGOpCode::Asinh:
1412 _code <<
"<mi>asinh</mi>";
1414 case CGOpCode::Acosh:
1415 _code <<
"<mi>acosh</mi>";
1417 case CGOpCode::Atanh:
1418 _code <<
"<mi>atanh</mi>";
1420 case CGOpCode::Expm1:
1421 _code <<
"<mi>expm1</mi>";
1423 case CGOpCode::Log1p:
1424 _code <<
"<mi>log1p</mi>";
1428 throw CGException(
"Unknown function name for operation code '",
op.getOperationType(),
"'.");
1431 _code <<
"<mo>⁡</mo>"
1433 print(
op.getArguments()[0]);
1434 _code <<
"</mrow></mfenced>";
1437 virtual void printPowFunction(Node&
op) {
1438 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for pow() function")
1441 while (node !=
nullptr) {
1442 if (getVariableID(*node) != 0)
1444 if (node->getOperationType() == CGOpCode::Alias)
1445 node = node->getArguments()[0].getOperation();
1449 return node !=
nullptr &&
1450 getVariableID(*node) == 0 &&
1451 !isFunction(node->getOperationType());
1460 _code <<
"<mfenced>";
1462 print(
op.getArguments()[0]);
1465 _code <<
"</mfenced>";
1467 _code <<
"<mfenced>";
1469 print(
op.getArguments()[1]);
1472 _code <<
"</mfenced>";
1476 virtual unsigned printOperationAlias(Node&
op) {
1477 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 1,
"Invalid number of arguments for alias")
1478 return print(
op.getArguments()[0]);
1481 virtual void printOperationAdd(Node&
op) {
1482 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for addition")
1487 if(
right.getParameter() ==
nullptr || (*
right.getParameter() >= 0)) {
1489 _code <<
"<mo>+</mo>";
1494 _code <<
"<mo>-</mo>";
1495 printParameter(-*
right.getParameter());
1499 virtual void printOperationMinus(Node&
op) {
1500 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for subtraction")
1506 if(
right.getParameter() ==
nullptr || (*
right.getParameter() >= 0)) {
1510 _code <<
"<mo>-</mo>";
1512 _code <<
"<mfenced><mrow>";
1516 _code <<
"</mrow></mfenced>";
1521 _code <<
"<mo>+</mo>";
1522 printParameter(-*
right.getParameter());
1526 virtual void printOperationDiv(Node&
op) {
1527 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for division")
1539 _code << "</
mfrac>";
1543 if (
arg.getParameter() !=
nullptr) {
1544 return ((*
arg.getParameter()) < 0);
1546 return encloseInParenthesesMul(
arg.getOperation());
1550 inline bool encloseInParenthesesMul(
const Node* node)
const {
1551 while (node !=
nullptr) {
1552 if (getVariableID(*node) != 0) {
1554 }
else if (node->getOperationType() == CGOpCode::Alias) {
1555 node = node->getArguments()[0].getOperation();
1560 return node !=
nullptr &&
1561 getVariableID(*node) == 0 &&
1562 node->getOperationType() != CGOpCode::Div &&
1563 node->getOperationType() != CGOpCode::Mul &&
1564 !isFunction(node->getOperationType());
1567 virtual void printOperationMul(Node&
op) {
1568 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 2,
"Invalid number of arguments for multiplication")
1577 while (node !=
nullptr) {
1578 if (getVariableID(*node) != 0) {
1581 CGOpCode
op = node->getOperationType();
1582 if (
op == CGOpCode::Alias) {
1583 node = node->getArguments()[0].getOperation();
1585 }
else if (
op == CGOpCode::Mul) {
1586 node = node->getArguments()[
pos].getOperation();
1587 }
else if (
pos == 0 &&
op == CGOpCode::Pow) {
1588 node = node->getArguments()[0].getOperation();
1597 _code <<
"<mfenced><mrow>";
1601 _code <<
"</mrow></mfenced>";
1605 _code << _multValOpStr;
1607 _code << _multOpStr;
1610 _code <<
"<mfenced><mrow>";
1614 _code <<
"</mrow></mfenced>";
1618 virtual void printOperationUnaryMinus(Node&
op) {
1619 CPPADCG_ASSERT_KNOWN(
op.getArguments().size() == 1,
"Invalid number of arguments for unary minus")
1625 _code << "<
mo>-</
mo>";
1627 _code <<
"<mfenced><mrow>";
1631 _code <<
"</mrow></mfenced>";
1635 virtual void printConditionalAssignment(Node& node) {
1636 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1638 const std::vector<Arg>&
args = node.getArguments();
1644 bool isDep = isDependent(node);
1652 printAssignmentEnd(node);
1655 _code << _ifStart << _startEq <<
"<mi>if</mi>"
1659 getComparison(_code, node.getOperationType());
1662 _code <<
"</mrow></mfenced>" << _endEq << _endline
1663 << _condBodyStart << _endline;
1668 printAssignmentEnd(node);
1669 _code << _condBodyEnd << _endline << _ifEnd << _endline;
1672 _code << _elseStart << _startEq <<
"<mi>else</mi>" << _endEq << _endline
1673 << _condBodyStart << _endline;
1677 printAssignmentEnd(node);
1678 _code << _condBodyEnd << _endline << _elseEnd << _endline;
1682 inline bool isSameArgument(
const Arg&
newArg,
1685 if (
oldArg->getParameter() !=
nullptr) {
1686 if (
newArg.getParameter() !=
nullptr) {
1687 return (*
newArg.getParameter() == *
oldArg->getParameter());
1690 return (
newArg.getOperation() ==
oldArg->getOperation());
1696 virtual void printArrayCreationOp(Node&
op);
1698 virtual void printSparseArrayCreationOp(Node&
op);
1700 inline void printArrayStructInit(
const std::string&
dataArrayName,
1702 const std::vector<Node*>&
arrays,
1705 inline void printArrayStructInit(
const std::string&
dataArrayName,
1708 inline void markArrayChanged(Node&
ty);
1710 inline size_t printArrayCreationUsingLoop(
size_t startPos,
1715 inline std::string getTempArrayName(
const Node&
op);
1717 virtual void printArrayElementOp(Node&
op);
1720 CPPADCG_ASSERT_KNOWN(
atomicFor.getInfo().size() == 3,
"Invalid number of information elements for atomic forward operation")
1725 CPPADCG_ASSERT_KNOWN(
opArgs.size() ==
p1 * 2,
"Invalid number of arguments for atomic forward operation")
1729 for (
size_t k = 0;
k <
p1;
k++) {
1734 CPPADCG_ASSERT_KNOWN(
tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1735 CPPADCG_ASSERT_KNOWN(
p == 0 ||
tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1736 CPPADCG_ASSERT_KNOWN(
ty[
p]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1739 for (
size_t k = 0;
k <
p1;
k++) {
1740 printArrayStructInit(_ATOMIC_TX,
k,
tx,
k);
1743 printArrayStructInit(_ATOMIC_TY, *
ty[
p]);
1748 "<mfenced separators=','>"
1749 "<mn>" <<
q <<
"</mn>"
1750 "<mn>" <<
p <<
"</mn>"
1751 "<mrow class='tmp'>" << _ATOMIC_TX <<
"</mrow>"
1752 "<mrow><mo>&</mo><mrow class='tmp'>" << _ATOMIC_TY <<
"</mrow></mrow>"
1754 << _endEq << _endline;
1759 markArrayChanged(*
ty[
p]);
1763 CPPADCG_ASSERT_KNOWN(
atomicRev.getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation")
1767 CPPADCG_ASSERT_KNOWN(
opArgs.size() ==
p1 * 4,
"Invalid number of arguments for atomic reverse operation")
1771 for (
size_t k = 0;
k <
p1;
k++) {
1777 CPPADCG_ASSERT_KNOWN(
tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1778 CPPADCG_ASSERT_KNOWN(
p == 0 ||
tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1780 CPPADCG_ASSERT_KNOWN(
px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1782 CPPADCG_ASSERT_KNOWN(
py[0]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1783 CPPADCG_ASSERT_KNOWN(
p == 0 ||
py[1]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1786 for (
size_t k = 0;
k <
p1;
k++) {
1787 printArrayStructInit(_ATOMIC_TX,
k,
tx,
k);
1790 for (
size_t k = 0;
k <
p1;
k++) {
1791 printArrayStructInit(_ATOMIC_PY,
k,
py,
k);
1794 printArrayStructInit(_ATOMIC_PX, *
px[0]);
1799 "<mfenced separators=','>"
1800 "<mn>" <<
p <<
"</mn>"
1801 "<mrow class='tmp'>" << _ATOMIC_TX <<
"</mrow>"
1802 "<mrow><mo>&</mo><mrow class='tmp'>" << _ATOMIC_PX <<
"</mrow></mrow>"
1803 "<mrow class='tmp'>" << _ATOMIC_PY <<
"</mrow>"
1805 << _endEq << _endline;
1810 markArrayChanged(*
px[0]);
1813 virtual unsigned printDependentMultiAssign(Node& node) {
1814 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type")
1815 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "
Invalid number of arguments")
1821 if (
arg.getParameter() !=
nullptr) {
1824 CGOpCode
op =
arg.getOperation()->getOperationType();
1825 useArg =
op != CGOpCode::DependentRefRhs &&
op != CGOpCode::LoopEnd &&
op != CGOpCode::EndIf;
1829 printAssignment(node,
arg);
1836 virtual void printLoopStart(Node& node) {
1837 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart,
"Invalid node type")
1840 _currentLoops.push_back(&
lnode);
1844 if (
lnode.getIterationCountNode() !=
nullptr) {
1845 lastIt = *
lnode.getIterationCountNode()->getIndex().getName() +
" <mo>-</mo> <mn>1</mn>";
1847 lastIt =
"<mn>" + std::to_string(
lnode.getIterationCount() - 1) +
"</mn>";
1850 _code << _forStart << _startEq <<
"<mi>for</mi>"
1851 "<mfenced><mrow><mi class='index'>"
1852 <<
jj <<
"</mi><mo>∈</mo>"
1853 "<mfenced open='[' close='[' separators=';'>"
1854 "<mn>0</mn>" <<
lastIt <<
1856 "</mrow></mfenced>" << _endEq << _endline
1858 _indentationLevel++;
1861 virtual void printLoopEnd(Node& node) {
1862 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd,
"Invalid node type")
1864 _indentationLevel--;
1866 _code << _forBodyEnd << _forEnd << _endline;
1868 _currentLoops.pop_back();
1871 virtual void printLoopIndexedDep(Node& node) {
1872 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1,
"Invalid number of arguments for loop indexed dependent operation")
1875 print(node.getArguments()[0]);
1878 virtual void printLoopIndexedIndep(Node& node) {
1879 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep,
"Invalid node type")
1883 size_t pos = node.getInfo()[1];
1884 const IndexPattern*
ip = _info->loopIndependentIndexPatterns[
pos];
1885 _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *
ip);
1888 virtual void printLoopIndexedTmp(Node& node) {
1889 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type")
1891 Node*
tmpVar = node.getArguments()[0].getOperation();
1894 print(node.getArguments()[1]);
1897 virtual void printTmpVar(Node& node) {
1898 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp,
"Invalid node type")
1900 Node*
tmpVar = node.getArguments()[0].getOperation();
1906 virtual void printIndexAssign(Node& node) {
1907 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign,
"Invalid node type")
1914 << "<
mi class='index'>"<< (*
inode.getIndex().getName()) << "</
mi>"
1916 indexPattern2String(_code,
ip,
inode.getIndexPatternIndexes());
1917 _code << _endEq << _endline;
1920 virtual void printIndexCondExprOp(Node& node) {
1921 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr,
"Invalid node type")
1926 const std::vector<
size_t>&
info = node.getInfo();
1928 auto& iterationIndexOp =
static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1929 const std::
string& index = *iterationIndexOp.getIndex().getName();
1931 printIndexCondExpr(_code,
info, index);
1939 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf,
"Invalid node type")
1940 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1,
"Invalid number of arguments for an 'if start' operation")
1941 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'if start' operation")
1943 _code << _ifStart << _startEq <<
"<mi>if</mi>"
1945 printIndexCondExprOp(*node.getArguments()[0].getOperation());
1946 _code <<
"</mrow></mfenced>" << _endEq << _endline
1947 << _condBodyStart << _endline;
1949 _indentationLevel++;
1958 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::ElseIf,
"Invalid node type")
1959 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 2,
"Invalid number of arguments for an 'else if' operation")
1960 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation")
1961 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation")
1963 _indentationLevel--;
1966 _code << _condBodyEnd << _endline;
1968 if (
nType == CGOpCode::StartIf) {
1969 _code << _ifEnd << _endline;
1970 }
else if (
nType == CGOpCode::ElseIf) {
1971 _code << _elseIfEnd << _endline;
1975 _code << _elseIfStart << _startEq <<
"<mi>else if</mi>"
1977 printIndexCondExprOp(*node.
getArguments()[1].getOperation());
1978 _code <<
"</mrow></mfenced>" << _endEq << _endline
1979 << _condBodyStart << _endline;
1981 _indentationLevel++;
1989 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Else,
"Invalid node type")
1990 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'else' operation")
1992 _indentationLevel--;
1995 _code << _condBodyEnd << _endline;
1997 if (
nType == CGOpCode::StartIf) {
1998 _code << _ifEnd << _endline;
1999 }
else if (
nType == CGOpCode::ElseIf) {
2000 _code << _elseIfEnd << _endline;
2004 _code << _elseStart << _startEq <<
"<mi>else</mi>" << _endEq << _endline
2005 << _condBodyStart << _endline;
2006 _code << _elseStart;
2008 _indentationLevel++;
2011 virtual void printEndIf(Node& node) {
2012 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation")
2014 _indentationLevel--;
2017 _code << _condBodyEnd << _endline;
2018 CGOpCode
nType = node.getArguments()[0].getOperation()->getOperationType();
2019 if (
nType == CGOpCode::StartIf) {
2020 _code << _ifEnd << _endline;
2021 }
else if (
nType == CGOpCode::ElseIf) {
2022 _code << _elseIfEnd << _endline;
2025 _code << _elseEnd << _endline;
2029 virtual void printCondResult(Node& node) {
2030 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult,
"Invalid node type")
2036 Node&
nodeArg = *node.getArguments()[1].getOperation();
2040 virtual void printUserCustom(Node& node) {
2041 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom,
"Invalid node type")
2047 if (
arg.getOperationType() == CGOpCode::LoopIndexedDep) {
2050 size_t id = getVariableID(
arg);
2051 return id > _independentSize &&
id < _minTemporaryVarID;
2054 virtual void printParameter(
const Base& value) {
2056 std::ostringstream os;
2057 os << std::setprecision(_parameterPrecision) << value;
2059 std::string
number = os.str();
2061 if (
pos != std::string::npos) {
2062 _code <<
"<mn>" <<
number.substr(0,
pos) <<
"</mn><mo>×</mo>";
2063 _code <<
"<msup><mn>10</mn><mn>";
2074 _code <<
number.substr(
pos) <<
"</mn></msup>";
2077 _code <<
"<mn>" <<
number <<
"</mn>";
2083 virtual void getComparison(std::ostream& os,
enum CGOpCode
op)
const {
2085 case CGOpCode::ComLt:
2089 case CGOpCode::ComLe:
2093 case CGOpCode::ComEq:
2097 case CGOpCode::ComGe:
2101 case CGOpCode::ComGt:
2105 case CGOpCode::ComNe:
2117 return isUnaryFunction(
op) ||
op == CGOpCode::Pow;
2120 static bool isUnaryFunction(
enum CGOpCode
op) {
2123 case CGOpCode::Acos:
2124 case CGOpCode::Asin:
2125 case CGOpCode::Atan:
2126 case CGOpCode::Cosh:
2130 case CGOpCode::Sign:
2131 case CGOpCode::Sinh:
2133 case CGOpCode::Sqrt:
2134 case CGOpCode::Tanh:
2136#if CPPAD_USE_CPLUSPLUS_2011
2138 case CGOpCode::Erfc:
2139 case CGOpCode::Asinh:
2140 case CGOpCode::Acosh:
2141 case CGOpCode::Atanh:
2142 case CGOpCode::Expm1:
2143 case CGOpCode::Log1p:
2151 static bool isCondAssign(
enum CGOpCode
op) {
2153 case CGOpCode::ComLt:
2154 case CGOpCode::ComLe:
2155 case CGOpCode::ComEq:
2156 case CGOpCode::ComGe:
2157 case CGOpCode::ComGt:
2158 case CGOpCode::ComNe: