CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_c.hpp
1#ifndef CPPAD_CG_LANGUAGE_C_INCLUDED
2#define CPPAD_CG_LANGUAGE_C_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2012 Ciengis
6 * Copyright (C) 2018 Joao Leal
7 *
8 * CppADCodeGen is distributed under multiple licenses:
9 *
10 * - Eclipse Public License Version 1.0 (EPL1), and
11 * - GNU General Public License Version 3 (GPL3).
12 *
13 * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14 * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15 * ----------------------------------------------------------------------------
16 * Author: Joao Leal
17 */
18
19#define CPPAD_CG_C_LANG_FUNCNAME(fn) \
20inline virtual const std::string& fn ## FuncName() {\
21 static const std::string name(#fn);\
22 return name;\
23}
24
25namespace CppAD {
26namespace cg {
27
33template<class Base>
34class LanguageC : public Language<Base> {
35public:
37 using Arg = Argument<Base>;
38public:
39 static const std::string U_INDEX_TYPE;
40 static const std::string ATOMICFUN_STRUCT_DEFINITION;
41protected:
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;
54private:
55 class AtomicFuncArray; //forward declaration
56protected:
57 // the type name of the Base class (e.g. "double")
58 const std::string _baseTypeName;
59 // spaces for 1 level indentation
60 const std::string _spaces;
61 // information from the code handler (not owned)
62 std::unique_ptr<LanguageGenerationData<Base>> _info;
63 // current indentation
64 std::string _indentation;
65 // variable name used for the inlet variable
66 std::string _inArgName;
67 // variable name used for the outlet variable
68 std::string _outArgName;
69 // variable name used for the atomic functions array
70 std::string _atomicArgName;
71 // output stream for the generated source code
72 std::ostringstream _code;
73 // creates the variable names
75 // auxiliary string stream
76 std::ostringstream _ss;
77 //
78 LangStreamStack<Base> _streamStack;
79 //
80 size_t _independentSize;
81 //
82 size_t _minTemporaryVarID;
83 // maps the variable IDs to the their position in the dependent vector
84 // (some IDs may be the same as the independent variables when dep = indep)
85 std::map<size_t, size_t> _dependentIDs;
86 // the dependent variable vector
87 const ArrayView<CG<Base> >* _dependent;
88 // the temporary variables that may require a declaration
89 std::map<size_t, Node*> _temporary;
90 // the operator used for assignment of dependent variables
91 std::string _depAssignOperation;
92 // whether or not to ignore assignment of constant zero values to dependent variables
93 bool _ignoreZeroDepAssign;
94 // the name of the function to be created (if the string is empty no function is created)
95 std::string _functionName;
96 // the maximum number of assignments (~lines) per local function
97 size_t _maxAssignmentsPerFunction;
98 // the maximum number of operations per variable assignment
99 size_t _maxOperationsPerAssignment;
100 // maps file names to with their contents
101 std::map<std::string, std::string>* _sources;
102 // the values in the temporary array
103 std::vector<const Arg*> _tmpArrayValues;
104 // the values in the temporary sparse array
105 std::vector<const Arg*> _tmpSparseArrayValues;
106 // the current state of Array structures used by atomic functions
107 std::map<std::string, AtomicFuncArray> _atomicFuncArrays;
108 // indexes defined as function arguments
109 std::vector<const Node*> _funcArgIndexes;
110 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
111 // the maximum precision used to print values
112 size_t _parameterPrecision;
113private:
114 std::vector<std::string> funcArgDcl_;
115 std::vector<std::string> localFuncArgDcl_;
116 std::string localFuncArgs_;
117 std::string auxArrayName_;
118
119public:
120
127 explicit LanguageC(std::string varTypeName,
128 size_t spaces = 3) :
129 _baseTypeName(std::move(varTypeName)),
130 _spaces(spaces, ' '),
131 _info(nullptr),
132 _inArgName("in"),
133 _outArgName("out"),
134 _atomicArgName("atomicFun"),
135 _nameGen(nullptr),
136 _streamStack(_code),
137 _independentSize(0), // not really required (but it avoids warnings)
138 _minTemporaryVarID(0), // not really required (but it avoids warnings)
139 _dependent(nullptr),
140 _depAssignOperation("="),
141 _ignoreZeroDepAssign(false),
142 _maxAssignmentsPerFunction(0),
143 _maxOperationsPerAssignment((std::numeric_limits<size_t>::max)()),
144 _sources(nullptr),
145 _parameterPrecision(std::numeric_limits<Base>::digits10) {
146 }
147
148 inline virtual ~LanguageC() = default;
149
150 inline const std::string& getArgumentIn() const {
151 return _inArgName;
152 }
153
154 inline void setArgumentIn(const std::string& inArgName) {
155 _inArgName = inArgName;
156 }
157
158 inline const std::string& getArgumentOut() const {
159 return _outArgName;
160 }
161
162 inline void setArgumentOut(const std::string& outArgName) {
163 _outArgName = outArgName;
164 }
165
166 inline const std::string& getArgumentAtomic() const {
167 return _atomicArgName;
168 }
169
170 inline void setArgumentAtomic(const std::string& atomicArgName) {
171 _atomicArgName = atomicArgName;
172 }
173
174 inline const std::string& getDependentAssignOperation() const {
175 return _depAssignOperation;
176 }
177
178 inline void setDependentAssignOperation(const std::string& depAssignOperation) {
179 _depAssignOperation = depAssignOperation;
180 }
181
189 inline bool isIgnoreZeroDepAssign() const {
190 return _ignoreZeroDepAssign;
191 }
192
200 inline void setIgnoreZeroDepAssign(bool ignore) {
201 _ignoreZeroDepAssign = ignore;
202 }
203
204 virtual void setGenerateFunction(const std::string& functionName) {
205 _functionName = functionName;
206 }
207
208 virtual void setFunctionIndexArgument(const Node& funcArgIndex) {
209 _funcArgIndexes.resize(1);
210 _funcArgIndexes[0] = &funcArgIndex;
211 }
212
213 virtual void setFunctionIndexArguments(const std::vector<const Node*>& funcArgIndexes) {
214 _funcArgIndexes = funcArgIndexes;
215 }
216
217 virtual const std::vector<const Node*>& getFunctionIndexArguments() const {
218 return _funcArgIndexes;
219 }
220
227 virtual size_t getParameterPrecision() const {
228 return _parameterPrecision;
229 }
230
237 virtual void setParameterPrecision(size_t p) {
238 _parameterPrecision = p;
239 }
240
252 virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction,
253 std::map<std::string, std::string>* sources) {
254 _maxAssignmentsPerFunction = maxAssignmentsPerFunction;
255 _sources = sources;
256 }
257
263 inline size_t getMaxOperationsPerAssignment() const {
264 return _maxOperationsPerAssignment;
265 }
266
273 inline void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment) {
274 _maxOperationsPerAssignment = maxOperationsPerAssignment;
275 }
276
277 inline std::string generateTemporaryVariableDeclaration(bool isWrapperFunction,
278 bool zeroArrayDependents,
279 const std::vector<int>& atomicMaxForward,
280 const std::vector<int>& atomicMaxReverse) {
281 int maxForward = -1;
282 if (!atomicMaxForward.empty())
283 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
284
285 int maxReverse = -1;
286 if (!atomicMaxReverse.empty())
287 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
288
289 return generateTemporaryVariableDeclaration(isWrapperFunction, zeroArrayDependents,
290 maxForward, maxReverse);
291 }
292
308 virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction = false,
309 bool zeroArrayDependents = false,
310 int maxForwardOrder = -1,
311 int maxReverseOrder = -1) {
312 CPPADCG_ASSERT_UNKNOWN(_nameGen != nullptr);
313
314 // declare variables
315 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
316
317 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
318 "There must be two temporary variables")
319
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";
328 }
329 } else if (_temporary.size() > 0) {
330 for (const std::pair<size_t, Node*>& p : _temporary) {
331 Node* var = p.second;
332 if (var->getName() == nullptr) {
333 var->setName(_nameGen->generateTemporary(*var, getVariableID(*var)));
334 }
335 }
336
337 Node* var1 = _temporary.begin()->second;
338 const std::string& varName1 = *var1->getName();
339 _ss << _spaces << _baseTypeName << " " << varName1;
340
341 typename std::map<size_t, Node*>::const_iterator it = _temporary.begin();
342 for (it++; it != _temporary.end(); ++it) {
343 _ss << ", " << *it->second->getName();
344 }
345 _ss << ";\n";
346 }
347
351 size_t arraySize = _nameGen->getMaxTemporaryArrayVariableID();
352 if (arraySize > 0 || isWrapperFunction) {
353 _ss << _spaces << _baseTypeName << " " << tmpArg[1].name << "[" << arraySize << "];\n";
354 }
355
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";
363 }
364
365 if (!isWrapperFunction) {
366 generateArrayContainersDeclaration(_ss, maxForwardOrder, maxReverseOrder);
367 }
368
369 //
370 if (!isWrapperFunction && (arraySize > 0 || sArraySize > 0)) {
371 _ss << _spaces << _baseTypeName << "* " << auxArrayName_ << ";\n";
372 }
373
374 if ((isWrapperFunction && zeroArrayDependents) ||
375 (!isWrapperFunction && (arraySize > 0 || sArraySize > 0 || zeroArrayDependents))) {
376 _ss << _spaces << U_INDEX_TYPE << " i;\n";
377 }
378
379 // loop indexes
380 createIndexDeclaration();
381
382 // clean-up
383 std::string code = _ss.str();
384 _ss.str("");
385
386 return code;
387 }
388
389 inline void generateArrayContainersDeclaration(std::ostringstream& ss,
390 const std::vector<int>& atomicMaxForward,
391 const std::vector<int>& atomicMaxReverse) {
392 int maxForward = -1;
393 if (!atomicMaxForward.empty())
394 maxForward = *std::max_element(atomicMaxForward.begin(), atomicMaxForward.end());
395
396 int maxReverse = -1;
397 if (!atomicMaxReverse.empty())
398 maxReverse = *std::max_element(atomicMaxReverse.begin(), atomicMaxReverse.end());
399
400 generateArrayContainersDeclaration(ss, maxForward, maxReverse);
401 }
402
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";
413 }
414 }
415 }
416
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")
421
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";
425 }
426
427 std::string code = _ss.str();
428 _ss.str("");
429 return code;
430 }
431
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")
436
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";
440 }
441
442 std::string code = _ss.str();
443 _ss.str("");
444 return code;
445 }
446
447 inline std::string generateArgumentAtomicDcl() const {
448 return "struct LangCAtomicFun " + _atomicArgName;
449 }
450
451 virtual std::string generateFunctionArgumentsDcl() const {
452 std::string args = generateFunctionIndexArgumentsDcl();
453 if (!args.empty())
454 args += ", ";
455 args += generateDefaultFunctionArgumentsDcl();
456
457 return args;
458 }
459
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());
464 return args;
465 }
466
467 virtual std::string generateDefaultFunctionArgumentsDcl() const {
468 return implode(generateDefaultFunctionArgumentsDcl2(), ", ");
469 }
470
471 virtual std::vector<std::string> generateDefaultFunctionArgumentsDcl2() const {
472 return std::vector<std::string> {_baseTypeName + " const *const * " + _inArgName,
473 _baseTypeName + "*const * " + _outArgName,
474 generateArgumentAtomicDcl()};
475 }
476
477 virtual std::string generateFunctionIndexArgumentsDcl() const {
478 return implode(generateFunctionIndexArgumentsDcl2(), ", ");
479 }
480
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();
485 }
486 return argtxt;
487 }
488
489 virtual std::string generateDefaultFunctionArguments() const {
490 return _inArgName + ", " + _outArgName + ", " + _atomicArgName;
491 }
492
493 virtual std::string generateFunctionIndexArguments() const {
494 std::string argtxt;
495 for (size_t a = 0; a < _funcArgIndexes.size(); a++) {
496 if (a > 0) argtxt += ", ";
497 argtxt += *_funcArgIndexes[a]->getName();
498 }
499 return argtxt;
500 }
501
502 inline void createIndexDeclaration();
503
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)
518
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)
527#endif
528
538 static inline void printFunctionDeclaration(std::ostringstream& out,
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 << "(";
544 size_t i = 0;
545 size_t offset = returnType.size() + 1 + functionName.size() + 1;
546 for (const std::string& a : arguments) {
547 if (i > 0) {
548 out << ",\n" << std::setw(offset) << " ";
549 }
550 out << a;
551 ++i;
552 }
553 for (const std::string& a : arguments2) {
554 if (i > 0) {
555 out << ",\n" << std::setw(offset) << " ";
556 }
557 out << a;
558 ++i;
559 }
560 out << ")";
561 }
562
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")
567
568 size_t infoSize = info.size();
569 for (size_t e = 0; e < infoSize; e += 2) {
570 if (e > 0) {
571 out << " || ";
572 }
573 size_t min = info[e];
574 size_t max = info[e + 1];
575 if (min == max) {
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;
581 } else {
582 if (infoSize != 2)
583 out << "(";
584
585 if (max - min == 1)
586 out << min << " == " << index << " || " << index << " == " << max;
587 else
588 out << min << " <= " << index << " && " << index << " <= " << max;
589
590 if (infoSize != 2)
591 out << ")";
592 }
593 }
594 }
595
596 /***********************************************************************
597 *
598 **********************************************************************/
599
600 static inline void printStaticIndexArray(std::ostringstream& os,
601 const std::string& name,
602 const std::vector<size_t>& values);
603
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);
607
608 /***********************************************************************
609 * index patterns
610 **********************************************************************/
611 static inline void generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns);
612
613 static inline void printRandomIndexPatternDeclaration(std::ostringstream& os,
614 const std::string& identation,
615 const std::set<RandomIndexPattern*>& randomPatterns);
616
617 static inline std::string indexPattern2String(const IndexPattern& ip,
618 const Node& index);
619
620 static inline std::string indexPattern2String(const IndexPattern& ip,
621 const std::string& index);
622
623 static inline std::string indexPattern2String(const IndexPattern& ip,
624 const std::vector<const Node*>& indexes);
625
626 static inline std::string indexPattern2String(const IndexPattern& ip,
627 const std::vector<const std::string*>& indexes);
628
629 static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
630 const Node& index);
631
632 static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
633 const std::string& index);
634
635 static inline bool isOffsetBy(const IndexPattern* ip,
636 const IndexPattern* refIp,
637 long offset);
638
639 static inline bool isOffsetBy(const LinearIndexPattern* lIp,
640 const LinearIndexPattern* refLIp,
641 long offset);
642
643 static inline bool isOffsetBy(const LinearIndexPattern& lIp,
644 const LinearIndexPattern& refLIp,
645 long offset);
646
647
648 static inline bool isOffsetBy(const SectionedIndexPattern* sIp,
649 const SectionedIndexPattern* refSecp,
650 long offset);
651
652 static inline bool isOffsetBy(const SectionedIndexPattern& lIp,
653 const SectionedIndexPattern& refSecp,
654 long offset);
655
656 static inline Plane2DIndexPattern* encapsulateIndexPattern(const LinearIndexPattern& refLIp,
657 size_t starti);
658
659 static inline Plane2DIndexPattern* encapsulateIndexPattern(const SectionedIndexPattern& refSecp,
660 size_t starti);
661protected:
662
663 void generateSourceCode(std::ostream& out,
664 std::unique_ptr<LanguageGenerationData<Base> > info) override {
665
666 const bool createFunction = !_functionName.empty();
667 const bool multiFunction = createFunction && _maxAssignmentsPerFunction > 0 && _sources != nullptr;
668
669 // clean up
670 _code.str("");
671 _ss.str("");
672 _temporary.clear();
673 _indentation = _spaces;
674 funcArgDcl_.clear();
675 localFuncArgDcl_.clear();
676 localFuncArgs_ = "";
677 auxArrayName_ = "";
678 _currentLoops.clear();
679 _atomicFuncArrays.clear();
680 _streamStack.clear();
681 _dependentIDs.clear();
682
683 // save some info
684 _info = std::move(info);
685 _independentSize = _info->independent.size();
686 _dependent = &_info->dependent;
687 _nameGen = &_info->nameGen;
688 _minTemporaryVarID = _info->minTemporaryVarID;
689 const ArrayView<CG<Base> >& dependent = _info->dependent;
690 const std::vector<Node*>& variableOrder = _info->variableOrder;
691
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);
696
700 generateNames4RandomIndexPatterns(_info->indexRandomPatterns);
701
705 //generate names for the independent variables
706 for (size_t j = 0; j < _independentSize; j++) {
707 Node& op = *_info->independent[j];
708 if (op.getName() == nullptr) {
709 op.setName(_nameGen->generateIndependent(op, getVariableID(op)));
710 }
711 }
712
713 // generate names for the dependent variables (must be after naming independents)
714 for (size_t i = 0; i < dependent.size(); i++) {
715 Node* node = dependent[i].getOperationNode();
716 if (node != nullptr && node->getOperationType() != CGOpCode::LoopEnd && node->getName() == nullptr) {
717 if (node->getOperationType() == CGOpCode::LoopIndexedDep) {
718 size_t pos = node->getInfo()[0];
719 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
720 node->setName(_nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip));
721
722 } else {
723 node->setName(_nameGen->generateDependent(i));
724 }
725 }
726 }
727
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")
738
739 if (createFunction) {
740 funcArgDcl_ = generateFunctionArgumentsDcl2();
741
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);
748
749 localFuncArgs_ = generateDefaultFunctionArguments() + ", "
750 + tmpArg[0].name + ", "
751 + tmpArg[1].name + ", "
752 + tmpArg[2].name + ", "
753 + _C_SPARSE_INDEX_ARRAY;
754 }
755
756 auxArrayName_ = tmpArg[1].name + "p";
757
761 // dependent variables indexes that are copies of other dependent variables
762 std::set<size_t> dependentDuplicates;
763
764 for (size_t i = 0; i < dependent.size(); i++) {
765 Node* node = dependent[i].getOperationNode();
766 if (node != nullptr) {
767 CGOpCode type = node->getOperationType();
768 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
769 size_t varID = getVariableID(*node);
770 if (varID > 0) {
771 auto it2 = _dependentIDs.find(varID);
772 if (it2 == _dependentIDs.end()) {
773 _dependentIDs[getVariableID(*node)] = i;
774 } else {
775 // there can be several dependent variables with the same ID
776 dependentDuplicates.insert(i);
777 }
778 }
779 }
780 }
781 }
782
783 // the names of local functions
784 std::vector<std::string> localFuncNames;
785 if (multiFunction) {
786 localFuncNames.reserve(variableOrder.size() / _maxAssignmentsPerFunction);
787 }
788
792 if (variableOrder.size() > 0) {
793 // generate names for temporary variables
794 for (Node* node : variableOrder) {
795 CGOpCode op = node->getOperationType();
796 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
797 // variable names for temporaries must always be created since they might have been used before with a different name/id
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)));
804 }
805 }
806 }
807
811 if (_info->zeroDependents) {
812 // zero initial values
813 for (size_t i = 0; i < depArg.size(); i++) {
814 const FuncArgument& a = depArg[i];
815 if (a.array) {
816 _code << _indentation << "for(i = 0; i < " << _dependent->size() << "; i++) " << a.name << "[i]";
817 } else {
818 _code << _indentation << _nameGen->generateDependent(i);
819 }
820 _code << " = ";
821 printParameter(Base(0.0));
822 _code << ";\n";
823 }
824 }
825
826 size_t assignCount = 0;
827 for (size_t i = 0; i < variableOrder.size(); ++i) {
828 Node* it = variableOrder[i];
829
830 // check if a new function should start
831 if (assignCount >= _maxAssignmentsPerFunction && multiFunction && _currentLoops.empty()) {
832 assignCount = 0;
833 saveLocalFunction(localFuncNames, localFuncNames.empty() && _info->zeroDependents);
834 }
835
836 Node& node = *it;
837
838 // a dependent variable assigned by a loop does require any source code (its done inside the loop)
839 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
840 continue; // nothing to do (this operation is right hand side only)
841 } else if (node.getOperationType() == CGOpCode::TmpDcl) { // temporary variable declaration does not need any source code here
842 continue; // nothing to do (bogus operation)
843 } else if (node.getOperationType() == CGOpCode::LoopIndexedDep) {
844 // try to detect a pattern and use a loop instead of individual assignments
845 i = printLoopIndexDeps(variableOrder, i);
846 continue;
847 }
848
849 assignCount += printAssignment(node);
850
851 CPPAD_ASSERT_KNOWN(_streamStack.empty(), "Error writing all operations to output stream")
852 }
853
854 if (!localFuncNames.empty() && assignCount > 0) {
855 assignCount = 0;
856 saveLocalFunction(localFuncNames, false);
857 }
858 }
859
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")
866
867 _code << ATOMICFUN_STRUCT_DEFINITION << "\n\n";
868 // forward declarations
869 std::string localFuncArgDcl2 = implode(localFuncArgDcl_, ", ");
870 for (auto & localFuncName : localFuncNames) {
871 _code << "void " << localFuncName << "(" << localFuncArgDcl2 << ");\n";
872 }
873 _code << "\n";
874 printFunctionDeclaration(_code, "void", _functionName, funcArgDcl_);
875 _code << " {\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";
885 }
886 }
887
888 // dependent duplicates
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();
895
896 _code << _spaces << varName << " " << _depAssignOperation << " " << origVarName << ";\n";
897 }
898 }
899
900 // constant dependent variables
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;
908 }
909 std::string varName = _nameGen->generateDependent(i);
910 _code << _spaces << varName << " " << _depAssignOperation << " ";
911 printParameter(dependent[i].getValue());
912 _code << ";\n";
913 }
914 } else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
915 if (!commentWritten) {
916 _code << _spaces << "// dependent variables without operations\n";
917 commentWritten = true;
918 }
919 std::string varName = _nameGen->generateDependent(i);
920 const std::string& indepName = *dependent[i].getOperationNode()->getName();
921 _code << _spaces << varName << " " << _depAssignOperation << " " << indepName << ";\n";
922 }
923 }
924
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";
933 printFunctionDeclaration(_ss, "void", _functionName, funcArgDcl_);
934 _ss << " {\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);
942 _ss << _code.str();
943 _nameGen->finalizeCustomFunctionVariables(_ss);
944 _ss << "}\n\n";
945
946 out << _ss.str();
947
948 if (_sources != nullptr) {
949 (*_sources)[_functionName + ".c"] = _ss.str();
950 }
951 } else {
952 _nameGen->finalizeCustomFunctionVariables(_code);
953 _code << "}\n\n";
954
955 (*_sources)[_functionName + ".c"] = _code.str();
956 }
957 } else {
958 out << _code.str();
959 }
960 }
961
962 inline size_t getVariableID(const Node& node) const {
963 return _info->varId[node];
964 }
965
966 inline unsigned printAssignment(Node& node) {
967 return pushAssignment(node, node);
968 }
969
970 inline unsigned pushAssignment(Node& nodeName,
971 const Arg& nodeRhs) {
972 if (nodeRhs.getOperation() != nullptr) {
973 return pushAssignment(nodeName, *nodeRhs.getOperation());
974 } else {
975 pushAssignmentStart(nodeName);
976 pushParameter(*nodeRhs.getParameter());
977 pushAssignmentEnd(nodeName);
978
979 _streamStack.flush();
980
981 return 1;
982 }
983 }
984
985 inline unsigned pushAssignment(Node& nodeName,
986 Node& nodeRhs) {
987 bool createsVar = directlyAssignsVariable(nodeRhs); // do we need to do the assignment here?
988 if (!createsVar) {
989 pushAssignmentStart(nodeName);
990 }
991 unsigned lines = pushExpressionNoVarCheck2(nodeRhs);
992 if (!createsVar) {
993 pushAssignmentEnd(nodeRhs);
994 }
995
996 _streamStack.flush();
997
998 if (nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
999 Node* array = nodeRhs.getArguments()[0].getOperation();
1000 size_t arrayId = getVariableID(*array);
1001 size_t pos = nodeRhs.getInfo()[0];
1002 if (array->getOperationType() == CGOpCode::ArrayCreation)
1003 _tmpArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1004 else
1005 _tmpSparseArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1006 }
1007
1008 return lines;
1009 }
1010
1011 inline virtual void pushAssignmentStart(Node& op) {
1012 pushAssignmentStart(op, createVariableName(op), isDependent(op));
1013 }
1014
1015 inline virtual void pushAssignmentStart(Node& node,
1016 const std::string& varName,
1017 bool isDep) {
1018 if (!isDep) {
1019 _temporary[getVariableID(node)] = &node;
1020 }
1021
1022 _streamStack << _indentation << varName << " ";
1023 if (isDep) {
1024 CGOpCode op = node.getOperationType();
1025 if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
1026 _streamStack << "+=";
1027 } else {
1028 _streamStack << _depAssignOperation;
1029 }
1030 } else {
1031 _streamStack << "=";
1032 }
1033 _streamStack << " ";
1034 }
1035
1036 inline virtual void pushAssignmentEnd(Node& op) {
1037 _streamStack << ";\n";
1038 }
1039
1040 virtual std::string argumentDeclaration(const FuncArgument& funcArg) const {
1041 std::string dcl = _baseTypeName;
1042 if (funcArg.array) {
1043 dcl += "*";
1044 }
1045 return dcl + " " + funcArg.name;
1046 }
1047
1048 virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
1049 bool zeroDependentArray) {
1050 _ss << _functionName << "__" << (localFuncNames.size() + 1);
1051 std::string funcName = _ss.str();
1052 _ss.str("");
1053
1054 _ss << "#include <math.h>\n"
1055 "#include <stdio.h>\n\n"
1056 << ATOMICFUN_STRUCT_DEFINITION << "\n\n";
1057 printFunctionDeclaration(_ss, "void", funcName, localFuncArgDcl_);
1058 _ss << " {\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";
1066 }
1067
1068 generateArrayContainersDeclaration(_ss,
1069 _info->atomicFunctionsMaxForward,
1070 _info->atomicFunctionsMaxReverse);
1071
1072 if (arraySize > 0 || sArraySize > 0 || zeroDependentArray) {
1073 _ss << _spaces << U_INDEX_TYPE << " i;\n";
1074 }
1075
1076 // loop indexes
1077 createIndexDeclaration();
1078
1079 _nameGen->prepareCustomFunctionVariables(_ss);
1080 _ss << _code.str();
1081 _nameGen->finalizeCustomFunctionVariables(_ss);
1082 _ss << "}\n\n";
1083
1084 (*_sources)[funcName + ".c"] = _ss.str();
1085 localFuncNames.push_back(funcName);
1086
1087 _code.str("");
1088 _ss.str("");
1089 }
1090
1091 bool createsNewVariable(const Node& var,
1092 size_t totalUseCount,
1093 size_t opCount) const override {
1094 CGOpCode op = var.getOperationType();
1095 if (totalUseCount > 1) {
1096 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1097 } else {
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;
1114 }
1115 }
1116
1117 virtual bool requiresVariableName(const Node& var) const {
1118 CGOpCode op = var.getOperationType();
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);
1134 } else {
1135 return isCondAssign(op);
1136 }
1137 }
1138
1146 virtual bool directlyAssignsVariable(const Node& var) const {
1147 CGOpCode op = var.getOperationType();
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;
1164 }
1165
1166 bool requiresVariableArgument(enum CGOpCode op, size_t argIndex) const override {
1167 return op == CGOpCode::Sign || op == CGOpCode::CondResult || op == CGOpCode::Pri;
1168 }
1169
1170 inline const std::string& createVariableName(Node& var) {
1171 CGOpCode op = var.getOperationType();
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)
1180
1181 if (var.getName() == nullptr) {
1182 if (op == CGOpCode::ArrayCreation) {
1183 var.setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
1184
1185 } else if (op == CGOpCode::SparseArrayCreation) {
1186 var.setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
1187
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));
1192
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));
1197
1198 } else if (getVariableID(var) <= _independentSize) {
1199 // independent variable
1200 var.setName(_nameGen->generateIndependent(var, getVariableID(var)));
1201
1202 } else if (getVariableID(var) < _minTemporaryVarID) {
1203 // dependent variable
1204 auto it = _dependentIDs.find(getVariableID(var));
1205 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end())
1206
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")
1211 Node* tmpVar = var.getArguments()[0].getOperation();
1212 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr, "Invalid argument for print operation")
1213 return createVariableName(*tmpVar);
1214
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")
1217 Node* tmpVar = var.getArguments()[0].getOperation();
1218 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1219 return createVariableName(*tmpVar);
1220
1221 } else {
1222 // temporary variable
1223 var.setName(_nameGen->generateTemporary(var, getVariableID(var)));
1224 }
1225 }
1226
1227
1228 return *var.getName();
1229 }
1230
1231 bool requiresVariableDependencies() const override {
1232 return false;
1233 }
1234
1235 virtual void pushIndependentVariableName(Node& op) {
1236 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 0, "Invalid number of arguments for independent variable")
1237
1238 _streamStack << _nameGen->generateIndependent(op, getVariableID(op));
1239 }
1240
1241 virtual unsigned push(const Arg& arg) {
1242 if (arg.getOperation() != nullptr) {
1243 // expression
1244 return pushExpression(*arg.getOperation());
1245 } else {
1246 // parameter
1247 pushParameter(*arg.getParameter());
1248 return 1;
1249 }
1250 }
1251
1252 virtual unsigned pushExpression(Node& op) {
1253 if (getVariableID(op) > 0) {
1254 // use variable name
1255 _streamStack << createVariableName(op);
1256 return 1;
1257 } else {
1258 // print expression code
1259 _streamStack << op;
1260 return 0;
1261 }
1262 }
1263
1264 virtual unsigned pushExpressionNoVarCheck2(Node& node) {
1265 Node* n;
1266
1267 unsigned lines = pushExpressionNoVarCheck(node);
1268
1269 while (true) {
1270
1271 _streamStack.flush();
1272 if (!_streamStack.empty()) {
1273 n = &_streamStack.startNewOperationNode();
1274 } else {
1275 n = nullptr;
1276 }
1277
1278 if (n == nullptr)
1279 break;
1280
1281 unsigned lines2 = pushExpressionNoVarCheck(*n);
1282
1283 lines = std::max<unsigned>(lines, lines2);
1284 }
1285
1286 return lines;
1287 }
1288
1289 virtual unsigned pushExpressionNoVarCheck(Node& node) {
1290 CGOpCode op = node.getOperationType();
1291 switch (op) {
1292 case CGOpCode::ArrayCreation:
1293 pushArrayCreationOp(node);
1294 break;
1295 case CGOpCode::SparseArrayCreation:
1296 pushSparseArrayCreationOp(node);
1297 break;
1298 case CGOpCode::ArrayElement:
1299 pushArrayElementOp(node);
1300 break;
1301 case CGOpCode::Assign:
1302 return pushAssignOp(node);
1303
1304 case CGOpCode::Abs:
1305 case CGOpCode::Acos:
1306 case CGOpCode::Asin:
1307 case CGOpCode::Atan:
1308 case CGOpCode::Cosh:
1309 case CGOpCode::Cos:
1310 case CGOpCode::Exp:
1311 case CGOpCode::Log:
1312 case CGOpCode::Sinh:
1313 case CGOpCode::Sin:
1314 case CGOpCode::Sqrt:
1315 case CGOpCode::Tanh:
1316 case CGOpCode::Tan:
1317#if CPPAD_USE_CPLUSPLUS_2011
1318 case CGOpCode::Erf:
1319 case CGOpCode::Erfc:
1320 case CGOpCode::Asinh:
1321 case CGOpCode::Acosh:
1322 case CGOpCode::Atanh:
1323 case CGOpCode::Expm1:
1324 case CGOpCode::Log1p:
1325#endif
1326 pushUnaryFunction(node);
1327 break;
1328 case CGOpCode::AtomicForward: // atomicFunction.forward(q, p, vx, vy, tx, ty)
1329 pushAtomicForwardOp(node);
1330 break;
1331 case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
1332 pushAtomicReverseOp(node);
1333 break;
1334 case CGOpCode::Add:
1335 pushOperationAdd(node);
1336 break;
1337 case CGOpCode::Alias:
1338 return pushOperationAlias(node);
1339
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);
1347 break;
1348 case CGOpCode::Div:
1349 pushOperationDiv(node);
1350 break;
1351 case CGOpCode::Inv:
1352 pushIndependentVariableName(node);
1353 break;
1354 case CGOpCode::Mul:
1355 pushOperationMul(node);
1356 break;
1357 case CGOpCode::Pow:
1358 pushPowFunction(node);
1359 break;
1360 case CGOpCode::Pri:
1361 pushPrintOperation(node);
1362 break;
1363 case CGOpCode::Sign:
1364 pushSignFunction(node);
1365 break;
1366 case CGOpCode::Sub:
1367 pushOperationMinus(node);
1368 break;
1369
1370 case CGOpCode::UnMinus:
1371 pushOperationUnaryMinus(node);
1372 break;
1373
1374 case CGOpCode::DependentMultiAssign:
1375 return pushDependentMultiAssign(node);
1376
1377 case CGOpCode::Index:
1378 return 0; // nothing to do
1379 case CGOpCode::IndexAssign:
1380 pushIndexAssign(node);
1381 break;
1382 case CGOpCode::IndexDeclaration:
1383 return 0; // already done
1384
1385 case CGOpCode::LoopStart:
1386 pushLoopStart(node);
1387 break;
1388 case CGOpCode::LoopIndexedIndep:
1389 pushLoopIndexedIndep(node);
1390 break;
1391 case CGOpCode::LoopIndexedDep:
1392 pushLoopIndexedDep(node);
1393 break;
1394 case CGOpCode::LoopIndexedTmp:
1395 pushLoopIndexedTmp(node);
1396 break;
1397 case CGOpCode::TmpDcl:
1398 // nothing to do
1399 return 0;
1400 case CGOpCode::Tmp:
1401 pushTmpVar(node);
1402 break;
1403 case CGOpCode::LoopEnd:
1404 pushLoopEnd(node);
1405 break;
1406 case CGOpCode::IndexCondExpr:
1407 pushIndexCondExprOp(node);
1408 break;
1409 case CGOpCode::StartIf:
1410 pushStartIf(node);
1411 break;
1412 case CGOpCode::ElseIf:
1413 pushElseIf(node);
1414 break;
1415 case CGOpCode::Else:
1416 pushElse(node);
1417 break;
1418 case CGOpCode::EndIf:
1419 pushEndIf(node);
1420 break;
1421 case CGOpCode::CondResult:
1422 pushCondResult(node);
1423 break;
1424 case CGOpCode::UserCustom:
1425 pushUserCustom(node);
1426 break;
1427 default:
1428 throw CGException("Unknown operation code '", op, "'.");
1429 }
1430 return 1;
1431 }
1432
1433 virtual unsigned pushAssignOp(Node& node) {
1434 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for assign operation")
1435
1436 return push(node.getArguments()[0]);
1437 }
1438
1439 virtual void pushUnaryFunction(Node& op) {
1440 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary function")
1441
1442 switch (op.getOperationType()) {
1443 case CGOpCode::Abs:
1444 _streamStack << absFuncName();
1445 break;
1446 case CGOpCode::Acos:
1447 _streamStack << acosFuncName();
1448 break;
1449 case CGOpCode::Asin:
1450 _streamStack << asinFuncName();
1451 break;
1452 case CGOpCode::Atan:
1453 _streamStack << atanFuncName();
1454 break;
1455 case CGOpCode::Cosh:
1456 _streamStack << coshFuncName();
1457 break;
1458 case CGOpCode::Cos:
1459 _streamStack << cosFuncName();
1460 break;
1461 case CGOpCode::Exp:
1462 _streamStack << expFuncName();
1463 break;
1464 case CGOpCode::Log:
1465 _streamStack << logFuncName();
1466 break;
1467 case CGOpCode::Sinh:
1468 _streamStack << sinhFuncName();
1469 break;
1470 case CGOpCode::Sin:
1471 _streamStack << sinFuncName();
1472 break;
1473 case CGOpCode::Sqrt:
1474 _streamStack << sqrtFuncName();
1475 break;
1476 case CGOpCode::Tanh:
1477 _streamStack << tanhFuncName();
1478 break;
1479 case CGOpCode::Tan:
1480 _streamStack << tanFuncName();
1481 break;
1482#if CPPAD_USE_CPLUSPLUS_2011
1483 case CGOpCode::Erf:
1484 _streamStack << erfFuncName();
1485 break;
1486 case CGOpCode::Erfc:
1487 _streamStack << erfcFuncName();
1488 break;
1489 case CGOpCode::Asinh:
1490 _streamStack << asinhFuncName();
1491 break;
1492 case CGOpCode::Acosh:
1493 _streamStack << acoshFuncName();
1494 break;
1495 case CGOpCode::Atanh:
1496 _streamStack << atanhFuncName();
1497 break;
1498 case CGOpCode::Expm1:
1499 _streamStack << expm1FuncName();
1500 break;
1501 case CGOpCode::Log1p:
1502 _streamStack << log1pFuncName();
1503 break;
1504#endif
1505 default:
1506 throw CGException("Unknown function name for operation code '", op.getOperationType(), "'.");
1507 }
1508
1509 _streamStack << "(";
1510 push(op.getArguments()[0]);
1511 _streamStack << ")";
1512 }
1513
1514 virtual void pushPowFunction(Node& op) {
1515 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for pow() function")
1516
1517 _streamStack <<powFuncName() << "(";
1518 push(op.getArguments()[0]);
1519 _streamStack << ", ";
1520 push(op.getArguments()[1]);
1521 _streamStack << ")";
1522 }
1523
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)
1528
1529 Node& arg = *op.getArguments()[0].getOperation();
1530
1531 const std::string& argName = createVariableName(arg);
1532
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 << "))";
1544 }
1545
1546 virtual unsigned pushOperationAlias(Node& op) {
1547 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for alias")
1548 return push(op.getArguments()[0]);
1549 }
1550
1551 virtual void pushOperationAdd(Node& op) {
1552 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for addition")
1553
1554 const Arg& left = op.getArguments()[0];
1555 const Arg& right = op.getArguments()[1];
1556
1557 if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1558 push(left);
1559 _streamStack << " + ";
1560 push(right);
1561 } else {
1562 // right has a negative parameter so we would get v0 + -v1
1563 push(left);
1564 _streamStack << " - ";
1565 pushParameter(-*right.getParameter()); // make it positive
1566 }
1567 }
1568
1569 virtual void pushOperationMinus(Node& op) {
1570 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for subtraction")
1571
1572 const Arg& left = op.getArguments()[0];
1573 const Arg& right = op.getArguments()[1];
1574
1575 if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1576 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1577
1578 push(left);
1579 _streamStack << " - ";
1580 if (encloseRight) {
1581 _streamStack << "(";
1582 }
1583 push(right);
1584 if (encloseRight) {
1585 _streamStack << ")";
1586 }
1587 } else {
1588 // right has a negative parameter so we would get v0 - -v1
1589 push(left);
1590 _streamStack << " + ";
1591 pushParameter(-*right.getParameter()); // make it positive
1592 }
1593 }
1594
1595 inline bool encloseInParenthesesDiv(const Node* node) const {
1596 while (node != nullptr) {
1597 if (getVariableID(*node) != 0)
1598 return false;
1599 if (node->getOperationType() == CGOpCode::Alias)
1600 node = node->getArguments()[0].getOperation();
1601 else
1602 break;
1603 }
1604 return node != nullptr &&
1605 getVariableID(*node) == 0 &&
1606 !isFunction(node->getOperationType());
1607 }
1608
1609 virtual void pushOperationDiv(Node& op) {
1610 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for division")
1611
1612 const Arg& left = op.getArguments()[0];
1613 const Arg& right = op.getArguments()[1];
1614
1615 bool encloseLeft = encloseInParenthesesDiv(left.getOperation());
1616 bool encloseRight = encloseInParenthesesDiv(right.getOperation());
1617
1618 if (encloseLeft) {
1619 _streamStack << "(";
1620 }
1621 push(left);
1622 if (encloseLeft) {
1623 _streamStack << ")";
1624 }
1625 _streamStack << " / ";
1626 if (encloseRight) {
1627 _streamStack << "(";
1628 }
1629 push(right);
1630 if (encloseRight) {
1631 _streamStack << ")";
1632 }
1633 }
1634
1635 inline bool encloseInParenthesesMul(const Node* node) const {
1636 while (node != nullptr) {
1637 if (getVariableID(*node) != 0)
1638 return false;
1639 else if (node->getOperationType() == CGOpCode::Alias)
1640 node = node->getArguments()[0].getOperation();
1641 else
1642 break;
1643 }
1644 return node != nullptr &&
1645 getVariableID(*node) == 0 &&
1646 node->getOperationType() != CGOpCode::Div &&
1647 node->getOperationType() != CGOpCode::Mul &&
1648 !isFunction(node->getOperationType());
1649 }
1650
1651 virtual void pushOperationMul(Node& op) {
1652 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for multiplication")
1653
1654 const Arg& left = op.getArguments()[0];
1655 const Arg& right = op.getArguments()[1];
1656
1657 bool encloseLeft = encloseInParenthesesMul(left.getOperation());
1658 bool encloseRight = encloseInParenthesesMul(right.getOperation());
1659
1660 if (encloseLeft) {
1661 _streamStack << "(";
1662 }
1663 push(left);
1664 if (encloseLeft) {
1665 _streamStack << ")";
1666 }
1667 _streamStack << " * ";
1668 if (encloseRight) {
1669 _streamStack << "(";
1670 }
1671 push(right);
1672 if (encloseRight) {
1673 _streamStack << ")";
1674 }
1675 }
1676
1677 virtual void pushOperationUnaryMinus(Node& op) {
1678 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary minus")
1679
1680 const Arg& arg = op.getArguments()[0];
1681
1682 bool enclose = encloseInParenthesesMul(arg.getOperation());
1683
1684 _streamStack << "-";
1685 if (enclose) {
1686 _streamStack << "(";
1687 } else {
1688 _streamStack << " "; // there may be several - together -> space required
1689 }
1690 push(arg);
1691 if (enclose) {
1692 _streamStack << ")";
1693 }
1694 }
1695
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")
1699
1700 const auto& pnode = static_cast<const PrintOperationNode<Base>&> (node);
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, "\"", "\\\"");
1707
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 << ", ";
1712 push(args[a]);
1713 }
1714 _streamStack << ");\n";
1715 }
1716
1717 virtual void pushConditionalAssignment(Node& node) {
1718 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1719
1720 const std::vector<Arg>& args = node.getArguments();
1721 const Arg &left = args[0];
1722 const Arg &right = args[1];
1723 const Arg &trueCase = args[2];
1724 const Arg &falseCase = args[3];
1725
1726 bool isDep = isDependent(node);
1727 const std::string& varName = createVariableName(node);
1728
1729 if ((trueCase.getParameter() != nullptr && falseCase.getParameter() != nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1730 (trueCase.getOperation() != nullptr && falseCase.getOperation() != nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1731 // true and false cases are the same
1732 pushAssignmentStart(node, varName, isDep);
1733 push(trueCase);
1734 pushAssignmentEnd(node);
1735 } else {
1736 _streamStack <<_indentation << "if( ";
1737 push(left);
1738 _streamStack << " " << getComparison(node.getOperationType()) << " ";
1739 push(right);
1740 _streamStack << " ) {\n";
1741 _streamStack <<_spaces;
1742 pushAssignmentStart(node, varName, isDep);
1743 push(trueCase);
1744 pushAssignmentEnd(node);
1745 _streamStack <<_indentation << "} else {\n";
1746 _streamStack <<_spaces;
1747 pushAssignmentStart(node, varName, isDep);
1748 push(falseCase);
1749 pushAssignmentEnd(node);
1750 _streamStack <<_indentation << "}\n";
1751 }
1752 }
1753
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());
1760 }
1761 } else {
1762 return (newArg.getOperation() == oldArg->getOperation());
1763 }
1764 }
1765 return false;
1766 }
1767
1768 virtual void pushArrayCreationOp(Node& op);
1769
1770 virtual void pushSparseArrayCreationOp(Node& op);
1771
1772 inline void printArrayStructInit(const std::string& dataArrayName,
1773 size_t pos,
1774 const std::vector<Node*>& arrays,
1775 size_t k);
1776
1777 inline void printArrayStructInit(const std::string& dataArrayName,
1778 Node& array);
1779
1780 inline void markArrayChanged(Node& ty);
1781
1782 inline size_t printArrayCreationUsingLoop(size_t startPos,
1783 Node& array,
1784 size_t startj,
1785 std::vector<const Arg*>& tmpArrayValues);
1786
1787 inline std::string getTempArrayName(const Node& op);
1788
1789 virtual void pushArrayElementOp(Node& op);
1790
1791 virtual void pushAtomicForwardOp(Node& atomicFor) {
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];
1795 size_t p1 = p + 1;
1796 const std::vector<Arg>& opArgs = atomicFor.getArguments();
1797 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments for atomic forward operation")
1798
1799 size_t id = atomicFor.getInfo()[0];
1800 size_t atomicIndex = _info->atomicFunctionId2Index.at(id);
1801
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();
1806 }
1807
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")
1810
1811 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1812
1813 // tx
1814 for (size_t k = 0; k < p1; k++) {
1815 printArrayStructInit(_ATOMIC_TX, k, tx, k); // also does indentation
1816 }
1817 // ty
1818 printArrayStructInit(_ATOMIC_TY, *ty[p]); // also does indentation
1819 _ss.str("");
1820
1821 _streamStack << _indentation << "atomicFun.forward(atomicFun.libModel, "
1822 << atomicIndex << ", " << q << ", " << p << ", "
1823 << _ATOMIC_TX << ", &" << _ATOMIC_TY << "); // "
1824 << _info->atomicFunctionId2Name.at(id)
1825 << "\n";
1826
1830 markArrayChanged(*ty[p]);
1831 }
1832
1833 virtual void pushAtomicReverseOp(Node& atomicRev) {
1834 CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements for atomic reverse operation")
1835 int p = atomicRev.getInfo()[1];
1836 size_t p1 = p + 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")
1839
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();
1847 }
1848
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")
1851
1852 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1853
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")
1856
1857 // tx
1858 for (size_t k = 0; k < p1; k++) {
1859 printArrayStructInit(_ATOMIC_TX, k, tx, k); // also does indentation
1860 }
1861 // py
1862 for (size_t k = 0; k < p1; k++) {
1863 printArrayStructInit(_ATOMIC_PY, k, py, k); // also does indentation
1864 }
1865 // px
1866 printArrayStructInit(_ATOMIC_PX, *px[0]); // also does indentation
1867 _ss.str("");
1868
1869 _streamStack << _indentation << "atomicFun.reverse(atomicFun.libModel, "
1870 << atomicIndex << ", " << p << ", "
1871 << _ATOMIC_TX << ", &" << _ATOMIC_PX << ", " << _ATOMIC_PY << "); // "
1872 << _info->atomicFunctionId2Name.at(id)
1873 << "\n";
1874
1878 markArrayChanged(*px[0]);
1879 }
1880
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")
1884
1885 const std::vector<Arg>& args = node.getArguments();
1886 for (size_t a = 0; a < args.size(); a++) {
1887 bool useArg;
1888 const Arg& arg = args[a];
1889 if (arg.getParameter() != nullptr) {
1890 useArg = true;
1891 } else {
1892 CGOpCode op = arg.getOperation()->getOperationType();
1893 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1894 }
1895
1896 if (useArg) {
1897 pushAssignment(node, arg); // ignore other arguments!
1898 return 1;
1899 }
1900 }
1901 return 0;
1902 }
1903
1904 virtual void pushLoopStart(Node& node) {
1905 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node type")
1906
1907 auto& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1908 _currentLoops.push_back(&lnode);
1909
1910 const std::string& jj = *lnode.getIndex().getName();
1911 std::string iterationCount;
1912 if (lnode.getIterationCountNode() != nullptr) {
1913 iterationCount = *lnode.getIterationCountNode()->getIndex().getName();
1914 } else {
1915 std::ostringstream oss;
1916 oss << lnode.getIterationCount();
1917 iterationCount = oss.str();
1918 }
1919
1920 _streamStack << _spaces << "for("
1921 << jj << " = 0; "
1922 << jj << " < " << iterationCount << "; "
1923 << jj << "++) {\n";
1924 _indentation += _spaces;
1925 }
1926
1927 virtual void pushLoopEnd(Node& node) {
1928 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node type")
1929
1930 _indentation.resize(_indentation.size() - _spaces.size());
1931
1932 _streamStack <<_indentation << "}\n";
1933
1934 _currentLoops.pop_back();
1935 }
1936
1937
1938 virtual size_t printLoopIndexDeps(const std::vector<Node*>& variableOrder,
1939 size_t pos);
1940
1941 virtual size_t printLoopIndexedDepsUsingLoop(const std::vector<Node*>& variableOrder,
1942 size_t starti);
1943
1944 virtual void pushLoopIndexedDep(Node& node);
1945
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")
1949
1950 // CGLoopIndexedIndepOp
1951 size_t pos = node.getInfo()[1];
1952 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1953 _streamStack <<_nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1954 }
1955
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")
1959 Node* tmpVar = node.getArguments()[0].getOperation();
1960 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1961
1962 push(node.getArguments()[1]);
1963 }
1964
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")
1968 Node* tmpVar = node.getArguments()[0].getOperation();
1969 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1970
1971 _streamStack <<*tmpVar->getName();
1972 }
1973
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")
1977
1978 auto& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1979
1980 const IndexPattern& ip = inode.getIndexPattern();
1981 _streamStack <<_indentation << (*inode.getIndex().getName())
1982 << " = " << indexPattern2String(ip, inode.getIndexPatternIndexes()) << ";\n";
1983 }
1984
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")
1990
1991 const std::vector<size_t>& info = node.getInfo();
1992
1993 auto& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1994 const std::string& index = *iterationIndexOp.getIndex().getName();
1995
1996 printIndexCondExpr(_code, info, index);
1997 }
1998
1999 virtual void pushStartIf(Node& node) {
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")
2007
2008 _streamStack <<_indentation << "if(";
2009 pushIndexCondExprOp(*node.getArguments()[0].getOperation());
2010 _streamStack << ") {\n";
2011
2012 _indentation += _spaces;
2013 }
2014
2015 virtual void pushElseIf(Node& node) {
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")
2025
2026 _indentation.resize(_indentation.size() - _spaces.size());
2027
2028 _streamStack <<_indentation << "} else if(";
2029 pushIndexCondExprOp(*node.getArguments()[1].getOperation());
2030 _streamStack << ") {\n";
2031
2032 _indentation += _spaces;
2033 }
2034
2035 virtual void pushElse(Node& node) {
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")
2042
2043 _indentation.resize(_indentation.size() - _spaces.size());
2044
2045 _streamStack <<_indentation << "} else {\n";
2046
2047 _indentation += _spaces;
2048 }
2049
2050 virtual void pushEndIf(Node& node) {
2051 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node type for an 'end if' operation")
2052
2053 _indentation.resize(_indentation.size() - _spaces.size());
2054
2055 _streamStack <<_indentation << "}\n";
2056 }
2057
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")
2063
2064 // just follow the argument
2065 Node& nodeArg = *node.getArguments()[1].getOperation();
2066 printAssignment(nodeArg);
2067 }
2068
2069 virtual void pushUserCustom(Node& node) {
2070 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom, "Invalid node type")
2071
2072 throw CGException("Unable to generate C source code for user custom operation nodes.");
2073 }
2074
2075 inline bool isDependent(const Node& arg) const {
2076 if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
2077 return true;
2078 }
2079 size_t id = getVariableID(arg);
2080 return id > _independentSize && id < _minTemporaryVarID;
2081 }
2082
2083 virtual void printParameter(const Base& value) {
2084 writeParameter(value, _code);
2085 }
2086
2087 virtual void pushParameter(const Base& value) {
2088 writeParameter(value, _streamStack);
2089 }
2090
2091 template<class Output>
2092 void writeParameter(const Base& value, Output& output) {
2093 // make sure all digits of floating point values are printed
2094 std::ostringstream os;
2095 os << std::setprecision(_parameterPrecision) << value;
2096
2097 std::string number = os.str();
2098 output << number;
2099
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) {
2102 // also make sure there is always a '.' after the number in
2103 // order to avoid integer overflows
2104 output << '.';
2105 }
2106 }
2107 }
2108
2109 virtual const std::string& getComparison(enum CGOpCode op) const {
2110 switch (op) {
2111 case CGOpCode::ComLt:
2112 return _C_COMP_OP_LT;
2113
2114 case CGOpCode::ComLe:
2115 return _C_COMP_OP_LE;
2116
2117 case CGOpCode::ComEq:
2118 return _C_COMP_OP_EQ;
2119
2120 case CGOpCode::ComGe:
2121 return _C_COMP_OP_GE;
2122
2123 case CGOpCode::ComGt:
2124 return _C_COMP_OP_GT;
2125
2126 case CGOpCode::ComNe:
2127 return _C_COMP_OP_NE;
2128
2129 default:
2130 CPPAD_ASSERT_UNKNOWN(0)
2131 break;
2132 }
2133 throw CGException("Invalid comparison operator code"); // should never get here
2134 }
2135
2136 inline const std::string& getPrintfBaseFormat() {
2137 static const std::string format; // empty string
2138 return format;
2139 }
2140
2141 static bool isFunction(enum CGOpCode op) {
2142 return isUnaryFunction(op) || op == CGOpCode::Pow;
2143 }
2144
2145 static bool isUnaryFunction(enum CGOpCode op) {
2146 switch (op) {
2147 case CGOpCode::Abs:
2148 case CGOpCode::Acos:
2149 case CGOpCode::Asin:
2150 case CGOpCode::Atan:
2151 case CGOpCode::Cosh:
2152 case CGOpCode::Cos:
2153 case CGOpCode::Exp:
2154 case CGOpCode::Log:
2155 case CGOpCode::Sinh:
2156 case CGOpCode::Sin:
2157 case CGOpCode::Sqrt:
2158 case CGOpCode::Tanh:
2159 case CGOpCode::Tan:
2160#if CPPAD_USE_CPLUSPLUS_2011
2161 case CGOpCode::Erf:
2162 case CGOpCode::Erfc:
2163 case CGOpCode::Asinh:
2164 case CGOpCode::Acosh:
2165 case CGOpCode::Atanh:
2166 case CGOpCode::Expm1:
2167 case CGOpCode::Log1p:
2168#endif
2169 return true;
2170 default:
2171 return false;
2172 }
2173 }
2174
2175 inline static bool isCondAssign(enum CGOpCode op) {
2176 switch (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:
2183 return true;
2184 default:
2185 return false;
2186 }
2187 }
2188private:
2189
2190 class AtomicFuncArray {
2191 public:
2192 std::string data;
2193 unsigned long size;
2194 bool sparse;
2195 size_t idx_id;
2196 unsigned long nnz;
2197 unsigned short scope;
2198 };
2199};
2200template<class Base>
2201const std::string LanguageC<Base>::U_INDEX_TYPE = "unsigned long"; // NOLINT(cert-err58-cpp)
2202
2203template<class Base>
2204const std::string LanguageC<Base>::_C_COMP_OP_LT = "<"; // NOLINT(cert-err58-cpp)
2205template<class Base>
2206const std::string LanguageC<Base>::_C_COMP_OP_LE = "<="; // NOLINT(cert-err58-cpp)
2207template<class Base>
2208const std::string LanguageC<Base>::_C_COMP_OP_EQ = "=="; // NOLINT(cert-err58-cpp)
2209template<class Base>
2210const std::string LanguageC<Base>::_C_COMP_OP_GE = ">="; // NOLINT(cert-err58-cpp)
2211template<class Base>
2212const std::string LanguageC<Base>::_C_COMP_OP_GT = ">"; // NOLINT(cert-err58-cpp)
2213template<class Base>
2214const std::string LanguageC<Base>::_C_COMP_OP_NE = "!="; // NOLINT(cert-err58-cpp)
2215
2216template<class Base>
2217const std::string LanguageC<Base>::_C_STATIC_INDEX_ARRAY = "index"; // NOLINT(cert-err58-cpp)
2218
2219template<class Base>
2220const std::string LanguageC<Base>::_C_SPARSE_INDEX_ARRAY = "idx"; // NOLINT(cert-err58-cpp)
2221
2222template<class Base>
2223const std::string LanguageC<Base>::_ATOMIC_TX = "atx"; // NOLINT(cert-err58-cpp)
2224
2225template<class Base>
2226const std::string LanguageC<Base>::_ATOMIC_TY = "aty"; // NOLINT(cert-err58-cpp)
2227
2228template<class Base>
2229const std::string LanguageC<Base>::_ATOMIC_PX = "apx"; // NOLINT(cert-err58-cpp)
2230
2231template<class Base>
2232const std::string LanguageC<Base>::_ATOMIC_PY = "apy"; // NOLINT(cert-err58-cpp)
2233
2234template<class Base>
2235const std::string LanguageC<Base>::ATOMICFUN_STRUCT_DEFINITION = // NOLINT(cert-err58-cpp)
2236"typedef struct Array {\n"
2237" void* data;\n"
2238" " + U_INDEX_TYPE + " size;\n"
2239" int sparse;\n"
2240" const " + U_INDEX_TYPE + "* idx;\n"
2241" " + U_INDEX_TYPE + " nnz;\n"
2242"} Array;\n"
2243"\n"
2244"struct LangCAtomicFun {\n"
2245" void* libModel;\n"
2246" int (*forward)(void* libModel,\n"
2247" int atomicIndex,\n"
2248" int q,\n"
2249" int p,\n"
2250" const Array tx[],\n"
2251" Array* ty);\n"
2252" int (*reverse)(void* libModel,\n"
2253" int atomicIndex,\n"
2254" int p,\n"
2255" const Array tx[],\n"
2256" Array* px,\n"
2257" const Array py[]);\n"
2258"};";
2259
2260} // END cg namespace
2261} // END CppAD namespace
2262
2263#endif
size_t size() const noexcept
virtual void pushAtomicReverseOp(Node &atomicRev)
virtual void setParameterPrecision(size_t p)
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
virtual void pushElseIf(Node &node)
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
void setIgnoreZeroDepAssign(bool ignore)
size_t getMaxOperationsPerAssignment() const
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={})
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node * > &variableOrder, size_t starti)
virtual size_t getParameterPrecision() const
LanguageC(std::string varTypeName, size_t spaces=3)
virtual void pushAtomicForwardOp(Node &atomicFor)
bool requiresVariableDependencies() const override
virtual bool directlyAssignsVariable(const Node &var) const
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
virtual std::string generateTemporaryVariableDeclaration(bool isWrapperFunction=false, bool zeroArrayDependents=false, int maxForwardOrder=-1, int maxReverseOrder=-1)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
bool isIgnoreZeroDepAssign() const
virtual void pushStartIf(Node &node)
virtual void pushElse(Node &node)
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern * > &randomPatterns)
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg * > &tmpArrayValues)
void setName(const std::string &name)
const std::vector< size_t > & getInfo() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const
const std::string * getName() const
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getDependent() const
virtual size_t getMaxTemporarySparseArrayVariableID() const =0
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getIndependent() const
virtual const std::vector< FuncArgument > & getTemporary() const
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
virtual size_t getMinTemporaryVariableID() const =0
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual size_t getMaxTemporaryArrayVariableID() const =0
virtual std::string generateDependent(size_t index)=0
virtual size_t getMaxTemporaryVariableID() const =0
cg::CG< Base > pow(const cg::CG< Base > &x, const cg::CG< Base > &y)