CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_c_arrays.hpp
1#ifndef CPPAD_CG_LANGUAGE_C_ARRAYS_INCLUDED
2#define CPPAD_CG_LANGUAGE_C_ARRAYS_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2014 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>::pushArrayCreationOp(OperationNode <Base>& array) {
24 CPPADCG_ASSERT_KNOWN(array.getArguments().size() > 0, "Invalid number of arguments for array creation operation")
25 const size_t id = getVariableID(array);
26 const std::vector<Argument<Base> >& args = array.getArguments();
27 const size_t argSize = args.size();
28
29 size_t startPos = id - 1;
30
31 bool firstElement = true;
32 for (size_t i = 0; i < argSize; i++) {
33 bool newValue = !isSameArgument(args[i], _tmpArrayValues[startPos + i]);
34
35 if (newValue) {
36 if (firstElement) {
37 _streamStack << _indentation << auxArrayName_ << " = " << _nameGen->generateTemporaryArray(array, getVariableID(array)) << "; // size: " << args.size() << "\n";
38 firstElement = false;
39 }
40
41 // try to use a loop for element assignment
42 size_t newI = printArrayCreationUsingLoop(startPos, array, i, _tmpArrayValues);
43
44 if (newI == i) {
45 // individual element assignment
46 _streamStack << _indentation << auxArrayName_ << "[" << i << "] = ";
47 push(args[i]);
48 _streamStack << ";\n";
49
50 _tmpArrayValues[startPos + i] = &args[i];
51
52 } else {
53 i = newI - 1;
54 }
55 }
56 }
57}
58
59template<class Base>
60void LanguageC<Base>::pushSparseArrayCreationOp(OperationNode <Base>& array) {
61 const std::vector<size_t>& info = array.getInfo();
62 CPPADCG_ASSERT_KNOWN(!info.empty(), "Invalid number of information elements for sparse array creation operation")
63
64 const std::vector<Argument<Base> >& args = array.getArguments();
65 const size_t argSize = args.size();
66
67 CPPADCG_ASSERT_KNOWN(info.size() == argSize + 1, "Invalid number of arguments for sparse array creation operation")
68
69 if (argSize == 0)
70 return; // empty array
71
72 const size_t id = getVariableID(array);
73 size_t startPos = id - 1;
74
75 bool firstElement = true;
76 for (size_t i = 0; i < argSize; i++) {
77 bool newValue = !isSameArgument(args[i], _tmpSparseArrayValues[startPos + i]);
78
79 if (newValue) {
80 if (firstElement) {
81 _streamStack << _indentation << auxArrayName_ << " = " << _nameGen->generateTemporarySparseArray(array, getVariableID(array))
82 << "; // nnz: " << args.size() << " size:" << info[0] << "\n";
83 firstElement = false;
84 }
85
86 // try to use a loop for element assignment
87 size_t newI = printArrayCreationUsingLoop(startPos, array, i, _tmpSparseArrayValues);
88
89 if (newI == i) {
90 // individual element assignment
91 _streamStack << _indentation << auxArrayName_ << "[" << i << "] = ";
92 push(args[i]);
93 _streamStack << "; ";
94 // print indexes (location of values)
95 _streamStack << _C_SPARSE_INDEX_ARRAY << "[";
96 if (startPos != 0) _streamStack << startPos << "+";
97 _streamStack << i << "] = " << info[i + 1] << ";\n";
98
99 _tmpSparseArrayValues[startPos + i] = &args[i];
100
101 } else {
102 // print indexes (location of values)
103 for (size_t j = i; j < newI; j++) {
104 _streamStack << _indentation << _C_SPARSE_INDEX_ARRAY << "[";
105 if (startPos != 0) _streamStack << startPos << "+";
106 _streamStack << j << "] = " << info[j + 1] << ";\n";
107 }
108
109 i = newI - 1;
110 }
111
112
113 } else {
114 // print indexes (location of values)
115 _streamStack << _indentation
116 << _C_SPARSE_INDEX_ARRAY << "[";
117 if (startPos != 0) _streamStack << startPos << "+";
118 _streamStack << i << "] = " << info[i + 1] << ";\n";
119 }
120
121 }
122}
123
124template<class Base>
126 OperationNode<Base>& array,
127 size_t starti,
128 std::vector<const Argument<Base>*>& tmpArrayValues) {
129 const std::vector<Argument<Base> >& args = array.getArguments();
130 const size_t argSize = args.size();
131 size_t i = starti + 1;
132
133 std::ostringstream arrayAssign;
134
135 const Argument<Base>& ref = args[starti];
136 if (ref.getOperation() != nullptr) {
137 //
138 const OperationNode<Base>& refOp = *ref.getOperation();
139 CGOpCode op = refOp.getOperationType();
140 if (op == CGOpCode::Inv) {
144 for (; i < argSize; i++) {
145 if (isSameArgument(args[i], tmpArrayValues[startPos + i]))
146 break; // no assignment needed
147
148 if (args[i].getOperation() == nullptr ||
149 args[i].getOperation()->getOperationType() != CGOpCode::Inv ||
150 !_nameGen->isConsecutiveInIndepArray(*args[i - 1].getOperation(), getVariableID(*args[i - 1].getOperation()),
151 *args[i].getOperation(), getVariableID(*args[i].getOperation()))) {
152 break;
153 }
154 }
155
156 if (i - starti < 3)
157 return starti;
158
159 // use loop
160 const std::string& indep = _nameGen->getIndependentArrayName(refOp, getVariableID(refOp));
161 size_t start = _nameGen->getIndependentArrayIndex(refOp, getVariableID(refOp));
162 long offset = long(start) - starti;
163 if (offset == 0)
164 arrayAssign << indep << "[i]";
165 else
166 arrayAssign << indep << "[" << offset << " + i]";
167
168 } else if (op == CGOpCode::LoopIndexedIndep) {
172 size_t pos = refOp.getInfo()[1];
173 IndexPattern* refIp = _info->loopIndependentIndexPatterns[pos];
174
175 LinearIndexPattern* refLIp = nullptr;
176 SectionedIndexPattern* refSecp = nullptr;
177
178 if (refIp->getType() == IndexPatternType::Linear) {
179 refLIp = dynamic_cast<LinearIndexPattern*> (refIp);
180 } else if (refIp->getType() == IndexPatternType::Sectioned) {
181 refSecp = dynamic_cast<SectionedIndexPattern*> (refIp);
182 } else {
183 return starti; // cannot determine consecutive elements
184 }
185
186 for (; i < argSize; i++) {
187 if (isSameArgument(args[i], tmpArrayValues[startPos + i]))
188 break; // no assignment needed
189
190 if (args[i].getOperation() == nullptr ||
191 args[i].getOperation()->getOperationType() != CGOpCode::LoopIndexedIndep) {
192 break; // not an independent index pattern
193 }
194
195 if (!_nameGen->isInSameIndependentArray(refOp, getVariableID(refOp),
196 *args[i].getOperation(), getVariableID(*args[i].getOperation())))
197 break;
198
199 pos = args[i].getOperation()->getInfo()[1];
200 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
201
202 if (!isOffsetBy(ip, refIp, long(i) - long(starti))) {
203 break; // different pattern type
204 }
205 }
206
207 if (i - starti < 3)
208 return starti;
209
210 std::unique_ptr<Plane2DIndexPattern> p2dip;
211 if (refLIp != nullptr) {
212 p2dip.reset(encapsulateIndexPattern(*refLIp, starti));
213 } else {
214 assert(refSecp != nullptr);
215 p2dip.reset(encapsulateIndexPattern(*refSecp, starti));
216 }
217
218 std::unique_ptr<OperationNode<Base>> op2(OperationNode<Base>::makeTemporaryNode(CGOpCode::LoopIndexedIndep, refOp.getInfo(), refOp.getArguments()));
219 op2->getInfo()[1] = (std::numeric_limits<size_t>::max)(); // just to be safe (this would be the index pattern id in the handler)
220 op2->getArguments().push_back(_info->auxIterationIndexOp);
221
222 arrayAssign << _nameGen->generateIndexedIndependent(*op2, 0, *p2dip);
223 } else if (getVariableID(refOp) >= this->_minTemporaryVarID && op != CGOpCode::LoopIndexedDep && op != CGOpCode::LoopIndexedTmp && op != CGOpCode::Tmp) {
227 for (; i < argSize; i++) {
228 if (isSameArgument(args[i], tmpArrayValues[startPos + i]))
229 break; // no assignment needed
230 else if (args[i].getOperation() == nullptr)
231 break;
232
233 const OperationNode<Base>& opNode2 = *args[i].getOperation();
234 if (getVariableID(opNode2) < this->_minTemporaryVarID)
235 break;
236
237 CGOpCode op2 = opNode2.getOperationType();
238 if (op2 == CGOpCode::LoopIndexedIndep || op2 == CGOpCode::LoopIndexedDep || op2 == CGOpCode::LoopIndexedTmp || op2 == CGOpCode::Tmp)
239 break;
240
241 if (!_nameGen->isConsecutiveInTemporaryVarArray(*args[i - 1].getOperation(), getVariableID(*args[i - 1].getOperation()),
242 *args[i].getOperation(), getVariableID(*args[i].getOperation())))
243 break;
244 }
245
246 if (i - starti < 3)
247 return starti;
248
249 // use loop
250 const std::string& tmpName = _nameGen->getTemporaryVarArrayName(refOp, getVariableID(refOp));
251 size_t start = _nameGen->getTemporaryVarArrayIndex(refOp, getVariableID(refOp));
252 long offset = long(start) - starti;
253 if (offset == 0)
254 arrayAssign << tmpName << "[i]";
255 else
256 arrayAssign << tmpName << "[" << offset << " + i]";
257
258 } else {
259 // no loop used
260 return starti;
261 }
262 } else {
266 const Base& value = *args[starti].getParameter();
267 for (; i < argSize; i++) {
268 if (args[i].getParameter() == nullptr || *args[i].getParameter() != value) {
269 break; // not the same constant value
270 }
271
272 const Argument<Base>* oldArg = tmpArrayValues[startPos + i];
273 if (oldArg != nullptr && oldArg->getParameter() != nullptr && *oldArg->getParameter() == value) {
274 break; // values are the same (no need to redefine)
275 }
276 }
277
278 if (i - starti < 3)
279 return starti;
280
281 arrayAssign << value;
282 }
283
287 _streamStack << _indentation << "for(i = " << starti << "; i < " << i << "; i++) "
288 << auxArrayName_ << "[i] = " << arrayAssign.str() << ";\n";
289
293 for (size_t ii = starti; ii < i; ii++) {
294 tmpArrayValues[startPos + ii] = &args[ii];
295 }
296
297 return i;
298}
299
300template<class Base>
301inline std::string LanguageC<Base>::getTempArrayName(const OperationNode<Base>& op) {
302 if (op.getOperationType() == CGOpCode::ArrayCreation)
303 return _nameGen->generateTemporaryArray(op);
304 else
305 return _nameGen->generateTemporarySparseArray(op);
306}
307
308template<class Base>
309void LanguageC<Base>::pushArrayElementOp(OperationNode <Base>& op) {
310 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for array element operation")
311 CPPADCG_ASSERT_KNOWN(op.getArguments()[0].getOperation() != nullptr, "Invalid argument for array element operation")
312 CPPADCG_ASSERT_KNOWN(op.getInfo().size() == 1, "Invalid number of information indexes for array element operation")
313
314 OperationNode<Base>& arrayOp = *op.getArguments()[0].getOperation();
315 std::string arrayName;
316 if (arrayOp.getOperationType() == CGOpCode::ArrayCreation)
317 arrayName = _nameGen->generateTemporaryArray(arrayOp, getVariableID(arrayOp));
318 else
319 arrayName = _nameGen->generateTemporarySparseArray(arrayOp, getVariableID(arrayOp));
320
321 _streamStack << "(" << arrayName << ")[" << op.getInfo()[0] << "]";
322}
323
324template<class Base>
325inline void LanguageC<Base>::printArrayStructInit(const std::string& dataArrayName,
326 size_t pos,
327 const std::vector<OperationNode<Base>*>& arrays,
328 size_t k) {
329 _ss.str("");
330 _ss << dataArrayName << "[" << pos << "]";
331 printArrayStructInit(_ss.str(), *arrays[k]);
332}
333
334template<class Base>
335inline void LanguageC<Base>::printArrayStructInit(const std::string& dataArrayName,
336 OperationNode<Base>& array) {
337 const std::string& aName = createVariableName(array);
338
339 // lets see what was the previous values in this array
340 auto itLast = _atomicFuncArrays.find(dataArrayName);
341 bool firstTime = itLast == _atomicFuncArrays.end() || itLast->second.scope != _info->scope[array];
342 AtomicFuncArray& lastArray = firstTime ? _atomicFuncArrays[dataArrayName] : itLast->second;
343
344 bool changed = false;
345
346 // apply the differences
347 if (array.getOperationType() == CGOpCode::ArrayCreation) {
348 size_t size = array.getArguments().size();
349
350 if (size > 0) {
351 if (firstTime || aName != lastArray.data) {
352 _streamStack << _indentation;
353 _streamStack << dataArrayName << ".data = " << aName << "; ";
354 lastArray.data = aName;
355 changed = true;
356 }
357 } else {
358 if (firstTime || "NULL" != lastArray.data) {
359 _streamStack << _indentation;
360 _streamStack << dataArrayName << ".data = NULL; ";
361 lastArray.data = "NULL";
362 changed = true;
363 }
364 }
365
366 if (firstTime || size != lastArray.size) {
367 if (!changed) _streamStack << _indentation;
368 _streamStack << dataArrayName << ".size = " << size << "; ";
369 lastArray.size = size;
370 changed = true;
371 }
372 if (firstTime || lastArray.sparse) {
373 if (!changed) _streamStack << _indentation;
374 _streamStack << dataArrayName << ".sparse = " << false << ";";
375 lastArray.sparse = false;
376 changed = true;
377 }
378
379 } else {
380 CPPADCG_ASSERT_KNOWN(array.getOperationType() == CGOpCode::SparseArrayCreation, "Invalid node type")
381 size_t nnz = array.getArguments().size();
382 size_t size = array.getInfo()[0];
383
384 if (nnz > 0) {
385 if (firstTime || aName != lastArray.data) {
386 _streamStack << _indentation;
387 _streamStack << dataArrayName << ".data = " << aName << "; ";
388 lastArray.data = aName;
389 changed = true;
390 }
391 } else {
392 if (firstTime || "NULL" != lastArray.data) {
393 _streamStack << _indentation;
394 _streamStack << dataArrayName << ".data = NULL; ";
395 lastArray.data = "NULL";
396 changed = true;
397 }
398 }
399
400 if (firstTime || size != lastArray.size) {
401 if (!changed) _streamStack << _indentation;
402 _streamStack << dataArrayName << ".size = " << size << "; ";
403 lastArray.size = size;
404 changed = true;
405 }
406 if (firstTime || !lastArray.sparse) {
407 if (!changed) _streamStack << _indentation;
408 _streamStack << dataArrayName << ".sparse = " << true << "; ";
409 lastArray.sparse = true;
410 changed = true;
411 }
412 if (firstTime || nnz != lastArray.nnz) {
413 if (!changed) _streamStack << _indentation;
414 _streamStack << dataArrayName << ".nnz = " << nnz << "; ";
415 lastArray.nnz = nnz;
416 changed = true;
417 }
418
419 if (nnz > 0) {
420 size_t id = getVariableID(array);
421 if (firstTime || id != lastArray.idx_id) {
422 if (!changed) _streamStack << _indentation;
423 _streamStack << dataArrayName << ".idx = &(" << _C_SPARSE_INDEX_ARRAY << "[" << (id - 1) << "]);";
424 lastArray.idx_id = id;
425 changed = true;
426 }
427 } else {
428 lastArray.idx_id = (std::numeric_limits<size_t>::max)();
429 }
430 }
431
432 lastArray.scope = _info->scope[array];
433
434 if (changed)
435 _streamStack << "\n";
436}
437
438template<class Base>
439inline void LanguageC<Base>::markArrayChanged(OperationNode<Base>& ty) {
440 size_t id = getVariableID(ty);
441 size_t tySize = ty.getArguments().size();
442
443 if (ty.getOperationType() == CGOpCode::ArrayCreation) {
444 for (size_t i = 0; i < tySize; i++) {
445 _tmpArrayValues[id - 1 + i] = nullptr;
446 }
447 } else {
448 for (size_t i = 0; i < tySize; i++) {
449 _tmpSparseArrayValues[id - 1 + i] = nullptr;
450 }
451 }
452}
453
454} // END cg namespace
455} // END CppAD namespace
456
457#endif
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg * > &tmpArrayValues)
const std::vector< size_t > & getInfo() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const