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(
"<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) {
165 inline const std::string& getAssignMarkup()
const {
169 inline void setAssignMarkup(
const std::string& assign) {
173 inline const std::string& getAddAssignMarkup()
const {
174 return _assignAddStr;
177 inline void setAddAssignMarkup(
const std::string& assignAdd) {
178 _assignAddStr = assignAdd;
201 _multOpStr = multOpStr;
210 return _multValOpStr;
222 _multValOpStr = multValOpStr;
225 inline bool isIgnoreZeroDepAssign()
const {
226 return _ignoreZeroDepAssign;
229 inline void setIgnoreZeroDepAssign(
bool ignore) {
230 _ignoreZeroDepAssign = ignore;
233 void setFilename(
const std::string& name) {
246 const std::string& getStyle()
const {
256 _javascript = javascript;
259 const std::string& getJavascript()
const {
269 _headExtra = headExtra;
272 const std::string& getHeadExtraMarkup()
const {
283 const std::string& end) {
309 const std::string& end) {
335 const std::string& end) {
361 const std::string& end) {
362 _elseIfStart = begin;
387 const std::string& end) {
413 return _parameterPrecision;
423 _parameterPrecision = p;
435 _powBaseEnclose = enclose;
445 return _powBaseEnclose;
448 virtual void setMaxAssignmentsPerFunction(
size_t maxAssignmentsPerFunction,
449 std::map<std::string, std::string>* sources) {
450 _maxAssignmentsPerFile = maxAssignmentsPerFunction;
454 inline void setSaveVariableRelations(
bool save) {
455 _saveVariableRelations = save;
459 return _saveVariableRelations;
465 static inline void printIndexCondExpr(std::ostringstream& out,
466 const std::vector<size_t>& info,
467 const std::string& index) {
468 CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0,
"Invalid number of information elements for an index condition expression operation");
470 size_t infoSize = info.size();
471 for (
size_t e = 0; e < infoSize; e += 2) {
473 out <<
"<mo>∨</mo>";
475 size_t min = info[e];
476 size_t max = info[e + 1];
478 out <<
"<mi class='index'>" << index <<
"</mi><mo>==</mo><mn>" << min <<
"</nm>";
479 }
else if (min == 0) {
480 out <<
"<mi class='index'>" << index <<
"</mi><mo>≤</mo><mn>" << max <<
"</mn>";
481 }
else if (max == std::numeric_limits<size_t>::max()) {
482 out <<
"<mn>" << min <<
"</mn><mo>≤</mo><mi class='index'>" << index <<
"</mi>";
485 out <<
"<mfenced><mrow>";
488 out <<
"<mn>" << min <<
"</mn><mo>==</mo><mi class='index'>" << index <<
"</mi><mo>∨</mo><mi class='index'>" << index <<
"</mi><mo>==</mo><mn>" << max <<
"</mn>";
490 out <<
"<mn>" << min <<
"</mn><mo>≤</mo><mi class='index'>" << index <<
"</mi><mo>∧</mo><mi class='index'>" << index <<
"</mi><mo>≤</mo><mn>" << max <<
"</mn";
493 out <<
"</mrow></mfenced>";
502 inline void printStaticIndexArray(std::ostringstream& os,
503 const std::string& name,
504 const std::vector<size_t>& values);
507 const std::string& name,
508 const std::map<
size_t, std::map<size_t, size_t> >& values);
513 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>& randomPatterns);
516 const std::string& identation,
517 const std::set<RandomIndexPattern*>& randomPatterns);
519 static void indexPattern2String(std::ostream& os,
523 static void indexPattern2String(std::ostream& os,
525 const std::vector<const Node*>& indexes);
527 static inline void linearIndexPattern2String(std::ostream& os,
539 const bool multiFile = _maxAssignmentsPerFile > 0 && _sources !=
nullptr;
544 _indentationLevel = 0;
546 _currentLoops.clear();
547 depConstIds_.clear();
548 depIsIndepIds_.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.size() > 0 && depArg.size() > 0,
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 std::map<size_t, size_t>::const_iterator 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.size() > 0 && 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.size() > 0) {
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)
const override {
1008 if (totalUseCount > 1) {
1009 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1011 return ( op == CGOpCode::ArrayCreation ||
1012 op == CGOpCode::SparseArrayCreation ||
1013 op == CGOpCode::AtomicForward ||
1014 op == CGOpCode::AtomicReverse ||
1015 op == CGOpCode::ComLt ||
1016 op == CGOpCode::ComLe ||
1017 op == CGOpCode::ComEq ||
1018 op == CGOpCode::ComGe ||
1019 op == CGOpCode::ComGt ||
1020 op == CGOpCode::ComNe ||
1021 op == CGOpCode::LoopIndexedDep ||
1022 op == CGOpCode::LoopIndexedTmp ||
1023 op == CGOpCode::IndexAssign ||
1024 op == CGOpCode::Assign) &&
1025 op != CGOpCode::CondResult;
1029 virtual bool requiresVariableName(
const Node& var)
const {
1032 op != CGOpCode::AtomicForward &&
1033 op != CGOpCode::AtomicReverse &&
1034 op != CGOpCode::LoopStart &&
1035 op != CGOpCode::LoopEnd &&
1036 op != CGOpCode::Index &&
1037 op != CGOpCode::IndexAssign &&
1038 op != CGOpCode::StartIf &&
1039 op != CGOpCode::ElseIf &&
1040 op != CGOpCode::Else &&
1041 op != CGOpCode::EndIf &&
1042 op != CGOpCode::CondResult &&
1043 op != CGOpCode::LoopIndexedTmp &&
1044 op != CGOpCode::Tmp);
1056 return isCondAssign(op) ||
1057 op == CGOpCode::ArrayCreation ||
1058 op == CGOpCode::SparseArrayCreation ||
1059 op == CGOpCode::AtomicForward ||
1060 op == CGOpCode::AtomicReverse ||
1061 op == CGOpCode::DependentMultiAssign ||
1062 op == CGOpCode::LoopStart ||
1063 op == CGOpCode::LoopEnd ||
1064 op == CGOpCode::IndexAssign ||
1065 op == CGOpCode::StartIf ||
1066 op == CGOpCode::ElseIf ||
1067 op == CGOpCode::Else ||
1068 op == CGOpCode::EndIf ||
1069 op == CGOpCode::CondResult ||
1070 op == CGOpCode::IndexDeclaration;
1073 bool requiresVariableArgument(
enum CGOpCode op,
size_t argIndex)
const override {
1074 return op == CGOpCode::CondResult;
1077 inline const std::string& createVariableName(
Node& var) {
1079 CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0);
1080 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward);
1081 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse);
1082 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart);
1083 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd);
1084 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index);
1085 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign);
1086 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration);
1088 if (var.
getName() ==
nullptr) {
1089 if (op == CGOpCode::ArrayCreation) {
1092 }
else if (op == CGOpCode::SparseArrayCreation) {
1095 }
else if (op == CGOpCode::LoopIndexedDep) {
1096 size_t pos = var.
getInfo()[0];
1097 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
1100 }
else if (op == CGOpCode::LoopIndexedIndep) {
1101 size_t pos = var.
getInfo()[1];
1102 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1105 }
else if (getVariableID(var) <= _independentSize) {
1109 }
else if (getVariableID(var) < _minTemporaryVarID) {
1111 std::map<size_t, size_t>::const_iterator it = _dependentIDs.find(getVariableID(var));
1112 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
1114 size_t index = it->second;
1117 }
else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
1118 CPPADCG_ASSERT_KNOWN(var.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed temporary operation");
1120 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1121 return createVariableName(*tmpVar);
1152 if (varIds_.size() <= id) {
1153 varIds_.resize(
id + 1 + varIds_.size() * 3 / 2, 0);
1156 int n = varIds_[id];
1160 return "v" + std::to_string(
id);
1162 return "v" + std::to_string(
id) +
"_" + std::to_string(n);
1165 virtual void printIndependentVariableName(
Node& op) {
1166 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 0,
"Invalid number of arguments for independent variable");
1170 virtual unsigned print(
const Arg& arg) {
1171 if (arg.getOperation() !=
nullptr) {
1173 return printExpression(*arg.getOperation());
1176 printParameter(*arg.getParameter());
1181 virtual unsigned printExpression(
Node& node) {
1182 if (getVariableID(node) > 0) {
1183 const std::string& name = createVariableName(node);
1186 if (getVariableID(node) >= _minTemporaryVarID || op == CGOpCode::ArrayCreation || op == CGOpCode::SparseArrayCreation || op == CGOpCode::LoopIndexedDep || op == CGOpCode::LoopIndexedIndep) {
1188 _code <<
"<mrow id='" <<
createHtmlID(node) <<
"' class='tmp'>" << name <<
"</mrow>";
1190 }
else if (getVariableID(node) <= _independentSize) {
1192 _code <<
"<mrow id='" <<
createHtmlID(node) <<
"' class='indep'>" << name <<
"</mrow>";
1196 _code <<
"<mrow id='" <<
createHtmlID(node) <<
"' class='dep'>" << name <<
"</mrow>";
1203 return printExpressionNoVarCheck(node);
1207 virtual unsigned printExpressionNoVarCheck(
Node& node) {
1210 case CGOpCode::ArrayCreation:
1211 printArrayCreationOp(node);
1213 case CGOpCode::SparseArrayCreation:
1214 printSparseArrayCreationOp(node);
1216 case CGOpCode::ArrayElement:
1217 printArrayElementOp(node);
1219 case CGOpCode::Assign:
1220 return printAssignOp(node);
1223 case CGOpCode::Acos:
1224 case CGOpCode::Asin:
1225 case CGOpCode::Atan:
1226 case CGOpCode::Cosh:
1230 case CGOpCode::Sign:
1231 case CGOpCode::Sinh:
1233 case CGOpCode::Sqrt:
1234 case CGOpCode::Tanh:
1236 printUnaryFunction(node);
1238 case CGOpCode::AtomicForward:
1241 case CGOpCode::AtomicReverse:
1245 printOperationAdd(node);
1247 case CGOpCode::Alias:
1248 return printOperationAlias(node);
1250 case CGOpCode::ComLt:
1251 case CGOpCode::ComLe:
1252 case CGOpCode::ComEq:
1253 case CGOpCode::ComGe:
1254 case CGOpCode::ComGt:
1255 case CGOpCode::ComNe:
1256 printConditionalAssignment(node);
1259 printOperationDiv(node);
1262 printIndependentVariableName(node);
1265 printOperationMul(node);
1268 printPowFunction(node);
1274 printOperationMinus(node);
1277 case CGOpCode::UnMinus:
1278 printOperationUnaryMinus(node);
1281 case CGOpCode::DependentMultiAssign:
1282 return printDependentMultiAssign(node);
1284 case CGOpCode::Index:
1286 case CGOpCode::IndexAssign:
1287 printIndexAssign(node);
1289 case CGOpCode::IndexDeclaration:
1292 case CGOpCode::LoopStart:
1293 printLoopStart(node);
1295 case CGOpCode::LoopIndexedIndep:
1296 printLoopIndexedIndep(node);
1298 case CGOpCode::LoopIndexedDep:
1299 printLoopIndexedDep(node);
1301 case CGOpCode::LoopIndexedTmp:
1302 printLoopIndexedTmp(node);
1304 case CGOpCode::TmpDcl:
1310 case CGOpCode::LoopEnd:
1313 case CGOpCode::IndexCondExpr:
1314 printIndexCondExprOp(node);
1316 case CGOpCode::StartIf:
1319 case CGOpCode::ElseIf:
1322 case CGOpCode::Else:
1325 case CGOpCode::EndIf:
1328 case CGOpCode::CondResult:
1329 printCondResult(node);
1331 case CGOpCode::UserCustom:
1332 printUserCustom(node);
1335 throw CGException(
"Unknown operation code '", op,
"'.");
1340 virtual unsigned printAssignOp(
Node& node) {
1341 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for assign operation");
1346 virtual void printUnaryFunction(
Node& op) {
1347 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary function");
1351 _code <<
"<mi>abs</mi>";
1353 case CGOpCode::Acos:
1354 _code <<
"<mi>arccos</mi>";
1356 case CGOpCode::Asin:
1357 _code <<
"<mi>arcsin</mi>";
1359 case CGOpCode::Atan:
1360 _code <<
"<mi>arctan</mi>";
1362 case CGOpCode::Cosh:
1363 _code <<
"<mi>cosh</mi>";
1366 _code <<
"<mi>cos</mi>";
1369 _code <<
"<mi>exp</mi>";
1372 _code <<
"<mi>ln</mi>";
1374 case CGOpCode::Sinh:
1375 _code <<
"<mi>sinh</mi>";
1377 case CGOpCode::Sign:
1378 _code <<
"<mi>sgn</mi>";
1381 _code <<
"<mi>sin</mi>";
1383 case CGOpCode::Sqrt:
1384 _code <<
"<msqrt><mrow>";
1386 _code <<
"</mrow></msqrt>";
1388 case CGOpCode::Tanh:
1389 _code <<
"<mi>tanh</mi>";
1392 _code <<
"<mi>tan</mi>";
1398 _code <<
"<mo>⁡</mo>" 1401 _code <<
"</mrow></mfenced>";
1404 virtual void printPowFunction(
Node& op) {
1405 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for pow() function");
1407 auto encloseInParentheses = [
this](
const Node* node) {
1408 while (node !=
nullptr) {
1409 if (getVariableID(*node) != 0)
1416 return node !=
nullptr &&
1417 getVariableID(*node) == 0 &&
1422 bool encloseBase = _powBaseEnclose || encloseInParentheses(op.
getArguments()[0].getOperation());
1423 bool encloseExpo = encloseInParentheses(op.
getArguments()[1].getOperation());
1427 _code <<
"<mfenced>";
1432 _code <<
"</mfenced>";
1434 _code <<
"<mfenced>";
1439 _code <<
"</mfenced>";
1443 virtual unsigned printOperationAlias(
Node& op) {
1444 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias");
1448 virtual void printOperationAdd(
Node& op) {
1449 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for addition");
1454 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1456 _code <<
"<mo>+</mo>";
1461 _code <<
"<mo>-</mo>";
1462 printParameter(-*right.getParameter());
1466 virtual void printOperationMinus(
Node& op) {
1467 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for subtraction");
1473 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1474 bool encloseRight = encloseInParenthesesMul(right);
1477 _code <<
"<mo>-</mo>";
1479 _code <<
"<mfenced><mrow>";
1483 _code <<
"</mrow></mfenced>";
1488 _code <<
"<mo>+</mo>";
1489 printParameter(-*right.getParameter());
1493 virtual void printOperationDiv(
Node& op) {
1494 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for division");
1506 _code <<
"</mfrac>";
1509 inline bool encloseInParenthesesMul(
const Arg& arg)
const {
1510 if (arg.getParameter() !=
nullptr) {
1511 return ((*arg.getParameter()) < 0);
1513 return encloseInParenthesesMul(arg.getOperation());
1517 inline bool encloseInParenthesesMul(
const Node* node)
const {
1518 while (node !=
nullptr) {
1519 if (getVariableID(*node) != 0) {
1527 return node !=
nullptr &&
1528 getVariableID(*node) == 0 &&
1534 virtual void printOperationMul(
Node& op) {
1535 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication");
1540 bool encloseLeft = encloseInParenthesesMul(left);
1541 bool encloseRight = encloseInParenthesesMul(right);
1543 auto isNumber = [
this](
const Node* node,
int pos) ->
bool {
1544 while (node !=
nullptr) {
1545 if (getVariableID(*node) != 0) {
1549 if (op == CGOpCode::Alias) {
1552 }
else if (op == CGOpCode::Mul) {
1554 }
else if (pos == 0 && op == CGOpCode::Pow) {
1564 _code <<
"<mfenced><mrow>";
1568 _code <<
"</mrow></mfenced>";
1571 if (isNumber(left.getOperation(), 1) && isNumber(right.getOperation(), 0))
1572 _code << _multValOpStr;
1574 _code << _multOpStr;
1577 _code <<
"<mfenced><mrow>";
1581 _code <<
"</mrow></mfenced>";
1585 virtual void printOperationUnaryMinus(
Node& op) {
1586 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary minus");
1590 bool enclose = encloseInParenthesesMul(arg);
1592 _code <<
"<mo>-</mo>";
1594 _code <<
"<mfenced><mrow>";
1598 _code <<
"</mrow></mfenced>";
1602 virtual void printConditionalAssignment(
Node& node) {
1603 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
1606 const Arg &left = args[0];
1607 const Arg &right = args[1];
1608 const Arg &trueCase = args[2];
1609 const Arg &falseCase = args[3];
1611 bool isDep = isDependent(node);
1612 const std::string& varName = createVariableName(node);
1614 if ((trueCase.getParameter() !=
nullptr && falseCase.getParameter() !=
nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1615 (trueCase.getOperation() !=
nullptr && falseCase.getOperation() !=
nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1617 printAssignmentStart(node, varName, isDep);
1619 printAssignmentEnd(node);
1622 _code << _ifStart << _startEq <<
"<mi>if</mi>" 1629 _code <<
"</mrow></mfenced>" << _endEq << _endline
1630 << _condBodyStart << _endline;
1633 printAssignmentStart(node, varName, isDep);
1635 printAssignmentEnd(node);
1636 _code << _condBodyEnd << _endline << _ifEnd << _endline;
1639 _code << _elseStart << _startEq <<
"<mi>else</mi>" << _endEq << _endline
1640 << _condBodyStart << _endline;
1642 printAssignmentStart(node, varName, isDep);
1644 printAssignmentEnd(node);
1645 _code << _condBodyEnd << _endline << _elseEnd << _endline;
1649 inline bool isSameArgument(
const Arg& newArg,
1650 const Arg* oldArg) {
1651 if (oldArg !=
nullptr) {
1652 if (oldArg->getParameter() !=
nullptr) {
1653 if (newArg.getParameter() !=
nullptr) {
1654 return (*newArg.getParameter() == *oldArg->getParameter());
1657 return (newArg.getOperation() == oldArg->getOperation());
1663 virtual void printArrayCreationOp(
Node& op);
1665 virtual void printSparseArrayCreationOp(
Node& op);
1667 inline void printArrayStructInit(
const std::string& dataArrayName,
1669 const std::vector<Node*>& arrays,
1672 inline void printArrayStructInit(
const std::string& dataArrayName,
1675 inline void markArrayChanged(
Node& ty);
1680 std::vector<const Arg*>& tmpArrayValues);
1682 inline std::string getTempArrayName(
const Node& op);
1684 virtual void printArrayElementOp(
Node& op);
1687 CPPADCG_ASSERT_KNOWN(atomicFor.
getInfo().size() == 3,
"Invalid number of information elements for atomic forward operation");
1688 int q = atomicFor.
getInfo()[1];
1689 int p = atomicFor.
getInfo()[2];
1691 const std::vector<Arg>& opArgs = atomicFor.
getArguments();
1692 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2,
"Invalid number of arguments for atomic forward operation");
1694 size_t id = atomicFor.
getInfo()[0];
1695 std::vector<Node*> tx(p1), ty(p1);
1696 for (
size_t k = 0; k < p1; k++) {
1697 tx[k] = opArgs[0 * p1 + k].getOperation();
1698 ty[k] = opArgs[1 * p1 + k].getOperation();
1701 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1702 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1703 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1706 for (
size_t k = 0; k < p1; k++) {
1707 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1710 printArrayStructInit(_ATOMIC_TY, *ty[p]);
1715 "<mfenced separators=','>" 1716 "<mn>" << q <<
"</mn>" 1717 "<mn>" << p <<
"</mn>" 1718 "<mrow class='tmp'>" << _ATOMIC_TX <<
"</mrow>" 1719 "<mrow><mo>&</mo><mrow class='tmp'>" << _ATOMIC_TY <<
"</mrow></mrow>" 1721 << _endEq << _endline;
1726 markArrayChanged(*ty[p]);
1730 CPPADCG_ASSERT_KNOWN(atomicRev.
getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation");
1731 int p = atomicRev.
getInfo()[1];
1733 const std::vector<Arg>& opArgs = atomicRev.
getArguments();
1734 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4,
"Invalid number of arguments for atomic reverse operation");
1736 size_t id = atomicRev.
getInfo()[0];
1737 std::vector<Node*> tx(p1), px(p1), py(p1);
1738 for (
size_t k = 0; k < p1; k++) {
1739 tx[k] = opArgs[0 * p1 + k].getOperation();
1740 px[k] = opArgs[2 * p1 + k].getOperation();
1741 py[k] = opArgs[3 * p1 + k].getOperation();
1744 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1745 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1747 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1749 CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1750 CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1753 for (
size_t k = 0; k < p1; k++) {
1754 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1757 for (
size_t k = 0; k < p1; k++) {
1758 printArrayStructInit(_ATOMIC_PY, k, py, k);
1761 printArrayStructInit(_ATOMIC_PX, *px[0]);
1766 "<mfenced separators=','>" 1767 "<mn>" << p <<
"</mn>" 1768 "<mrow class='tmp'>" << _ATOMIC_TX <<
"</mrow>" 1769 "<mrow><mo>&</mo><mrow class='tmp'>" << _ATOMIC_PX <<
"</mrow></mrow>" 1770 "<mrow class='tmp'>" << _ATOMIC_PY <<
"</mrow>" 1772 << _endEq << _endline;
1777 markArrayChanged(*px[0]);
1780 virtual unsigned printDependentMultiAssign(
Node& node) {
1781 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type");
1782 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments");
1785 for (
size_t a = 0; a < args.size(); a++) {
1786 bool useArg =
false;
1787 const Arg& arg = args[a];
1788 if (arg.getParameter() !=
nullptr) {
1791 CGOpCode op = arg.getOperation()->getOperationType();
1792 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1796 printAssignment(node, arg);
1803 virtual void printLoopStart(
Node& node) {
1804 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopStart,
"Invalid node type");
1807 _currentLoops.push_back(&lnode);
1809 const std::string& jj = *lnode.getIndex().getName();
1811 if (lnode.getIterationCountNode() !=
nullptr) {
1812 lastIt = *lnode.getIterationCountNode()->getIndex().getName() +
" <mo>-</mo> <mn>1</mn>";
1814 lastIt =
"<mn>" + std::to_string(lnode.getIterationCount() - 1) +
"</mn>";
1817 _code << _forStart << _startEq <<
"<mi>for</mi>" 1818 "<mfenced><mrow><mi class='index'>" 1819 << jj <<
"</mi><mo>∈</mo>" 1820 "<mfenced open='[' close='[' separators=';'>" 1821 "<mn>0</mn>" << lastIt <<
1823 "</mrow></mfenced>" << _endEq << _endline
1825 _indentationLevel++;
1828 virtual void printLoopEnd(
Node& node) {
1829 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopEnd,
"Invalid node type");
1831 _indentationLevel--;
1833 _code << _forBodyEnd << _forEnd << _endline;
1835 _currentLoops.pop_back();
1838 virtual void printLoopIndexedDep(
Node& node) {
1839 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed dependent operation");
1845 virtual void printLoopIndexedIndep(
Node& node) {
1846 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedIndep,
"Invalid node type");
1847 CPPADCG_ASSERT_KNOWN(node.
getInfo().size() == 1,
"Invalid number of information elements for loop indexed independent operation");
1850 size_t pos = node.
getInfo()[1];
1851 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1855 virtual void printLoopIndexedTmp(
Node& node) {
1856 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type");
1857 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for loop indexed temporary operation");
1859 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1864 virtual void printTmpVar(
Node& node) {
1865 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Tmp,
"Invalid node type");
1866 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for temporary variable usage operation");
1868 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1870 _code <<
"<mrow id='" <<
createHtmlID(tmpVar) <<
"' class='tmp'>" << *tmpVar->getName() <<
"</mrow>";
1873 virtual void printIndexAssign(
Node& node) {
1874 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexAssign,
"Invalid node type");
1875 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for an index assignment operation");
1881 <<
"<mi class='index'>"<< (*inode.getIndex().getName()) <<
"</mi>" 1883 indexPattern2String(_code, ip, inode.getIndexPatternIndexes());
1884 _code << _endEq << _endline;
1887 virtual void printIndexCondExprOp(
Node& node) {
1888 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexCondExpr,
"Invalid node type");
1889 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for an index condition expression operation");
1890 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an index condition expression operation");
1891 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index,
"Invalid argument for an index condition expression operation");
1893 const std::vector<size_t>& info = node.
getInfo();
1896 const std::string& index = *iterationIndexOp.getIndex().getName();
1898 printIndexCondExpr(_code, info, index);
1906 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::StartIf,
"Invalid node type");
1907 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'if start' operation");
1908 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'if start' operation");
1910 _code << _ifStart << _startEq <<
"<mi>if</mi>" 1912 printIndexCondExprOp(*node.
getArguments()[0].getOperation());
1913 _code <<
"</mrow></mfenced>" << _endEq << _endline
1914 << _condBodyStart << _endline;
1916 _indentationLevel++;
1925 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::ElseIf,
"Invalid node type");
1926 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 2,
"Invalid number of arguments for an 'else if' operation");
1927 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation");
1928 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation");
1930 _indentationLevel--;
1933 _code << _condBodyEnd << _endline;
1934 CGOpCode nType = node.
getArguments()[0].getOperation()->getOperationType();
1935 if (nType == CGOpCode::StartIf) {
1936 _code << _ifEnd << _endline;
1937 }
else if (nType == CGOpCode::ElseIf) {
1938 _code << _elseIfEnd << _endline;
1942 _code << _elseIfStart << _startEq <<
"<mi>else if</mi>" 1944 printIndexCondExprOp(*node.
getArguments()[1].getOperation());
1945 _code <<
"</mrow></mfenced>" << _endEq << _endline
1946 << _condBodyStart << _endline;
1948 _indentationLevel++;
1956 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Else,
"Invalid node type");
1957 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'else' operation");
1959 _indentationLevel--;
1962 _code << _condBodyEnd << _endline;
1963 CGOpCode nType = node.
getArguments()[0].getOperation()->getOperationType();
1964 if (nType == CGOpCode::StartIf) {
1965 _code << _ifEnd << _endline;
1966 }
else if (nType == CGOpCode::ElseIf) {
1967 _code << _elseIfEnd << _endline;
1971 _code << _elseStart << _startEq <<
"<mi>else</mi>" << _endEq << _endline
1972 << _condBodyStart << _endline;
1973 _code << _elseStart;
1975 _indentationLevel++;
1978 virtual void printEndIf(
Node& node) {
1979 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation");
1981 _indentationLevel--;
1984 _code << _condBodyEnd << _endline;
1985 CGOpCode nType = node.
getArguments()[0].getOperation()->getOperationType();
1986 if (nType == CGOpCode::StartIf) {
1987 _code << _ifEnd << _endline;
1988 }
else if (nType == CGOpCode::ElseIf) {
1989 _code << _elseIfEnd << _endline;
1991 assert(nType == CGOpCode::Else);
1992 _code << _elseEnd << _endline;
1996 virtual void printCondResult(
Node& node) {
1997 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::CondResult,
"Invalid node type");
1998 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for an assignment inside an if/else operation");
1999 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation");
2000 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation");
2004 printAssignment(nodeArg);
2007 virtual void printUserCustom(
Node& node) {
2008 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::UserCustom,
"Invalid node type");
2010 throw CGException(
"Unable to generate MathML for user custom operation nodes.");
2013 inline bool isDependent(
const Node& arg)
const {
2017 size_t id = getVariableID(arg);
2018 return id > _independentSize &&
id < _minTemporaryVarID;
2021 virtual void printParameter(
const Base& value) {
2023 std::ostringstream os;
2024 os << std::setprecision(_parameterPrecision) << value;
2026 std::string number = os.str();
2027 size_t pos = number.find(
'e');
2028 if (pos != std::string::npos) {
2029 _code <<
"<mn>" << number.substr(0, pos) <<
"</mn><mo>×</mo>";
2030 _code <<
"<msup><mn>10</mn><mn>";
2032 if (number[pos] ==
'-') {
2035 }
else if (number[pos] ==
'+') {
2038 while (pos < number.size() - 1 && number[pos] ==
'0')
2041 _code << number.substr(pos) <<
"</mn></msup>";
2044 _code <<
"<mn>" << number <<
"</mn>";
2050 virtual void getComparison(std::ostream& os,
enum CGOpCode op)
const {
2052 case CGOpCode::ComLt:
2056 case CGOpCode::ComLe:
2060 case CGOpCode::ComEq:
2064 case CGOpCode::ComGe:
2068 case CGOpCode::ComGt:
2072 case CGOpCode::ComNe:
2077 CPPAD_ASSERT_UNKNOWN(0);
2079 throw CGException(
"Invalid comparison operator code");
2082 static bool isFunction(
enum CGOpCode op) {
2083 return isUnaryFunction(op) || op == CGOpCode::Pow;
2086 static bool isUnaryFunction(
enum CGOpCode op) {
2089 case CGOpCode::Acos:
2090 case CGOpCode::Asin:
2091 case CGOpCode::Atan:
2092 case CGOpCode::Cosh:
2096 case CGOpCode::Sign:
2097 case CGOpCode::Sinh:
2099 case CGOpCode::Sqrt:
2100 case CGOpCode::Tanh:
2108 static bool isCondAssign(
enum CGOpCode op) {
2110 case CGOpCode::ComLt:
2111 case CGOpCode::ComLe:
2112 case CGOpCode::ComEq:
2113 case CGOpCode::ComGe:
2114 case CGOpCode::ComGt:
2115 case CGOpCode::ComNe:
2123 template<
class Base>
2126 template<
class Base>
2129 template<
class Base>
2132 template<
class Base>
2135 template<
class Base>
2138 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
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
void generateSourceCode(std::ostream &out, const std::unique_ptr< LanguageGenerationData< Base > > &info) override
virtual const std::string & getElseIfStartMarkup() const
virtual void setElseMarkup(const std::string &begin, const std::string &end)
bool createsNewVariable(const Node &var, size_t totalUseCount) const override
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
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