CppADCodeGen  HEAD
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  * 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 
19 namespace CppAD {
20 namespace cg {
21 
22 template<class Base>
23 void 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 
59 template<class Base>
60 void 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 
124 template<class Base>
125 inline size_t LanguageC<Base>::printArrayCreationUsingLoop(size_t startPos,
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 
300 template<class Base>
301 inline 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 
308 template<class Base>
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 
324 template<class Base>
325 inline 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 
334 template<class Base>
335 inline 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 
438 template<class Base>
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
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