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