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 std::unique_ptr<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 LangStreamStack<Base> _streamStack;
80 size_t _independentSize;
82 size_t _minTemporaryVarID;
85 std::map<size_t, size_t> _dependentIDs;
87 const ArrayView<CG<Base> >* _dependent;
89 std::map<size_t, Node*> _temporary;
91 std::string _depAssignOperation;
93 bool _ignoreZeroDepAssign;
95 std::string _functionName;
97 size_t _maxAssignmentsPerFunction;
99 size_t _maxOperationsPerAssignment;
101 std::map<std::string, std::string>* _sources;
103 std::vector<const Arg*> _tmpArrayValues;
105 std::vector<const Arg*> _tmpSparseArrayValues;
107 std::map<std::string, AtomicFuncArray> _atomicFuncArrays;
109 std::vector<const Node*> _funcArgIndexes;
110 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
112 size_t _parameterPrecision;
114 std::vector<std::string> funcArgDcl_;
115 std::vector<std::string> localFuncArgDcl_;
116 std::string localFuncArgs_;
117 std::string auxArrayName_;
129 _baseTypeName(
std::move(varTypeName)),
130 _spaces(spaces,
' '),
134 _atomicArgName(
"atomicFun"),
138 _minTemporaryVarID(0),
140 _depAssignOperation(
"="),
141 _ignoreZeroDepAssign(false),
142 _maxAssignmentsPerFunction(0),
143 _maxOperationsPerAssignment((
std::numeric_limits<size_t>::max)()),
145 _parameterPrecision(
std::numeric_limits<Base>::digits10) {
150 inline const std::string& getArgumentIn()
const {
154 inline void setArgumentIn(
const std::string& inArgName) {
155 _inArgName = inArgName;
158 inline const std::string& getArgumentOut()
const {
162 inline void setArgumentOut(
const std::string& outArgName) {
163 _outArgName = outArgName;
166 inline const std::string& getArgumentAtomic()
const {
167 return _atomicArgName;
170 inline void setArgumentAtomic(
const std::string& atomicArgName) {
171 _atomicArgName = atomicArgName;
174 inline const std::string& getDependentAssignOperation()
const {
175 return _depAssignOperation;
178 inline void setDependentAssignOperation(
const std::string& depAssignOperation) {
179 _depAssignOperation = depAssignOperation;
190 return _ignoreZeroDepAssign;
201 _ignoreZeroDepAssign = ignore;
204 virtual void setGenerateFunction(
const std::string& functionName) {
205 _functionName = functionName;
208 virtual void setFunctionIndexArgument(
const Node& funcArgIndex) {
209 _funcArgIndexes.resize(1);
210 _funcArgIndexes[0] = &funcArgIndex;
213 virtual void setFunctionIndexArguments(
const std::vector<const Node*>& funcArgIndexes) {
214 _funcArgIndexes = funcArgIndexes;
217 virtual const std::vector<const Node*>& getFunctionIndexArguments()
const {
218 return _funcArgIndexes;
228 return _parameterPrecision;
238 _parameterPrecision = p;
253 std::map<std::string, std::string>* sources) {
254 _maxAssignmentsPerFunction = maxAssignmentsPerFunction;
264 return _maxOperationsPerAssignment;
274 _maxOperationsPerAssignment = maxOperationsPerAssignment;
277 inline std::string generateTemporaryVariableDeclaration(
bool isWrapperFunction,
278 bool zeroArrayDependents,
279 const std::vector<int>& atomicMaxForward,
280 const std::vector<int>& atomicMaxReverse) {
282 if (!atomicMaxForward.empty())
283 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
286 if (!atomicMaxReverse.empty())
287 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
289 return generateTemporaryVariableDeclaration(isWrapperFunction, zeroArrayDependents,
290 maxForward, maxReverse);
309 bool zeroArrayDependents =
false,
310 int maxForwardOrder = -1,
311 int maxReverseOrder = -1) {
312 CPPADCG_ASSERT_UNKNOWN(_nameGen !=
nullptr);
315 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
317 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
318 "There must be two temporary variables")
320 _ss << _spaces <<
"// auxiliary variables\n";
324 if (tmpArg[0].array) {
325 size_t size = _nameGen->getMaxTemporaryVariableID() + 1 - _nameGen->getMinTemporaryVariableID();
326 if (size > 0 || isWrapperFunction) {
327 _ss << _spaces << _baseTypeName <<
" " << tmpArg[0].name <<
"[" << size <<
"];\n";
329 }
else if (_temporary.size() > 0) {
330 for (
const auto& p : _temporary) {
331 Node* var = p.second;
332 if (var->
getName() ==
nullptr) {
333 var->
setName(_nameGen->generateTemporary(*var, getVariableID(*var)));
337 Node* var1 = _temporary.begin()->second;
338 const std::string& varName1 = *var1->
getName();
339 _ss << _spaces << _baseTypeName <<
" " << varName1;
341 typename std::map<size_t, Node*>::const_iterator it = _temporary.begin();
342 for (it++; it != _temporary.end(); ++it) {
343 _ss <<
", " << *it->second->getName();
351 size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
352 if (arraySize > 0 || isWrapperFunction) {
353 _ss << _spaces << _baseTypeName <<
" " << tmpArg[1].name <<
"[" << arraySize <<
"];\n";
359 size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
360 if (sArraySize > 0 || isWrapperFunction) {
361 _ss << _spaces << _baseTypeName <<
" " << tmpArg[2].name <<
"[" << sArraySize <<
"];\n";
362 _ss << _spaces << U_INDEX_TYPE <<
" " << _C_SPARSE_INDEX_ARRAY <<
"[" << sArraySize <<
"];\n";
365 if (!isWrapperFunction) {
366 generateArrayContainersDeclaration(_ss, maxForwardOrder, maxReverseOrder);
370 if (!isWrapperFunction && (arraySize > 0 || sArraySize > 0)) {
371 _ss << _spaces << _baseTypeName <<
"* " << auxArrayName_ <<
";\n";
374 if ((isWrapperFunction && zeroArrayDependents) ||
375 (!isWrapperFunction && (arraySize > 0 || sArraySize > 0 || zeroArrayDependents))) {
376 _ss << _spaces << U_INDEX_TYPE <<
" i;\n";
380 createIndexDeclaration();
383 std::string code = _ss.str();
389 inline void generateArrayContainersDeclaration(std::ostringstream& ss,
390 const std::vector<int>& atomicMaxForward,
391 const std::vector<int>& atomicMaxReverse) {
393 if (!atomicMaxForward.empty())
394 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
397 if (!atomicMaxReverse.empty())
398 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
400 generateArrayContainersDeclaration(ss, maxForward, maxReverse);
403 virtual void generateArrayContainersDeclaration(std::ostringstream& ss,
404 int maxForwardOrder = -1,
405 int maxReverseOrder = -1) {
406 if (maxForwardOrder >= 0 || maxReverseOrder >= 0) {
407 ss << _spaces <<
"Array " << _ATOMIC_TX <<
"[" << (std::max<int>(maxForwardOrder, maxReverseOrder) + 1) <<
"];\n";
408 if (maxForwardOrder >= 0)
409 ss << _spaces <<
"Array " << _ATOMIC_TY <<
";\n";
410 if (maxReverseOrder >= 0) {
411 ss << _spaces <<
"Array " << _ATOMIC_PX <<
";\n";
412 ss << _spaces <<
"Array " << _ATOMIC_PY <<
"[" << (maxReverseOrder + 1) <<
"];\n";
417 virtual std::string generateDependentVariableDeclaration() {
418 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
419 CPPADCG_ASSERT_KNOWN(!depArg.empty(),
420 "There must be at least one dependent argument")
422 _ss << _spaces <<
"//dependent variables\n";
423 for (
size_t i = 0; i < depArg.size(); i++) {
424 _ss << _spaces << argumentDeclaration(depArg[i]) <<
" = " << _outArgName <<
"[" << i <<
"];\n";
427 std::string code = _ss.str();
432 virtual std::string generateIndependentVariableDeclaration() {
433 const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
434 CPPADCG_ASSERT_KNOWN(!indArg.empty(),
435 "There must be at least one independent argument")
437 _ss << _spaces <<
"//independent variables\n";
438 for (
size_t i = 0; i < indArg.size(); i++) {
439 _ss << _spaces <<
"const " << argumentDeclaration(indArg[i]) <<
" = " << _inArgName <<
"[" << i <<
"];\n";
442 std::string code = _ss.str();
447 inline std::string generateArgumentAtomicDcl()
const {
448 return "struct LangCAtomicFun " + _atomicArgName;
451 virtual std::string generateFunctionArgumentsDcl()
const {
452 std::string args = generateFunctionIndexArgumentsDcl();
455 args += generateDefaultFunctionArgumentsDcl();
460 virtual std::vector<std::string> generateFunctionArgumentsDcl2()
const {
461 std::vector<std::string> args = generateFunctionIndexArgumentsDcl2();
462 std::vector<std::string> dArgs = generateDefaultFunctionArgumentsDcl2();
463 args.insert(args.end(), dArgs.begin(), dArgs.end());
467 virtual std::string generateDefaultFunctionArgumentsDcl()
const {
468 return implode(generateDefaultFunctionArgumentsDcl2(),
", ");
471 virtual std::vector<std::string> generateDefaultFunctionArgumentsDcl2()
const {
472 return std::vector<std::string> {_baseTypeName +
" const *const * " + _inArgName,
473 _baseTypeName +
"*const * " + _outArgName,
474 generateArgumentAtomicDcl()};
477 virtual std::string generateFunctionIndexArgumentsDcl()
const {
478 return implode(generateFunctionIndexArgumentsDcl2(),
", ");
481 virtual std::vector<std::string> generateFunctionIndexArgumentsDcl2()
const {
482 std::vector<std::string> argtxt(_funcArgIndexes.size());
483 for (
size_t a = 0; a < _funcArgIndexes.size(); a++) {
484 argtxt[a] = U_INDEX_TYPE +
" " + *_funcArgIndexes[a]->getName();
489 virtual std::string generateDefaultFunctionArguments()
const {
490 return _inArgName +
", " + _outArgName +
", " + _atomicArgName;
493 virtual std::string generateFunctionIndexArguments()
const {
495 for (
size_t a = 0; a < _funcArgIndexes.size(); a++) {
496 if (a > 0) argtxt +=
", ";
497 argtxt += *_funcArgIndexes[a]->getName();
502 inline void createIndexDeclaration();
504 CPPAD_CG_C_LANG_FUNCNAME(abs)
505 CPPAD_CG_C_LANG_FUNCNAME(acos)
506 CPPAD_CG_C_LANG_FUNCNAME(asin)
507 CPPAD_CG_C_LANG_FUNCNAME(atan)
508 CPPAD_CG_C_LANG_FUNCNAME(cosh)
509 CPPAD_CG_C_LANG_FUNCNAME(cos)
510 CPPAD_CG_C_LANG_FUNCNAME(exp)
511 CPPAD_CG_C_LANG_FUNCNAME(log)
512 CPPAD_CG_C_LANG_FUNCNAME(sinh)
513 CPPAD_CG_C_LANG_FUNCNAME(sin)
514 CPPAD_CG_C_LANG_FUNCNAME(sqrt)
515 CPPAD_CG_C_LANG_FUNCNAME(tanh)
516 CPPAD_CG_C_LANG_FUNCNAME(tan)
517 CPPAD_CG_C_LANG_FUNCNAME(
pow)
519 #if CPPAD_USE_CPLUSPLUS_2011 520 CPPAD_CG_C_LANG_FUNCNAME(erf)
521 CPPAD_CG_C_LANG_FUNCNAME(erfc)
522 CPPAD_CG_C_LANG_FUNCNAME(asinh)
523 CPPAD_CG_C_LANG_FUNCNAME(acosh)
524 CPPAD_CG_C_LANG_FUNCNAME(atanh)
525 CPPAD_CG_C_LANG_FUNCNAME(expm1)
526 CPPAD_CG_C_LANG_FUNCNAME(log1p)
539 const std::string& returnType,
540 const std::string& functionName,
541 const std::vector<std::string>& arguments,
542 const std::vector<std::string>& arguments2 = {}) {
543 out << returnType <<
" " << functionName <<
"(";
545 size_t offset = returnType.size() + 1 + functionName.size() + 1;
546 for (
const std::string& a : arguments) {
548 out <<
",\n" << std::setw(offset) <<
" ";
553 for (
const std::string& a : arguments2) {
555 out <<
",\n" << std::setw(offset) <<
" ";
563 static inline void printIndexCondExpr(std::ostringstream& out,
564 const std::vector<size_t>& info,
565 const std::string& index) {
566 CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0,
"Invalid number of information elements for an index condition expression operation")
568 size_t infoSize = info.size();
569 for (
size_t e = 0; e < infoSize; e += 2) {
573 size_t min = info[e];
574 size_t max = info[e + 1];
576 out << index <<
" == " << min;
577 }
else if (min == 0) {
578 out << index <<
" <= " << max;
579 }
else if (max == (std::numeric_limits<size_t>::max)()) {
580 out << min <<
" <= " << index;
586 out << min <<
" == " << index <<
" || " << index <<
" == " << max;
588 out << min <<
" <= " << index <<
" && " << index <<
" <= " << max;
600 static inline void printStaticIndexArray(std::ostringstream& os,
601 const std::string& name,
602 const std::vector<size_t>& values);
604 static inline void printStaticIndexMatrix(std::ostringstream& os,
605 const std::string& name,
606 const std::map<
size_t, std::map<size_t, size_t> >& values);
611 static inline void generateNames4RandomIndexPatterns(
const std::set<RandomIndexPattern*>& randomPatterns);
614 const std::string& identation,
615 const std::set<RandomIndexPattern*>& randomPatterns);
617 static inline std::string indexPattern2String(
const IndexPattern& ip,
620 static inline std::string indexPattern2String(
const IndexPattern& ip,
621 const std::string& index);
623 static inline std::string indexPattern2String(
const IndexPattern& ip,
624 const std::vector<const Node*>& indexes);
626 static inline std::string indexPattern2String(
const IndexPattern& ip,
627 const std::vector<const std::string*>& indexes);
633 const std::string& index);
666 const bool createFunction = !_functionName.empty();
667 const bool multiFunction = createFunction && _maxAssignmentsPerFunction > 0 && _sources !=
nullptr;
673 _indentation = _spaces;
675 localFuncArgDcl_.clear();
678 _currentLoops.clear();
679 _atomicFuncArrays.clear();
680 _streamStack.clear();
681 _dependentIDs.clear();
684 _info = std::move(info);
685 _independentSize = _info->independent.size();
686 _dependent = &_info->dependent;
687 _nameGen = &_info->nameGen;
688 _minTemporaryVarID = _info->minTemporaryVarID;
690 const std::vector<Node*>& variableOrder = _info->variableOrder;
692 _tmpArrayValues.resize(_nameGen->getMaxTemporaryArrayVariableID());
693 std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(),
nullptr);
694 _tmpSparseArrayValues.resize(_nameGen->getMaxTemporarySparseArrayVariableID());
695 std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(),
nullptr);
700 generateNames4RandomIndexPatterns(_info->indexRandomPatterns);
706 for (
size_t j = 0; j < _independentSize; j++) {
707 Node& op = *_info->independent[j];
709 op.
setName(_nameGen->generateIndependent(op, getVariableID(op)));
714 for (
size_t i = 0; i < dependent.
size(); i++) {
715 Node* node = dependent[i].getOperationNode();
718 size_t pos = node->
getInfo()[0];
719 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
720 node->
setName(_nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip));
723 node->
setName(_nameGen->generateDependent(i));
731 const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
732 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
733 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
734 CPPADCG_ASSERT_KNOWN(!indArg.empty() && !depArg.empty(),
735 "There must be at least one dependent and one independent argument")
736 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
737 "There must be three temporary variables")
739 if (createFunction) {
740 funcArgDcl_ = generateFunctionArgumentsDcl2();
742 localFuncArgDcl_.reserve(funcArgDcl_.size() + 4);
743 localFuncArgDcl_ = funcArgDcl_;
744 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[0]));
745 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[1]));
746 localFuncArgDcl_.push_back(argumentDeclaration(tmpArg[2]));
747 localFuncArgDcl_.push_back(U_INDEX_TYPE +
"* " + _C_SPARSE_INDEX_ARRAY);
749 localFuncArgs_ = generateDefaultFunctionArguments() +
", " 750 + tmpArg[0].name +
", " 751 + tmpArg[1].name +
", " 752 + tmpArg[2].name +
", " 753 + _C_SPARSE_INDEX_ARRAY;
756 auxArrayName_ = tmpArg[1].name +
"p";
762 std::set<size_t> dependentDuplicates;
764 for (
size_t i = 0; i < dependent.
size(); i++) {
765 Node* node = dependent[i].getOperationNode();
766 if (node !=
nullptr) {
768 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
769 size_t varID = getVariableID(*node);
771 auto it2 = _dependentIDs.find(varID);
772 if (it2 == _dependentIDs.end()) {
773 _dependentIDs[getVariableID(*node)] = i;
776 dependentDuplicates.insert(i);
784 std::vector<std::string> localFuncNames;
786 localFuncNames.reserve(variableOrder.size() / _maxAssignmentsPerFunction);
792 if (variableOrder.size() > 0) {
794 for (
Node* node : variableOrder) {
795 CGOpCode op = node->getOperationType();
796 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
798 if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
799 node->setName(_nameGen->generateTemporary(*node, getVariableID(*node)));
800 }
else if (op == CGOpCode::ArrayCreation) {
801 node->setName(_nameGen->generateTemporaryArray(*node, getVariableID(*node)));
802 }
else if (op == CGOpCode::SparseArrayCreation) {
803 node->setName(_nameGen->generateTemporarySparseArray(*node, getVariableID(*node)));
811 if (_info->zeroDependents) {
813 for (
size_t i = 0; i < depArg.size(); i++) {
816 _code << _indentation <<
"for(i = 0; i < " << _dependent->size() <<
"; i++) " << a.name <<
"[i]";
818 _code << _indentation << _nameGen->generateDependent(i);
821 printParameter(Base(0.0));
826 size_t assignCount = 0;
827 for (
size_t i = 0; i < variableOrder.size(); ++i) {
828 Node* it = variableOrder[i];
831 if (assignCount >= _maxAssignmentsPerFunction && multiFunction && _currentLoops.empty()) {
833 saveLocalFunction(localFuncNames, localFuncNames.empty() && _info->zeroDependents);
839 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
841 }
else if (node.getOperationType() == CGOpCode::TmpDcl) {
843 }
else if (node.getOperationType() == CGOpCode::LoopIndexedDep) {
845 i = printLoopIndexDeps(variableOrder, i);
849 assignCount += printAssignment(node);
851 CPPAD_ASSERT_KNOWN(_streamStack.empty(),
"Error writing all operations to output stream")
854 if (!localFuncNames.empty() && assignCount > 0) {
856 saveLocalFunction(localFuncNames,
false);
860 if (!localFuncNames.empty()) {
864 CPPADCG_ASSERT_KNOWN(tmpArg[0].array,
865 "The temporary variables must be saved in an array in order to generate multiple functions")
867 _code << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
869 std::string localFuncArgDcl2 = implode(localFuncArgDcl_,
", ");
870 for (
auto & localFuncName : localFuncNames) {
871 _code <<
"void " << localFuncName <<
"(" << localFuncArgDcl2 <<
");\n";
876 _nameGen->customFunctionVariableDeclarations(_code);
877 _code << generateIndependentVariableDeclaration() <<
"\n";
878 _code << generateDependentVariableDeclaration() <<
"\n";
879 _code << generateTemporaryVariableDeclaration(
true,
false,
880 _info->atomicFunctionsMaxForward,
881 _info->atomicFunctionsMaxReverse) <<
"\n";
882 _nameGen->prepareCustomFunctionVariables(_code);
883 for (
auto & localFuncName : localFuncNames) {
884 _code << _spaces << localFuncName <<
"(" << localFuncArgs_ <<
");\n";
889 if (!dependentDuplicates.empty()) {
890 _code << _spaces <<
"// variable duplicates: " << dependentDuplicates.size() <<
"\n";
891 for (
size_t index : dependentDuplicates) {
892 const CG<Base>& dep = (*_dependent)[index];
893 std::string varName = _nameGen->generateDependent(index);
894 const std::string& origVarName = *dep.getOperationNode()->getName();
896 _code << _spaces << varName <<
" " << _depAssignOperation <<
" " << origVarName <<
";\n";
901 bool commentWritten =
false;
902 for (
size_t i = 0; i < dependent.
size(); i++) {
903 if (dependent[i].isParameter()) {
904 if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
905 if (!commentWritten) {
906 _code << _spaces <<
"// dependent variables without operations\n";
907 commentWritten =
true;
909 std::string varName = _nameGen->generateDependent(i);
910 _code << _spaces << varName <<
" " << _depAssignOperation <<
" ";
911 printParameter(dependent[i].getValue());
914 }
else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
915 if (!commentWritten) {
916 _code << _spaces <<
"// dependent variables without operations\n";
917 commentWritten =
true;
919 std::string varName = _nameGen->generateDependent(i);
920 const std::string& indepName = *dependent[i].getOperationNode()->getName();
921 _code << _spaces << varName <<
" " << _depAssignOperation <<
" " << indepName <<
";\n";
928 if (createFunction) {
929 if (localFuncNames.empty()) {
930 _ss <<
"#include <math.h>\n" 931 "#include <stdio.h>\n\n" 932 << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
935 _nameGen->customFunctionVariableDeclarations(_ss);
936 _ss << generateIndependentVariableDeclaration() <<
"\n";
937 _ss << generateDependentVariableDeclaration() <<
"\n";
938 _ss << generateTemporaryVariableDeclaration(
false, _info->zeroDependents,
939 _info->atomicFunctionsMaxForward,
940 _info->atomicFunctionsMaxReverse) <<
"\n";
941 _nameGen->prepareCustomFunctionVariables(_ss);
943 _nameGen->finalizeCustomFunctionVariables(_ss);
948 if (_sources !=
nullptr) {
949 (*_sources)[_functionName +
".c"] = _ss.str();
952 _nameGen->finalizeCustomFunctionVariables(_code);
955 (*_sources)[_functionName +
".c"] = _code.str();
962 inline size_t getVariableID(
const Node& node)
const {
963 return _info->varId[node];
966 inline unsigned printAssignment(
Node& node) {
967 return pushAssignment(node, node);
970 inline unsigned pushAssignment(
Node& nodeName,
971 const Arg& nodeRhs) {
972 if (nodeRhs.getOperation() !=
nullptr) {
973 return pushAssignment(nodeName, *nodeRhs.getOperation());
975 pushAssignmentStart(nodeName);
976 pushParameter(*nodeRhs.getParameter());
977 pushAssignmentEnd(nodeName);
979 _streamStack.flush();
985 inline unsigned pushAssignment(
Node& nodeName,
989 pushAssignmentStart(nodeName);
991 unsigned lines = pushExpressionNoVarCheck2(nodeRhs);
993 pushAssignmentEnd(nodeRhs);
996 _streamStack.flush();
1000 size_t arrayId = getVariableID(*array);
1001 size_t pos = nodeRhs.
getInfo()[0];
1003 _tmpArrayValues[arrayId - 1 + pos] =
nullptr;
1005 _tmpSparseArrayValues[arrayId - 1 + pos] =
nullptr;
1011 inline virtual void pushAssignmentStart(
Node& op) {
1012 pushAssignmentStart(op, createVariableName(op), isDependent(op));
1015 inline virtual void pushAssignmentStart(
Node& node,
1016 const std::string& varName,
1019 _temporary[getVariableID(node)] = &node;
1022 _streamStack << _indentation << varName <<
" ";
1025 if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.
getInfo()[1] == 1)) {
1026 _streamStack <<
"+=";
1028 _streamStack << _depAssignOperation;
1031 _streamStack <<
"=";
1033 _streamStack <<
" ";
1036 inline virtual void pushAssignmentEnd(
Node& op) {
1037 _streamStack <<
";\n";
1040 virtual std::string argumentDeclaration(
const FuncArgument& funcArg)
const {
1041 std::string dcl = _baseTypeName;
1042 if (funcArg.array) {
1045 return dcl +
" " + funcArg.name;
1048 virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
1049 bool zeroDependentArray) {
1050 _ss << _functionName <<
"__" << (localFuncNames.size() + 1);
1051 std::string funcName = _ss.str();
1054 _ss <<
"#include <math.h>\n" 1055 "#include <stdio.h>\n\n" 1056 << ATOMICFUN_STRUCT_DEFINITION <<
"\n\n";
1059 _nameGen->customFunctionVariableDeclarations(_ss);
1060 _ss << generateIndependentVariableDeclaration() <<
"\n";
1061 _ss << generateDependentVariableDeclaration() <<
"\n";
1062 size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
1063 size_t sArraySize = _nameGen->getMaxTemporarySparseArrayVariableID();
1064 if (arraySize > 0 || sArraySize > 0) {
1065 _ss << _spaces << _baseTypeName <<
"* " << auxArrayName_ <<
";\n";
1068 generateArrayContainersDeclaration(_ss,
1069 _info->atomicFunctionsMaxForward,
1070 _info->atomicFunctionsMaxReverse);
1072 if (arraySize > 0 || sArraySize > 0 || zeroDependentArray) {
1073 _ss << _spaces << U_INDEX_TYPE <<
" i;\n";
1077 createIndexDeclaration();
1079 _nameGen->prepareCustomFunctionVariables(_ss);
1081 _nameGen->finalizeCustomFunctionVariables(_ss);
1084 (*_sources)[funcName +
".c"] = _ss.str();
1085 localFuncNames.push_back(funcName);
1092 size_t totalUseCount,
1093 size_t opCount)
const override {
1095 if (totalUseCount > 1) {
1096 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1098 return (op == CGOpCode::ArrayCreation ||
1099 op == CGOpCode::SparseArrayCreation ||
1100 op == CGOpCode::AtomicForward ||
1101 op == CGOpCode::AtomicReverse ||
1102 op == CGOpCode::ComLt ||
1103 op == CGOpCode::ComLe ||
1104 op == CGOpCode::ComEq ||
1105 op == CGOpCode::ComGe ||
1106 op == CGOpCode::ComGt ||
1107 op == CGOpCode::ComNe ||
1108 op == CGOpCode::LoopIndexedDep ||
1109 op == CGOpCode::LoopIndexedTmp ||
1110 op == CGOpCode::IndexAssign ||
1111 op == CGOpCode::Assign ||
1112 opCount >= _maxOperationsPerAssignment) &&
1113 op != CGOpCode::CondResult;
1117 virtual bool requiresVariableName(
const Node& var)
const {
1119 if (_info->totalUseCount.get(var) > 1) {
1120 return (op != CGOpCode::Pri &&
1121 op != CGOpCode::AtomicForward &&
1122 op != CGOpCode::AtomicReverse &&
1123 op != CGOpCode::LoopStart &&
1124 op != CGOpCode::LoopEnd &&
1125 op != CGOpCode::Index &&
1126 op != CGOpCode::IndexAssign &&
1127 op != CGOpCode::StartIf &&
1128 op != CGOpCode::ElseIf &&
1129 op != CGOpCode::Else &&
1130 op != CGOpCode::EndIf &&
1131 op != CGOpCode::CondResult &&
1132 op != CGOpCode::LoopIndexedTmp &&
1133 op != CGOpCode::Tmp);
1135 return isCondAssign(op);
1148 return isCondAssign(op) ||
1149 op == CGOpCode::Pri ||
1150 op == CGOpCode::ArrayCreation ||
1151 op == CGOpCode::SparseArrayCreation ||
1152 op == CGOpCode::AtomicForward ||
1153 op == CGOpCode::AtomicReverse ||
1154 op == CGOpCode::DependentMultiAssign ||
1155 op == CGOpCode::LoopStart ||
1156 op == CGOpCode::LoopEnd ||
1157 op == CGOpCode::IndexAssign ||
1158 op == CGOpCode::StartIf ||
1159 op == CGOpCode::ElseIf ||
1160 op == CGOpCode::Else ||
1161 op == CGOpCode::EndIf ||
1162 op == CGOpCode::CondResult ||
1163 op == CGOpCode::IndexDeclaration;
1166 bool requiresVariableArgument(
enum CGOpCode op,
size_t argIndex)
const override {
1167 return op == CGOpCode::Sign || op == CGOpCode::CondResult || op == CGOpCode::Pri;
1170 inline const std::string& createVariableName(
Node& var) {
1172 CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0)
1173 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward)
1174 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse)
1175 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart)
1176 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd)
1177 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index)
1178 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign)
1179 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration)
1181 if (var.
getName() ==
nullptr) {
1182 if (op == CGOpCode::ArrayCreation) {
1183 var.
setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
1185 }
else if (op == CGOpCode::SparseArrayCreation) {
1186 var.
setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
1188 }
else if (op == CGOpCode::LoopIndexedDep) {
1189 size_t pos = var.
getInfo()[0];
1190 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
1191 var.
setName(_nameGen->generateIndexedDependent(var, getVariableID(var), *ip));
1193 }
else if (op == CGOpCode::LoopIndexedIndep) {
1194 size_t pos = var.
getInfo()[1];
1195 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1196 var.
setName(_nameGen->generateIndexedIndependent(var, getVariableID(var), *ip));
1198 }
else if (getVariableID(var) <= _independentSize) {
1200 var.
setName(_nameGen->generateIndependent(var, getVariableID(var)));
1202 }
else if (getVariableID(var) < _minTemporaryVarID) {
1204 auto it = _dependentIDs.find(getVariableID(var));
1205 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end())
1207 size_t index = it->second;
1208 var.
setName(_nameGen->generateDependent(index));
1209 }
else if (op == CGOpCode::Pri) {
1210 CPPADCG_ASSERT_KNOWN(var.
getArguments().size() == 1,
"Invalid number of arguments for print operation")
1212 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr,
"Invalid argument for print operation")
1213 return createVariableName(*tmpVar);
1215 }
else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
1216 CPPADCG_ASSERT_KNOWN(var.
getArguments().size() >= 1,
"Invalid number of arguments for loop indexed temporary operation")
1218 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1219 return createVariableName(*tmpVar);
1223 var.
setName(_nameGen->generateTemporary(var, getVariableID(var)));
1235 virtual void pushIndependentVariableName(
Node& op) {
1236 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 0,
"Invalid number of arguments for independent variable")
1238 _streamStack << _nameGen->generateIndependent(op, getVariableID(op));
1241 virtual unsigned push(
const Arg& arg) {
1242 if (arg.getOperation() !=
nullptr) {
1244 return pushExpression(*arg.getOperation());
1247 pushParameter(*arg.getParameter());
1252 virtual unsigned pushExpression(
Node& op) {
1253 if (getVariableID(op) > 0) {
1255 _streamStack << createVariableName(op);
1264 virtual unsigned pushExpressionNoVarCheck2(
Node& node) {
1267 unsigned lines = pushExpressionNoVarCheck(node);
1271 _streamStack.flush();
1272 if (!_streamStack.empty()) {
1273 n = &_streamStack.startNewOperationNode();
1281 unsigned lines2 = pushExpressionNoVarCheck(*n);
1283 lines = std::max<unsigned>(lines, lines2);
1289 virtual unsigned pushExpressionNoVarCheck(
Node& node) {
1292 case CGOpCode::ArrayCreation:
1293 pushArrayCreationOp(node);
1295 case CGOpCode::SparseArrayCreation:
1296 pushSparseArrayCreationOp(node);
1298 case CGOpCode::ArrayElement:
1299 pushArrayElementOp(node);
1301 case CGOpCode::Assign:
1302 return pushAssignOp(node);
1305 case CGOpCode::Acos:
1306 case CGOpCode::Asin:
1307 case CGOpCode::Atan:
1308 case CGOpCode::Cosh:
1312 case CGOpCode::Sinh:
1314 case CGOpCode::Sqrt:
1315 case CGOpCode::Tanh:
1317 #if CPPAD_USE_CPLUSPLUS_2011 1319 case CGOpCode::Erfc:
1320 case CGOpCode::Asinh:
1321 case CGOpCode::Acosh:
1322 case CGOpCode::Atanh:
1323 case CGOpCode::Expm1:
1324 case CGOpCode::Log1p:
1326 pushUnaryFunction(node);
1328 case CGOpCode::AtomicForward:
1331 case CGOpCode::AtomicReverse:
1335 pushOperationAdd(node);
1337 case CGOpCode::Alias:
1338 return pushOperationAlias(node);
1340 case CGOpCode::ComLt:
1341 case CGOpCode::ComLe:
1342 case CGOpCode::ComEq:
1343 case CGOpCode::ComGe:
1344 case CGOpCode::ComGt:
1345 case CGOpCode::ComNe:
1346 pushConditionalAssignment(node);
1349 pushOperationDiv(node);
1352 pushIndependentVariableName(node);
1355 pushOperationMul(node);
1358 pushPowFunction(node);
1361 pushPrintOperation(node);
1363 case CGOpCode::Sign:
1364 pushSignFunction(node);
1367 pushOperationMinus(node);
1370 case CGOpCode::UnMinus:
1371 pushOperationUnaryMinus(node);
1374 case CGOpCode::DependentMultiAssign:
1375 return pushDependentMultiAssign(node);
1377 case CGOpCode::Index:
1379 case CGOpCode::IndexAssign:
1380 pushIndexAssign(node);
1382 case CGOpCode::IndexDeclaration:
1385 case CGOpCode::LoopStart:
1386 pushLoopStart(node);
1388 case CGOpCode::LoopIndexedIndep:
1389 pushLoopIndexedIndep(node);
1391 case CGOpCode::LoopIndexedDep:
1392 pushLoopIndexedDep(node);
1394 case CGOpCode::LoopIndexedTmp:
1395 pushLoopIndexedTmp(node);
1397 case CGOpCode::TmpDcl:
1403 case CGOpCode::LoopEnd:
1406 case CGOpCode::IndexCondExpr:
1407 pushIndexCondExprOp(node);
1409 case CGOpCode::StartIf:
1412 case CGOpCode::ElseIf:
1415 case CGOpCode::Else:
1418 case CGOpCode::EndIf:
1421 case CGOpCode::CondResult:
1422 pushCondResult(node);
1424 case CGOpCode::UserCustom:
1425 pushUserCustom(node);
1428 throw CGException(
"Unknown operation code '", op,
"'.");
1433 virtual unsigned pushAssignOp(
Node& node) {
1434 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for assign operation")
1439 virtual void pushUnaryFunction(
Node& op) {
1440 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary function")
1444 _streamStack << absFuncName();
1446 case CGOpCode::Acos:
1447 _streamStack << acosFuncName();
1449 case CGOpCode::Asin:
1450 _streamStack << asinFuncName();
1452 case CGOpCode::Atan:
1453 _streamStack << atanFuncName();
1455 case CGOpCode::Cosh:
1456 _streamStack << coshFuncName();
1459 _streamStack << cosFuncName();
1462 _streamStack << expFuncName();
1465 _streamStack << logFuncName();
1467 case CGOpCode::Sinh:
1468 _streamStack << sinhFuncName();
1471 _streamStack << sinFuncName();
1473 case CGOpCode::Sqrt:
1474 _streamStack << sqrtFuncName();
1476 case CGOpCode::Tanh:
1477 _streamStack << tanhFuncName();
1480 _streamStack << tanFuncName();
1482 #if CPPAD_USE_CPLUSPLUS_2011 1484 _streamStack << erfFuncName();
1486 case CGOpCode::Erfc:
1487 _streamStack << erfcFuncName();
1489 case CGOpCode::Asinh:
1490 _streamStack << asinhFuncName();
1492 case CGOpCode::Acosh:
1493 _streamStack << acoshFuncName();
1495 case CGOpCode::Atanh:
1496 _streamStack << atanhFuncName();
1498 case CGOpCode::Expm1:
1499 _streamStack << expm1FuncName();
1501 case CGOpCode::Log1p:
1502 _streamStack << log1pFuncName();
1509 _streamStack <<
"(";
1511 _streamStack <<
")";
1514 virtual void pushPowFunction(
Node& op) {
1515 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for pow() function")
1517 _streamStack <<powFuncName() <<
"(";
1519 _streamStack <<
", ";
1521 _streamStack <<
")";
1524 virtual void pushSignFunction(
Node& op) {
1525 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for sign() function")
1526 CPPADCG_ASSERT_UNKNOWN(op.
getArguments()[0].getOperation() !=
nullptr)
1527 CPPADCG_ASSERT_UNKNOWN(getVariableID(*op.
getArguments()[0].getOperation()) > 0)
1531 const std::string& argName = createVariableName(arg);
1533 _streamStack <<
"(" << argName <<
" " << _C_COMP_OP_GT <<
" ";
1534 pushParameter(Base(0.0));
1535 _streamStack <<
"?";
1536 pushParameter(Base(1.0));
1537 _streamStack <<
":(" << argName <<
" " << _C_COMP_OP_LT <<
" ";
1538 pushParameter(Base(0.0));
1539 _streamStack <<
"?";
1540 pushParameter(Base(-1.0));
1541 _streamStack <<
":";
1542 pushParameter(Base(0.0));
1543 _streamStack <<
"))";
1546 virtual unsigned pushOperationAlias(
Node& op) {
1547 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for alias")
1551 virtual void pushOperationAdd(
Node& op) {
1552 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for addition")
1557 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1559 _streamStack <<
" + ";
1564 _streamStack <<
" - ";
1565 pushParameter(-*right.getParameter());
1569 virtual void pushOperationMinus(
Node& op) {
1570 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for subtraction")
1575 if(right.getParameter() ==
nullptr || (*right.getParameter() >= 0)) {
1576 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1579 _streamStack <<
" - ";
1581 _streamStack <<
"(";
1585 _streamStack <<
")";
1590 _streamStack <<
" + ";
1591 pushParameter(-*right.getParameter());
1595 inline bool encloseInParenthesesDiv(
const Node* node)
const {
1596 while (node !=
nullptr) {
1597 if (getVariableID(*node) != 0)
1604 return node !=
nullptr &&
1605 getVariableID(*node) == 0 &&
1609 virtual void pushOperationDiv(
Node& op) {
1610 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for division")
1615 bool encloseLeft = encloseInParenthesesDiv(left.getOperation());
1616 bool encloseRight = encloseInParenthesesDiv(right.getOperation());
1619 _streamStack <<
"(";
1623 _streamStack <<
")";
1625 _streamStack <<
" / ";
1627 _streamStack <<
"(";
1631 _streamStack <<
")";
1635 inline bool encloseInParenthesesMul(
const Node* node)
const {
1636 while (node !=
nullptr) {
1637 if (getVariableID(*node) != 0)
1644 return node !=
nullptr &&
1645 getVariableID(*node) == 0 &&
1651 virtual void pushOperationMul(
Node& op) {
1652 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 2,
"Invalid number of arguments for multiplication")
1657 bool encloseLeft = encloseInParenthesesMul(left.getOperation());
1658 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1661 _streamStack <<
"(";
1665 _streamStack <<
")";
1667 _streamStack <<
" * ";
1669 _streamStack <<
"(";
1673 _streamStack <<
")";
1677 virtual void pushOperationUnaryMinus(
Node& op) {
1678 CPPADCG_ASSERT_KNOWN(op.
getArguments().size() == 1,
"Invalid number of arguments for unary minus")
1682 bool enclose = encloseInParenthesesMul(arg.getOperation());
1684 _streamStack <<
"-";
1686 _streamStack <<
"(";
1688 _streamStack <<
" ";
1692 _streamStack <<
")";
1696 virtual void pushPrintOperation(
const Node& node) {
1697 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Pri,
"Invalid node type")
1698 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for print operation")
1701 std::string before = pnode.getBeforeString();
1702 replaceString(before,
"\n",
"\\n");
1703 replaceString(before,
"\"",
"\\\"");
1704 std::string after = pnode.getAfterString();
1705 replaceString(after,
"\n",
"\\n");
1706 replaceString(after,
"\"",
"\\\"");
1708 _streamStack <<_indentation <<
"fprintf(stderr, \"" << before << getPrintfBaseFormat() << after <<
"\"";
1709 const std::vector<Arg>& args = pnode.getArguments();
1710 for (
size_t a = 0; a < args.size(); a++) {
1711 _streamStack <<
", ";
1714 _streamStack <<
");\n";
1717 virtual void pushConditionalAssignment(
Node& node) {
1718 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1721 const Arg &left = args[0];
1722 const Arg &right = args[1];
1723 const Arg &trueCase = args[2];
1724 const Arg &falseCase = args[3];
1726 bool isDep = isDependent(node);
1727 const std::string& varName = createVariableName(node);
1729 if ((trueCase.getParameter() !=
nullptr && falseCase.getParameter() !=
nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1730 (trueCase.getOperation() !=
nullptr && falseCase.getOperation() !=
nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1732 pushAssignmentStart(node, varName, isDep);
1734 pushAssignmentEnd(node);
1736 _streamStack <<_indentation <<
"if( ";
1740 _streamStack <<
" ) {\n";
1741 _streamStack <<_spaces;
1742 pushAssignmentStart(node, varName, isDep);
1744 pushAssignmentEnd(node);
1745 _streamStack <<_indentation <<
"} else {\n";
1746 _streamStack <<_spaces;
1747 pushAssignmentStart(node, varName, isDep);
1749 pushAssignmentEnd(node);
1750 _streamStack <<_indentation <<
"}\n";
1754 inline bool isSameArgument(
const Arg& newArg,
1755 const Arg* oldArg) {
1756 if (oldArg !=
nullptr) {
1757 if (oldArg->getParameter() !=
nullptr) {
1758 if (newArg.getParameter() !=
nullptr) {
1759 return (*newArg.getParameter() == *oldArg->getParameter());
1762 return (newArg.getOperation() == oldArg->getOperation());
1768 virtual void pushArrayCreationOp(
Node& op);
1770 virtual void pushSparseArrayCreationOp(
Node& op);
1772 inline void printArrayStructInit(
const std::string& dataArrayName,
1774 const std::vector<Node*>& arrays,
1777 inline void printArrayStructInit(
const std::string& dataArrayName,
1780 inline void markArrayChanged(
Node& ty);
1785 std::vector<const Arg*>& tmpArrayValues);
1787 inline std::string getTempArrayName(
const Node& op);
1789 virtual void pushArrayElementOp(
Node& op);
1792 CPPADCG_ASSERT_KNOWN(atomicFor.
getInfo().size() == 3,
"Invalid number of information elements for atomic forward operation")
1793 int q = atomicFor.
getInfo()[1];
1794 int p = atomicFor.
getInfo()[2];
1796 const std::vector<Arg>& opArgs = atomicFor.
getArguments();
1797 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2,
"Invalid number of arguments for atomic forward operation")
1799 size_t id = atomicFor.
getInfo()[0];
1800 size_t atomicIndex = _info->atomicFunctionId2Index.at(
id);
1802 std::vector<Node*> tx(p1), ty(p1);
1803 for (
size_t k = 0; k < p1; k++) {
1804 tx[k] = opArgs[0 * p1 + k].getOperation();
1805 ty[k] = opArgs[1 * p1 + k].getOperation();
1808 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1809 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1811 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1814 for (
size_t k = 0; k < p1; k++) {
1815 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1818 printArrayStructInit(_ATOMIC_TY, *ty[p]);
1821 _streamStack << _indentation <<
"atomicFun.forward(atomicFun.libModel, " 1822 << atomicIndex <<
", " << q <<
", " << p <<
", " 1823 << _ATOMIC_TX <<
", &" << _ATOMIC_TY <<
"); // " 1824 << _info->atomicFunctionId2Name.at(
id)
1830 markArrayChanged(*ty[p]);
1834 CPPADCG_ASSERT_KNOWN(atomicRev.
getInfo().size() == 2,
"Invalid number of information elements for atomic reverse operation")
1835 int p = atomicRev.
getInfo()[1];
1837 const std::vector<Arg>& opArgs = atomicRev.
getArguments();
1838 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4,
"Invalid number of arguments for atomic reverse operation")
1840 size_t id = atomicRev.
getInfo()[0];
1841 size_t atomicIndex = _info->atomicFunctionId2Index.at(
id);
1842 std::vector<Node*> tx(p1), px(p1), py(p1);
1843 for (
size_t k = 0; k < p1; k++) {
1844 tx[k] = opArgs[0 * p1 + k].getOperation();
1845 px[k] = opArgs[2 * p1 + k].getOperation();
1846 py[k] = opArgs[3 * p1 + k].getOperation();
1849 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1850 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1852 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1854 CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array type")
1855 CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation,
"Invalid array type")
1858 for (
size_t k = 0; k < p1; k++) {
1859 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1862 for (
size_t k = 0; k < p1; k++) {
1863 printArrayStructInit(_ATOMIC_PY, k, py, k);
1866 printArrayStructInit(_ATOMIC_PX, *px[0]);
1869 _streamStack << _indentation <<
"atomicFun.reverse(atomicFun.libModel, " 1870 << atomicIndex <<
", " << p <<
", " 1871 << _ATOMIC_TX <<
", &" << _ATOMIC_PX <<
", " << _ATOMIC_PY <<
"); // " 1872 << _info->atomicFunctionId2Name.at(
id)
1878 markArrayChanged(*px[0]);
1881 virtual unsigned pushDependentMultiAssign(
Node& node) {
1882 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::DependentMultiAssign,
"Invalid node type")
1883 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments")
1886 for (
size_t a = 0; a < args.size(); a++) {
1888 const Arg& arg = args[a];
1889 if (arg.getParameter() !=
nullptr) {
1892 CGOpCode op = arg.getOperation()->getOperationType();
1893 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1897 pushAssignment(node, arg);
1904 virtual void pushLoopStart(
Node& node) {
1905 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopStart,
"Invalid node type")
1908 _currentLoops.push_back(&lnode);
1910 const std::string& jj = *lnode.getIndex().getName();
1911 std::string iterationCount;
1912 if (lnode.getIterationCountNode() !=
nullptr) {
1913 iterationCount = *lnode.getIterationCountNode()->getIndex().getName();
1915 std::ostringstream oss;
1916 oss << lnode.getIterationCount();
1917 iterationCount = oss.str();
1920 _streamStack << _spaces <<
"for(" 1922 << jj <<
" < " << iterationCount <<
"; " 1924 _indentation += _spaces;
1927 virtual void pushLoopEnd(
Node& node) {
1928 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopEnd,
"Invalid node type")
1930 _indentation.resize(_indentation.size() - _spaces.size());
1932 _streamStack <<_indentation <<
"}\n";
1934 _currentLoops.pop_back();
1938 virtual size_t printLoopIndexDeps(
const std::vector<Node*>& variableOrder,
1944 virtual void pushLoopIndexedDep(
Node& node);
1946 virtual void pushLoopIndexedIndep(
Node& node) {
1947 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedIndep,
"Invalid node type")
1948 CPPADCG_ASSERT_KNOWN(node.
getInfo().size() == 1,
"Invalid number of information elements for loop indexed independent operation")
1951 size_t pos = node.
getInfo()[1];
1952 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1953 _streamStack <<_nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1956 virtual void pushLoopIndexedTmp(
Node& node) {
1957 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::LoopIndexedTmp,
"Invalid node type")
1958 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for loop indexed temporary operation")
1960 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1965 virtual void pushTmpVar(
Node& node) {
1966 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Tmp,
"Invalid node type")
1967 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for temporary variable usage operation")
1969 CPPADCG_ASSERT_KNOWN(tmpVar !=
nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl,
"Invalid arguments for loop indexed temporary operation")
1971 _streamStack <<*tmpVar->getName();
1974 virtual void pushIndexAssign(
Node& node) {
1975 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexAssign,
"Invalid node type")
1976 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() > 0,
"Invalid number of arguments for an index assignment operation")
1981 _streamStack <<_indentation << (*inode.getIndex().getName())
1982 <<
" = " << indexPattern2String(ip, inode.getIndexPatternIndexes()) <<
";\n";
1985 virtual void pushIndexCondExprOp(
Node& node) {
1986 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::IndexCondExpr,
"Invalid node type")
1987 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 1,
"Invalid number of arguments for an index condition expression operation")
1988 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an index condition expression operation")
1989 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index,
"Invalid argument for an index condition expression operation")
1991 const std::vector<size_t>& info = node.
getInfo();
1994 const std::string& index = *iterationIndexOp.getIndex().getName();
1996 printIndexCondExpr(_code, info, index);
2004 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::StartIf,
"Invalid node type")
2005 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'if start' operation")
2006 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'if start' operation")
2008 _streamStack <<_indentation <<
"if(";
2009 pushIndexCondExprOp(*node.
getArguments()[0].getOperation());
2010 _streamStack <<
") {\n";
2012 _indentation += _spaces;
2021 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::ElseIf,
"Invalid node type")
2022 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 2,
"Invalid number of arguments for an 'else if' operation")
2023 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation")
2024 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an 'else if' operation")
2026 _indentation.resize(_indentation.size() - _spaces.size());
2028 _streamStack <<_indentation <<
"} else if(";
2029 pushIndexCondExprOp(*node.
getArguments()[1].getOperation());
2030 _streamStack <<
") {\n";
2032 _indentation += _spaces;
2040 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::Else,
"Invalid node type")
2041 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() >= 1,
"Invalid number of arguments for an 'else' operation")
2043 _indentation.resize(_indentation.size() - _spaces.size());
2045 _streamStack <<_indentation <<
"} else {\n";
2047 _indentation += _spaces;
2050 virtual void pushEndIf(
Node& node) {
2051 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::EndIf,
"Invalid node type for an 'end if' operation")
2053 _indentation.resize(_indentation.size() - _spaces.size());
2055 _streamStack <<_indentation <<
"}\n";
2058 virtual void pushCondResult(
Node& node) {
2059 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::CondResult,
"Invalid node type")
2060 CPPADCG_ASSERT_KNOWN(node.
getArguments().size() == 2,
"Invalid number of arguments for an assignment inside an if/else operation")
2061 CPPADCG_ASSERT_KNOWN(node.
getArguments()[0].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation")
2062 CPPADCG_ASSERT_KNOWN(node.
getArguments()[1].getOperation() !=
nullptr,
"Invalid argument for an an assignment inside an if/else operation")
2066 printAssignment(nodeArg);
2069 virtual void pushUserCustom(
Node& node) {
2070 CPPADCG_ASSERT_KNOWN(node.
getOperationType() == CGOpCode::UserCustom,
"Invalid node type")
2072 throw CGException(
"Unable to generate C source code for user custom operation nodes.");
2075 inline bool isDependent(
const Node& arg)
const {
2079 size_t id = getVariableID(arg);
2080 return id > _independentSize &&
id < _minTemporaryVarID;
2083 virtual void printParameter(
const Base& value) {
2084 writeParameter(value, _code);
2087 virtual void pushParameter(
const Base& value) {
2088 writeParameter(value, _streamStack);
2091 template<
class Output>
2092 void writeParameter(
const Base& value, Output& output) {
2094 std::ostringstream os;
2095 os << std::setprecision(_parameterPrecision) << value;
2097 std::string number = os.str();
2100 if (std::abs(value) > Base(0) && value != Base(1) && value != Base(-1)) {
2101 if (number.find(
'.') == std::string::npos && number.find(
'e') == std::string::npos) {
2109 virtual const std::string& getComparison(
enum CGOpCode op)
const {
2111 case CGOpCode::ComLt:
2112 return _C_COMP_OP_LT;
2114 case CGOpCode::ComLe:
2115 return _C_COMP_OP_LE;
2117 case CGOpCode::ComEq:
2118 return _C_COMP_OP_EQ;
2120 case CGOpCode::ComGe:
2121 return _C_COMP_OP_GE;
2123 case CGOpCode::ComGt:
2124 return _C_COMP_OP_GT;
2126 case CGOpCode::ComNe:
2127 return _C_COMP_OP_NE;
2130 CPPAD_ASSERT_UNKNOWN(0)
2133 throw CGException(
"Invalid comparison operator code");
2136 inline const std::string& getPrintfBaseFormat() {
2137 static const std::string format;
2141 static bool isFunction(
enum CGOpCode op) {
2142 return isUnaryFunction(op) || op == CGOpCode::Pow;
2145 static bool isUnaryFunction(
enum CGOpCode op) {
2148 case CGOpCode::Acos:
2149 case CGOpCode::Asin:
2150 case CGOpCode::Atan:
2151 case CGOpCode::Cosh:
2155 case CGOpCode::Sinh:
2157 case CGOpCode::Sqrt:
2158 case CGOpCode::Tanh:
2160 #if CPPAD_USE_CPLUSPLUS_2011 2162 case CGOpCode::Erfc:
2163 case CGOpCode::Asinh:
2164 case CGOpCode::Acosh:
2165 case CGOpCode::Atanh:
2166 case CGOpCode::Expm1:
2167 case CGOpCode::Log1p:
2175 inline static bool isCondAssign(
enum CGOpCode op) {
2177 case CGOpCode::ComLt:
2178 case CGOpCode::ComLe:
2179 case CGOpCode::ComEq:
2180 case CGOpCode::ComGe:
2181 case CGOpCode::ComGt:
2182 case CGOpCode::ComNe:
2190 class AtomicFuncArray {
2197 unsigned short scope;
2200 template<
class Base>
2203 template<
class Base>
2205 template<
class Base>
2207 template<
class Base>
2209 template<
class Base>
2211 template<
class Base>
2213 template<
class Base>
2216 template<
class Base>
2219 template<
class Base>
2222 template<
class Base>
2225 template<
class Base>
2228 template<
class Base>
2231 template<
class Base>
2234 template<
class Base>
2236 "typedef struct Array {\n" 2238 " " + U_INDEX_TYPE +
" size;\n" 2240 " const " + U_INDEX_TYPE +
"* idx;\n" 2241 " " + U_INDEX_TYPE +
" nnz;\n" 2244 "struct LangCAtomicFun {\n" 2245 " void* libModel;\n" 2246 " int (*forward)(void* libModel,\n" 2247 " int atomicIndex,\n" 2250 " const Array tx[],\n" 2252 " int (*reverse)(void* libModel,\n" 2253 " int atomicIndex,\n" 2255 " const Array tx[],\n" 2257 " const Array py[]);\n"
virtual void pushAtomicForwardOp(Node &atomicFor)
virtual bool directlyAssignsVariable(const Node &var) const
const std::string * getName() const
const std::vector< Argument< Base > > & getArguments() const
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
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
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
virtual void pushAtomicReverseOp(Node &atomicRev)
CGOpCode getOperationType() const
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg *> &tmpArrayValues)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
size_t getMaxOperationsPerAssignment() const
bool requiresVariableDependencies() const override
virtual void setParameterPrecision(size_t p)
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node *> &variableOrder, size_t starti)
void setIgnoreZeroDepAssign(bool ignore)
virtual void pushStartIf(Node &node)
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
void setName(const std::string &name)
size_t size() const noexcept
virtual void pushElse(Node &node)
virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction=false, bool zeroArrayDependents=false, int maxForwardOrder=-1, int maxReverseOrder=-1)
bool isIgnoreZeroDepAssign() const
virtual void pushElseIf(Node &node)
const std::vector< size_t > & getInfo() const
LanguageC(std::string varTypeName, size_t spaces=3)