CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
language_latex_arrays.hpp
1 #ifndef CPPAD_CG_LANGUAGE_LATEX_ARRAYS_INCLUDED
2 #define CPPAD_CG_LANGUAGE_LATEX_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 LanguageLatex<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 << _startAlgLine << _startEq
37  << auxArrayName_ << _assignStr << _nameGen->generateTemporaryArray(array, getVariableID(array))
38  << _endEq << _endAlgLine
39  << " % size: " << args.size() << _endline;
40  firstElement = false;
41  }
42 
43  // try to use a loop for element assignment
44  size_t newI = printArrayCreationUsingLoop(startPos, array, i, _tmpArrayValues);
45 
46  // print elements not assign in a loop
47  if (newI == i) {
48  // individual element assignment
49  _code << _startAlgLine << _startEq
50  << auxArrayName_ << "[" << i << "]" << _assignStr;
51  print(args[i]);
52  _code << _endEq << _endAlgLine << _endline;
53 
54  _tmpArrayValues[startPos + i] = &args[i];
55 
56  } else {
57  i = newI - 1;
58  }
59  }
60  }
61 }
62 
63 template<class Base>
64 void LanguageLatex<Base>::printSparseArrayCreationOp(OperationNode<Base>& array) {
65  const std::vector<size_t>& info = array.getInfo();
66  CPPADCG_ASSERT_KNOWN(info.size() > 0, "Invalid number of information elements for sparse array creation operation");
67 
68  const std::vector<Argument<Base> >& args = array.getArguments();
69  const size_t argSize = args.size();
70 
71  CPPADCG_ASSERT_KNOWN(info.size() == argSize + 1, "Invalid number of arguments for sparse array creation operation");
72 
73  if (argSize == 0)
74  return; // empty array
75 
76  const size_t id = getVariableID(array);
77  size_t startPos = id - 1;
78 
79  bool firstElement = true;
80  for (size_t i = 0; i < argSize; i++) {
81  bool newValue = !isSameArgument(args[i], _tmpSparseArrayValues[startPos + i]);
82 
83  if (newValue) {
84  if (firstElement) {
85  _code << _startAlgLine << _startEq
86  << auxArrayName_ << _assignStr << _nameGen->generateTemporarySparseArray(array, getVariableID(array))
87  << _endEq << _endAlgLine
88  << " % nnz: " << args.size() << " size:" << info[0] << _endline;
89  firstElement = false;
90  }
91 
92  // try to use a loop for element assignment
93  size_t newI = printArrayCreationUsingLoop(startPos, array, i, _tmpSparseArrayValues);
94 
95  // print element values not assign in a loop
96  if (newI == i) {
97  // individual element assignment
98  _code << _startAlgLine << _startEq
99  << auxArrayName_ << "[" << i << "]" << _assignStr;
100  print(args[i]);
101  _code << _endEq;
102  _code << ", ";
103  // print indexes (location of values)
104  _code << _startEq
105  << _C_SPARSE_INDEX_ARRAY << "[";
106  if (startPos != 0) _code << startPos << "+";
107  _code << i << "]" << _assignStr << info[i + 1]
108  << _endEq << _endAlgLine << _endline;
109 
110  _tmpSparseArrayValues[startPos + i] = &args[i];
111 
112  } else {
113  // print indexes (location of values)
114  for (size_t j = i; j < newI; j++) {
115  _code << _startAlgLine << _startEq
116  << _C_SPARSE_INDEX_ARRAY << "[";
117  if (startPos != 0) _code << startPos << "+";
118  _code << j << "]" << _assignStr << info[j + 1]
119  << _endEq << _endAlgLine << _endline;
120  }
121 
122  i = newI - 1;
123  }
124 
125 
126  } else {
127  // print indexes (location of values)
128  _code << _startAlgLine << _startEq
129  << _C_SPARSE_INDEX_ARRAY << "[";
130  if (startPos != 0) _code << startPos << "+";
131  _code << i << "]" << _assignStr << info[i + 1]
132  << _endEq << _endAlgLine << _endline;
133  }
134 
135  }
136 }
137 
138 template<class Base>
140  OperationNode<Base>& array,
141  size_t starti,
142  std::vector<const Argument<Base>*>& tmpArrayValues) {
143  const std::vector<Argument<Base> >& args = array.getArguments();
144  const size_t argSize = args.size();
145  size_t i = starti + 1;
146 
147  std::ostringstream arrayAssign;
148 
149  const Argument<Base>& ref = args[starti];
150  if (ref.getOperation() != nullptr) {
151  //
152  const OperationNode<Base>& refOp = *ref.getOperation();
153  if (refOp.getOperationType() == CGOpCode::Inv) {
157  for (; i < argSize; i++) {
158  if (isSameArgument(args[i], tmpArrayValues[startPos + i]))
159  break; // no assignment needed
160 
161  if (args[i].getOperation() == nullptr ||
162  args[i].getOperation()->getOperationType() != CGOpCode::Inv ||
163  !_nameGen->isConsecutiveInIndepArray(*args[i - 1].getOperation(), getVariableID(*args[i - 1].getOperation()),
164  *args[i].getOperation(), getVariableID(*args[i].getOperation()))) {
165  break;
166  }
167  }
168 
169  if (i - starti < 3)
170  return starti;
171 
172  // use loop
173  const std::string& indep = _nameGen->getIndependentArrayName(refOp, getVariableID(refOp));
174  size_t start = _nameGen->getIndependentArrayIndex(refOp, getVariableID(refOp));
175  long offset = long(start) - starti;
176  if (offset == 0)
177  arrayAssign << indep << "[i]";
178  else
179  arrayAssign << indep << "[" << offset << " + i]";
180 
181  } else if (refOp.getOperationType() == CGOpCode::LoopIndexedIndep) {
185  size_t pos = refOp.getInfo()[1];
186  IndexPattern* refIp = _info->loopIndependentIndexPatterns[pos];
187  if (refIp->getType() != IndexPatternType::Linear) {
188  return starti; // cannot determine consecutive elements
189  }
190 
191  LinearIndexPattern* refLIp = static_cast<LinearIndexPattern*> (refIp);
192 
193  for (; i < argSize; i++) {
194  if (isSameArgument(args[i], tmpArrayValues[startPos + i]))
195  break; // no assignment needed
196 
197  if (args[i].getOperation() == nullptr ||
198  args[i].getOperation()->getOperationType() != CGOpCode::LoopIndexedIndep) {
199  break; // not an independent index pattern
200  }
201 
202  if (!_nameGen->isInSameIndependentArray(refOp, getVariableID(refOp),
203  *args[i].getOperation(), getVariableID(*args[i].getOperation())))
204  break;
205 
206  pos = args[i].getOperation()->getInfo()[1];
207  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
208  if (ip->getType() != IndexPatternType::Linear) {
209  break; // different pattern type
210  }
211  const LinearIndexPattern* lIp = static_cast<const LinearIndexPattern*> (ip);
212  if (refLIp->getLinearSlopeDx() != lIp->getLinearSlopeDx() ||
213  refLIp->getLinearSlopeDy() != lIp->getLinearSlopeDy() ||
214  refLIp->getXOffset() != lIp->getXOffset() ||
215  refLIp->getLinearConstantTerm() - long(starti) != lIp->getLinearConstantTerm() - long(i)) {
216  break;
217  }
218  }
219 
220  if (i - starti < 3)
221  return starti;
222 
223  LinearIndexPattern* lip2 = new LinearIndexPattern(*refLIp);
224  lip2->setLinearConstantTerm(lip2->getLinearConstantTerm() - starti);
225  Plane2DIndexPattern p2dip(lip2,
226  new LinearIndexPattern(0, 1, 1, 0));
227 
228  std::unique_ptr<OperationNode<Base>> op2(OperationNode<Base>::makeTemporaryNode(CGOpCode::LoopIndexedIndep, refOp.getInfo(), refOp.getArguments()));
229  op2->getInfo()[1] = std::numeric_limits<size_t>::max(); // just to be safe (this would be the index pattern id in the handler)
230  op2->getArguments().push_back(_info->auxIterationIndexOp);
231 
232  arrayAssign << _nameGen->generateIndexedIndependent(*op2, 0, p2dip);
233 
234  } else {
235  // no loop used
236  return starti;
237  }
238  } else {
242  const Base& value = *args[starti].getParameter();
243  for (; i < argSize; i++) {
244  if (args[i].getParameter() == nullptr || *args[i].getParameter() != value) {
245  break; // not the same constant value
246  }
247 
248  const Argument<Base>* oldArg = tmpArrayValues[startPos + i];
249  if (oldArg != nullptr && oldArg->getParameter() != nullptr && *oldArg->getParameter() == value) {
250  break; // values are the same (no need to redefine)
251  }
252  }
253 
254  if (i - starti < 3)
255  return starti;
256 
257  arrayAssign << value;
258  }
259 
263  _code << _forStart << "{$i \\in \\left[" << starti << ", " << (i - 1) << "\\right]$}" << _endline;
264  _indentationLevel++;
265  _code << _startAlgLine << _startEq
266  << auxArrayName_ << "[i]" << _assignStr << arrayAssign.str()
267  << _endEq << _endAlgLine << _endline;
268  _indentationLevel--;
269  _code << _forEnd << _endline;
270 
274  for (size_t ii = starti; ii < i; ii++) {
275  tmpArrayValues[startPos + ii] = &args[ii];
276  }
277 
278  return i;
279 }
280 
281 template<class Base>
282 inline std::string LanguageLatex<Base>::getTempArrayName(const OperationNode<Base>& op) {
283  if (op.getOperationType() == CGOpCode::ArrayCreation)
284  return _nameGen->generateTemporaryArray(op);
285  else
286  return _nameGen->generateTemporarySparseArray(op);
287 }
288 
289 template<class Base>
291  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for array element operation");
292  CPPADCG_ASSERT_KNOWN(op.getArguments()[0].getOperation() != nullptr, "Invalid argument for array element operation");
293  CPPADCG_ASSERT_KNOWN(op.getInfo().size() == 1, "Invalid number of information indexes for array element operation");
294 
295  OperationNode<Base>& arrayOp = *op.getArguments()[0].getOperation();
296  std::string arrayName;
297  if (arrayOp.getOperationType() == CGOpCode::ArrayCreation)
298  arrayName = _nameGen->generateTemporaryArray(arrayOp, getVariableID(arrayOp));
299  else
300  arrayName = _nameGen->generateTemporarySparseArray(arrayOp, getVariableID(arrayOp));
301 
302  _code << "(" << arrayName << ")[" << op.getInfo()[0] << "]";
303 }
304 
305 template<class Base>
306 inline void LanguageLatex<Base>::printArrayStructInit(const std::string& dataArrayName,
307  size_t pos,
308  const std::vector<OperationNode<Base>*>& arrays,
309  size_t k) {
310  _ss.str("");
311  _ss << dataArrayName << "[" << pos << "]";
312  printArrayStructInit(_ss.str(), *arrays[k]);
313 }
314 
315 template<class Base>
316 inline void LanguageLatex<Base>::printArrayStructInit(const std::string& dataArrayName,
317  OperationNode<Base>& array) {
321  const std::string& aName = createVariableName(array);
322 
323  if (array.getOperationType() == CGOpCode::ArrayCreation) {
324  // dense array
325  size_t size = array.getArguments().size();
326  if (size > 0)
327  _code << dataArrayName << ".data = " << aName << "; ";
328  else
329  _code << dataArrayName << ".data = NULL; ";
330  _code << dataArrayName << ".size = " << size << "; "
331  << dataArrayName << ".sparse = " << false << ";";
332  } else {
333  // sparse array
334  CPPADCG_ASSERT_KNOWN(array.getOperationType() == CGOpCode::SparseArrayCreation, "Invalid node type");
335  size_t nnz = array.getArguments().size();
336  if (nnz > 0)
337  _code << dataArrayName << ".data = " << aName << "; ";
338  else
339  _code << dataArrayName << ".data = NULL; ";
340  _code << dataArrayName << ".size = " << array.getInfo()[0] << "; "
341  << dataArrayName << ".sparse = " << true << "; "
342  << dataArrayName << ".nnz = " << nnz << "; ";
343  if (nnz > 0) {
344  size_t id = getVariableID(array);
345  _code << dataArrayName << ".idx = &(" << _C_SPARSE_INDEX_ARRAY << "[" << (id - 1) << "]);";
346  }
347  }
348  _code << _endline;
349 }
350 
351 template<class Base>
353  size_t id = getVariableID(ty);
354  size_t tySize = ty.getArguments().size();
355 
356  if (ty.getOperationType() == CGOpCode::ArrayCreation) {
357  for (size_t i = 0; i < tySize; i++) {
358  _tmpArrayValues[id - 1 + i] = nullptr;
359  }
360  } else {
361  for (size_t i = 0; i < tySize; i++) {
362  _tmpSparseArrayValues[id - 1 + i] = nullptr;
363  }
364  }
365 }
366 
367 } // END cg namespace
368 } // END CppAD namespace
369 
370 #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