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