CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
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 
18 namespace CppAD {
19 namespace cg {
20 
21 template<class Base>
22 void 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 
63 template<class Base>
64 void 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 
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 << "<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 
287 template<class Base>
288 inline std::string LanguageMathML<Base>::getTempArrayName(const OperationNode<Base>& op) {
289  if (op.getOperationType() == CGOpCode::ArrayCreation)
290  return _nameGen->generateTemporaryArray(op);
291  else
292  return _nameGen->generateTemporarySparseArray(op);
293 }
294 
295 template<class Base>
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 
311 template<class Base>
312 inline 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 
321 template<class Base>
322 inline 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 
357 template<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
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