CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
18namespace CppAD {
19namespace cg {
20
21namespace loops {
22
23/***********************************************************************
24 * Utility classes
25 **********************************************************************/
26template<class Base>
28public:
29 CG<Base> value;
30 std::map<size_t, size_t> locations;
31public:
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
43template<class Base>
45public:
46 std::set<size_t> iterations;
48};
49
50template <class Base>
52public:
53 std::map<SizeN1stIt, IfBranchInfo<Base> > firstIt2Branch;
55
56 inline IfElseInfo() :
57 endIf(nullptr) {
58 }
59};
60
62public:
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
76template<class Base>
78public:
79 std::vector<size_t> indexes;
80 std::vector<CG<Base> > origVals;
81 IndexPattern* pattern;
82
84 pattern(nullptr) {
85 }
86};
87
88template<class Base>
89inline 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
110template<class Base>
111inline 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
144template<class Base>
145inline 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
168template<class Base>
169inline 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
200template<class Base>
201LoopEndOperationNode<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
240template<class Base>
241inline 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
268template<class Base>
270private:
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_;
275public:
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
349template<class Base>
350inline 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
379template<class Base>
380OperationNode<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
390std::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
454template<class Base>
455inline 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
564template<class Base>
565CG<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
647template<class Base>
648std::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
727public:
728 IndexPattern* resultPattern;
729 IndexPattern* compressedPattern;
730public:
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
751public:
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
762public:
763 std::unique_ptr<IndexPattern> pattern;
764 std::unique_ptr<IndexPattern> startLocPattern;
766};
767
777template<class Base>
778inline 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
895template<class Base>
896void 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
918 SmartVectorPointer<ArrayGroup> garbage;
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
971 LanguageC<Base>::generateNames4RandomIndexPatterns(indexRandomPatterns);
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
1164template<class Base>
1165std::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
1254template<class Base>
1255void 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
static IndexPattern * detect(const VectorSizeT &x2y)
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={})
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern * > &randomPatterns)
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const