1 #ifndef CPPAD_CG_LANGUAGE_C_INCLUDED 2 #define CPPAD_CG_LANGUAGE_C_INCLUDED 19 #define CPPAD_CG_C_LANG_FUNCNAME(fn) \ 20 inline virtual const std::string& fn ## FuncName() {\ 21 static const std::string name(#fn);\ 34 class LanguageC :
public Language<Base> {
36 using Node = OperationNode<Base>;
37 using Arg = Argument<Base>;
39 static const std::string U_INDEX_TYPE;
40 static const std::string ATOMICFUN_STRUCT_DEFINITION;
42 static const std::string _C_COMP_OP_LT;
43 static const std::string _C_COMP_OP_LE;
44 static const std::string _C_COMP_OP_EQ;
45 static const std::string _C_COMP_OP_GE;
46 static const std::string _C_COMP_OP_GT;
47 static const std::string _C_COMP_OP_NE;
48 static const std::string _C_STATIC_INDEX_ARRAY;
49 static const std::string _C_SPARSE_INDEX_ARRAY;
50 static const std::string _ATOMIC_TX;
51 static const std::string _ATOMIC_TY;
52 static const std::string _ATOMIC_PX;
53 static const std::string _ATOMIC_PY;
55 class AtomicFuncArray;
58 const std::string _baseTypeName;
60 const std::string _spaces;
62 LanguageGenerationData<Base>* _info;
64 std::string _indentation;
66 std::string _inArgName;
68 std::string _outArgName;
70 std::string _atomicArgName;
72 std::ostringstream _code;
74 VariableNameGenerator<Base>* _nameGen;
76 std::ostringstream _ss;
78 size_t _independentSize;
80 size_t _minTemporaryVarID;
83 std::map<size_t, size_t> _dependentIDs;
85 const ArrayView<CG<Base> >* _dependent;
87 std::map<size_t, Node*> _temporary;
89 std::string _depAssignOperation;
91 bool _ignoreZeroDepAssign;
93 std::string _functionName;
95 std::string _localFunctionArguments;
97 size_t _maxAssigmentsPerFunction;
99 std::map<std::string, std::string>* _sources;
101 std::vector<const Arg*> _tmpArrayValues;
103 std::vector<const Arg*> _tmpSparseArrayValues;
105 std::map<std::string, AtomicFuncArray> _atomicFuncArrays;
107 std::vector<const Node*> _funcArgIndexes;
108 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
110 size_t _parameterPrecision;
112 std::vector<std::string> funcArgDcl_;
113 std::vector<std::string> localFuncArgDcl_;
114 std::string localFuncArgs_;
115 std::string auxArrayName_;
127 _baseTypeName(varTypeName),
128 _spaces(spaces,
' '),
132 _atomicArgName(
"atomicFun"),
135 _minTemporaryVarID(0),
137 _depAssignOperation(
"="),
138 _ignoreZeroDepAssign(false),
139 _maxAssigmentsPerFunction(0),
141 _parameterPrecision(
std::numeric_limits<Base>::digits10) {
146 inline const std::string& getArgumentIn()
const {
150 inline void setArgumentIn(
const std::string& inArgName) {
151 _inArgName = inArgName;
154 inline const std::string& getArgumentOut()
const {
158 inline void setArgumentOut(
const std::string& outArgName) {
159 _outArgName = outArgName;
162 inline const std::string& getArgumentAtomic()
const {
163 return _atomicArgName;
166 inline void setArgumentAtomic(
const std::string& atomicArgName) {
167 _atomicArgName = atomicArgName;
170 inline const std::string& getDependentAssignOperation()
const {
171 return _depAssignOperation;
174 inline void setDependentAssignOperation(
const std::string& depAssignOperation) {
175 _depAssignOperation = depAssignOperation;
178 inline bool isIgnoreZeroDepAssign()
const {
179 return _ignoreZeroDepAssign;
182 inline void setIgnoreZeroDepAssign(
bool ignore) {
183 _ignoreZeroDepAssign = ignore;
186 virtual void setGenerateFunction(
const std::string& functionName) {
187 _functionName = functionName;
190 virtual void setFunctionIndexArgument(
const Node& funcArgIndex) {
191 _funcArgIndexes.resize(1);
192 _funcArgIndexes[0] = &funcArgIndex;
195 virtual void setFunctionIndexArguments(
const std::vector<const Node*>& funcArgIndexes) {
196 _funcArgIndexes = funcArgIndexes;
199 virtual const std::vector<const Node*>& getFunctionIndexArguments()
const {
200 return _funcArgIndexes;
210 return _parameterPrecision;
220 _parameterPrecision = p;
223 virtual void setMaxAssigmentsPerFunction(
size_t maxAssigmentsPerFunction,
224 std::map<std::string, std::string>* sources) {
225 _maxAssigmentsPerFunction = maxAssigmentsPerFunction;
229 inline std::string generateTemporaryVariableDeclaration(
bool isWrapperFunction,
230 bool zeroArrayDependents,
231 const std::vector<int>& atomicMaxForward,
232 const std::vector<int>& atomicMaxReverse) {
234 if (!atomicMaxForward.empty())
235 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
238 if (!atomicMaxReverse.empty())
239 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
241 return generateTemporaryVariableDeclaration(isWrapperFunction, zeroArrayDependents,
242 maxForward, maxReverse);
261 bool zeroArrayDependents =
false,
262 int maxForwardOrder = -1,
263 int maxReverseOrder = -1) {
264 CPPADCG_ASSERT_UNKNOWN(_nameGen !=
nullptr);
267 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
269 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
270 "There must be two temporary variables");
272 _ss << _spaces <<
"// auxiliary variables\n";
276 if (tmpArg[0].array) {
277 size_t size = _nameGen->getMaxTemporaryVariableID() + 1 - _nameGen->getMinTemporaryVariableID();
278 if (size > 0 || isWrapperFunction) {
279 _ss << _spaces << _baseTypeName <<
" " << tmpArg[0].name <<
"[" << size <<
"];\n";
281 }
else if (_temporary.size() > 0) {
282 for (
const std::pair<size_t, Node*>& p : _temporary) {
283 Node* var = p.second;
284 if (var->
getName() ==
nullptr) {
285 var->
setName(_nameGen->generateTemporary(*var, getVariableID(*var)));
289 Node* var1 = _temporary.begin()->second;
290 const std::string& varName1 = *var1->
getName();
291 _ss << _spaces << _baseTypeName <<
" " << varName1;
293 typename std::map<size_t, Node*>::const_iterator it = _temporary.begin();
294 for (it++; it != _temporary.end(); ++it) {
295 _ss <<
", " << *it->second->getName();
303 size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
304 if (arraySize > 0 || isWrapperFunction) {
305 _ss << _spaces << _baseTypeName <<
" " << tmpArg[1].name <<
"[" << arraySize <<
"];\n";
311 size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
312 if (sArraySize > 0 || isWrapperFunction) {
313 _ss << _spaces << _baseTypeName <<
" " << tmpArg[2].name <<
"[" << sArraySize <<
"];\n";
314 _ss << _spaces << U_INDEX_TYPE <<
" " << _C_SPARSE_INDEX_ARRAY <<
"[" << sArraySize <<
"];\n";
317 if (!isWrapperFunction) {
318 generateArrayContainersDeclaration(_ss, maxForwardOrder, maxReverseOrder);
322 if (!isWrapperFunction && (arraySize > 0 || sArraySize > 0)) {
323 _ss << _spaces << _baseTypeName <<
"* " << auxArrayName_ <<
";\n";
326 if ((isWrapperFunction && zeroArrayDependents) ||
327 (!isWrapperFunction && (arraySize > 0 || sArraySize > 0 || zeroArrayDependents))) {
328 _ss << _spaces << U_INDEX_TYPE <<
" i;\n";
332 createIndexDeclaration();
335 std::string code = _ss.str();
341 inline void generateArrayContainersDeclaration(std::ostringstream& ss,
342 const std::vector<int>& atomicMaxForward,
343 const std::vector<int>& atomicMaxReverse) {
345 if (!atomicMaxForward.empty())
346 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
349 if (!atomicMaxReverse.empty())
350 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
352 generateArrayContainersDeclaration(ss, maxForward, maxReverse);
355 virtual void generateArrayContainersDeclaration(std::ostringstream& ss,
356 int maxForwardOrder = -1,
357 int maxReverseOrder = -1) {
358 if (maxForwardOrder >= 0 || maxReverseOrder >= 0) {
359 ss << _spaces <<
"Array " << _ATOMIC_TX <<
"[" << (std::max(maxForwardOrder, maxReverseOrder) + 1) <<
"];\n";
360 if (maxForwardOrder >= 0)
361 ss << _spaces <<
"Array " << _ATOMIC_TY <<
";\n";
362 if (maxReverseOrder >= 0) {
363 ss << _spaces <<
"Array " << _ATOMIC_PX <<
";\n";
364 ss << _spaces <<
"Array " << _ATOMIC_PY <<
"[" << (maxReverseOrder + 1) <<
"];\n";
369 virtual std::string generateDependentVariableDeclaration() {
370 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
371 CPPADCG_ASSERT_KNOWN(depArg.size() > 0,
372 "There must be at least one dependent argument");
374 _ss << _spaces <<
"//dependent variables\n";
375 for (
size_t i = 0; i < depArg.size(); i++) {
376 _ss << _spaces << argumentDeclaration(depArg[i]) <<
" = " << _outArgName <<
"[" << i <<
"];\n";
379 std::string code = _ss.str();
384 virtual std::string generateIndependentVariableDeclaration() {
385 const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
386 CPPADCG_ASSERT_KNOWN(indArg.size() > 0,
387 "There must be at least one independent argument");
389 _ss << _spaces <<
"//independent variables\n";
390 for (
size_t i = 0; i < indArg.size(); i++) {
391 _ss << _spaces <<
"const " << argumentDeclaration(indArg[i]) <<
" = " << _inArgName <<
"[" << i <<
"];\n";
394 std::string code = _ss.str();
399 inline std::string generateArgumentAtomicDcl()
const {
400 return "struct LangCAtomicFun " + _atomicArgName;
403 virtual std::string generateFunctionArgumentsDcl()
const {
404 std::string args = generateFunctionIndexArgumentsDcl();
407 args += generateDefaultFunctionArgumentsDcl();
412 virtual std::vector<std::string> generateFunctionArgumentsDcl2()
const {
413 std::vector<std::string> args = generateFunctionIndexArgumentsDcl2();
414 std::vector<std::string> dArgs = generateDefaultFunctionArgumentsDcl2();
415 args.insert(args.end(), dArgs.begin(), dArgs.end());
419 virtual std::string generateDefaultFunctionArgumentsDcl()
const {
420 return implode(generateDefaultFunctionArgumentsDcl2(),
", ");
423 virtual std::vector<std::string> generateDefaultFunctionArgumentsDcl2()
const {
424 return std::vector<std::string> {_baseTypeName +
" const *const * " + _inArgName,
425 _baseTypeName +
"*const * " + _outArgName,
426 generateArgumentAtomicDcl()};
429 virtual std::string generateFunctionIndexArgumentsDcl()
const {
430 return implode(generateFunctionIndexArgumentsDcl2(),
", ");
433 virtual std::vector<std::string> generateFunctionIndexArgumentsDcl2()
const {
434 std::vector<std::string> argtxt(_funcArgIndexes.size());
435 for (
size_t a = 0; a < _funcArgIndexes.size(); a++) {
436 argtxt[a] = U_INDEX_TYPE +
" " + *_funcArgIndexes[a]->getName();
441 virtual std::string generateDefaultFunctionArguments()
const {
442 return _inArgName +
", " + _outArgName +
", " + _atomicArgName;
445 virtual std::string generateFunctionIndexArguments()
const {
447 for (
size_t a = 0; a < _funcArgIndexes.size(); a++) {
448 if (a > 0) argtxt +=
", ";
449 argtxt += *_funcArgIndexes[a]->getName();
454 inline void createIndexDeclaration();
456 CPPAD_CG_C_LANG_FUNCNAME(abs)
457 CPPAD_CG_C_LANG_FUNCNAME(acos)
458 CPPAD_CG_C_LANG_FUNCNAME(asin)
459 CPPAD_CG_C_LANG_FUNCNAME(atan)
460 CPPAD_CG_C_LANG_FUNCNAME(cosh)
461 CPPAD_CG_C_LANG_FUNCNAME(cos)
462 CPPAD_CG_C_LANG_FUNCNAME(exp)
463 CPPAD_CG_C_LANG_FUNCNAME(log)
464 CPPAD_CG_C_LANG_FUNCNAME(sinh)
465 CPPAD_CG_C_LANG_FUNCNAME(sin)
466 CPPAD_CG_C_LANG_FUNCNAME(sqrt)
467 CPPAD_CG_C_LANG_FUNCNAME(tanh)
468 CPPAD_CG_C_LANG_FUNCNAME(tan)
469 CPPAD_CG_C_LANG_FUNCNAME(
pow)
471 #if CPPAD_USE_CPLUSPLUS_2011 472 CPPAD_CG_C_LANG_FUNCNAME(erf)
473 CPPAD_CG_C_LANG_FUNCNAME(asinh)
474 CPPAD_CG_C_LANG_FUNCNAME(acosh)
475 CPPAD_CG_C_LANG_FUNCNAME(atanh)
476 CPPAD_CG_C_LANG_FUNCNAME(expm1)
477 CPPAD_CG_C_LANG_FUNCNAME(log1p)
490 const std::string& returnType,
491 const std::string& functionName,
492 const std::vector<std::string>& arguments,
493 const std::vector<std::string>& arguments2 = {}) {
494 out << returnType <<
" " << functionName <<
"(";
496 size_t offset = returnType.size() + 1 + functionName.size() + 1;
497 for (
const std::string& a : arguments) {
499 out <<
",\n" << std::setw(offset) <<
" ";
504 for (
const std::string& a : arguments2) {
506 out <<
",\n" << std::setw(offset) <<
" ";
514 static inline void printIndexCondExpr(std::ostringstream& out,
515 const std::vector<size_t>& info,
516 const std::string& index) {
517 CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0,
"Invalid number of information elements for an index condition expression operation");
519 size_t infoSize = info.size();
520 for (
size_t e = 0; e < infoSize; e += 2) {
524 size_t min = info[e];
525 size_t max = info[e + 1];
527 out << index <<
" == " << min;
528 }
else if (min == 0) {
529 out << index <<
" <= " << max;
530 }
else if (max == std::numeric_limits<size_t>::max()) {
531 out << min <<
" <= " << index;
537 out << min <<
" == " << index <<
" || " << index <<
" == " << max;
539 out << min <<
" <= " << index <<
" && " << index <<
" <= " << max;
551 static inline void printStaticIndexArray(std::ostringstream& os,
552 const std::string& name,
553 const std::vector<size_t>& values);
555 static inline void printStaticIndexMatrix(std::ostringstream& os,
556 const std::string& name,
557 const std::map<
size_t, std::map<size_t, size_t> >& values);
562 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>& randomPatterns);
565 const std::string& identation,
566 const std::set<RandomIndexPattern*>& randomPatterns);
568 static inline std::string indexPattern2String(
const IndexPattern& ip,
571 static inline std::string indexPattern2String(
const IndexPattern& ip,
572 const std::string& index);
574 static inline std::string indexPattern2String(
const IndexPattern& ip,
575 const std::vector<const Node*>& indexes);
577 static inline std::string indexPattern2String(
const IndexPattern& ip,
578 const std::vector<const std::string*>& indexes);
584 const std::string& index);
617 const bool createFunction = !_functionName.empty();
618 const bool multiFunction = createFunction && _maxAssigmentsPerFunction > 0 && _sources !=
nullptr;
624 _indentation = _spaces;
626 localFuncArgDcl_.clear();
629 _currentLoops.clear();
630 _atomicFuncArrays.clear();
634 _independentSize = info->independent.size();
635 _dependent = &info->dependent;
636 _nameGen = &info->nameGen;
637 _minTemporaryVarID = info->minTemporaryVarID;
639 const std::vector<Node*>& variableOrder = info->variableOrder;
641 _tmpArrayValues.resize(_nameGen->getMaxTemporaryArrayVariableID());
642 std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(),
nullptr);
643 _tmpSparseArrayValues.resize(_nameGen->getMaxTemporarySparseArrayVariableID());
644 std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(),
nullptr);
649 generateNames4RandomIndexPatterns(info->indexRandomPatterns);
655 for (
size_t j = 0; j < _independentSize; j++) {
656 Node& op = *info->independent[j];
658 op.
setName(_nameGen->generateIndependent(op, getVariableID(op)));
663 for (
size_t i = 0; i < dependent.
size(); i++) {
664 Node* node = dependent[i].getOperationNode();
667 size_t pos = node->
getInfo()[0];
668 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
669 node->
setName(_nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip));
672 node->
setName(_nameGen->generateDependent(i));
680 const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
681 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
682 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
683 CPPADCG_ASSERT_KNOWN(indArg.size() > 0 && depArg.size() > 0,
684 "There must be at least one dependent and one independent argument");
685 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
686 "There must be three temporary variables");
688 if (createFunction) {
689 funcArgDcl_ = generateFunctionArgumentsDcl2();
691 localFuncArgDcl_.reserve(funcArgDcl_.size() + 4);
692 localFuncArgDcl_ = funcArgDcl_;
693 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[0]));
694 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[1]));
695 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[2]));
696 localFuncArgDcl_.push_back(U_INDEX_TYPE +
"* " + _C_SPARSE_INDEX_ARRAY);
698 localFuncArgs_ = generateDefaultFunctionArguments() +
", " 699 + tmpArg[0].name +
", " 700 + tmpArg[1].name +
", " 701 + tmpArg[2].name +
", " 702 + _C_SPARSE_INDEX_ARRAY;
705 auxArrayName_ = tmpArg[1].name +
"p";
711 std::set<size_t> dependentDuplicates;
713 for (
size_t i = 0; i < dependent.
size(); i++) {
714 Node* node = dependent[i].getOperationNode();
715 if (node !=
nullptr) {
717 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
718 size_t varID = getVariableID(*node);
720 std::map<size_t, size_t>::const_iterator it2 = _dependentIDs.find(varID);
721 if (it2 == _dependentIDs.end()) {
722 _dependentIDs[getVariableID(*node)] = i;
725 dependentDuplicates.insert(i);
733 std::vector<std::string> localFuncNames;
735 localFuncNames.reserve(variableOrder.size() / _maxAssigmentsPerFunction);
741 if (variableOrder.size() > 0) {
743 for (
Node* node : variableOrder) {
744 CGOpCode op = node->getOperationType();
745 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
747 if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
748 node->setName(_nameGen->generateTemporary(*node, getVariableID(*node)));
749 }
else if (op == CGOpCode::ArrayCreation) {
750 node->setName(_nameGen->generateTemporaryArray(*node, getVariableID(*node)));
751 }
else if (op == CGOpCode::SparseArrayCreation) {
752 node->setName(_nameGen->generateTemporarySparseArray(*node, getVariableID(*node)));
760 if (info->zeroDependents) {
762 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
763 for (
size_t i = 0; i < depArg.size(); i++) {
766 _code << _indentation <<
"for(i = 0; i < " << _dependent->size() <<
"; i++) " << a.name <<
"[i]";
768 _code << _indentation << _nameGen->generateDependent(i);
771 printParameter(Base(0.0));
776 size_t assignCount = 0;
777 for (
size_t i = 0; i < variableOrder.size(); ++i) {
778 Node* it = variableOrder[i];
781 if (assignCount >= _maxAssigmentsPerFunction && multiFunction && _currentLoops.empty()) {
783 saveLocalFunction(localFuncNames, localFuncNames.empty() && info->zeroDependents);
789 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
791 }
else if (node.getOperationType() == CGOpCode::TmpDcl) {
793 }
else if (node.getOperationType() == CGOpCode::LoopIndexedDep) {
795 i = printLoopIndexDeps(variableOrder, i);
799 assignCount += printAssignment(node);
802 if (localFuncNames.size() > 0 && assignCount > 0) {
804 saveLocalFunction(localFuncNames,
false);
808 if (localFuncNames.size() > 0) {
812 CPPADCG_ASSERT_KNOWN(tmpArg[0].array,
813 "The temporary variables must be saved in an array in order to generate multiple functions");
815 _code << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
817 std::string localFuncArgDcl2 = implode(localFuncArgDcl_,
", ");
818 for (
size_t i = 0; i < localFuncNames.size(); i++) {
819 _code <<
"void " << localFuncNames[i] <<
"(" << localFuncArgDcl2 <<
");\n";
824 _nameGen->customFunctionVariableDeclarations(_code);
825 _code << generateIndependentVariableDeclaration() <<
"\n";
826 _code << generateDependentVariableDeclaration() <<
"\n";
827 _code << generateTemporaryVariableDeclaration(
true,
false,
828 info->atomicFunctionsMaxForward,
829 info->atomicFunctionsMaxReverse) <<
"\n";
830 _nameGen->prepareCustomFunctionVariables(_code);
831 for (
size_t i = 0; i < localFuncNames.size(); i++) {
832 _code << _spaces << localFuncNames[i] <<
"(" << localFuncArgs_ <<
");\n";
837 if (dependentDuplicates.size() > 0) {
838 _code << _spaces <<
"// variable duplicates: " << dependentDuplicates.size() <<
"\n";
839 for (
size_t index : dependentDuplicates) {
840 const CG<Base>& dep = (*_dependent)[index];
841 std::string varName = _nameGen->generateDependent(index);
842 const std::string& origVarName = *dep.getOperationNode()->getName();
844 _code << _spaces << varName <<
" " << _depAssignOperation <<
" " << origVarName <<
";\n";
849 bool commentWritten =
false;
850 for (
size_t i = 0; i < dependent.
size(); i++) {
851 if (dependent[i].isParameter()) {
852 if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
853 if (!commentWritten) {
854 _code << _spaces <<
"// dependent variables without operations\n";
855 commentWritten =
true;
857 std::string varName = _nameGen->generateDependent(i);
858 _code << _spaces << varName <<
" " << _depAssignOperation <<
" ";
859 printParameter(dependent[i].getValue());
862 }
else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
863 if (!commentWritten) {
864 _code << _spaces <<
"// dependent variables without operations\n";
865 commentWritten =
true;
867 std::string varName = _nameGen->generateDependent(i);
868 const std::string& indepName = *dependent[i].getOperationNode()->getName();
869 _code << _spaces << varName <<
" " << _depAssignOperation <<
" " << indepName <<
";\n";
876 if (createFunction) {
877 if (localFuncNames.empty()) {
878 _ss <<
"#include <math.h>\n" 879 "#include <stdio.h>\n\n" 880 << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
883 _nameGen->customFunctionVariableDeclarations(_ss);
884 _ss << generateIndependentVariableDeclaration() <<
"\n";
885 _ss << generateDependentVariableDeclaration() <<
"\n";
886 _ss << generateTemporaryVariableDeclaration(
false, info->zeroDependents,
887 info->atomicFunctionsMaxForward,
888 info->atomicFunctionsMaxReverse) <<
"\n";
889 _nameGen->prepareCustomFunctionVariables(_ss);
891 _nameGen->finalizeCustomFunctionVariables(_ss);
896 if (_sources !=
nullptr) {
897 (*_sources)[_functionName +
".c"] = _ss.str();
900 _nameGen->finalizeCustomFunctionVariables(_code);
903 (*_sources)[_functionName +
".c"] = _code.str();
910 inline size_t getVariableID(
const Node& node)
const {
911 return _info->varId[node];
914 inline unsigned printAssignment(
Node& node) {
915 return printAssignment(node, node);
918 inline unsigned printAssignment(
Node& nodeName,
919 const Arg& nodeRhs) {
920 if (nodeRhs.getOperation() !=
nullptr) {
921 return printAssignment(nodeName, *nodeRhs.getOperation());
923 printAssignmentStart(nodeName);
924 printParameter(*nodeRhs.getParameter());
925 printAssignmentEnd(nodeName);
930 inline unsigned printAssignment(
Node& nodeName,
934 printAssignmentStart(nodeName);
936 unsigned lines = printExpressionNoVarCheck(nodeRhs);
938 printAssignmentEnd(nodeRhs);
943 size_t arrayId = getVariableID(*array);
944 size_t pos = nodeRhs.
getInfo()[0];
946 _tmpArrayValues[arrayId - 1 + pos] =
nullptr;
948 _tmpSparseArrayValues[arrayId - 1 + pos] =
nullptr;
954 inline virtual void printAssignmentStart(
Node& op) {
955 printAssignmentStart(op, createVariableName(op), isDependent(op));
958 inline virtual void printAssignmentStart(
Node& node,
959 const std::string& varName,
962 _temporary[getVariableID(node)] = &node;
965 _code << _indentation << varName <<
" ";
968 if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.
getInfo()[1] == 1)) {
971 _code << _depAssignOperation;
979 inline virtual void printAssignmentEnd(
Node& op) {
983 virtual std::string argumentDeclaration(
const FuncArgument& funcArg)
const {
984 std::string dcl = _baseTypeName;
988 return dcl +
" " + funcArg.name;
991 virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
992 bool zeroDependentArray) {
993 _ss << _functionName <<
"__" << (localFuncNames.size() + 1);
994 std::string funcName = _ss.str();
997 _ss <<
"#include <math.h>\n" 998 "#include <stdio.h>\n\n" 999 << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
1002 _nameGen->customFunctionVariableDeclarations(_ss);
1003 _ss << generateIndependentVariableDeclaration() <<
"\n";
1004 _ss << generateDependentVariableDeclaration() <<
"\n";
1005 size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
1006 size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
1007 if (arraySize > 0 || sArraySize > 0) {
1008 _ss << _spaces << _baseTypeName <<
"* " << auxArrayName_ <<
";\n";
1011 generateArrayContainersDeclaration(_ss,
1012 _info->atomicFunctionsMaxForward,
1013 _info->atomicFunctionsMaxReverse);
1015 if (arraySize > 0 || sArraySize > 0 || zeroDependentArray) {
1016 _ss << _spaces << U_INDEX_TYPE <<
" i;\n";
1020 createIndexDeclaration();
1022 _nameGen->prepareCustomFunctionVariables(_ss);
1024 _nameGen->finalizeCustomFunctionVariables(_ss);
1027 (*_sources)[funcName +
".c"] = _ss.str();
1028 localFuncNames.push_back(funcName);
1035 size_t totalUseCount)
const override {
1037 if (totalUseCount > 1) {
1038 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1040 return ( op == CGOpCode::ArrayCreation ||
1041 op == CGOpCode::SparseArrayCreation ||
1042 op == CGOpCode::AtomicForward ||
1043 op == CGOpCode::AtomicReverse ||
1044 op == CGOpCode::ComLt ||
1045 op == CGOpCode::ComLe ||
1046 op == CGOpCode::ComEq ||
1047 op == CGOpCode::ComGe ||
1048 op == CGOpCode::ComGt ||
1049 op == CGOpCode::ComNe ||
1050 op == CGOpCode::LoopIndexedDep ||
1051 op == CGOpCode::LoopIndexedTmp ||
1052 op == CGOpCode::IndexAssign ||
1053 op == CGOpCode::Assign) &&
1054 op != CGOpCode::CondResult;
1058 virtual bool requiresVariableName(
const Node& var)
const {
1060 if (_info->totalUseCount.get(var) > 1) {
1061 return (op != CGOpCode::Pri &&
1062 op != CGOpCode::AtomicForward &&
1063 op != CGOpCode::AtomicReverse &&
1064 op != CGOpCode::LoopStart &&
1065 op != CGOpCode::LoopEnd &&
1066 op != CGOpCode::Index &&
1067 op != CGOpCode::IndexAssign &&
1068 op != CGOpCode::StartIf &&
1069 op != CGOpCode::ElseIf &&
1070 op != CGOpCode::Else &&
1071 op != CGOpCode::EndIf &&
1072 op != CGOpCode::CondResult &&
1073 op != CGOpCode::LoopIndexedTmp &&
1074 op != CGOpCode::Tmp);
1076 return isCondAssign(op);
1089 return isCondAssign(op) ||
1090 op == CGOpCode::Pri ||
1091 op == CGOpCode::ArrayCreation ||
1092 op == CGOpCode::SparseArrayCreation ||
1093 op == CGOpCode::AtomicForward ||
1094 op == CGOpCode::AtomicReverse ||
1095 op == CGOpCode::DependentMultiAssign ||
1096 op == CGOpCode::LoopStart ||
1097 op == CGOpCode::LoopEnd ||
1098 op == CGOpCode::IndexAssign ||
1099 op == CGOpCode::StartIf ||
1100 op == CGOpCode::ElseIf ||
1101 op == CGOpCode::Else ||
1102 op == CGOpCode::EndIf ||
1103 op == CGOpCode::CondResult ||
1104 op == CGOpCode::IndexDeclaration;
1107 bool requiresVariableArgument(
enum CGOpCode op,
size_t argIndex)
const override {
1108 return op == CGOpCode::Sign || op == CGOpCode::CondResult || op == CGOpCode::Pri;
1111 inline const std::string& createVariableName(
Node& var) {
1113 CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0);
1114 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward);
1115 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse);
1116 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart);
1117 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd);
1118 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index);
1119 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign);
1120 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration);
1122 if (var.
getName() ==
nullptr) {
1123 if (op == CGOpCode::ArrayCreation) {
1124 var.
setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
1126 }
else if (op == CGOpCode::SparseArrayCreation) {
1127 var.
setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
1129 }
else if (op == CGOpCode::LoopIndexedDep) {
1130 size_t pos = var.
getInfo()[0];
1131 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
1132 var.
setName(_nameGen->generateIndexedDependent(var, getVariableID(var), *ip));
1134 }
else if (op == CGOpCode::LoopIndexedIndep) {
1135 size_t pos = var.
getInfo()[1];
1136 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1137 var.
setName(_nameGen->generateIndexedIndependent(var, getVariableID(var), *ip));
1139 }
else if (getVariableID(var) <= _independentSize) {
1141 var.
setName(_nameGen->generateIndependent(var, getVariableID(var)));
1143 }
else if (getVariableID(var) < _minTemporaryVarID) {
1145 std::map<size_t, size_t>::const_iterator it = _dependentIDs.find(getVariableID(var));
1146 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end());
1148 size_t index = it->second;
1149 var.
setName(_nameGen->generateDependent(index));
1150 }
else if (op == CGOpCode::Pri) {
1151 CPPADCG_ASSERT_KNOWN(var.
getArguments().size() == 1,
"Invalid number of arguments for print operation");
1153 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr,
"Invalid argument for print operation");
1154 return createVariableName(*tmpVar);
1156 }
else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
1157 CPPADCG_ASSERT_KNOWN(var.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed temporary operation");
1159 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1160 return createVariableName(*tmpVar);
1164 var.
setName(_nameGen->generateTemporary(var, getVariableID(var)));
1176 virtual void printIndependentVariableName(
Node& op) {
1177 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 0,
"Invalid number of arguments for independent variable");
1179 _code << _nameGen->generateIndependent(op, getVariableID(op));
1182 virtual unsigned print(
const Arg& arg) {
1183 if (arg.getOperation() !=
nullptr) {
1185 return printExpression(*arg.getOperation());
1188 printParameter(*arg.getParameter());
1193 virtual unsigned printExpression(
Node& op) {
1194 if (getVariableID(op) > 0) {
1196 _code << createVariableName(op);
1200 return printExpressionNoVarCheck(op);
1204 virtual unsigned printExpressionNoVarCheck(
Node& node) {
1207 case CGOpCode::ArrayCreation:
1208 printArrayCreationOp(node);
1210 case CGOpCode::SparseArrayCreation:
1211 printSparseArrayCreationOp(node);
1213 case CGOpCode::ArrayElement:
1214 printArrayElementOp(node);
1216 case CGOpCode::Assign:
1217 return printAssignOp(node);
1220 case CGOpCode::Acos:
1221 case CGOpCode::Asin:
1222 case CGOpCode::Atan:
1223 case CGOpCode::Cosh:
1227 case CGOpCode::Sinh:
1229 case CGOpCode::Sqrt:
1230 case CGOpCode::Tanh:
1232 #if CPPAD_USE_CPLUSPLUS_2011 1234 case CGOpCode::Asinh:
1235 case CGOpCode::Acosh:
1236 case CGOpCode::Atanh:
1237 case CGOpCode::Expm1:
1238 case CGOpCode::Log1p:
1240 printUnaryFunction(node);
1242 case CGOpCode::AtomicForward:
1245 case CGOpCode::AtomicReverse:
1249 printOperationAdd(node);
1251 case CGOpCode::Alias:
1252 return printOperationAlias(node);
1254 case CGOpCode::ComLt:
1255 case CGOpCode::ComLe:
1256 case CGOpCode::ComEq:
1257 case CGOpCode::ComGe:
1258 case CGOpCode::ComGt:
1259 case CGOpCode::ComNe:
1260 printConditionalAssignment(node);
1263 printOperationDiv(node);
1266 printIndependentVariableName(node);
1269 printOperationMul(node);
1272 printPowFunction(node);
1275 printPrintOperation(node);
1277 case CGOpCode::Sign:
1278 printSignFunction(node);
1281 printOperationMinus(node);
1284 case CGOpCode::UnMinus:
1285 printOperationUnaryMinus(node);
1288 case CGOpCode::DependentMultiAssign:
1289 return printDependentMultiAssign(node);
1291 case CGOpCode::Index:
1293 case CGOpCode::IndexAssign:
1294 printIndexAssign(node);
1296 case CGOpCode::IndexDeclaration:
1299 case CGOpCode::LoopStart:
1300 printLoopStart(node);
1302 case CGOpCode::LoopIndexedIndep:
1303 printLoopIndexedIndep(node);
1305 case CGOpCode::LoopIndexedDep:
1306 printLoopIndexedDep(node);
1308 case CGOpCode::LoopIndexedTmp:
1309 printLoopIndexedTmp(node);
1311 case CGOpCode::TmpDcl:
1317 case CGOpCode::LoopEnd:
1320 case CGOpCode::IndexCondExpr:
1321 printIndexCondExprOp(node);
1323 case CGOpCode::StartIf:
1326 case CGOpCode::ElseIf:
1329 case CGOpCode::Else:
1332 case CGOpCode::EndIf:
1335 case CGOpCode::CondResult:
1336 printCondResult(node);
1338 case CGOpCode::UserCustom:
1339 printUserCustom(node);
1342 throw CGException(
"Unknown operation code '", op,
"'.");
1347 virtual unsigned printAssignOp(
Node& node) {
1348 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for assign operation");
1353 virtual void printUnaryFunction(
Node& op) {
1354 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary function");
1358 _code << absFuncName();
1360 case CGOpCode::Acos:
1361 _code << acosFuncName();
1363 case CGOpCode::Asin:
1364 _code << asinFuncName();
1366 case CGOpCode::Atan:
1367 _code << atanFuncName();
1369 case CGOpCode::Cosh:
1370 _code << coshFuncName();
1373 _code << cosFuncName();
1376 _code << expFuncName();
1379 _code << logFuncName();
1381 case CGOpCode::Sinh:
1382 _code << sinhFuncName();
1385 _code << sinFuncName();
1387 case CGOpCode::Sqrt:
1388 _code << sqrtFuncName();
1390 case CGOpCode::Tanh:
1391 _code << tanhFuncName();
1394 _code << tanFuncName();
1396 #if CPPAD_USE_CPLUSPLUS_2011 1398 _code << erfFuncName();
1400 case CGOpCode::Asinh:
1401 _code << asinhFuncName();
1403 case CGOpCode::Acosh:
1404 _code << acoshFuncName();
1406 case CGOpCode::Atanh:
1407 _code << atanhFuncName();
1409 case CGOpCode::Expm1:
1410 _code << expm1FuncName();
1412 case CGOpCode::Log1p:
1413 _code << log1pFuncName();
1425 virtual void printPowFunction(
Node& op) {
1426 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for pow() function");
1428 _code << powFuncName() <<
"(";
1435 virtual void printSignFunction(
Node& op) {
1436 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for sign() function");
1437 CPPADCG_ASSERT_UNKNOWN(op.
getArguments()[0].getOperation() !=
nullptr);
1438 CPPADCG_ASSERT_UNKNOWN(getVariableID(*op.
getArguments()[0].getOperation()) > 0);
1442 const std::string& argName = createVariableName(arg);
1444 _code <<
"(" << argName <<
" " << _C_COMP_OP_GT <<
" ";
1445 printParameter(Base(0.0));
1447 printParameter(Base(1.0));
1448 _code <<
":(" << argName <<
" " << _C_COMP_OP_LT <<
" ";
1449 printParameter(Base(0.0));
1451 printParameter(Base(-1.0));
1453 printParameter(Base(0.0));
1457 virtual unsigned printOperationAlias(
Node& op) {
1458 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias");
1462 virtual void printOperationAdd(
Node& op) {
1463 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for addition");
1468 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1476 printParameter(-*right.getParameter());
1480 virtual void printOperationMinus(
Node& op) {
1481 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for subtraction");
1486 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1487 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1502 printParameter(-*right.getParameter());
1506 inline bool encloseInParenthesesDiv(
const Node* node)
const {
1507 while (node !=
nullptr) {
1508 if (getVariableID(*node) != 0)
1515 return node !=
nullptr &&
1516 getVariableID(*node) == 0 &&
1520 virtual void printOperationDiv(
Node& op) {
1521 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for division");
1526 bool encloseLeft = encloseInParenthesesDiv(left.getOperation());
1527 bool encloseRight = encloseInParenthesesDiv(right.getOperation());
1546 inline bool encloseInParenthesesMul(
const Node* node)
const {
1547 while (node !=
nullptr) {
1548 if (getVariableID(*node) != 0)
1555 return node !=
nullptr &&
1556 getVariableID(*node) == 0 &&
1562 virtual void printOperationMul(
Node& op) {
1563 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication");
1568 bool encloseLeft = encloseInParenthesesMul(left.getOperation());
1569 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1588 virtual void printOperationUnaryMinus(
Node& op) {
1589 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary minus");
1593 bool enclose = encloseInParenthesesMul(arg.getOperation());
1607 virtual void printPrintOperation(
const Node& node) {
1608 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Pri,
"Invalid node type");
1609 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for print operation");
1612 std::string before = pnode.getBeforeString();
1613 replaceString(before,
"\n",
"\\n");
1614 replaceString(before,
"\"",
"\\\"");
1615 std::string after = pnode.getAfterString();
1616 replaceString(after,
"\n",
"\\n");
1617 replaceString(after,
"\"",
"\\\"");
1619 _code << _indentation <<
"fprintf(stderr, \"" << before << getPrintfBaseFormat() << after <<
"\"";
1620 const std::vector<Arg>& args = pnode.getArguments();
1621 for (
size_t a = 0; a < args.size(); a++) {
1628 virtual void printConditionalAssignment(
Node& node) {
1629 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
1632 const Arg &left = args[0];
1633 const Arg &right = args[1];
1634 const Arg &trueCase = args[2];
1635 const Arg &falseCase = args[3];
1637 bool isDep = isDependent(node);
1638 const std::string& varName = createVariableName(node);
1640 if ((trueCase.getParameter() !=
nullptr && falseCase.getParameter() !=
nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1641 (trueCase.getOperation() !=
nullptr && falseCase.getOperation() !=
nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1643 printAssignmentStart(node, varName, isDep);
1645 printAssignmentEnd(node);
1647 _code << _indentation <<
"if( ";
1653 printAssignmentStart(node, varName, isDep);
1655 printAssignmentEnd(node);
1656 _code << _indentation <<
"} else {\n";
1658 printAssignmentStart(node, varName, isDep);
1660 printAssignmentEnd(node);
1661 _code << _indentation <<
"}\n";
1665 inline bool isSameArgument(
const Arg& newArg,
1666 const Arg* oldArg) {
1667 if (oldArg !=
nullptr) {
1668 if (oldArg->getParameter() !=
nullptr) {
1669 if (newArg.getParameter() !=
nullptr) {
1670 return (*newArg.getParameter() == *oldArg->getParameter());
1673 return (newArg.getOperation() == oldArg->getOperation());
1679 virtual void printArrayCreationOp(
Node& op);
1681 virtual void printSparseArrayCreationOp(
Node& op);
1683 inline void printArrayStructInit(
const std::string& dataArrayName,
1685 const std::vector<Node*>& arrays,
1688 inline void printArrayStructInit(
const std::string& dataArrayName,
1691 inline void markArrayChanged(
Node& ty);
1696 std::vector<const Arg*>& tmpArrayValues);
1698 inline std::string getTempArrayName(
const Node& op);
1700 virtual void printArrayElementOp(
Node& op);
1703 CPPADCG_ASSERT_KNOWN(atomicFor.
getInfo().size() == 3,
"Invalid number of information elements for atomic forward operation");
1704 int q = atomicFor.
getInfo()[1];
1705 int p = atomicFor.
getInfo()[2];
1707 const std::vector<Arg>& opArgs = atomicFor.
getArguments();
1708 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2,
"Invalid number of arguments for atomic forward operation");
1710 size_t id = atomicFor.
getInfo()[0];
1711 size_t atomicIndex = _info->atomicFunctionId2Index.at(
id);
1713 std::vector<Node*> tx(p1), ty(p1);
1714 for (
size_t k = 0; k < p1; k++) {
1715 tx[k] = opArgs[0 * p1 + k].getOperation();
1716 ty[k] = opArgs[1 * p1 + k].getOperation();
1719 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1720 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1722 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1725 for (
size_t k = 0; k < p1; k++) {
1726 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1729 printArrayStructInit(_ATOMIC_TY, *ty[p]);
1732 _code << _indentation <<
"atomicFun.forward(atomicFun.libModel, " 1733 << atomicIndex <<
", " << q <<
", " << p <<
", " 1734 << _ATOMIC_TX <<
", &" << _ATOMIC_TY <<
"); // " 1735 << _info->atomicFunctionId2Name.at(
id)
1741 markArrayChanged(*ty[p]);
1745 CPPADCG_ASSERT_KNOWN(atomicRev.
getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation");
1746 int p = atomicRev.
getInfo()[1];
1748 const std::vector<Arg>& opArgs = atomicRev.
getArguments();
1749 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4,
"Invalid number of arguments for atomic reverse operation");
1751 size_t id = atomicRev.
getInfo()[0];
1752 size_t atomicIndex = _info->atomicFunctionId2Index.at(
id);
1753 std::vector<Node*> tx(p1), px(p1), py(p1);
1754 for (
size_t k = 0; k < p1; k++) {
1755 tx[k] = opArgs[0 * p1 + k].getOperation();
1756 px[k] = opArgs[2 * p1 + k].getOperation();
1757 py[k] = opArgs[3 * p1 + k].getOperation();
1760 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1761 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1763 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1765 CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type");
1766 CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type");
1769 for (
size_t k = 0; k < p1; k++) {
1770 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1773 for (
size_t k = 0; k < p1; k++) {
1774 printArrayStructInit(_ATOMIC_PY, k, py, k);
1777 printArrayStructInit(_ATOMIC_PX, *px[0]);
1780 _code << _indentation <<
"atomicFun.reverse(atomicFun.libModel, " 1781 << atomicIndex <<
", " << p <<
", " 1782 << _ATOMIC_TX <<
", &" << _ATOMIC_PX <<
", " << _ATOMIC_PY <<
"); // " 1783 << _info->atomicFunctionId2Name.at(
id)
1789 markArrayChanged(*px[0]);
1792 virtual unsigned printDependentMultiAssign(
Node& node) {
1793 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type");
1794 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments");
1797 for (
size_t a = 0; a < args.size(); a++) {
1798 bool useArg =
false;
1799 const Arg& arg = args[a];
1800 if (arg.getParameter() !=
nullptr) {
1803 CGOpCode op = arg.getOperation()->getOperationType();
1804 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1808 printAssignment(node, arg);
1815 virtual void printLoopStart(
Node& node) {
1816 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopStart,
"Invalid node type");
1819 _currentLoops.push_back(&lnode);
1821 const std::string& jj = *lnode.getIndex().getName();
1822 std::string iterationCount;
1823 if (lnode.getIterationCountNode() !=
nullptr) {
1824 iterationCount = *lnode.getIterationCountNode()->getIndex().getName();
1826 std::ostringstream oss;
1827 oss << lnode.getIterationCount();
1828 iterationCount = oss.str();
1831 _code << _spaces <<
"for(" 1833 << jj <<
" < " << iterationCount <<
"; " 1835 _indentation += _spaces;
1838 virtual void printLoopEnd(
Node& node) {
1839 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopEnd,
"Invalid node type");
1841 _indentation.resize(_indentation.size() - _spaces.size());
1843 _code << _indentation <<
"}\n";
1845 _currentLoops.pop_back();
1849 virtual size_t printLoopIndexDeps(
const std::vector<Node*>& variableOrder,
1855 virtual void printLoopIndexedDep(
Node& node);
1857 virtual void printLoopIndexedIndep(
Node& node) {
1858 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedIndep,
"Invalid node type");
1859 CPPADCG_ASSERT_KNOWN(node.
getInfo().size() == 1,
"Invalid number of information elements for loop indexed independent operation");
1862 size_t pos = node.
getInfo()[1];
1863 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1864 _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1867 virtual void printLoopIndexedTmp(
Node& node) {
1868 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type");
1869 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for loop indexed temporary operation");
1871 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1876 virtual void printTmpVar(
Node& node) {
1877 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Tmp,
"Invalid node type");
1878 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for temporary variable usage operation");
1880 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation");
1882 _code << *tmpVar->getName();
1885 virtual void printIndexAssign(
Node& node) {
1886 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexAssign,
"Invalid node type");
1887 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for an index assignment operation");
1892 _code << _indentation << (*inode.getIndex().getName())
1893 <<
" = " << indexPattern2String(ip, inode.getIndexPatternIndexes()) <<
";\n";
1896 virtual void printIndexCondExprOp(
Node& node) {
1897 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexCondExpr,
"Invalid node type");
1898 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for an index condition expression operation");
1899 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an index condition expression operation");
1900 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index,
"Invalid argument for an index condition expression operation");
1902 const std::vector<size_t>& info = node.
getInfo();
1905 const std::string& index = *iterationIndexOp.getIndex().getName();
1907 printIndexCondExpr(_code, info, index);
1915 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::StartIf,
"Invalid node type");
1916 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'if start' operation");
1917 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'if start' operation");
1919 _code << _indentation <<
"if(";
1920 printIndexCondExprOp(*node.
getArguments()[0].getOperation());
1923 _indentation += _spaces;
1932 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::ElseIf,
"Invalid node type");
1933 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 2,
"Invalid number of arguments for an 'else if' operation");
1934 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation");
1935 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation");
1937 _indentation.resize(_indentation.size() - _spaces.size());
1939 _code << _indentation <<
"} else if(";
1940 printIndexCondExprOp(*node.
getArguments()[1].getOperation());
1943 _indentation += _spaces;
1951 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Else,
"Invalid node type");
1952 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'else' operation");
1954 _indentation.resize(_indentation.size() - _spaces.size());
1956 _code << _indentation <<
"} else {\n";
1958 _indentation += _spaces;
1961 virtual void printEndIf(
Node& node) {
1962 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation");
1964 _indentation.resize(_indentation.size() - _spaces.size());
1966 _code << _indentation <<
"}\n";
1969 virtual void printCondResult(
Node& node) {
1970 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::CondResult,
"Invalid node type");
1971 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for an assignment inside an if/else operation");
1972 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation");
1973 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation");
1977 printAssignment(nodeArg);
1980 virtual void printUserCustom(
Node& node) {
1981 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::UserCustom,
"Invalid node type");
1983 throw CGException(
"Unable to generate C source code for user custom operation nodes.");
1986 inline bool isDependent(
const Node& arg)
const {
1990 size_t id = getVariableID(arg);
1991 return id > _independentSize &&
id < _minTemporaryVarID;
1994 virtual void printParameter(
const Base& value) {
1996 std::ostringstream os;
1997 os << std::setprecision(_parameterPrecision) << value;
1999 std::string number = os.str();
2002 if (std::abs(value) > Base(0) && value != Base(1) && value != Base(-1)) {
2003 if (number.find(
'.') == std::string::npos && number.find(
'e') == std::string::npos) {
2011 virtual const std::string& getComparison(
enum CGOpCode op)
const {
2013 case CGOpCode::ComLt:
2014 return _C_COMP_OP_LT;
2016 case CGOpCode::ComLe:
2017 return _C_COMP_OP_LE;
2019 case CGOpCode::ComEq:
2020 return _C_COMP_OP_EQ;
2022 case CGOpCode::ComGe:
2023 return _C_COMP_OP_GE;
2025 case CGOpCode::ComGt:
2026 return _C_COMP_OP_GT;
2028 case CGOpCode::ComNe:
2029 return _C_COMP_OP_NE;
2032 CPPAD_ASSERT_UNKNOWN(0);
2034 throw CGException(
"Invalid comparison operator code");
2037 inline const std::string& getPrintfBaseFormat() {
2038 static const std::string format;
2042 static bool isFunction(
enum CGOpCode op) {
2043 return isUnaryFunction(op) || op == CGOpCode::Pow;
2046 static bool isUnaryFunction(
enum CGOpCode op) {
2049 case CGOpCode::Acos:
2050 case CGOpCode::Asin:
2051 case CGOpCode::Atan:
2052 case CGOpCode::Cosh:
2056 case CGOpCode::Sinh:
2058 case CGOpCode::Sqrt:
2059 case CGOpCode::Tanh:
2061 #if CPPAD_USE_CPLUSPLUS_2011 2063 case CGOpCode::Asinh:
2064 case CGOpCode::Acosh:
2065 case CGOpCode::Atanh:
2066 case CGOpCode::Expm1:
2067 case CGOpCode::Log1p:
2075 inline static bool isCondAssign(
enum CGOpCode op) {
2077 case CGOpCode::ComLt:
2078 case CGOpCode::ComLe:
2079 case CGOpCode::ComEq:
2080 case CGOpCode::ComGe:
2081 case CGOpCode::ComGt:
2082 case CGOpCode::ComNe:
2090 class AtomicFuncArray {
2097 unsigned short scope;
2100 template<
class Base>
2103 template<
class Base>
2105 template<
class Base>
2107 template<
class Base>
2109 template<
class Base>
2111 template<
class Base>
2113 template<
class Base>
2116 template<
class Base>
2119 template<
class Base>
2122 template<
class Base>
2125 template<
class Base>
2128 template<
class Base>
2131 template<
class Base>
2134 template<
class Base>
2136 "typedef struct Array {\n" 2138 " " + U_INDEX_TYPE +
" size;\n" 2140 " const " + U_INDEX_TYPE +
"* idx;\n" 2141 " " + U_INDEX_TYPE +
" nnz;\n" 2144 "struct LangCAtomicFun {\n" 2145 " void* libModel;\n" 2146 " int (*forward)(void* libModel,\n" 2147 " int atomicIndex,\n" 2150 " const Array tx[],\n" 2152 " int (*reverse)(void* libModel,\n" 2153 " int atomicIndex,\n" 2155 " const Array tx[],\n" 2157 " const Array py[]);\n"
virtual void printElseIf(Node &node)
LanguageC(const std::string &varTypeName, size_t spaces=3)
virtual bool directlyAssignsVariable(const Node &var) const
const std::string * getName() const
const std::vector< Argument< Base > > & getArguments() const
bool createsNewVariable(const Node &var, size_t totalUseCount) const override
virtual void printAtomicForwardOp(Node &atomicFor)
static void printFunctionDeclaration(std::ostringstream &out, const std::string &returnType, const std::string &functionName, const std::vector< std::string > &arguments, const std::vector< std::string > &arguments2={})
cg::CG< Base > pow(const cg::CG< Base > &x, const cg::CG< Base > &y)
virtual size_t getParameterPrecision() const
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
CGOpCode getOperationType() const
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg *> &tmpArrayValues)
virtual void printElse(Node &node)
bool requiresVariableDependencies() const override
virtual void setParameterPrecision(size_t p)
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node *> &variableOrder, size_t starti)
virtual void printStartIf(Node &node)
void setName(const std::string &name)
virtual void printAtomicReverseOp(Node &atomicRev)
void generateSourceCode(std::ostream &out, const std::unique_ptr< LanguageGenerationData< Base > > &info) override
size_t size() const noexcept
virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction=false, bool zeroArrayDependents=false, int maxForwardOrder=-1, int maxReverseOrder=-1)
const std::vector< size_t > & getInfo() const