CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
loop.hpp
1 #ifndef CPPAD_CG_LOOP_INCLUDED
2 #define CPPAD_CG_LOOP_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 template<class Base>
23 public:
24  // provides an independent variable for each loop iteration
25  const std::vector<const OperationNode<Base>*> order;
26 
27  inline IndependentOrder(const std::vector<const OperationNode<Base>*>& myOrder) :
28  order(myOrder) {
29  }
30 };
31 
32 template<class Base>
34 public:
35  std::map<size_t, IndependentOrder<Base>*> arg2Order;
36 };
37 
41 template<class Base>
42 class LoopCodeHandler : public CodeHandler<Base> {
43 public:
45 
46 };
47 
51 template<class Base>
52 class Loop {
53 private:
54  using IndexValue = std::pair<size_t, CG<Base> >;
55 public:
59  std::set<EquationPattern<Base>*> equations;
66 private:
70  CodeHandler<Base>* handlerOrig_;
74  std::unique_ptr<CodeHandlerVector<Base, size_t>> varId_;
78  std::unique_ptr<CodeHandlerVector<Base, bool>> varIndexed_;
82  size_t iterationCount_;
86  LoopCodeHandler<Base> handler_;
90  std::vector<EquationGroup<Base> > eqGroups_;
94  std::map<EquationPattern<Base>*, size_t> equationOrder_;
99  std::vector<std::set<size_t> > iterationDependents_;
103  std::map<size_t, size_t> dep2Iteration_;
107  size_t nIndependents_;
111  LoopModel<Base>* loopModel_;
115  std::map<const OperationNode<Base>*, IndexValue> independentsIndexed_;
119  std::map<const OperationNode<Base>*, IndexValue> independentsNonIndexed_;
123  std::map<const OperationNode<Base>*, IndexValue> independentsTemp_;
127  std::map<size_t, OperationNode<Base>*> clonesTemporary_;
131  std::map<const OperationNode<Base>*, OperationNode<Base>*> temporaryClone2Orig_;
135  std::map<const OperationNode<Base>*, OperationNode<Base>*> orig2ConstIndepClone_;
139  std::map<const IndependentOrder<Base>*, OperationNode<Base>*> indexedIndep2clone_;
145  std::map<const OperationNode<Base>*, std::vector<IndependentOrder<Base>*> > firstIndep2orders_;
150  std::map<const OperationNode<Base>*, OperationArgumentsIndepOrder<Base>* > op2Arg2IndepOrder_;
154  std::forward_list<OperationArgumentsIndepOrder<Base>*> arg2IndepOrder_;
158  size_t idCounter_;
159 public:
160 
161  inline Loop(EquationPattern<Base>& eq) :
162  handlerOrig_(eq.depRef.getCodeHandler()),
163  varId_(handlerOrig_ != nullptr ? new CodeHandlerVector<Base, size_t>(*handlerOrig_): nullptr),
164  varIndexed_(handlerOrig_ != nullptr ? new CodeHandlerVector<Base, bool>(*handlerOrig_): nullptr),
165  iterationCount_(0), // not known yet (only after all equations have been added)
166  eqGroups_(1),
167  nIndependents_(0),
168  loopModel_(nullptr),
169  idCounter_(0) { // not really required (but it avoids warnings)
170  //indexedOpIndep(eq.indexedOpIndep), // must be determined later for a different reference
171  //constOperationIndependents(eq.constOperationIndependents) {
172  equations.insert(&eq);
173  eqGroups_[0].equations.insert(&eq);
174 
175  if(varId_ != nullptr)
176  varId_->adjustSize();
177  }
178 
179  Loop(const Loop<Base>& other) = delete;
180  Loop& operator=(const Loop<Base>& rhs) = delete;
181 
182  inline void addEquation(EquationPattern<Base>& eq) {
183  equations.insert(&eq);
184  eqGroups_[0].equations.insert(&eq);
185  }
186 
187  inline void setLinkedDependents(const std::set<std::set<size_t>*>& newLoopRelations) {
188  CPPADCG_ASSERT_UNKNOWN(eqGroups_.size() == 1);
189 
190  eqGroups_[0].linkedDependents.clear();
191  eqGroups_[0].linkedDependents.reserve(newLoopRelations.size());
192 
193  for (std::set<size_t>* it : newLoopRelations)
194  eqGroups_[0].linkedDependents.push_back(*it);
195  }
196 
197  inline void addLinkedEquationsByNonIndexed(EquationPattern<Base>* eq1,
198  EquationPattern<Base>* eq2) {
199  eqGroups_[0].addLinkedEquationsByNonIndexed(eq1, eq2);
200  }
201 
202  inline size_t getLinkedEquationsByNonIndexedCount() const {
203  return eqGroups_[0].getLinkedEquationsByNonIndexedCount();
204  }
205 
209  inline size_t getIterationCount() const {
210  return iterationCount_;
211  }
212 
213  const std::vector<std::set<size_t> >& getIterationDependents() const {
214  return iterationDependents_;
215  }
216 
217  inline LoopModel<Base>* getModel() const {
218  return loopModel_;
219  }
220 
221  inline LoopModel<Base>* releaseLoopModel() {
222  LoopModel<Base>* loopAtomic = loopModel_;
223  loopModel_ = nullptr;
224  return loopAtomic;
225  }
226 
232  void merge(Loop<Base>& other,
233  const std::set<EquationPattern<Base>*>& indexedLoopRelations,
234  const std::vector<std::pair<EquationPattern<Base>*, EquationPattern<Base>*> >& nonIndexedLoopRelations) {
235  CPPADCG_ASSERT_UNKNOWN(iterationCount_ == other.iterationCount_)
236 
237 
238  equations.insert(other.equations.begin(), other.equations.end());
239  other.equations.clear(); // so that it does not delete the equations
240 
241  CPPADCG_ASSERT_UNKNOWN(eqGroups_.size() == 1)
242  CPPADCG_ASSERT_UNKNOWN(other.eqGroups_.size() == 1)
243 
244  EquationGroup<Base>& g = eqGroups_[0];
245  EquationGroup<Base>& og = other.eqGroups_[0];
246  g.equations.insert(og.equations.begin(), og.equations.end());
247 
248  CPPADCG_ASSERT_UNKNOWN(equationOrder_.empty())
249  CPPADCG_ASSERT_UNKNOWN(iterationDependents_.empty())
250 
251  g.linkedEquationsByNonIndexed.insert(og.linkedEquationsByNonIndexed.begin(), og.linkedEquationsByNonIndexed.end());
252  for (EquationPattern<Base>* itNIndexed : indexedLoopRelations) {
253  g.linkedEquationsByNonIndexed.erase(itNIndexed);
254  }
255 
256  for (size_t e = 0; e < nonIndexedLoopRelations.size(); e++) {
257  g.addLinkedEquationsByNonIndexed(nonIndexedLoopRelations[e].first, nonIndexedLoopRelations[e].second);
258  }
259 
260  }
261 
262  void mergeEqGroups(Loop<Base>& other) {
263  eqGroups_.insert(eqGroups_.end(), other.eqGroups_.begin(), other.eqGroups_.end());
264 
265  size_t nEq = equations.size();
266  equations.insert(other.equations.begin(), other.equations.end());
267  other.equations.clear(); // so that it does not delete the equations
268 
272  for (const auto& it : other.equationOrder_) {
273  equationOrder_[it.first] = it.second + nEq;
274  }
275 
276  CPPADCG_ASSERT_UNKNOWN(iterationDependents_.size() == other.iterationDependents_.size())
277  for (size_t iter = 0; iter < iterationDependents_.size(); iter++) {
278  iterationDependents_[iter].insert(other.iterationDependents_[iter].begin(), other.iterationDependents_[iter].end());
279  }
280 
281  }
282 
283  void createLoopModel(const std::vector<CG<Base> >& dependents,
284  const std::vector<CG<Base> >& independents,
285  const std::map<size_t, EquationPattern<Base>*>& dep2Equation,
286  std::map<OperationNode<Base>*, size_t>& origTemp2Index) {
287 
288  CPPADCG_ASSERT_UNKNOWN(dep2Iteration_.empty())
289  for (size_t iter = 0; iter < iterationCount_; iter++) {
290  const std::set<size_t>& deps = iterationDependents_[iter];
291 
292  for (size_t d : deps) {
293  dep2Iteration_[d] = iter;
294  }
295  }
296 
297  if(varIndexed_ != nullptr) {
298  varIndexed_->adjustSize();
299  varIndexed_->fill(false);
300  }
301 
305  for (size_t g = 0; g < eqGroups_.size(); g++) {
306  eqGroups_[g].findReferenceIteration();
307 #ifdef CPPADCG_PRINT_DEBUG
308  std::cout << "reference iteration=" << eqGroups_[g].refIteration << "\n";
309  print(eqGroups_[g].iterationDependents);
310  std::cout << std::endl;
311 
312  typename std::set<EquationPattern<Base>*>::const_iterator iteq;
313  for (iteq = eqGroups_[g].equations.begin(); iteq != eqGroups_[g].equations.end(); ++iteq) {
314  std::cout << "eq dependents=";
315  print((*iteq)->dependents);
316  std::cout << std::endl;
317  }
318 #endif
319  }
320 
321 
322  for (size_t g = 0; g < eqGroups_.size(); g++) {
323  const EquationGroup<Base>& group = eqGroups_[g];
324  const std::set<size_t>& refItDep = group.iterationDependents[group.refIteration];
325  CPPADCG_ASSERT_UNKNOWN(refItDep.size() == group.equations.size())
326 
327  for (size_t dep : refItDep) {
328  EquationPattern<Base>::uncolor(dependents[dep].getOperationNode(), *varIndexed_);
329  }
330 
331  for (size_t dep : refItDep) {
332  EquationPattern<Base>* eq = dep2Equation.at(dep);
333 
334  // operations that use indexed independent variables in the reference iteration
335  std::set<const OperationNode<Base>*> indexedOperations;
336 
337  eq->findIndexedPath(dep, dependents, *varIndexed_, indexedOperations);
338  if (dep == eq->depRefIndex) {
339  for (const auto& itop2a : eq->indexedOpIndep.op2Arguments) {
340  // currently there is no way to make a distinction between yi = xi and y_(i+1) = x_(i+1)
341  // since both operations which use indexed independents would be nullptr (the dependent)
342  // an alias is used for these cases
343  CPPADCG_ASSERT_UNKNOWN(itop2a.first != nullptr)
344  addOperationArguments2Loop(itop2a.first, itop2a.second);
345  }
346 
347  } else {
348  // generate loop references
349  for (const OperationNode<Base>* opLoopRef : indexedOperations) {
350  // currently there is no way to make a distinction between yi = xi and y_(i+1) = x_(i+1)
351  // since both operations which use indexed independents would be nullptr (the dependent)
352  // an alias is used for these cases
353  CPPADCG_ASSERT_UNKNOWN(opLoopRef != nullptr)
354 
355  const OperationNode<Base>* opEqRef = eq->operationEO2Reference.at(dep).at(opLoopRef);
356  addOperationArguments2Loop(opLoopRef, eq->indexedOpIndep.op2Arguments.at(opEqRef));
357  }
358  }
359 
360  // not needed anymore (lets free this memory now)
361  eq->indexedOpIndep.op2Arguments.clear();
362  }
363  }
364 
368  generateIndependentLoopIndexes();
369 
370  if(varId_ != nullptr)
371  varId_->fill(0);
372 
373  createLoopTapeNModel(dependents, independents, dep2Equation, origTemp2Index);
374 
378  if(varId_ != nullptr)
379  varId_->fill(0);
380  }
381 
382  void generateDependentLoopIndexes(const std::map<size_t, EquationPattern<Base>*>& dep2Equation) {
383  using namespace std;
384 
385  iterationDependents_.clear();
386  equationOrder_.clear();
387  iterationCount_ = 0;
388  size_t nMaxIt = 0;
392  map<EquationPattern<Base>*, set<size_t> > depsInEq;
393 
394  for (EquationPattern<Base>* eq : equations) {
395  depsInEq[eq] = eq->dependents;
396  nMaxIt = std::max<size_t>(nMaxIt, eq->dependents.size());
397  }
398 
399  iterationDependents_.reserve(nMaxIt + 2 * equations.size());
400 
401  for (size_t g = 0; g < eqGroups_.size(); g++) {
402  EquationGroup<Base>& group = eqGroups_[g];
403  const set<EquationPattern<Base>*>& eqs = group.equations;
404  const std::vector<set<size_t> >& linkedDependents = group.linkedDependents;
405  std::vector<set<size_t> >& relatedEqIterationDeps = group.iterationDependents;
406 
407  relatedEqIterationDeps.reserve(iterationDependents_.size());
408 
409  // assign an index to each equation
410  for (EquationPattern<Base>* eq : eqs) {
411  size_t eqo_size = equationOrder_.size();
412  equationOrder_[eq] = eqo_size;
413  }
414 
415  // sort dependents
416  set<size_t> dependents;
417  for (EquationPattern<Base>* eq : eqs) {
418  dependents.insert(eq->dependents.begin(), eq->dependents.end());
419  }
420 
421  map<size_t, map<EquationPattern<Base>*, set<size_t> > > nIndexedGroupPos2Eq2deps;
422 
423 
424  map<EquationPattern<Base>*, std::vector<size_t> > freeDependents; // ordered dependents not assign to any iteration
425  for (EquationPattern<Base>* eq : equations) {
426  freeDependents[eq].assign(eq->dependents.begin(), eq->dependents.end());
427  }
428 
429  DependentIndexSorter depSorter(group, freeDependents, dep2Equation);
430 
431  auto itDep = dependents.begin();
432  size_t i = 0; // iteration counter
433  while (itDep != dependents.end()) {
434  size_t dep = *itDep;
435  itDep++;
436 
437  if (iterationDependents_.size() <= i)
438  iterationDependents_.resize(i + 1);
439  set<size_t>& itDepi = iterationDependents_[i];
440 
441  if (relatedEqIterationDeps.size() <= i)
442  relatedEqIterationDeps.resize(i + 1);
443  set<size_t>& ritDepi = relatedEqIterationDeps[i];
444 
445  // this dependent might not be the best dependent if this equation is not present in all iterations
446 
447  EquationPattern<Base>* eq = dep2Equation.at(dep);
448  auto bestDep = depSorter.findBestDependentForIteration(dep, eq);
449  dep = bestDep.first;
450  eq = bestDep.second;
451 
452  long pos = group.findIndexedLinkedDependent(dep);
453  if (pos >= 0) {
454  // assign the dependent to the first iteration with all its relationships
455  for (size_t dep2 : linkedDependents[pos]) {
456  if (dep2 == *itDep) itDep++; //make sure the iterator is valid
457  itDepi.insert(dep2);
458  ritDepi.insert(dep2);
459  dependents.erase(dep2);
460 
461  EquationPattern<Base>* eq2 = dep2Equation.at(dep2);
462  std::vector<size_t>& eq2FreeDep = freeDependents[eq2];
463  typename std::vector<size_t>::const_iterator itFreeDep2;
464  itFreeDep2 = std::find(eq2FreeDep.cbegin(), eq2FreeDep.cend(), dep2); // consider using lower_bound instead
465  CPPADCG_ASSERT_UNKNOWN(itFreeDep2 != eq2FreeDep.cend())
466 
467  eq2FreeDep.erase(itFreeDep2);
468  }
469 
470  i++;
471  } else {
472  // maybe this dependent shares a non-indexed temporary variable
473  long posN = group.findNonIndexedLinkedRel(eq);
474  if (posN >= 0) {
475  // there are only non-indexed shared relations with other equations (delay processing...)
476  dependents.erase(dep); // safe because of itDep++
477  nIndexedGroupPos2Eq2deps[posN][eq].insert(dep);
478  } else {
479  itDepi.insert(dep);
480  ritDepi.insert(dep);
481 
482  std::vector<size_t>& eqFreeDep = freeDependents[eq];
483  auto itFreeDep = find(eqFreeDep.begin(), eqFreeDep.end(), dep); // consider using lower_bound instead
484  CPPADCG_ASSERT_UNKNOWN(itFreeDep != eqFreeDep.end())
485 
486  eqFreeDep.erase(itFreeDep);
487 
488  i++;
489  }
490  }
491 
492  }
493 
497  if (!nIndexedGroupPos2Eq2deps.empty()) {
498 
499  map<EquationPattern<Base>*, set<size_t> > eqIterations;
500  for (size_t i = 0; i < relatedEqIterationDeps.size(); i++) {
501  const set<size_t>& deps = relatedEqIterationDeps[i];
502  for (size_t dep : deps) {
503  eqIterations[dep2Equation.at(dep)].insert(i);
504  }
505  }
506 
507  for (auto& itPos2Eq2Dep : nIndexedGroupPos2Eq2deps) {
508  size_t posN = itPos2Eq2Dep.first;
509  // must pick one dependent from each equation for each iteration
510  std::vector<size_t> deps;
511  deps.reserve(itPos2Eq2Dep.second.size());
512 
513  set<size_t> usedIterations; // iterations used by these equations
514  // determine used iteration indexes
515  const set<EquationPattern<Base>*>& relations = group.linkedEquationsByNonIndexedRel[posN];
516  for (EquationPattern<Base>* itRel : relations) {
517  const set<size_t>& iters = eqIterations[itRel];
518  usedIterations.insert(iters.begin(), iters.end());
519  }
520 
521  while (true) {
522 
523  // must pick one dependent from each equation for each iteration
524  deps.clear();
525 
526  for (auto& itEq2Dep : itPos2Eq2Dep.second) {
527  if (!itEq2Dep.second.empty()) {
528  deps.push_back(*itEq2Dep.second.begin());
529  itEq2Dep.second.erase(itEq2Dep.second.begin());
530  }
531  }
532 
533  if (deps.empty()) {
534  break; // done
535  }
536 
537  // find a free iteration index
538  size_t i = 0;
539  set<size_t>::const_iterator itIter;
540  for (itIter = usedIterations.begin(); itIter != usedIterations.end();) {
541  size_t i1 = *itIter;
542  ++itIter;
543  if (itIter != usedIterations.end()) {
544  size_t i2 = *itIter;
545  if (i2 - i1 != 1) {
546  i = i1 + 1;
547  break;
548  }
549  } else {
550  i = i1 + 1;
551  }
552  }
553 
554  // add the dependents to the iteration
555  usedIterations.insert(i);
556 
557  if (iterationDependents_.size() <= i)
558  iterationDependents_.resize(i + 1);
559  set<size_t>& itDepi = iterationDependents_[i];
560 
561  if (relatedEqIterationDeps.size() <= i)
562  relatedEqIterationDeps.resize(i + 1);
563  set<size_t>& ritDepi = relatedEqIterationDeps[i];
564  itDepi.insert(deps.begin(), deps.end());
565  ritDepi.insert(deps.begin(), deps.end());
566  }
567  }
575  }
576 
577  iterationCount_ = std::max<size_t>(iterationCount_, iterationDependents_.size());
578  }
579 
580  }
581 
585  virtual ~Loop() {
586  for (const auto& itf : firstIndep2orders_) {
587  for (IndependentOrder<Base>* ito : itf.second) {
588  delete ito;
589  }
590  }
591 
592  for (OperationArgumentsIndepOrder<Base>* itio : arg2IndepOrder_) {
593  delete itio;
594  }
595 
596  for (EquationPattern<Base>* eq : equations) {
597  delete eq;
598  }
599 
600  delete loopModel_;
601  }
602 
603  /***********************************************************************
604  * private
605  **********************************************************************/
606 private:
607 
608  void addOperationArguments2Loop(const OperationNode<Base>* op,
609  const OperationIndexedIndependents<Base>& eqOpIndeIndep) {
610  CPPADCG_ASSERT_UNKNOWN(!dep2Iteration_.empty());
611 
612  OperationIndexedIndependents<Base>& loopOpIndeIndep = indexedOpIndep.op2Arguments[op];
613  loopOpIndeIndep.arg2Independents.resize(eqOpIndeIndep.arg2Independents.size());
614 
615  // some iterations might have not been defined by previous equation patterns
616  for (size_t a = 0; a < eqOpIndeIndep.arg2Independents.size(); a++) {
617  if (eqOpIndeIndep.arg2Independents[a].empty())
618  continue;
619 
620  for (const auto& itDepIndep : eqOpIndeIndep.arg2Independents[a]) {
621  size_t dep = itDepIndep.first;
622  size_t iter = dep2Iteration_.at(dep);
623  loopOpIndeIndep.arg2Independents[a][iter] = itDepIndep.second;
624  }
625  }
626 
627  }
628 
629  void generateIndependentLoopIndexes() {
630  CPPADCG_ASSERT_UNKNOWN(iterationCount_ > 0); //number of iterations and dependent indexes must have already been determined
631 
632  // loop all operations from the reference dependents which use indexed independents
633  for (const auto& it : indexedOpIndep.op2Arguments) {
634  const OperationNode<Base>* operation = it.first;
635  const OperationIndexedIndependents<Base>& opInd = it.second;
636 
637  auto* arg2orderPos = new OperationArgumentsIndepOrder<Base>();
638  op2Arg2IndepOrder_[operation] = arg2orderPos;
639 
640  arg2IndepOrder_.push_front(arg2orderPos);
641 
642  // loop all arguments
643  size_t aSize = opInd.arg2Independents.size();
644  for (size_t argumentIndex = 0; argumentIndex < aSize; argumentIndex++) {
645  const std::map<size_t, const OperationNode<Base>*>& dep2Indep = opInd.arg2Independents[argumentIndex];
646  if (dep2Indep.empty())
647  continue; // not an indexed variable
648 
649  std::vector<const OperationNode<Base>*> order(iterationCount_);
650 
654  CPPADCG_ASSERT_UNKNOWN(dep2Indep.size() > 0 && dep2Indep.size() <= iterationCount_)
655  for (const auto& itDep2Indep : dep2Indep) {
656  size_t iterationIndex = itDep2Indep.first;
657  const OperationNode<Base>* indep = itDep2Indep.second;
658 
659  order[iterationIndex] = indep;
660  }
661 
665  std::vector<IndependentOrder<Base>*>& availableOrders = firstIndep2orders_[order[0]];
666  IndependentOrder<Base>* match = nullptr;
667 
668  long a_size = availableOrders.size();
669  for (long o = 0; o < a_size; o++) {
670  IndependentOrder<Base>* orderO = availableOrders[o];
671  bool ok = true;
672  for (size_t iterationIndex = 0; iterationIndex < iterationCount_; iterationIndex++) {
673  if (orderO->order[iterationIndex] != order[iterationIndex]) {
674  ok = false;
675  break;
676  }
677  }
678  if (ok) {
679  match = orderO;
680  break;
681  }
682  }
683 
684  if (match != nullptr) {
685  // found another operation with the same independent variable order
686  arg2orderPos->arg2Order[argumentIndex] = match;
687  } else {
688  // brand new independent variable order
689  auto* iOrder = new IndependentOrder<Base>(order);
690  availableOrders.push_back(iOrder);
691  arg2orderPos->arg2Order[argumentIndex] = iOrder;
692  }
693 
694  }
695 
696  }
697  }
698 
707  void createLoopTapeNModel(const std::vector<CG<Base> >& dependents,
708  const std::vector<CG<Base> >& independents,
709  const std::map<size_t, EquationPattern<Base>*>& dep2Equation,
710  std::map<OperationNode<Base>*, size_t>& origTemp2Index) {
711  using CGB = CG<Base>;
712  using ADCGB = AD<CGB>;
713  CPPADCG_ASSERT_UNKNOWN(independents.size() > 0)
714  CPPADCG_ASSERT_UNKNOWN(independents[0].getCodeHandler() != nullptr)
715  CodeHandler<Base>& origHandler = *independents[0].getCodeHandler();
716 
720  nIndependents_ = 0;
721  idCounter_ = 1;
722 
723  CPPADCG_ASSERT_UNKNOWN(equationOrder_.size() == equations.size())
724 
725  std::vector<CGB> deps(equations.size());
726 
727  for (size_t g = 0; g < eqGroups_.size(); g++) {
728  const EquationGroup<Base>& group = eqGroups_[g];
729  const std::set<size_t>& iterationDependents = group.iterationDependents[group.refIteration];
730 
731  for (size_t depIndex : iterationDependents) {
732  EquationPattern<Base>* eq = dep2Equation.at(depIndex);
733  OperationNode<Base>* node = dependents[depIndex].getOperationNode();
734 
735  Argument<Base> aClone;
736 
737  if (node != nullptr) {
738  if (node->getOperationType() == CGOpCode::Inv) {
739  aClone = createIndependentClone(nullptr, 0, *node);
740  } else {
741  aClone = makeGraphClones(*eq, *node);
742  }
743  } else {
744  aClone = dependents[depIndex].getValue();
745  }
746 
747  size_t i = equationOrder_.at(eq);
748  deps[i] = CGB(aClone);
749  }
750  }
751 
752  /*******************************************************************
753  * create the tape for the reference iteration
754  ******************************************************************/
755  // indexed independents
756  CPPADCG_ASSERT_UNKNOWN(indexedIndep2clone_.size() == independentsIndexed_.size());
757 
758  std::vector<const OperationNode<Base>*> indexedCloneOrder;
759  indexedCloneOrder.reserve(indexedIndep2clone_.size());
760 
761  std::map<const OperationNode<Base>*, const IndependentOrder<Base>*> clone2indexedIndep;
762  for (const auto& it : indexedIndep2clone_) {
763  clone2indexedIndep[it.second] = it.first;
764  indexedCloneOrder.push_back(it.second);
765  }
766 
767  struct IndexedIndepSorter indexedSorter(clone2indexedIndep);
768  std::sort(indexedCloneOrder.begin(), indexedCloneOrder.end(), indexedSorter);
769 
770  // original indep index -> non-indexed independent clones
771  std::map<size_t, const OperationNode<Base>*> nonIndexedCloneOrder;
772 
773  // [tape variable] = original independent index
774  std::map<const OperationNode<Base>*, const OperationNode<Base>*> clones2ConstIndep;
775  size_t s = 0;
776  for (auto itc = orig2ConstIndepClone_.begin(); itc != orig2ConstIndepClone_.end(); ++itc, s++) {
777  const OperationNode<Base>* orig = itc->first;
778  OperationNode<Base>* clone = itc->second;
779 
780  size_t j = orig->getInfo()[0];
781  clones2ConstIndep[clone] = orig;
782  nonIndexedCloneOrder[j] = clone;
783  }
784 
785  size_t nIndexed = indexedCloneOrder.size();
786  size_t nNonIndexed = nonIndexedCloneOrder.size();
787  size_t nTmpIndexed = independentsTemp_.size();
788 
789  // tape independent array
790  size_t nIndep = independentsIndexed_.size() +
791  independentsNonIndexed_.size() +
792  independentsTemp_.size();
793  std::vector<ADCGB> loopIndeps(nIndep);
794 
795  typename std::map<const OperationNode<Base>*, IndexValue>::const_iterator itt;
796  typename std::map<size_t, const OperationNode<Base>*>::const_iterator origJ2CloneIt;
797 
798  if (nIndep == 0) {
799  loopIndeps.resize(1); // the tape cannot have 0 independents
800  loopIndeps[0] = Base(0);
801 
802  } else {
803 
807  for (size_t j = 0; j < nIndexed; j++) {
808  const IndexValue& iv = independentsIndexed_.at(indexedCloneOrder[j]);
809  loopIndeps[j] = iv.second;
810  }
811 
812  s = 0;
813  for (origJ2CloneIt = nonIndexedCloneOrder.begin(); origJ2CloneIt != nonIndexedCloneOrder.end(); ++origJ2CloneIt, s++) {
814  const IndexValue& iv = independentsNonIndexed_.at(origJ2CloneIt->second);
815  loopIndeps[nIndexed + s] = iv.second;
816  }
817 
818  s = 0;
819  for (itt = independentsTemp_.begin(); itt != independentsTemp_.end(); ++itt, s++) {
820  const IndexValue& iv = itt->second;
821  loopIndeps[nIndexed + nNonIndexed + s] = iv.second;
822  }
823  }
824 
828  CppAD::Independent(loopIndeps);
829 
833  std::vector<ADCGB> localIndeps(nIndep);
834  if (nIndep > 0) {
835  for (size_t j = 0; j < nIndexed; j++) {
836  const IndexValue& iv = independentsIndexed_.at(indexedCloneOrder[j]);
837  size_t localIndex = iv.first;
838  localIndeps[localIndex] = loopIndeps[j];
839  }
840 
841  s = 0;
842  for (origJ2CloneIt = nonIndexedCloneOrder.begin(); origJ2CloneIt != nonIndexedCloneOrder.end(); ++origJ2CloneIt, s++) {
843  size_t localIndex = independentsNonIndexed_.at(origJ2CloneIt->second).first;
844  localIndeps[localIndex] = loopIndeps[nIndexed + s];
845  }
846 
847  s = 0;
848  for (itt = independentsTemp_.begin(); itt != independentsTemp_.end(); ++itt, s++) {
849  size_t localIndex = itt->second.first;
850  localIndeps[localIndex] = loopIndeps[nIndexed + nNonIndexed + s];
851  }
852  }
853 
857  Evaluator<Base, CGB> evaluator1stIt(handler_);
858 
859  // load any atomic function used in the original model
860  const std::map<size_t, CGAbstractAtomicFun<Base>* >& atomicsOrig = origHandler.getAtomicFunctions();
861  std::map<size_t, atomic_base<CGB>* > atomics;
862  atomics.insert(atomicsOrig.begin(), atomicsOrig.end());
863  evaluator1stIt.addAtomicFunctions(atomics);
864 
865  std::vector<ADCGB> newDeps = evaluator1stIt.evaluate(localIndeps, deps);
866 
867  bool containsAtoms = evaluator1stIt.getNumberOfEvaluatedAtomics() > 0;
868 
869  std::unique_ptr<ADFun<CGB> >funIndexed(new ADFun<CGB>());
870  funIndexed->Dependent(newDeps);
871 
872  /*******************************************************************
873  * create the loop model object
874  ******************************************************************/
875  std::vector<std::vector<size_t> > dependentOrigIndexes(equations.size(), std::vector<size_t> (iterationCount_, (std::numeric_limits<size_t>::max)()));
876  for (size_t it = 0; it < iterationCount_; it++) {
877  const std::set<size_t>& itDeps = iterationDependents_[it];
878  for (size_t origDep : itDeps) {
879  EquationPattern<Base>* eq = dep2Equation.at(origDep);
880  size_t i = equationOrder_.at(eq);
881  dependentOrigIndexes[i][it] = origDep;
882  }
883  }
884 
885  //[tape variable][iteration] = original independent index
886  std::vector<std::vector<size_t> > indexedIndependents(nIndexed, std::vector<size_t>(iterationCount_));
887  for (size_t j = 0; j < indexedCloneOrder.size(); j++) {
888  const IndependentOrder<Base>* origOrder = clone2indexedIndep.at(indexedCloneOrder[j]);
889  for (size_t it = 0; it < iterationCount_; it++) {
890  const OperationNode<Base>* indep = origOrder->order[it];
891  size_t index;
892  if (indep != nullptr) {
893  index = indep->getInfo()[0];
894  } else {
895  index = (std::numeric_limits<size_t>::max)(); // not used at this iteration by any equation
896  }
897  indexedIndependents[j][it] = index;
898  }
899  }
900 
901  std::vector<size_t> temporaryIndependents(nTmpIndexed);
902 
903  size_t j = 0;
904  for (itt = independentsTemp_.begin(); itt != independentsTemp_.end(); ++itt, j++) {
905  const OperationNode<Base>* tmpClone = itt->first;
906  OperationNode<Base>* origTmpNode = temporaryClone2Orig_.at(tmpClone);
907 
911  size_t k;
912  typename std::map<OperationNode<Base>*, size_t>::const_iterator itz = origTemp2Index.find(origTmpNode);
913  if (itz == origTemp2Index.end()) {
914  k = origTemp2Index.size();
915  origTemp2Index[origTmpNode] = k; // new index for a temporary variable
916  } else {
917  k = itz->second;
918  }
919 
920  temporaryIndependents[j] = k;
921  }
922 
923  std::vector<size_t> nonIndexedIndependents(orig2ConstIndepClone_.size());
924  s = 0;
925  for (origJ2CloneIt = nonIndexedCloneOrder.begin(); origJ2CloneIt != nonIndexedCloneOrder.end(); ++origJ2CloneIt, s++) {
926  nonIndexedIndependents[s] = origJ2CloneIt->first;
927  }
928 
929  loopModel_ = new LoopModel<Base>(funIndexed.release(),
930  containsAtoms,
931  iterationCount_,
932  dependentOrigIndexes,
933  indexedIndependents,
934  nonIndexedIndependents,
935  temporaryIndependents);
936 
937  loopModel_->detectIndexPatterns();
938  }
939 
940  inline Argument<Base> makeGraphClones(const EquationPattern<Base>& eq,
941  OperationNode<Base>& node) {
942 
943  CPPADCG_ASSERT_UNKNOWN(node.getOperationType() != CGOpCode::Inv)
944 
945  size_t id = (*varId_)[node];
946 
947  if (id > 0) {
948  // been here before
949  return Argument<Base>(*clonesTemporary_.at(id));
950  }
951 
952  //handler_.markVisited(node);
953 
954  id = idCounter_++;
955  (*varId_)[node] = id;
956 
957  if ((*varIndexed_)[node] || node.getOperationType() == CGOpCode::ArrayCreation) {
962  const std::vector<Argument<Base> >& args = node.getArguments();
963  size_t arg_size = args.size();
964  std::vector<Argument<Base> > cloneArgs(arg_size);
965 
966  for (size_t a = 0; a < arg_size; a++) {
967  OperationNode<Base>* argOp = args[a].getOperation();
968  if (argOp == nullptr) {
969  // parameter
970  cloneArgs[a] = *args[a].getParameter();
971  } else {
972  // variable
973  if (argOp->getOperationType() == CGOpCode::Inv) {
974  cloneArgs[a] = createIndependentClone(&node, a, *argOp);
975  } else {
976  cloneArgs[a] = makeGraphClones(eq, *argOp);
977  }
978  }
979  }
980 
981  OperationNode<Base>* cloneOp = handler_.makeNode(node.getOperationType(),
982  node.getInfo(),
983  cloneArgs);
984 
985  clonesTemporary_[id] = cloneOp;
986  return Argument<Base>(*cloneOp);
987 
988  } else {
993  return makeTemporaryVarClone(node);
994  }
995  }
996 
997  inline OperationNode<Base>& createIndependentClone(OperationNode<Base>* operation,
998  size_t argumentIndex,
999  OperationNode<Base>& independent) {
1000 
1001  // is it an indexed independent?
1002  typename std::map<const OperationNode<Base>*, OperationIndexedIndependents<Base> >::const_iterator it = indexedOpIndep.op2Arguments.find(operation);
1003  if (it != indexedOpIndep.op2Arguments.end()) {
1004  const OperationIndexedIndependents<Base>& yyy = it->second;
1005 
1006  if (!yyy.arg2Independents[argumentIndex].empty()) {
1007  // yes
1008  return getIndexedIndependentClone(operation, argumentIndex);
1009  }
1010  }
1011 
1012  // it is constant for all operation
1013  return getNonIndexedIndependentClone(independent);
1014  }
1015 
1016  OperationNode<Base>& getIndexedIndependentClone(const OperationNode<Base>* operation,
1017  size_t argIndex) {
1018  CPPADCG_ASSERT_UNKNOWN(operation == nullptr || operation->getArguments().size() > argIndex)
1019  CPPADCG_ASSERT_UNKNOWN(operation == nullptr || operation->getArguments()[argIndex].getOperation() != nullptr)
1020  CPPADCG_ASSERT_UNKNOWN(operation == nullptr || operation->getArguments()[argIndex].getOperation()->getOperationType() == CGOpCode::Inv)
1021 
1022  OperationArgumentsIndepOrder<Base>* args2Order = op2Arg2IndepOrder_.at(operation);
1023  IndependentOrder<Base>* indepOrder = args2Order->arg2Order.at(argIndex);
1024 
1025  typename std::map<const IndependentOrder<Base>*, OperationNode<Base>*>::const_iterator it;
1026  it = indexedIndep2clone_.find(indepOrder);
1027  if (it != indexedIndep2clone_.end()) {
1028  return *it->second;
1029  } else {
1030  CG<Base> newIndep;
1031  handler_.makeVariable(newIndep);
1032  independentsIndexed_[newIndep.getOperationNode()] = IndexValue(nIndependents_, newIndep);
1033  nIndependents_++;
1034 
1035  OperationNode<Base>* clone = newIndep.getOperationNode();
1036  indexedIndep2clone_[indepOrder] = clone;
1037  return *clone;
1038  }
1039  }
1040 
1041  OperationNode<Base>& getNonIndexedIndependentClone(const OperationNode<Base>& node) {
1042  CPPADCG_ASSERT_UNKNOWN(node.getOperationType() == CGOpCode::Inv)
1043 
1044  typename std::map<const OperationNode<Base>*, OperationNode<Base>*>::iterator it;
1045  it = orig2ConstIndepClone_.find(&node);
1046  if (it != orig2ConstIndepClone_.end()) {
1047  return *it->second;
1048  }
1049 
1050  CG<Base> newIndep;
1051  handler_.makeVariable(newIndep);
1052  independentsNonIndexed_[newIndep.getOperationNode()] = IndexValue(nIndependents_, newIndep);
1053  nIndependents_++;
1054 
1055  OperationNode<Base>* clone = newIndep.getOperationNode();
1056  orig2ConstIndepClone_[&node] = clone;
1057  return *clone;
1058  }
1059 
1066  OperationNode<Base>& makeTemporaryVarClone(OperationNode<Base>& node) {
1067  CPPADCG_ASSERT_UNKNOWN(node.getOperationType() != CGOpCode::Inv)
1068  CPPADCG_ASSERT_UNKNOWN(node.getOperationType() != CGOpCode::ArrayCreation)
1069  CPPADCG_ASSERT_UNKNOWN(node.getOperationType() != CGOpCode::SparseArrayCreation)
1070 
1071  CG<Base> newIndep;
1072  handler_.makeVariable(newIndep);
1073  OperationNode<Base>* cloneOp = newIndep.getOperationNode();
1074 
1075  temporaryClone2Orig_[cloneOp] = &node;
1076  independentsTemp_[cloneOp] = IndexValue(nIndependents_, newIndep);
1077  nIndependents_++;
1078 
1079  size_t id = idCounter_++;
1080  clonesTemporary_[id] = cloneOp;
1081  (*varId_)[node] = id;
1082 
1083  return *cloneOp;
1084  }
1085 
1089  class DependentIndexSorter {
1090  private:
1091  const EquationGroup<Base>& group;
1092  const std::map<EquationPattern<Base>*, std::vector<size_t> >& freeDependents;
1093  const std::map<size_t, EquationPattern<Base>*>& dep2Equation;
1094  std::set<EquationPattern<Base>*> visitedEq;
1095  public:
1096 
1097  inline DependentIndexSorter(const EquationGroup<Base>& g,
1098  const std::map<EquationPattern<Base>*, std::vector<size_t> >& f,
1099  const std::map<size_t, EquationPattern<Base>*>& d2e) :
1100  group(g),
1101  freeDependents(f),
1102  dep2Equation(d2e) {
1103  }
1104 
1113  inline std::pair<size_t, EquationPattern<Base>*> findBestDependentForIteration(size_t dep, EquationPattern<Base>* eq) {
1114  visitedEq.clear();
1115  return findBestDependent(dep, eq);
1116  }
1117 
1118  private:
1119 
1120  inline size_t findRelativeFreeDependentInEq(EquationPattern<Base>* eq, size_t dep) {
1121  // find relative order of the dependent in the equation
1122  const std::vector<size_t>& eqFreeDep = freeDependents.at(eq);
1123  for (size_t depRelPos = 0; depRelPos < eqFreeDep.size(); depRelPos++) {// consider using lower_bound
1124  if (eqFreeDep[depRelPos] == dep)
1125  return depRelPos; // found it
1126  }
1127 
1128  assert(false);
1129  return eqFreeDep.size(); // should not happen
1130  }
1131 
1139  inline std::pair<size_t, EquationPattern<Base>*> findBestDependent(size_t dep, EquationPattern<Base>* eq) {
1140  visitedEq.insert(eq);
1141 
1142  auto best = std::make_pair(dep, eq);
1143 
1144  // find the group of dependents in the same iteration (associated by indexed independents)
1145  long pos = group.findIndexedLinkedDependent(dep);
1146  if (pos >= 0) {
1147  size_t depRelPos = findRelativeFreeDependentInEq(eq, dep);
1148 
1149  // this dependent might not be the best dependent if this
1150  // equation is not present in all iterations
1151  for (size_t dep2 : group.linkedDependents[pos]) {
1152  EquationPattern<Base>* eq2 = dep2Equation.at(dep2);
1153  if (visitedEq.find(eq2) != visitedEq.end()) continue;
1154 
1155  size_t dep2RelPos = findRelativeFreeDependentInEq(eq2, dep2);
1156  if (dep2RelPos > depRelPos) {
1157  // this equation has more dependents before
1158  // one these other dependents would be better
1159  best = std::make_pair(dep2, eq2);
1160  depRelPos = dep2RelPos;
1161  }
1162  }
1163 
1164  if (best.first != dep) {
1165  size_t bestDep = *freeDependents.at(best.second).begin();
1166  return findBestDependent(bestDep, best.second);
1167  }
1168 
1169  }
1170 
1171  return best;
1172  }
1173 
1174  };
1175 
1179  struct IndexedIndepSorter {
1180  const std::map<const OperationNode<Base>*, const IndependentOrder<Base>*>& clone2indexedIndep;
1181 
1182  IndexedIndepSorter(const std::map<const OperationNode<Base>*, const IndependentOrder<Base>*>& clone2indexedIndep_) :
1183  clone2indexedIndep(clone2indexedIndep_) {
1184  }
1185 
1186  bool operator()(const OperationNode<Base>* node1,
1187  const OperationNode<Base>* node2) {
1188  const IndependentOrder<Base>* indepOrder1 = clone2indexedIndep.at(node1);
1189  const IndependentOrder<Base>* indepOrder2 = clone2indexedIndep.at(node2);
1190  CPPADCG_ASSERT_UNKNOWN(indepOrder1->order.size() == indepOrder2->order.size())
1191 
1192  size_t size = indepOrder1->order.size();
1193  for (size_t j = 0; j < size; j++) {
1194  const OperationNode<Base>* indep1 = indepOrder1->order[j];
1195  const OperationNode<Base>* indep2 = indepOrder2->order[j];
1196  // some variables are not used in all iterations
1197  if (indep1 == nullptr) {
1198  if (indep2 == nullptr) {
1199  continue;
1200  }
1201  return false;
1202  } else if (indep2 == nullptr) {
1203  return true;
1204  }
1205 
1206  size_t index1 = indep1->getInfo()[0];
1207  size_t index2 = indep2->getInfo()[0];
1208  if (index1 < index2)
1209  return true;
1210  else if (index1 > index2)
1211  return false;
1212  }
1213 
1214  CPPADCG_ASSERT_UNKNOWN(false) // should never get here
1215  return false;
1216  }
1217  };
1218 
1219 };
1220 
1221 } // END cg namespace
1222 } // END CppAD namespace
1223 
1224 #endif
std::vector< ActiveOut > evaluate(ArrayView< const ActiveOut > indepNew, ArrayView< const CG< ScalarIn > > depOld)
Definition: evaluator.hpp:93
std::set< EquationPattern< Base > * > equations
Definition: loop.hpp:59
std::map< size_t, std::map< const OperationNode< Base > *, OperationNode< Base > * > > operationEO2Reference
void merge(Loop< Base > &other, const std::set< EquationPattern< Base > *> &indexedLoopRelations, const std::vector< std::pair< EquationPattern< Base > *, EquationPattern< Base > *> > &nonIndexedLoopRelations)
Definition: loop.hpp:232
void mergeEqGroups(Loop< Base > &other)
Definition: loop.hpp:262
const std::vector< Argument< Base > > & getArguments() const
size_t getIterationCount() const
Definition: loop.hpp:209
STL namespace.
std::vector< MapDep2Indep_type > arg2Independents
std::vector< std::set< size_t > > linkedDependents
std::vector< std::set< size_t > > iterationDependents
IndexedIndependent< Base > indexedOpIndep
Definition: loop.hpp:65
IndexedIndependent< Base > indexedOpIndep
CGOpCode getOperationType() const
void generateDependentLoopIndexes(const std::map< size_t, EquationPattern< Base > *> &dep2Equation)
Definition: loop.hpp:382
void makeVariable(AD< CGB > &variable)
void createLoopModel(const std::vector< CG< Base > > &dependents, const std::vector< CG< Base > > &independents, const std::map< size_t, EquationPattern< Base > *> &dep2Equation, std::map< OperationNode< Base > *, size_t > &origTemp2Index)
Definition: loop.hpp:283
std::vector< std::set< EquationPattern< Base > * > > linkedEquationsByNonIndexedRel
std::set< EquationPattern< Base > * > equations
virtual ~Loop()
Definition: loop.hpp:585
const std::vector< size_t > & getInfo() const