CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
19namespace CppAD {
20namespace cg {
21
22template<class Base>
23void 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
64template<class Base>
65void 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
139template<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
282template<class Base>
284 if (op.getOperationType() == CGOpCode::ArrayCreation)
285 return _nameGen->generateTemporaryArray(op);
286 else
287 return _nameGen->generateTemporarySparseArray(op);
288}
289
290template<class Base>
291void LanguageLatex<Base>::printArrayElementOp(OperationNode<Base>& op) {
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
306template<class Base>
307inline 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
316template<class Base>
317inline 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
352template<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
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