CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
18namespace CppAD {
19namespace cg {
20
21template<class Base>
23public:
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
32template<class Base>
34public:
35 std::map<size_t, IndependentOrder<Base>*> arg2Order;
36};
37
41template<class Base>
42class LoopCodeHandler : public CodeHandler<Base> {
43public:
44 using CodeHandler<Base>::manageOperationNode;
45
46};
47
51template<class Base>
52class Loop {
53private:
54 using IndexValue = std::pair<size_t, CG<Base> >;
55public:
59 std::set<EquationPattern<Base>*> equations;
66private:
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_;
159public:
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
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 **********************************************************************/
606private:
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
void makeVariable(AD< CGB > &variable)
std::vector< std::set< size_t > > linkedDependents
std::set< EquationPattern< Base > * > equations
std::vector< std::set< EquationPattern< Base > * > > linkedEquationsByNonIndexedRel
std::vector< std::set< size_t > > iterationDependents
IndexedIndependent< Base > indexedOpIndep
std::map< size_t, std::map< const OperationNode< Base > *, OperationNode< Base > * > > operationEO2Reference
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
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
size_t getIterationCount() const
Definition loop.hpp:209
std::set< EquationPattern< Base > * > equations
Definition loop.hpp:59
virtual ~Loop()
Definition loop.hpp:585
void generateDependentLoopIndexes(const std::map< size_t, EquationPattern< Base > * > &dep2Equation)
Definition loop.hpp:382
IndexedIndependent< Base > indexedOpIndep
Definition loop.hpp:65
void mergeEqGroups(Loop< Base > &other)
Definition loop.hpp:262
std::vector< MapDep2Indep_type > arg2Independents