CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_c_loops.hpp
1#ifndef CPPAD_CG_LANGUAGE_C_LOOPS_INCLUDED
2#define CPPAD_CG_LANGUAGE_C_LOOPS_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2015 Ciengis
6 * Copyright (C) 2019 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
19namespace CppAD {
20namespace cg {
21
22template<class Base>
23void LanguageC<Base>::pushLoopIndexedDep(OperationNode <Base>& node) {
24 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for loop indexed dependent operation")
25
26 // LoopIndexedDep
27 push(node.getArguments()[0]);
28}
29
30template<class Base>
31size_t LanguageC<Base>::printLoopIndexDeps(const std::vector<OperationNode<Base>*>& variableOrder,
32 size_t pos) {
33 CPPADCG_ASSERT_KNOWN(pos < variableOrder.size(), "Invalid number of arguments for array creation operation")
34 CPPADCG_ASSERT_KNOWN(variableOrder[pos]->getOperationType() == CGOpCode::LoopIndexedDep, "Invalid operation type")
35
36 const size_t vSize = variableOrder.size();
37
38 for (size_t i = pos; i < vSize; i++) {
39 if (variableOrder[i]->getOperationType() != CGOpCode::LoopIndexedDep) {
40 return i - 1;
41 }
42
43 // try to use a loop for element assignment
44 size_t newI = printLoopIndexedDepsUsingLoop(variableOrder, i);
45
46 if (newI == i) {
47 // individual element assignment
48 printAssignment(*variableOrder[i]);
49 } else {
50 i = newI;
51 }
52 }
53
54 return vSize - 1;
55}
56
57template<class Base>
58inline size_t LanguageC<Base>::printLoopIndexedDepsUsingLoop(const std::vector<OperationNode<Base>*>& variableOrder,
59 size_t starti) {
60 CPPADCG_ASSERT_KNOWN(variableOrder[starti] != nullptr, "Invalid node")
61 CPPADCG_ASSERT_KNOWN(variableOrder[starti]->getOperationType() == CGOpCode::LoopIndexedDep, "Invalid operation type")
62
63 const size_t vSize = variableOrder.size();
64
65 const OperationNode<Base>& ref = *variableOrder[starti];
66
67 const IndexPattern* refIp = _info->loopDependentIndexPatterns[ref.getInfo()[0]];
68 size_t refAssignOrAdd = ref.getInfo()[1];
69
73 const OperationNode<Base>* refLeft = ref.getArguments()[0].getOperation();
74 if (refLeft == nullptr) {
75 return starti;
76 } else if (refLeft->getOperationType() != CGOpCode::ArrayElement) {
77 return starti;
78 }
79
83 const LinearIndexPattern* refLIp = nullptr;
84 const SectionedIndexPattern* refSecp = nullptr;
85
86 if (refIp->getType() == IndexPatternType::Linear) {
87 refLIp = static_cast<const LinearIndexPattern*> (refIp);
88 } else if (refIp->getType() == IndexPatternType::Sectioned) {
89 refSecp = static_cast<const SectionedIndexPattern*> (refIp);
90 } else {
91 return starti; // cannot determine consecutive elements
92 }
93
97 const OperationNode<Base>* refArray = refLeft->getArguments()[0].getOperation();
98 const size_t startArrayIndex = refLeft->getInfo()[0];
99
100 size_t i = starti + 1;
101
102 for (; i < vSize; i++) {
103 OperationNode<Base>* node = variableOrder[i];
104 if (node->getOperationType() != CGOpCode::LoopIndexedDep)
105 break;
106
107 const OperationNode<Base>* nodeLeft = variableOrder[i]->getArguments()[0].getOperation();
108 if (nodeLeft->getOperationType() != CGOpCode::ArrayElement)
109 break;
110
111 const OperationNode<Base>* arrayi = nodeLeft->getArguments()[0].getOperation();
112 if (arrayi != refArray)
113 break;
114
115 long offset = long(i) - long(starti);
116
117 if (nodeLeft->getInfo()[0] != startArrayIndex + offset)
118 break;
119
120 if (node->getInfo()[1] != refAssignOrAdd)
121 break;
122
123 const IndexPattern* ip = _info->loopDependentIndexPatterns[node->getInfo()[0]];
124 if (!isOffsetBy(ip, refIp, offset)) {
125 break; // different pattern type
126 }
127 }
128
129 if (i - starti < 3)
130 return starti; // no point in looping for 2 elements
131
135 std::unique_ptr<Plane2DIndexPattern> p2dip;
136 if (refLIp != nullptr) {
137 p2dip.reset(encapsulateIndexPattern(*refLIp, 0));
138 } else {
139 assert(refSecp != nullptr);
140 p2dip.reset(encapsulateIndexPattern(*refSecp, 0));
141 }
142
143 std::unique_ptr<OperationNode<Base>> op2(OperationNode<Base>::makeTemporaryNode(CGOpCode::LoopIndexedDep, ref.getInfo(), ref.getArguments()));
144 op2->getInfo()[1] = (std::numeric_limits<size_t>::max)(); // just to be safe (this would be the index pattern id in the handler)
145 op2->getArguments().push_back(_info->auxIterationIndexOp);
146
147 std::ostringstream rightAssign;
148
149 rightAssign << _nameGen->generateIndexedDependent(*op2, 0, *p2dip);
150
154 size_t depVarCount = i - starti;
155 _streamStack << _indentation << "for(i = 0; i < " << depVarCount << "; i++) ";
156 _streamStack << rightAssign.str() << " ";
157 if (refAssignOrAdd == 1) {
158 _streamStack << "+=";
159 } else {
160 _streamStack << _depAssignOperation;
161 }
162 _streamStack << " ";
163
164 std::string arrayName;
165 if (refArray->getOperationType() == CGOpCode::ArrayCreation)
166 arrayName = _nameGen->generateTemporaryArray(*refArray, getVariableID(*refArray));
167 else
168 arrayName = _nameGen->generateTemporarySparseArray(*refArray, getVariableID(*refArray));
169
170 _streamStack << "(" << arrayName << ")[i + " << startArrayIndex << "];\n";
171
172 return i - 1;
173}
174
175
176} // END cg namespace
177} // END CppAD namespace
178
179#endif
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node * > &variableOrder, size_t starti)
const std::vector< size_t > & getInfo() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const