CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_mathml_arrays.hpp
1#ifndef CPPAD_CG_LANGUAGE_MATHML_ARRAYS_INCLUDED
2#define CPPAD_CG_LANGUAGE_MATHML_ARRAYS_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2015 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
18namespace CppAD {
19namespace cg {
20
21template<class Base>
22void LanguageMathML<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 << _startEq
37 << "<mrow class='tmp'>" << auxArrayName_ << "</mrow>" << _assignStr << _nameGen->generateTemporaryArray(array, getVariableID(array))
38 << _endEq
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 << _startEq
50 << "<mrow class='tmp'>" << auxArrayName_ << "</mrow><mfenced open='[' close=']'><mn>" << i << "</mn></mfenced>" << _assignStr;
51 print(args[i]);
52 _code << _endEq << _endline;
53
54 _tmpArrayValues[startPos + i] = &args[i];
55
56 } else {
57 i = newI - 1;
58 }
59 }
60 }
61}
62
63template<class Base>
64void LanguageMathML<Base>::printSparseArrayCreationOp(OperationNode<Base>& array) {
65 const std::vector<size_t>& info = array.getInfo();
66 CPPADCG_ASSERT_KNOWN(!info.empty(), "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 << _startEq
86 << "<mrow class='tmp'>" << auxArrayName_ << "</mrow>" << _assignStr << _nameGen->generateTemporarySparseArray(array, getVariableID(array))
87 << _endEq
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 << _startEq
99 << "<mrow class='tmp'>" << auxArrayName_ << "</mrow><mfenced open='[' close=']'><mn>" << i << "</mn></mfenced>" << _assignStr;
100 print(args[i]);
101 _code << _endEq;
102 _code << ", ";
103 // print indexes (location of values)
104 _code << _startEq
105 << "<mi>" << _C_SPARSE_INDEX_ARRAY << "</mi><mfenced open='[' close=']'><mrow>";
106 if (startPos != 0) _code << "<mn>" << startPos << "</mn><mo>+</mo>";
107 _code << "<mn>" << i << "</mn></mrow></mfenced>" << _assignStr << "<mn>" << info[i + 1] << "</mn>"
108 << _endEq << _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 << _startEq
116 << "<mi>" << _C_SPARSE_INDEX_ARRAY << "</mi><mfenced open='[' close=']'><mrow>";
117 if (startPos != 0) _code << "<mn>" << startPos << "</mn><mo>+</mo>";
118 _code << "<mn>" << j << "</mn></mrow></mfenced>" << _assignStr << "<mn>" << info[j + 1] << "</mn>"
119 << _endEq << _endline;
120 }
121
122 i = newI - 1;
123 }
124
125
126 } else {
127 // print indexes (location of values)
128 _code << _startEq
129 << "<mi>" << _C_SPARSE_INDEX_ARRAY << "</mi><mfenced open='[' close=']'><mrow>";
130 if (startPos != 0) _code << "<mn>" << startPos << "</mn><mo>+</mo>";
131 _code << "<mn>" << i << "</mn></mrow></mfenced>" << _assignStr << "<mn>" << info[i + 1] << "</mn>"
132 << _endEq << _endline;
133 }
134
135 }
136}
137
138template<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 << "<mrow class='indep'>" << indep << "</mrow>" << "<mfenced open='[' close=']'><mi>i</mi></mfenced>";
178 else
179 arrayAssign << "<mrow class='indep'>" << indep << "</mrow>" << "<mfenced open='[' close=']'><mrow><mn>" << offset << "</mn> <mo>+</mo> <mi>i</mi></mrow></mfenced>";
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 auto* 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 auto* 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 << _startEq << "<mi>for</mi>"
264 "<mfenced><mrow><mi>i</mi><mo>&isin;</mo>"
265 "<mfenced open='[' close=']' separators=';'>"
266 "<mn>" << starti << "</mn><mn>" << i << "</mn>"
267 "</mfenced>"
268 "</mrow></mfenced>" << _endEq << _endline
269 << _forBodyStart;
270 _indentationLevel++;
271 _code << _startEq
272 << "<mrow class='tmp'>" << auxArrayName_ << "</mrow><mfenced open='[' close=']'><mi>i</mi></mfenced>" << _assignStr << arrayAssign.str()
273 << _endEq << _endline;
274 _indentationLevel--;
275 _code << _forBodyEnd << _endline << _forEnd << _endline;
276
280 for (size_t ii = starti; ii < i; ii++) {
281 tmpArrayValues[startPos + ii] = &args[ii];
282 }
283
284 return i;
285}
286
287template<class Base>
289 if (op.getOperationType() == CGOpCode::ArrayCreation)
290 return _nameGen->generateTemporaryArray(op);
291 else
292 return _nameGen->generateTemporarySparseArray(op);
293}
294
295template<class Base>
296void LanguageMathML<Base>::printArrayElementOp(OperationNode<Base>& op) {
297 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for array element operation")
298 CPPADCG_ASSERT_KNOWN(op.getArguments()[0].getOperation() != nullptr, "Invalid argument for array element operation")
299 CPPADCG_ASSERT_KNOWN(op.getInfo().size() == 1, "Invalid number of information indexes for array element operation")
300
301 OperationNode<Base>& arrayOp = *op.getArguments()[0].getOperation();
302 std::string arrayName;
303 if (arrayOp.getOperationType() == CGOpCode::ArrayCreation)
304 arrayName = _nameGen->generateTemporaryArray(arrayOp, getVariableID(arrayOp));
305 else
306 arrayName = _nameGen->generateTemporarySparseArray(arrayOp, getVariableID(arrayOp));
307
308 _code << "<mo>(</mo><mrow class='tmp'>" << arrayName << "</mrow><mo>)</mo><mfenced open='[' close=']'><mn>" << op.getInfo()[0] << "</mn></mfenced>";
309}
310
311template<class Base>
312inline void LanguageMathML<Base>::printArrayStructInit(const std::string& dataArrayName,
313 size_t pos,
314 const std::vector<OperationNode<Base>*>& arrays,
315 size_t k) {
316 _ss.str("");
317 _ss << "<mrow class='tmp'>" << dataArrayName << "</mrow><mfenced open='[' close=']'><mn>" << pos << "</mn></mfenced>";
318 printArrayStructInit(_ss.str(), *arrays[k]);
319}
320
321template<class Base>
322inline void LanguageMathML<Base>::printArrayStructInit(const std::string& dataArrayName,
323 OperationNode<Base>& array) {
327 const std::string& aName = createVariableName(array);
328
329 if (array.getOperationType() == CGOpCode::ArrayCreation) {
330 // dense array
331 size_t size = array.getArguments().size();
332 if (size > 0)
333 _code << dataArrayName << "<mo>.</mo><mi>data</mi><mo>=</mo>" << aName;
334 else
335 _code << dataArrayName << "<mo>.</mo><mi>data</mi><mo>=</mo>NULL";
336 _code << dataArrayName << "<mo>.</mo><mi>size</mi><mo>=</mo><mn>" << size << "</mn>"
337 << dataArrayName << "<mo>.</mo><mi>sparse</mi><mo>=</mo><mn>" << false << "</mn>";
338 } else {
339 // sparse array
340 CPPADCG_ASSERT_KNOWN(array.getOperationType() == CGOpCode::SparseArrayCreation, "Invalid node type")
341 size_t nnz = array.getArguments().size();
342 if (nnz > 0)
343 _code << dataArrayName << "<mo>.</mo><mi>data</mi><mo>=</mo>" << aName;
344 else
345 _code << dataArrayName << "<mo>.</mo><mi>data</mi><mo>=</mo>NULL";
346 _code << dataArrayName << "<mo>.</mo><mi>size</mi><mo>=</mo><mn>" << array.getInfo()[0] << "</mn>"
347 << dataArrayName << "<mo>.</mo><mi>sparse</mi><mo>=</mo><mn>" << true << "</mn>"
348 << dataArrayName << "<mo>.</mo><mi>nnz</mi><mo>=</mo><mn>" << nnz << "</mn>";
349 if (nnz > 0) {
350 size_t id = getVariableID(array);
351 _code << dataArrayName << "<mo>.</mo><mi>idx</mi><mo>=</mo>&amp;<mo>(</mo><mi>" << _C_SPARSE_INDEX_ARRAY << "</mi><mfenced open='[' close=']'><mn>" << (id - 1) << "</mn></mfenced><mo>)</mo>";
352 }
353 }
354 _code << _endline;
355}
356
357template<class Base>
359 size_t id = getVariableID(ty);
360 size_t tySize = ty.getArguments().size();
361
362 if (ty.getOperationType() == CGOpCode::ArrayCreation) {
363 for (size_t i = 0; i < tySize; i++) {
364 _tmpArrayValues[id - 1 + i] = nullptr;
365 }
366 } else {
367 for (size_t i = 0; i < tySize; i++) {
368 _tmpSparseArrayValues[id - 1 + i] = nullptr;
369 }
370 }
371}
372
373} // END cg namespace
374} // END CppAD namespace
375
376#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