CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
model_c_source_gen_loops.hpp
1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_INCLUDED
2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2013 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 namespace loops {
22 
23 /***********************************************************************
24  * Utility classes
25  **********************************************************************/
26 template<class Base>
27 class IfBranchData {
28 public:
29  CG<Base> value;
30  std::map<size_t, size_t> locations;
31 public:
32 
33  inline IfBranchData() {
34  }
35 
36  inline IfBranchData(const CG<Base>& v,
37  const std::map<size_t, size_t>& loc) :
38  value(v),
39  locations(loc) {
40  }
41 };
42 
43 template<class Base>
44 class IfBranchInfo {
45 public:
46  std::set<size_t> iterations;
47  OperationNode<Base>* node;
48 };
49 
50 template <class Base>
51 class IfElseInfo {
52 public:
53  std::map<SizeN1stIt, IfBranchInfo<Base> > firstIt2Branch;
54  OperationNode<Base>* endIf;
55 
56  inline IfElseInfo() :
57  endIf(nullptr) {
58  }
59 };
60 
62 public:
63  // tape J index -> {locationIt0, locationIt1, ...}
64  std::map<size_t, std::vector<size_t> > indexedPositions;
65 
66  // original J index -> {locationIt0, locationIt1, ...}
67  std::map<size_t, std::vector<size_t> > nonIndexedPositions;
68 
69  // original J index
70  std::set<size_t> nonIndexedEvals;
71 
72  // original J index -> k index
73  std::map<size_t, std::set<size_t> > tmpEvals;
74 };
75 
76 template<class Base>
78 public:
79  std::vector<size_t> indexes;
80  std::vector<CG<Base> > origVals;
81  IndexPattern* pattern;
82 
83  inline IndexedDependentLoopInfo() :
84  pattern(nullptr) {
85  }
86 };
87 
88 template<class Base>
89 inline std::vector<CG<Base> > createIndexedIndependents(CodeHandler<Base>& handler,
90  LoopModel<Base>& loop,
91  IndexOperationNode<Base>& iterationIndexOp) {
92 
93  const std::vector<std::vector<LoopPosition> >& indexedIndepIndexes = loop.getIndexedIndepIndexes();
94  size_t nIndexed = indexedIndepIndexes.size();
95 
96  std::vector<CG<Base> > x(nIndexed); // zero order
97 
98  std::vector<Argument<Base> > xIndexedArgs{iterationIndexOp};
99  std::vector<size_t> info(2);
100  info[0] = 0; // tx
101 
102  for (size_t j = 0; j < nIndexed; j++) {
103  info[1] = handler.addLoopIndependentIndexPattern(*loop.getIndependentIndexPatterns()[j], j);
104  x[j] = CG<Base>(*handler.makeNode(CGOpCode::LoopIndexedIndep, info, xIndexedArgs));
105  }
106 
107  return x;
108 }
109 
110 template<class Base>
111 inline std::vector<CG<Base> > createLoopIndependentVector(CodeHandler<Base>& handler,
112  LoopModel<Base>& loop,
113  const std::vector<CG<Base> >& indexedIndeps,
114  const std::vector<CG<Base> >& nonIndexed,
115  const std::vector<CG<Base> >& nonIndexedTmps) {
116 
117  const std::vector<std::vector<LoopPosition> >& indexedIndepIndexes = loop.getIndexedIndepIndexes();
118  const std::vector<LoopPosition>& nonIndexedIndepIndexes = loop.getNonIndexedIndepIndexes();
119  const std::vector<LoopPosition>& temporaryIndependents = loop.getTemporaryIndependents();
120 
121  size_t nIndexed = indexedIndepIndexes.size();
122  size_t nNonIndexed = nonIndexedIndepIndexes.size();
123  size_t nTape = nIndexed + nNonIndexed + temporaryIndependents.size();
124 
125  // indexed independents
126  std::vector<CG<Base> > x(nTape);
127  for (size_t j = 0; j < nIndexed; j++) {
128  x[j] = indexedIndeps[j];
129  }
130 
131  // non indexed
132  for (size_t j = 0; j < nNonIndexed; j++) {
133  x[nIndexed + j] = nonIndexed[nonIndexedIndepIndexes[j].original];
134  }
135 
136  // temporaries
137  for (size_t j = 0; j < temporaryIndependents.size(); j++) {
138  x[nIndexed + nNonIndexed + j] = nonIndexedTmps[temporaryIndependents[j].original];
139  }
140 
141  return x;
142 }
143 
144 template<class Base>
145 inline std::vector<CG<Base> > createLoopDependentVector(CodeHandler<Base>& handler,
146  LoopModel<Base>& loop,
147  IndexOperationNode<Base>& iterationIndexOp) {
148 
149  const std::vector<IndexPattern*>& depIndexes = loop.getDependentIndexPatterns();
150  std::vector<CG<Base> > deps(depIndexes.size());
151 
152  size_t dep_size = depIndexes.size();
153  size_t x_size = loop.getTapeIndependentCount();
154 
155  std::vector<Argument<Base> > xIndexedArgs{iterationIndexOp};
156  std::vector<size_t> info(2);
157  info[0] = 2; // py2
158 
159  for (size_t i = 0; i < dep_size; i++) {
160  IndexPattern* ip = depIndexes[i];
161  info[1] = handler.addLoopIndependentIndexPattern(*ip, x_size + i); // dependent index pattern location
162  deps[i] = CG<Base>(*handler.makeNode(CGOpCode::LoopIndexedIndep, info, xIndexedArgs));
163  }
164 
165  return deps;
166 }
167 
168 template<class Base>
169 inline CG<Base> createLoopDependentFunctionResult(CodeHandler<Base>& handler,
170  size_t i, const CG<Base>& val, IndexPattern* ip,
171  IndexOperationNode<Base>& iterationIndexOp) {
172 
173  size_t assignOrAdd = 1; // add
174 
175  if (ip != nullptr) {
176  // {dependent index pattern location, }
177  std::vector<size_t> aInfo{handler.addLoopDependentIndexPattern(*ip), assignOrAdd};
178  // {indexed expression, index(jrowIndexOp) }
179  std::vector<Argument<Base> > indexedArgs{asArgument(val), iterationIndexOp};
180 
181  OperationNode<Base>* yIndexed = handler.makeNode(CGOpCode::LoopIndexedDep, aInfo, indexedArgs);
182 
183  return handler.createCG(Argument<Base>(*yIndexed));
184 
185  } else if (val.getOperationNode() != nullptr &&
186  val.getOperationNode()->getOperationType() == CGOpCode::EndIf) {
187 
188  // {i} : points to itself
189  return handler.createCG(*handler.makeNode(CGOpCode::DependentRefRhs,{i}, {*val.getOperationNode()}));
190 
191  } else {
192  return val;
193  }
194 }
195 
196 /***************************************************************************
197  * Methods related with loop insertion into the operation graph
198  **************************************************************************/
199 
200 template<class Base>
201 LoopEndOperationNode<Base>* createLoopEnd(CodeHandler<Base>& handler,
202  LoopStartOperationNode<Base>& loopStart,
203  const std::vector<std::pair<CG<Base>, IndexPattern*> >& indexedLoopResults,
204  const std::set<IndexOperationNode<Base>*>& indexesOps,
205  size_t assignOrAdd) {
206  std::vector<Argument<Base> > endArgs;
207  std::vector<Argument<Base> > indexedArgs(1 + indexesOps.size());
208  std::vector<size_t> info(2);
209 
210  size_t dep_size = indexedLoopResults.size();
211  endArgs.reserve(dep_size);
212 
213  for (size_t i = 0; i < dep_size; i++) {
214  const std::pair<CG<Base>, IndexPattern*>& depInfo = indexedLoopResults[i];
215  if (depInfo.second != nullptr) {
216  indexedArgs.resize(1);
217 
218  indexedArgs[0] = asArgument(depInfo.first); // indexed expression
219  for (IndexOperationNode<Base>* itIndexOp : indexesOps) {
220  indexedArgs.push_back(*itIndexOp); // dependency on the index
221  }
222 
223  info[0] = handler.addLoopDependentIndexPattern(*depInfo.second); // dependent index pattern location
224  info[1] = assignOrAdd;
225 
226  OperationNode<Base>* yIndexed = handler.makeNode(CGOpCode::LoopIndexedDep, info, indexedArgs);
227  endArgs.push_back(*yIndexed);
228  } else {
229  OperationNode<Base>* n = depInfo.first.getOperationNode();
230  CPPADCG_ASSERT_UNKNOWN(n != nullptr);
231  endArgs.push_back(*n);
232  }
233  }
234 
235  LoopEndOperationNode<Base>* loopEnd = handler.makeLoopEndNode(loopStart, endArgs);
236 
237  return loopEnd;
238 }
239 
240 template<class Base>
241 inline void moveNonIndexedOutsideLoop(CodeHandler<Base>& handler,
242  LoopStartOperationNode<Base>& loopStart,
243  LoopEndOperationNode<Base>& loopEnd) {
244  //EquationPattern<Base>::uncolor(dependents[dep].getOperationNode());
245  const OperationNode<Base>& loopIndex = loopStart.getIndex();
246  std::set<OperationNode<Base>*> nonIndexed;
247 
248  CodeHandlerVector<Base, short> indexed(handler); // 0 - unknown, 1 - non-indexed, 2 - indexed
249  indexed.adjustSize();
250  indexed.fill(0);
251 
252  const std::vector<Argument<Base> >& endArgs = loopEnd.getArguments();
253  for (size_t i = 0; i < endArgs.size(); i++) {
254  CPPADCG_ASSERT_UNKNOWN(endArgs[i].getOperation() != nullptr);
255  LoopNonIndexedLocator<Base>(handler, indexed, nonIndexed, loopIndex).findNonIndexedNodes(*endArgs[i].getOperation());
256  }
257 
258  std::vector<Argument<Base> >& startArgs = loopStart.getArguments();
259 
260  size_t sas = startArgs.size();
261  startArgs.resize(sas + nonIndexed.size());
262  size_t i = 0;
263  for (auto it = nonIndexed.begin(); it != nonIndexed.end(); ++it, i++) {
264  startArgs[sas + i] = **it;
265  }
266 }
267 
268 template<class Base>
269 class LoopNonIndexedLocator {
270 private:
271  CodeHandler<Base>& handler_;
272  CodeHandlerVector<Base, short>& indexed_; // 0 - unknown, 1 - non-indexed, 2 - indexed
273  std::set<OperationNode<Base>*>& nonIndexed_;
274  const OperationNode<Base>& loopIndex_;
275 public:
276 
279  std::set<OperationNode<Base>*>& nonIndexed,
280  const OperationNode<Base>& loopIndex) :
281  handler_(handler),
282  indexed_(indexed),
283  nonIndexed_(nonIndexed),
284  loopIndex_(loopIndex) {
285  indexed_.adjustSize();
286  }
287 
288  inline bool findNonIndexedNodes(OperationNode<Base>& node) {
289  short& idx = indexed_[node];
290  if (idx > 0)
291  return idx == 1;
292 
293  if (node.getOperationType() == CGOpCode::IndexDeclaration) {
294  if (&node == &loopIndex_) {
295  idx = 2;
296  return false; // depends on the loop index
297  }
298  }
299 
300  const std::vector<Argument<Base> >& args = node.getArguments();
301  size_t size = args.size();
302 
303  bool indexedPath = false; // whether or not this node depends on indexed independents
304  bool nonIndexedArgs = false; // whether or not there are non indexed arguments
305  for (size_t a = 0; a < size; a++) {
306  OperationNode<Base>* arg = args[a].getOperation();
307  if (arg != nullptr) {
308  bool nonIndexedArg = findNonIndexedNodes(*arg);
309  nonIndexedArgs |= nonIndexedArg;
310  indexedPath |= !nonIndexedArg;
311  }
312  }
313 
314  idx = indexedPath ? 2 : 1;
315 
316  if (node.getOperationType() == CGOpCode::ArrayElement ||
317  node.getOperationType() == CGOpCode::AtomicForward ||
318  node.getOperationType() == CGOpCode::AtomicReverse) {
319  return !indexedPath; // should not move array creation elements outside the loop
320  }
321 
322  if (indexedPath && nonIndexedArgs) {
323  for (size_t a = 0; a < size; a++) {
324  OperationNode<Base>* arg = args[a].getOperation();
325  if (arg != nullptr && indexed_[*arg] == 1) {// must be a non indexed expression
326  CGOpCode op = arg->getOperationType();
327  if (op != CGOpCode::Inv && op != CGOpCode::TmpDcl) {// no point in moving just one variable outside
328 
329  if (op == CGOpCode::LoopIndexedTmp) {
330  // must not place a LoopIndexedTmp operation outside the loop
331  Argument<Base> assignArg = arg->getArguments()[1];
332  if (assignArg.getOperation() != nullptr) { // no point in moving a constant value outside
333  OperationNode<Base>* assignNode = handler_.makeNode(CGOpCode::Assign, assignArg);
334  arg->getArguments()[1] = *assignNode;
335  nonIndexed_.insert(assignNode);
336  }
337  } else {
338  nonIndexed_.insert(arg);
339  }
340  }
341  }
342  }
343  }
344 
345  return !indexedPath;
346  }
347 };
348 
349 template<class Base>
350 inline IfElseInfo<Base>* findExistingIfElse(std::vector<IfElseInfo<Base> >& ifElses,
351  const std::map<SizeN1stIt, std::pair<size_t, std::set<size_t> > >& first2Iterations) {
352  using namespace std;
353 
354  // try to find an existing if-else where these operations can be added
355  for (size_t f = 0; f < ifElses.size(); f++) {
356  IfElseInfo<Base>& ifElse = ifElses[f];
357 
358  if (first2Iterations.size() != ifElse.firstIt2Branch.size())
359  continue;
360 
361  bool matches = true;
362  auto itLoc = first2Iterations.begin();
363  auto itBranches = ifElse.firstIt2Branch.begin();
364  for (; itLoc != first2Iterations.end(); ++itLoc, ++itBranches) {
365  if (itLoc->second.second != itBranches->second.iterations) {
366  matches = false;
367  break;
368  }
369  }
370 
371  if (matches) {
372  return &ifElse;
373  }
374  }
375 
376  return nullptr;
377 }
378 
379 template<class Base>
380 OperationNode<Base>* createIndexConditionExpressionOp(CodeHandler<Base>& handler,
381  const std::set<size_t>& iterations,
382  const std::set<size_t>& usedIter,
383  size_t maxIter,
384  IndexOperationNode<Base>& iterationIndexOp) {
385  std::vector<size_t> info = createIndexConditionExpression(iterations, usedIter, maxIter);
386  OperationNode<Base>* node = handler.makeNode(CGOpCode::IndexCondExpr, info,{iterationIndexOp});
387  return node;
388 }
389 
390 std::vector<size_t> createIndexConditionExpression(const std::set<size_t>& iterations,
391  const std::set<size_t>& usedIter,
392  size_t maxIter) {
393  CPPADCG_ASSERT_UNKNOWN(!iterations.empty());
394 
395  std::map<size_t, bool> allIters;
396  for (size_t it : usedIter) {
397  allIters[it] = false;
398  }
399  for (size_t it : iterations) {
400  allIters[it] = true;
401  }
402 
403  std::vector<size_t> info;
404  info.reserve(iterations.size() / 2 + 2);
405 
406  auto it = allIters.begin();
407  while (it != allIters.end()) {
408  auto min = it;
409  auto max = it;
410  auto minNew = allIters.end();
411  auto maxNew = allIters.end();
412  if (it->second) {
413  minNew = it;
414  maxNew = it;
415  }
416 
417  for (++it; it != allIters.end(); ++it) {
418  if (it->first != max->first + 1) {
419  break;
420  }
421 
422  max = it;
423  if (it->second) {
424  if (minNew == allIters.end())
425  minNew = it;
426  maxNew = it;
427  }
428  }
429 
430  if (minNew != allIters.end()) {
431  // contains elements from the current iteration set
432  if (maxNew->first == minNew->first) {
433  // only one element
434  info.push_back(minNew->first);
435  info.push_back(maxNew->first);
436  } else {
437  //several elements
438  if (min->first == 0)
439  info.push_back(min->first);
440  else
441  info.push_back(minNew->first);
442 
443  if (max->first == maxIter)
444  info.push_back((std::numeric_limits<size_t>::max)());
445  else
446  info.push_back(maxNew->first);
447  }
448  }
449  }
450 
451  return info;
452 }
453 
454 template<class Base>
455 inline CG<Base> createConditionalContribution(CodeHandler<Base>& handler,
456  const std::map<size_t, IfBranchData<Base> >& branches,
457  size_t maxIter,
458  size_t nLocalIter,
459  IndexOperationNode<Base>& iterationIndexOp,
460  std::vector<IfElseInfo<Base> >& ifElses,
461  bool printResult = false) {
462  using namespace std;
463 
464  map<SizeN1stIt, pair<size_t, set<size_t> > > firstIt2Count2Iterations;
465  for (const auto& itb : branches) {
466  set<size_t> iterations;
467  mapKeys(itb.second.locations, iterations);
468  firstIt2Count2Iterations[SizeN1stIt(iterations.size(), *iterations.begin())] = make_pair(itb.first, iterations);
469  }
470 
471  IfElseInfo<Base>* ifElseBranches = findExistingIfElse(ifElses, firstIt2Count2Iterations);
472  bool reusingIfElse = ifElseBranches != nullptr;
473  if (!reusingIfElse) {
474  size_t s = ifElses.size();
475  ifElses.resize(s + 1);
476  ifElseBranches = &ifElses[s];
477  }
478 
482  OperationNode<Base>* ifStart = nullptr;
483  OperationNode<Base>* ifBranch = nullptr;
484  Argument<Base> nextBranchArg;
485  set<size_t> usedIter;
486 
487  for (const auto& it1st2Count2Iters : firstIt2Count2Iterations) {
488  size_t firstIt = it1st2Count2Iters.first.second;
489  size_t count = it1st2Count2Iters.second.first;
490  const set<size_t>& iterations = it1st2Count2Iters.second.second;
491  const IfBranchData<Base>& branchData = branches.at(count);
492 
493  size_t iterCount = iterations.size();
494 
495  SizeN1stIt pos(iterCount, firstIt);
496 
497  if (reusingIfElse) {
498  //reuse existing node
499  ifBranch = ifElseBranches->firstIt2Branch.at(pos).node;
500  if (nextBranchArg.getOperation() != nullptr)
501  ifBranch->getArguments().push_back(nextBranchArg);
502 
503  } else if (usedIter.size() + iterCount == nLocalIter) {
504  // all other iterations: ELSE
505  ifBranch = handler.makeNode(CGOpCode::Else,{Argument<Base>(*ifBranch), nextBranchArg});
506  } else {
507  // depends on the iteration index
508  OperationNode<Base>* cond = createIndexConditionExpressionOp<Base>(handler, iterations, usedIter, maxIter, iterationIndexOp);
509 
510  if (ifStart == nullptr) {
511  // IF
512  ifStart = handler.makeNode(CGOpCode::StartIf, *cond);
513  ifBranch = ifStart;
514  } else {
515  // ELSE IF
516  ifBranch = handler.makeNode(CGOpCode::ElseIf,{*ifBranch, *cond, nextBranchArg});
517  }
518 
519  usedIter.insert(iterations.begin(), iterations.end());
520  }
521 
522  IndexPattern* pattern = IndexPattern::detect(branchData.locations);
523  handler.manageLoopDependentIndexPattern(pattern);
524 
525  Argument<Base> value;
526  if (printResult) {
527  PrintOperationNode<Base>* printNode = handler.makePrintNode("__________", asArgument(branchData.value), "\n");
528  value = *printNode;
529  } else {
530  value = asArgument(branchData.value);
531  }
532 
533  // {dependent index pattern location, assignOrAdd}
534  std::vector<size_t> ainfo{handler.addLoopDependentIndexPattern(*pattern), 1};
535  // {indexed expression, dependency on the index}
536  std::vector<Argument<Base> > indexedArgs{value, iterationIndexOp};
537  OperationNode<Base>* yIndexed = handler.makeNode(CGOpCode::LoopIndexedDep, ainfo, indexedArgs);
538 
539  OperationNode<Base>* ifAssign = handler.makeNode(CGOpCode::CondResult,{Argument<Base>(*ifBranch), Argument<Base>(*yIndexed)});
540  nextBranchArg = Argument<Base>(*ifAssign);
541 
542  if (!reusingIfElse) {
543  IfBranchInfo<Base>& branch = ifElseBranches->firstIt2Branch[pos]; // creates a new if branch
544  branch.iterations = iterations;
545  branch.node = ifBranch;
546  }
547  }
548 
552  if (reusingIfElse) {
553  ifElseBranches->endIf->getArguments().push_back(nextBranchArg);
554  } else {
555  ifElseBranches->endIf = handler.makeNode(CGOpCode::EndIf,{*ifBranch, nextBranchArg});
556  }
557 
558  return handler.createCG(Argument<Base>(*ifElseBranches->endIf));
559 }
560 
564 template<class Base>
565 CG<Base> createConditionalContribution(CodeHandler<Base>& handler,
566  LinearIndexPattern& pattern,
567  const std::set<size_t>& iterations,
568  size_t maxIter,
569  const CG<Base>& ddfdxdx,
570  IndexOperationNode<Base>& iterationIndexOp,
571  std::vector<IfElseInfo<Base> >& ifElses) {
572  using namespace std;
573 
574  CPPADCG_ASSERT_UNKNOWN(pattern.getLinearSlopeDy() == 0); // must be a constant index
575 
576  // try to find an existing if-else where these operations can be added
577  map<SizeN1stIt, pair<size_t, set<size_t> > > firstIt2Count2Iterations;
578  SizeN1stIt pos(iterations.size(), *iterations.begin());
579  firstIt2Count2Iterations[pos] = make_pair(1, iterations);
580 
581  IfElseInfo<Base>* ifElseBranches = findExistingIfElse(ifElses, firstIt2Count2Iterations);
582  bool reusingIfElse = ifElseBranches != nullptr;
583  if (!reusingIfElse) {
584  size_t s = ifElses.size();
585  ifElses.resize(s + 1);
586  ifElseBranches = &ifElses[s];
587  }
588 
592  OperationNode<Base>* ifBranch = nullptr;
593 
594  if (reusingIfElse) {
595  //reuse existing node
596  ifBranch = ifElseBranches->firstIt2Branch.at(pos).node;
597 
598  } else {
599  // depends on the iterations indexes
600  const set<size_t> usedIter;
601  OperationNode<Base>* cond = createIndexConditionExpressionOp<Base>(handler, iterations, usedIter, maxIter, iterationIndexOp);
602 
603  ifBranch = handler.makeNode(CGOpCode::StartIf, *cond);
604  }
605 
606  // {dependent index pattern location, assignOrAdd}
607  std::vector<size_t> ainfo{handler.addLoopDependentIndexPattern(pattern), 1};
608  // {indexed expression, dependency on the index}
609  std::vector<Argument<Base> > indexedArgs{asArgument(ddfdxdx), iterationIndexOp};
610 
611  OperationNode<Base>* yIndexed = handler.makeNode(CGOpCode::LoopIndexedDep, ainfo, indexedArgs);
612 
613  OperationNode<Base>* ifAssign = handler.makeNode(CGOpCode::CondResult,{*ifBranch, *yIndexed});
614  Argument<Base> nextBranchArg = *ifAssign;
615 
616  if (!reusingIfElse) {
617  IfBranchInfo<Base>& branch = ifElseBranches->firstIt2Branch[pos]; // creates a new if branch
618  branch.iterations = iterations;
619  branch.node = ifBranch;
620  }
621 
625  if (reusingIfElse) {
626  ifElseBranches->endIf->getArguments().push_back(nextBranchArg);
627  } else {
628  ifElseBranches->endIf = handler.makeNode(CGOpCode::EndIf,{*ifBranch, nextBranchArg});
629  }
630 
631  return handler.createCG(Argument<Base>(*ifElseBranches->endIf));
632 }
633 
647 template<class Base>
648 std::pair<CG<Base>, IndexPattern*> createLoopResult(CodeHandler<Base>& handler,
649  const std::map<size_t, size_t>& locationsIter2Pos,
650  size_t iterCount,
651  const CG<Base>& value,
652  IndexPattern* pattern,
653  size_t assignOrAdd,
654  IndexOperationNode<Base>& iterationIndexOp,
655  std::vector<IfElseInfo<Base> >& ifElses) {
656  using namespace std;
657 
658  if (locationsIter2Pos.size() == iterCount) {
659  // present in all iterations
660 
661  return make_pair(value, pattern);
662 
663  } else {
669  // try to find an existing if-else where these operations can be added
670  map<SizeN1stIt, pair<size_t, set<size_t> > > firstIt2Count2Iterations;
671 
672  set<size_t> iterations;
673  mapKeys(locationsIter2Pos, iterations);
674  SizeN1stIt pos(iterations.size(), *iterations.begin());
675  firstIt2Count2Iterations[pos] = make_pair(*iterations.begin(), iterations);
676 
677  IfElseInfo<Base>* ifElseBranches = findExistingIfElse(ifElses, firstIt2Count2Iterations);
678  bool reusingIfElse = ifElseBranches != nullptr;
679  if (!reusingIfElse) {
680  size_t s = ifElses.size();
681  ifElses.resize(s + 1);
682  ifElseBranches = &ifElses[s];
683  }
684 
685  OperationNode<Base>* ifStart;
686 
687  if (reusingIfElse) {
688  //reuse existing node
689  ifStart = ifElseBranches->firstIt2Branch.at(pos).node;
690  } else {
691  // depends on the iterations indexes
692  set<size_t> usedIter;
693  OperationNode<Base>* cond = createIndexConditionExpressionOp<Base>(handler, iterations, usedIter, iterCount - 1, iterationIndexOp);
694 
695  ifStart = handler.makeNode(CGOpCode::StartIf, *cond);
696  }
697 
698  // {dependent index pattern location, }
699  std::vector<size_t> ainfo{handler.addLoopDependentIndexPattern(*pattern), assignOrAdd};
700  // {indexed expression, dependency on the index}
701  std::vector<Argument<Base> > indexedArgs{asArgument(value), iterationIndexOp};
702 
703  OperationNode<Base>* yIndexed = handler.makeNode(CGOpCode::LoopIndexedDep, ainfo, indexedArgs);
704 
705  OperationNode<Base>* ifAssign = handler.makeNode(CGOpCode::CondResult,{*ifStart, *yIndexed});
706 
707  if (!reusingIfElse) {
708  // existing 'if' with the same iterations
709  IfBranchInfo<Base>& branch = ifElseBranches->firstIt2Branch[pos]; // creates a new if branch
710  branch.iterations = iterations;
711  branch.node = ifStart;
712  }
713 
714  if (reusingIfElse) {
715  ifElseBranches->endIf->getArguments().push_back(*ifAssign);
716  } else {
717  ifElseBranches->endIf = handler.makeNode(CGOpCode::EndIf,{*ifStart, *ifAssign});
718  }
719 
720  IndexPattern* p = nullptr;
721  return make_pair(handler.createCG(Argument<Base>(*ifElseBranches->endIf)), p);
722  }
723 
724 }
725 
727 public:
728  IndexPattern* resultPattern;
729  IndexPattern* compressedPattern;
730 public:
731 
732  inline ArrayElementCopyPattern() :
733  resultPattern(nullptr),
734  compressedPattern(nullptr) {
735  }
736 
737  inline ArrayElementCopyPattern(IndexPattern* resultPat,
738  IndexPattern* compressedPat) :
739  resultPattern(resultPat),
740  compressedPattern(compressedPat) {
741  }
742 
743  inline ~ArrayElementCopyPattern() {
744  delete resultPattern;
745  delete compressedPattern;
746  }
747 
748 };
749 
751 public:
752  std::set<size_t> keys;
753  std::vector<ArrayElementCopyPattern> elements;
754 
755  ArrayElementGroup(const std::set<size_t>& k, size_t size) :
756  keys(k),
757  elements(size) {
758  }
759 };
760 
761 class ArrayGroup {
762 public:
763  std::unique_ptr<IndexPattern> pattern;
764  std::unique_ptr<IndexPattern> startLocPattern;
766 };
767 
777 template<class Base>
778 inline void determineForRevUsagePatterns(const std::map<LoopModel<Base>*, std::map<size_t, std::map<size_t, std::set<size_t> > > >& loopGroups,
779  const std::map<size_t, CompressedVectorInfo>& matrixInfo,
780  std::map<size_t, std::map<LoopModel<Base>*, std::map<size_t, ArrayGroup*> > >& loopCalls,
782 
783  using namespace std;
784 
785  std::vector<size_t> arrayStart;
790  std::vector<size_t> localit2jcols;
791  for (const auto& itlge : loopGroups) {
792  LoopModel<Base>* loop = itlge.first;
793 
794  garbage.reserve(garbage.size() + itlge.second.size());
795 
796  for (const auto& itg : itlge.second) {
797  size_t group = itg.first;
798  const map<size_t, set<size_t> >& jcols2e = itg.second;
799 
800  // group by number of iterations
801  std::unique_ptr<ArrayGroup> data(new ArrayGroup());
802 
806  mapKeys(jcols2e, localit2jcols);
807  data->pattern.reset(IndexPattern::detect(localit2jcols));
808 
812  bool ordered = true;
813  for (size_t l = 0; l < localit2jcols.size(); l++) {
814  if (!matrixInfo.at(localit2jcols[l]).ordered) {
815  ordered = false;
816  break;
817  }
818  }
819 
820  if (ordered) {
821  arrayStart.resize(localit2jcols.size());
822 
823  for (size_t l = 0; l < localit2jcols.size(); l++) {
824  const std::vector<std::set<size_t> >& location = matrixInfo.at(localit2jcols[l]).locations;
825  arrayStart[l] = *location[0].begin();
826  }
827 
828  data->startLocPattern.reset(IndexPattern::detect(arrayStart));
829  } else {
834  map<size_t, map<size_t, size_t> > elCount2localIt2jcols;
835 
836  size_t localIt = 0;
837  for (auto itJcols2e = jcols2e.begin(); itJcols2e != jcols2e.end(); ++itJcols2e, localIt++) {
838  size_t elCount = itJcols2e->second.size();
839  elCount2localIt2jcols[elCount][localIt] = itJcols2e->first;
840  }
841 
842  for (const auto& elC2jcolIt : elCount2localIt2jcols) {
843  size_t commonElSize = elC2jcolIt.first;
844  const map<size_t, size_t>& localIt2keys = elC2jcolIt.second;
845 
846  // the same number of elements is always provided in each call
847  std::vector<std::map<size_t, size_t> > compressPos(commonElSize);
848  std::vector<std::map<size_t, size_t> > resultPos(commonElSize);
849 
850  set<size_t> keys;
851 
852  for (const auto& lIt2jcolIt : localIt2keys) {
853  size_t localIt = lIt2jcolIt.first;
854  size_t key = lIt2jcolIt.second;
855 
856  keys.insert(key);
857 
858  const std::vector<std::set<size_t> >& origPos = matrixInfo.at(key).locations;
859  const std::set<size_t>& compressed = jcols2e.at(key);
860 
861  size_t e = 0;
862  for (auto itE = compressed.begin(); itE != compressed.end(); ++itE, e++) {
863  CPPADCG_ASSERT_UNKNOWN(origPos[*itE].size() == 1);
864  resultPos[e][localIt] = *origPos[*itE].begin();
865 
866  compressPos[e][localIt] = *itE;
867  }
868  }
869 
870  ArrayElementGroup* eg = new ArrayElementGroup(keys, commonElSize);
871  data->elCount2elements[commonElSize] = eg;
872 
873  for (size_t e = 0; e < commonElSize; e++) {
874  eg->elements[e].resultPattern = IndexPattern::detect(resultPos[e]);
875  eg->elements[e].compressedPattern = IndexPattern::detect(compressPos[e]);
876  }
877 
878  }
879 
880  }
881 
882  // group by number of iterations
883  loopCalls[localit2jcols.size()][loop][group] = data.get();
884  garbage.push_back(data.release());
885  }
886  }
887 }
888 
895 template<class Base>
896 void printForRevUsageFunction(std::ostringstream& out,
897  const std::string& baseTypeName,
898  const std::string& modelName,
899  const std::string& modelFunction,
900  size_t inLocalSize,
901  const std::string& localFunction,
902  const std::string& suffix,
903  const std::string& keyIndexName,
904  const std::string& indexIt,
905  const std::string& resultName,
906  const std::map<LoopModel<Base>*, std::map<size_t, std::map<size_t, std::set<size_t> > > >& loopGroups,
907  const std::map<size_t, std::set<size_t> >& nonLoopElements,
908  const std::map<size_t, CompressedVectorInfo>& matrixInfo,
909  void (*generateLocalFunctionName)(std::ostringstream& cache, const std::string& modelName, const LoopModel<Base>& loop, size_t g),
910  size_t nnz,
911  size_t maxCompressedSize) {
912  using namespace std;
913 
919  map<size_t, map<LoopModel<Base>*, map<size_t, ArrayGroup*> > > loopCalls;
920 
925  determineForRevUsagePatterns(loopGroups, matrixInfo, loopCalls, garbage);
926 
927  string nlRev2Suffix = "noloop_" + suffix;
928 
929  LanguageC<Base> langC(baseTypeName);
930  string loopFArgs = "inLocal, outLocal, " + langC.getArgumentAtomic();
931  string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
932  std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
933 
934  LanguageC<Base>::printFunctionDeclaration(out, "void", modelFunction, argsDcl2);
935  out << " {\n";
936 
940  set<RandomIndexPattern*> indexRandomPatterns;
941 
942  for (const auto& itItlg : loopCalls) {
943 
944  for (const auto& itlg : itItlg.second) {
945 
946  for (const auto& itg : itlg.second) {
947  ArrayGroup* group = itg.second;
948 
949  CodeHandler<Base>::findRandomIndexPatterns(group->pattern.get(), indexRandomPatterns);
950 
951  if (group->startLocPattern.get() != nullptr) {
952  CodeHandler<Base>::findRandomIndexPatterns(group->startLocPattern.get(), indexRandomPatterns);
953 
954  } else {
955  for (const auto& itc : group->elCount2elements) {
956  const ArrayElementGroup* eg = itc.second;
957 
958  for (const ArrayElementCopyPattern& ePos : eg->elements) {
959  CodeHandler<Base>::findRandomIndexPatterns(ePos.resultPattern, indexRandomPatterns);
960  CodeHandler<Base>::findRandomIndexPatterns(ePos.compressedPattern, indexRandomPatterns);
961  }
962  }
963  }
964  }
965  }
966  }
967 
972  LanguageC<Base>::printRandomIndexPatternDeclaration(out, " ", indexRandomPatterns);
973 
977  out << " " << baseTypeName << " const * inLocal[" << inLocalSize << "];\n"
978  " " << baseTypeName << " inLocal1 = 1;\n"
979  " " << baseTypeName << " * outLocal[1];\n"
980  " unsigned long " << indexIt << ";\n"
981  " unsigned long " << keyIndexName << ";\n"
982  " unsigned long e;\n";
983  CPPADCG_ASSERT_UNKNOWN(indexIt != "e" && keyIndexName != "e");
984  if (maxCompressedSize > 0) {
985  out << " " << baseTypeName << " compressed[" << maxCompressedSize << "];\n";
986  }
987  out << " " << baseTypeName << " * " << resultName << " = out[0];\n"
988  "\n"
989  " inLocal[0] = in[0];\n"
990  " inLocal[1] = &inLocal1;\n";
991  for (size_t j = 2; j < inLocalSize; j++)
992  out << " inLocal[" << j << "] = in[" << (j - 1) << "];\n";
993 
994  out << "\n";
995 
999  out << " for(e = 0; e < " << nnz << "; e++) " << resultName << "[e] = 0;\n"
1000  "\n";
1001 
1006  langC.setArgumentIn("inLocal");
1007  langC.setArgumentOut("outLocal");
1008  string argsLocal = langC.generateDefaultFunctionArguments();
1009 
1010  bool lastCompressed = false;
1011  for (const auto& it : nonLoopElements) {
1012  size_t index = it.first;
1013  const set<size_t>& elPos = it.second;
1014  const std::vector<set<size_t> >& location = matrixInfo.at(index).locations;
1015  CPPADCG_ASSERT_UNKNOWN(elPos.size() <= location.size()); // it can be lower because not all elements have to be assigned
1016  CPPADCG_ASSERT_UNKNOWN(elPos.size() > 0);
1017  bool rowOrdered = matrixInfo.at(index).ordered;
1018 
1019  out << "\n";
1020  if (rowOrdered) {
1021  out << " outLocal[0] = &" << resultName << "[" << *location[0].begin() << "];\n";
1022  } else if (!lastCompressed) {
1023  out << " outLocal[0] = compressed;\n";
1024  }
1025  out << " " << localFunction << "_" << nlRev2Suffix << index << "(" << argsLocal << ");\n";
1026  if (!rowOrdered) {
1027  for (size_t e : elPos) {
1028  out << " ";
1029  for (size_t itl : location[e]) {
1030  out << resultName << "[" << itl << "] += compressed[" << e << "];\n";
1031  }
1032  }
1033  }
1034  lastCompressed = !rowOrdered;
1035  }
1036 
1040  for (const auto& itItlg : loopCalls) {
1041  size_t itCount = itItlg.first;
1042  if (itCount > 1) {
1043  lastCompressed = false;
1044  out << " for(" << indexIt << " = 0; " << indexIt << " < " << itCount << "; " << indexIt << "++) {\n";
1045  }
1046 
1047  for (const auto& itlg : itItlg.second) {
1048  LoopModel<Base>& loop = *itlg.first;
1049 
1050  for (const auto& itg : itlg.second) {
1051  size_t g = itg.first;
1052  ArrayGroup* group = itg.second;
1053 
1054  const map<size_t, set<size_t> >& key2Compressed = loopGroups.at(&loop).at(g);
1055 
1056  string indent = itCount == 1 ? " " : " "; //indentation
1057 
1058  if (group->startLocPattern.get() != nullptr) {
1059  // determine hessRowStart = f(it)
1060  out << indent << "outLocal[0] = &" << resultName << "[" << LanguageC<Base>::indexPattern2String(*group->startLocPattern, indexIt) << "];\n";
1061  } else {
1062  if (!lastCompressed) {
1063  out << indent << "outLocal[0] = compressed;\n";
1064  }
1065  out << indent << "for(e = 0; e < " << maxCompressedSize << "; e++) compressed[e] = 0;\n";
1066  }
1067 
1068  if (itCount > 1) {
1069  out << indent << keyIndexName << " = " << LanguageC<Base>::indexPattern2String(*group->pattern, indexIt) << ";\n";
1070  out << indent;
1071  (*generateLocalFunctionName)(out, modelName, loop, g);
1072  out << "(" << keyIndexName << ", " << loopFArgs << ");\n";
1073  } else {
1074  size_t key = key2Compressed.begin()->first; // only one jrow
1075  out << indent;
1076  (*generateLocalFunctionName)(out, modelName, loop, g);
1077  out << "(" << key << ", " << loopFArgs << ");\n";
1078  }
1079 
1080  if (group->startLocPattern.get() == nullptr) {
1081  CPPADCG_ASSERT_UNKNOWN(!group->elCount2elements.m.empty());
1082 
1083  std::set<size_t> usedIter;
1084 
1085  // add keys which are never used to usedIter to improve the if/else condition
1086  size_t eKey = 0;
1087  for (const auto& itKey : key2Compressed) {
1088  size_t key = itKey.first;
1089  for (size_t k = eKey; k < key; k++) {
1090  usedIter.insert(k);
1091  }
1092  eKey = key + 1;
1093  }
1094 
1095  bool withIfs = group->elCount2elements.size() > 1;
1096  for (auto itc = group->elCount2elements.begin(); itc != group->elCount2elements.end(); ++itc) {
1097  const ArrayElementGroup* eg = itc->second;
1098  CPPADCG_ASSERT_UNKNOWN(!eg->elements.empty());
1099 
1100  string indent2 = indent;
1101  if (withIfs) {
1102  out << indent;
1103  if (itc != group->elCount2elements.begin())
1104  out << "} else ";
1105  if (itc->first != group->elCount2elements.rbegin()->first) { // check that it is not the last branch
1106  out << "if(";
1107 
1108  size_t maxKey = key2Compressed.rbegin()->first;
1109  std::vector<size_t> info = createIndexConditionExpression(eg->keys, usedIter, maxKey);
1110  LanguageC<Base>::printIndexCondExpr(out, info, keyIndexName);
1111  out << ") ";
1112 
1113  usedIter.insert(eg->keys.begin(), eg->keys.end());
1114  }
1115  out << "{\n";
1116  indent2 += " ";
1117  }
1118 
1119  for (size_t e = 0; e < eg->elements.size(); e++) {
1120  const ArrayElementCopyPattern& ePos = eg->elements[e];
1121 
1122  out << indent2 << resultName << "["
1123  << LanguageC<Base>::indexPattern2String(*ePos.resultPattern, indexIt)
1124  << "] += compressed["
1125  << LanguageC<Base>::indexPattern2String(*ePos.compressedPattern, indexIt)
1126  << "];\n";
1127  }
1128  }
1129 
1130  if (withIfs) {
1131  out << indent << "}\n";
1132  }
1133  }
1134 
1135  out << "\n";
1136 
1137  lastCompressed = group->startLocPattern.get() == nullptr;
1138  }
1139  }
1140 
1141  if (itCount > 1) {
1142  out << " }\n";
1143  }
1144  }
1145 
1146  out << "\n"
1147  "}\n";
1148 }
1149 
1164 template<class Base>
1165 std::string generateGlobalForRevWithLoopsFunctionSource(const std::map<size_t, std::vector<size_t> >& elements,
1166  const std::map<LoopModel<Base>*, std::map<size_t, std::map<size_t, std::set<size_t> > > >& loopGroups,
1167  const std::map<size_t, std::set<size_t> >& nonLoopElements,
1168  const std::string& functionName,
1169  const std::string& modelName,
1170  const std::string& baseTypeName,
1171  const std::string& suffix,
1172  void (*generateLocalFunctionName)(std::ostringstream& cache, const std::string& modelName, const LoopModel<Base>& loop, size_t g)) {
1173 
1174  using namespace std;
1175 
1176  // functions for each row
1177  map<size_t, map<LoopModel<Base>*, set<size_t> > > functions;
1178 
1179  for (const auto& itlj1g : loopGroups) {
1180  LoopModel<Base>* loop = itlj1g.first;
1181 
1182  for (const auto& itg : itlj1g.second) {
1183  size_t group = itg.first;
1184  const map<size_t, set<size_t> >& jrows = itg.second;
1185 
1186  for (const auto& itJrow : jrows) {
1187  functions[itJrow.first][loop].insert(group);
1188  }
1189  }
1190  }
1191 
1195  LanguageC<Base> langC(baseTypeName);
1196  string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
1197  std::vector<string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
1198  string args = langC.generateDefaultFunctionArguments();
1199  string noLoopFunc = functionName + "_noloop_" + suffix;
1200 
1201  std::ostringstream out;
1202  out << LanguageC<Base>::ATOMICFUN_STRUCT_DEFINITION << "\n"
1203  "\n";
1204  ModelCSourceGen<Base>::generateFunctionDeclarationSource(out, functionName, "noloop_" + suffix, nonLoopElements, argsDcl);
1205  generateFunctionDeclarationSourceLoopForRev(out, langC, modelName, "j", loopGroups, generateLocalFunctionName);
1206  out << "\n";
1207  LanguageC<Base>::printFunctionDeclaration(out, "int", functionName, {"unsigned long pos"}, argsDcl2);
1208  out << " {\n"
1209  " \n"
1210  " switch(pos) {\n";
1211 
1212  for (const auto& it : elements) {
1213  size_t jrow = it.first;
1214  // the size of each sparsity row
1215  out << " case " << jrow << ":\n";
1216 
1221  const auto itnl = nonLoopElements.find(jrow);
1222  if (itnl != nonLoopElements.end()) {
1223  out << " " << noLoopFunc << jrow << "(" << args << ");\n";
1224  }
1225 
1229  const map<LoopModel<Base>*, set<size_t> >& rowFunctions = functions[jrow];
1230 
1231  for (const auto& itlg : rowFunctions) {
1232  LoopModel<Base>* loop = itlg.first;
1233 
1234  for (size_t itg : itlg.second) {
1235  out << " ";
1236  generateLocalFunctionName(out, modelName, *loop, itg);
1237  out << "(" << jrow << ", " << args << ");\n";
1238  }
1239  }
1240 
1244  out << " return 0; // done\n";
1245  }
1246  out << " default:\n"
1247  " return 1; // error\n"
1248  " };\n";
1249 
1250  out << "}\n";
1251  return out.str();
1252 }
1253 
1254 template<class Base>
1255 void generateFunctionDeclarationSourceLoopForRev(std::ostringstream& out,
1256  LanguageC<Base>& langC,
1257  const std::string& modelName,
1258  const std::string& keyName,
1259  const std::map<LoopModel<Base>*, std::map<size_t, std::map<size_t, std::set<size_t> > > >& loopGroups,
1260  void (*generateLocalFunctionName)(std::ostringstream& cache, const std::string& modelName, const LoopModel<Base>& loop, size_t g)) {
1261 
1262  std::string argsDcl = langC.generateFunctionArgumentsDcl();
1263  std::string argsDclLoop = "unsigned long " + keyName + ", " + argsDcl;
1264 
1265  for (const auto& itlg : loopGroups) {
1266  const LoopModel<Base>& loop = *itlg.first;
1267 
1268  for (const auto& itg : itlg.second) {
1269  size_t group = itg.first;
1270 
1271  out << "void ";
1272  (*generateLocalFunctionName)(out, modelName, loop, group);
1273  out << "(" << argsDclLoop << ");\n";
1274  }
1275  }
1276 }
1277 
1278 } // END loops namespace
1279 
1280 } // END cg namespace
1281 } // END CppAD namespace
1282 
1283 #endif
const std::vector< LoopPosition > & getTemporaryIndependents() const
Definition: loop_model.hpp:324
const std::vector< Argument< Base > > & getArguments() const
STL namespace.
static void printFunctionDeclaration(std::ostringstream &out, const std::string &returnType, const std::string &functionName, const std::vector< std::string > &arguments, const std::vector< std::string > &arguments2={})
Definition: language_c.hpp:538
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
CGOpCode getOperationType() const
static IndexPattern * detect(const VectorSizeT &x2y)
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
Definition: loop_model.hpp:316
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
Definition: loop_model.hpp:309
size_t getTapeIndependentCount() const
Definition: loop_model.hpp:284