1 #ifndef CPPAD_CG_LANGUAGE_MATHML_INCLUDED 2 #define CPPAD_CG_LANGUAGE_MATHML_INCLUDED 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),
157 _parameterPrecision(
std::numeric_limits<Base>::digits10),
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) {
177 _assignAddStr = assignAdd;
200 _multOpStr = multOpStr;
209 return _multValOpStr;
221 _multValOpStr = 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 {
255 _javascript = javascript;
258 const std::string& getJavascript()
const {
268 _headExtra = headExtra;
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;
434 _powBaseEnclose = enclose;
444 return _powBaseEnclose;
447 virtual void setMaxAssignmentsPerFunction(
size_t maxAssignmentsPerFunction,
448 std::map<std::string, std::string>* sources) {
449 _maxAssignmentsPerFile = maxAssignmentsPerFunction;
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")
469 size_t infoSize = info.size();
470 for (
size_t e = 0; e < infoSize; e += 2) {
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);
515 const std::string& identation,
516 const std::set<RandomIndexPattern*>& randomPatterns);
518 static void indexPattern2String(std::ostream& os,
522 static void indexPattern2String(std::ostream& os,
524 const std::vector<const Node*>& indexes);
526 static inline void linearIndexPattern2String(std::ostream& os,
538 const bool multiFile = _maxAssignmentsPerFile > 0 && _sources !=
nullptr;
543 _indentationLevel = 0;
545 _currentLoops.clear();
546 depConstIds_.clear();
547 depIsIndepIds_.clear();
548 _dependentIDs.clear();
553 _independentSize = info->independent.size();
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++) {
578 Node& op = *info->independent[j];
585 for (
size_t i = 0; i < dependent.
size(); i++) {
586 Node* node = dependent[i].getOperationNode();
589 size_t pos = node->
getInfo()[0];
590 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
602 const std::vector<FuncArgument>& indArg = _nameGen->
getIndependent();
603 const std::vector<FuncArgument>& depArg = _nameGen->
getDependent();
604 const std::vector<FuncArgument>& tmpArg = _nameGen->
getTemporary();
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";
616 std::set<size_t> dependentDuplicates;
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;
630 dependentDuplicates.insert(i);
638 std::vector<std::string> mathMLFiles;
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) {
667 const std::vector<FuncArgument>& depArg = _nameGen->
getDependent();
668 for (
size_t i = 0; i < depArg.size(); i++) {
674 _code <<
"<mrow id='" <<
createHtmlID(*(*_dependent)[i].getOperationNode()) <<
"' class='dep'>" << _nameGen->
generateDependent(i) <<
"</mrow>";
677 printParameter(Base(0.0));
678 _code << _endEq << _endline;
682 size_t assignCount = 0;
683 for (
Node* it : variableOrder) {
685 if (assignCount >= _maxAssignmentsPerFile && multiFile && _currentLoops.empty()) {
687 saveLocalFunction(mathMLFiles, mathMLFiles.empty() && info->zeroDependents);
693 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
695 }
else if (node.getOperationType() == CGOpCode::TmpDcl) {
699 assignCount += printAssignment(node);
702 if (!mathMLFiles.empty() && assignCount > 0) {
704 saveLocalFunction(mathMLFiles,
false);
708 if (!mathMLFiles.empty()) {
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);
715 for (
size_t i = 0; i < mathMLFiles.size(); i++) {
716 _code <<
"<a href='" << mathMLFiles[i] <<
".html'>part " << (i + 1) <<
"</a><br/>" << _endline;
718 printAlgorithmFileEnd(_code);
722 if (!dependentDuplicates.empty()) {
723 _code <<
"<!-- variable duplicates: " << dependentDuplicates.size() <<
" -->" << _endline;
725 for (
size_t index : dependentDuplicates) {
726 const CG<Base>& dep = dependent[index];
728 Node* depNode = dep.getOperationNode();
729 const std::string& origVarName = *depNode->
getName();
732 <<
"<mrow id='" <<
createHtmlID(depNode) <<
"' class='dep'>" << varName <<
"</mrow>" 734 <<
"<mrow id='" <<
createHtmlID(depNode) <<
"' class='dep'>" << origVarName <<
"</mrow>";
735 printAssignmentEnd();
740 bool commentWritten =
false;
741 for (
size_t i = 0; i < dependent.
size(); i++) {
742 if (dependent[i].isParameter()) {
743 if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
744 if (!commentWritten) {
745 _code <<
"<!-- dependent variables without operations -->" << _endline;
746 commentWritten =
true;
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) {
761 if (!commentWritten) {
762 _code <<
"<!-- dependent variables without operations -->" << _endline;
763 commentWritten =
true;
767 const std::string& indepName = *dependent[i].getOperationNode()->getName();
768 std::string depId =
createHtmlID(dependent[i].getOperationNode());
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());
783 if (mathMLFiles.empty()) {
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) {
825 out <<
"<script type=\"text/javascript\">" << _endline;
826 out <<
" var depConst = [];" << _endline;
827 out <<
" var depIsVar = [];" << _endline;
828 out <<
" var var2dep = {" << _endline;
833 for (
size_t i = 0; i < varDeps.size(); ++i) {
834 if (!varDeps[i].empty()) {
838 out <<
"," << _endline;
840 out <<
" \"" <<
getHtmlID(*varOrder[i]) <<
"\": [";
841 for (
const auto* n: varDeps[i]) {
842 if (n != *varDeps[i].begin()) out <<
", ";
848 out << _endline <<
" };" << _endline;
851 out <<
" var dep2var = {" << _endline;
853 std::map<size_t, std::set<size_t> > deps2Var;
854 for (
size_t i = 0; i < varDeps.size(); ++i) {
856 for (
const auto* n: varDeps[i]) {
858 deps2Var[idj].insert(idi);
862 for (
const auto& pair: deps2Var) {
863 if (pair.first != deps2Var.begin()->first) {
864 out <<
"," << _endline;
866 out <<
" \"" << pair.first <<
"\": [";
867 for (
size_t j: pair.second) {
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,
928 const Arg& nodeRhs) {
929 if (nodeRhs.getOperation() !=
nullptr) {
930 return printAssignment(nodeName, *nodeRhs.getOperation());
932 printAssignmentStart(nodeName);
933 printParameter(*nodeRhs.getParameter());
934 printAssignmentEnd(nodeName);
939 inline unsigned printAssignment(
Node& nodeName,
943 printAssignmentStart(nodeName);
945 unsigned lines = printExpressionNoVarCheck(nodeRhs);
947 printAssignmentEnd(nodeRhs);
952 size_t arrayId = getVariableID(*array);
953 size_t pos = nodeRhs.
getInfo()[0];
955 _tmpArrayValues[arrayId - 1 + pos] =
nullptr;
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>";
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,
988 bool zeroDependentArray) {
989 _ss << _filename <<
"__part_" << (localFuncNames.size() + 1);
990 std::string funcName = _ss.str();
994 _nameGen->prepareCustomFunctionVariables(_ss);
996 _nameGen->finalizeCustomFunctionVariables(_ss);
998 (*_sources)[funcName +
".html"] = _ss.str();
999 localFuncNames.push_back(funcName);
1006 size_t totalUseCount,
1007 size_t opCount)
const override {
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 {
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);
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) {
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())
1115 size_t index = it->second;
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")
1121 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1122 return createVariableName(*tmpVar);
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")
1171 virtual unsigned print(
const Arg& arg) {
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);
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) {
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:
1251 case CGOpCode::AtomicReverse:
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")
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>";
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>";
1431 _code <<
"<mo>⁡</mo>" 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")
1440 auto encloseInParentheses = [
this](
const Node* node) {
1441 while (node !=
nullptr) {
1442 if (getVariableID(*node) != 0)
1449 return node !=
nullptr &&
1450 getVariableID(*node) == 0 &&
1455 bool encloseBase = _powBaseEnclose || encloseInParentheses(op.
getArguments()[0].getOperation());
1456 bool encloseExpo = encloseInParentheses(op.
getArguments()[1].getOperation());
1460 _code <<
"<mfenced>";
1465 _code <<
"</mfenced>";
1467 _code <<
"<mfenced>";
1472 _code <<
"</mfenced>";
1476 virtual unsigned printOperationAlias(
Node& op) {
1477 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias")
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)) {
1507 bool encloseRight = encloseInParenthesesMul(right);
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>";
1542 inline bool encloseInParenthesesMul(
const Arg& arg)
const {
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) {
1560 return node !=
nullptr &&
1561 getVariableID(*node) == 0 &&
1567 virtual void printOperationMul(
Node& op) {
1568 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication")
1573 bool encloseLeft = encloseInParenthesesMul(left);
1574 bool encloseRight = encloseInParenthesesMul(right);
1576 auto isNumber = [
this](
const Node* node,
int pos) ->
bool {
1577 while (node !=
nullptr) {
1578 if (getVariableID(*node) != 0) {
1582 if (op == CGOpCode::Alias) {
1585 }
else if (op == CGOpCode::Mul) {
1587 }
else if (pos == 0 && op == CGOpCode::Pow) {
1597 _code <<
"<mfenced><mrow>";
1601 _code <<
"</mrow></mfenced>";
1604 if (isNumber(left.getOperation(), 1) && isNumber(right.getOperation(), 0))
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")
1623 bool enclose = encloseInParenthesesMul(arg);
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)
1639 const Arg &left = args[0];
1640 const Arg &right = args[1];
1641 const Arg &trueCase = args[2];
1642 const Arg &falseCase = args[3];
1644 bool isDep = isDependent(node);
1645 const std::string& varName = createVariableName(node);
1647 if ((trueCase.getParameter() !=
nullptr && falseCase.getParameter() !=
nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1648 (trueCase.getOperation() !=
nullptr && falseCase.getOperation() !=
nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1650 printAssignmentStart(node, varName, isDep);
1652 printAssignmentEnd(node);
1655 _code << _ifStart << _startEq <<
"<mi>if</mi>" 1662 _code <<
"</mrow></mfenced>" << _endEq << _endline
1663 << _condBodyStart << _endline;
1666 printAssignmentStart(node, varName, isDep);
1668 printAssignmentEnd(node);
1669 _code << _condBodyEnd << _endline << _ifEnd << _endline;
1672 _code << _elseStart << _startEq <<
"<mi>else</mi>" << _endEq << _endline
1673 << _condBodyStart << _endline;
1675 printAssignmentStart(node, varName, isDep);
1677 printAssignmentEnd(node);
1678 _code << _condBodyEnd << _endline << _elseEnd << _endline;
1682 inline bool isSameArgument(
const Arg& newArg,
1683 const Arg* oldArg) {
1684 if (oldArg !=
nullptr) {
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);
1713 std::vector<const Arg*>& tmpArrayValues);
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")
1721 int q = atomicFor.
getInfo()[1];
1722 int p = atomicFor.
getInfo()[2];
1724 const std::vector<Arg>& opArgs = atomicFor.
getArguments();
1725 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2,
"Invalid number of arguments for atomic forward operation")
1727 size_t id = atomicFor.
getInfo()[0];
1728 std::vector<Node*> tx(p1), ty(p1);
1729 for (
size_t k = 0; k < p1; k++) {
1730 tx[k] = opArgs[0 * p1 + k].getOperation();
1731 ty[k] = opArgs[1 * p1 + k].getOperation();
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")
1764 int p = atomicRev.
getInfo()[1];
1766 const std::vector<Arg>& opArgs = atomicRev.
getArguments();
1767 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4,
"Invalid number of arguments for atomic reverse operation")
1769 size_t id = atomicRev.
getInfo()[0];
1770 std::vector<Node*> tx(p1), px(p1), py(p1);
1771 for (
size_t k = 0; k < p1; k++) {
1772 tx[k] = opArgs[0 * p1 + k].getOperation();
1773 px[k] = opArgs[2 * p1 + k].getOperation();
1774 py[k] = opArgs[3 * p1 + k].getOperation();
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")
1818 for (
size_t a = 0; a < args.size(); a++) {
1820 const Arg& arg = args[a];
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);
1842 const std::string& jj = *lnode.getIndex().getName();
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")
1878 virtual void printLoopIndexedIndep(
Node& node) {
1879 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedIndep,
"Invalid node type")
1880 CPPADCG_ASSERT_KNOWN(node.
getInfo().size() == 1,
"Invalid number of information elements for loop indexed independent operation")
1883 size_t pos = node.
getInfo()[1];
1884 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1888 virtual void printLoopIndexedTmp(
Node& node) {
1889 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type")
1890 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for loop indexed temporary operation")
1892 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1897 virtual void printTmpVar(
Node& node) {
1898 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Tmp,
"Invalid node type")
1899 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for temporary variable usage operation")
1901 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1903 _code <<
"<mrow id='" <<
createHtmlID(tmpVar) <<
"' class='tmp'>" << *tmpVar->getName() <<
"</mrow>";
1906 virtual void printIndexAssign(
Node& node) {
1907 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexAssign,
"Invalid node type")
1908 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for an index assignment operation")
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")
1922 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for an index condition expression operation")
1923 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an index condition expression operation")
1924 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index,
"Invalid argument for an index condition expression operation")
1926 const std::vector<size_t>& info = node.
getInfo();
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;
1967 CGOpCode nType = node.
getArguments()[0].getOperation()->getOperationType();
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;
1996 CGOpCode nType = node.
getArguments()[0].getOperation()->getOperationType();
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;
2024 assert(nType == CGOpCode::Else);
2025 _code << _elseEnd << _endline;
2029 virtual void printCondResult(
Node& node) {
2030 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::CondResult,
"Invalid node type")
2031 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for an assignment inside an if/else operation")
2032 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation")
2033 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation")
2037 printAssignment(nodeArg);
2040 virtual void printUserCustom(
Node& node) {
2041 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::UserCustom,
"Invalid node type")
2043 throw CGException(
"Unable to generate MathML for user custom operation nodes.");
2046 inline bool isDependent(
const Node& arg)
const {
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();
2060 size_t pos = number.find(
'e');
2061 if (pos != std::string::npos) {
2062 _code <<
"<mn>" << number.substr(0, pos) <<
"</mn><mo>×</mo>";
2063 _code <<
"<msup><mn>10</mn><mn>";
2065 if (number[pos] ==
'-') {
2068 }
else if (number[pos] ==
'+') {
2071 while (pos < number.size() - 1 && number[pos] ==
'0')
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:
2110 CPPAD_ASSERT_UNKNOWN(0)
2113 throw CGException(
"Invalid comparison operator code");
2116 static bool isFunction(
enum CGOpCode op) {
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:
2166 template<
class Base>
2169 template<
class Base>
2172 template<
class Base>
2175 template<
class Base>
2178 template<
class Base>
2181 template<
class Base>
virtual void setEquationMarkup(const std::string &begin, const std::string &end)
void setHeadExtraMarkup(const std::string &headExtra)
virtual const std::string & getElseIfEndMarkup() const
virtual void printElse(Node &node)
const std::map< size_t, std::string > & atomicFunctionId2Name
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual bool isAlwaysEnclosePowBase() const
virtual size_t getMaxTemporaryArrayVariableID() const =0
virtual const std::string & getEquationEndMarkup() const
virtual void printElseIf(Node &node)
virtual const std::string & getEquationStartMarkup() const
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual void setForMarkup(const std::string &begin, const std::string &end)
virtual const std::string & getElseEndMarkup() const
const std::string * getName() const
const std::vector< Argument< Base > > & getArguments() const
virtual const std::vector< FuncArgument > & getTemporary() const
virtual size_t getParameterPrecision() const
virtual void setAlwaysEnclosePowBase(bool enclose)
size_t getHandlerPosition() const
virtual void printStartIf(Node &node)
const CodeHandlerVector< Base, size_t > & varId
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
virtual std::string generateDependent(size_t index)=0
size_t getHtmlID(const Node &var) const
virtual const std::string & getIfEndMarkup() const
void setStyle(const std::string &style)
void setJavascript(const std::string &javascript)
virtual void setParameterPrecision(size_t p)
const std::string & getMultiplicationMarkup() const
const CodeHandlerVector< Base, size_t > & totalUseCount
const std::string & getMultiplicationConstParMarkup() const
CGOpCode getOperationType() const
std::string createHtmlID(const Node *var)
virtual void setIfMarkup(const std::string &begin, const std::string &end)
virtual bool directlyAssignsVariable(const Node &var) const
virtual const std::string & getElseIfStartMarkup() const
virtual void setElseMarkup(const std::string &begin, const std::string &end)
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg *> &tmpArrayValues)
virtual size_t getMaxTemporarySparseArrayVariableID() const =0
virtual const std::vector< FuncArgument > & getDependent() const
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
virtual void setElseIfMarkup(const std::string &begin, const std::string &end)
virtual const std::string & getForEndMarkup() const
void setMultiplicationMarkup(const std::string &multOpStr)
virtual const std::vector< FuncArgument > & getIndependent() const
virtual const std::string & getForStartMarkup() const
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
void setName(const std::string &name)
virtual void printAtomicForwardOp(Node &atomicFor)
bool requiresVariableDependencies() const override
virtual const std::string & getIfStartMarkup() const
const std::vector< std::set< Node * > > & variableDependencies
virtual std::string createHtmlID(const Node &var)
const std::vector< Node * > & variableOrder
size_t size() const noexcept
virtual void printAtomicReverseOp(Node &atomicRev)
void printStaticIndexMatrix(std::ostringstream &os, const std::string &name, const std::map< size_t, std::map< size_t, size_t > > &values)
virtual const std::string & getElseStartMarkup() const
void setMultiplicationConstParMarkup(const std::string &multValOpStr)
const std::vector< size_t > & getInfo() const