CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
model_c_source_gen_loops_rev2.hpp
1#ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_REV2_INCLUDED
2#define CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_REV2_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
21/***************************************************************************
22 * Utility classes and functions
23 **************************************************************************/
24namespace loops {
25
26template<class Base>
27class HessianWithLoopsInfo;
28
29template<class Base>
30class HessianTermContrib;
31
32template<class Base>
33bool operator<(const HessianTermContrib<Base>& l, const HessianTermContrib<Base>& r);
34
35template<class Base>
36class HessianRowGroup;
37
38template<class Base>
39std::vector<std::pair<CG<Base>, IndexPattern*> > generateReverseTwoGroupOps(CodeHandler<Base>& handler,
40 const LoopModel<Base>& lModel,
41 const loops::HessianWithLoopsInfo<Base>& info,
42 HessianRowGroup<Base>& group,
43 const CG<Base>& tx1,
44 const std::map<size_t, std::map<size_t, CG<Base> > >& dzDx,
45 std::map<size_t, std::set<size_t> >& jrow2CompressedLoc);
46
47template<class Base>
48std::pair<CG<Base>, IndexPattern*> createReverseMode2Contribution(CodeHandler<Base>& handler,
49 HessianRowGroup<Base>& group,
50 const std::vector<HessianElement>& positions,
51 const CG<Base>& ddfdxdx,
52 const CG<Base>& tx1,
53 IndexOperationNode<Base>& iterationIndexOp,
54 std::map<size_t, std::set<size_t> >& jrow2CompressedLoc);
55} // END loops namespace
56
57/***************************************************************************
58 * Methods related with loop insertion into the operation graph
59 **************************************************************************/
60
61template<class Base>
62void ModelCSourceGen<Base>::prepareSparseReverseTwoWithLoops(const std::map<size_t, std::vector<size_t> >& elements) {
63 using namespace std;
64 using namespace CppAD::cg::loops;
65
66 size_t m = _fun.Range();
67 size_t n = _fun.Domain();
68
69 CodeHandler<Base> handler;
70 handler.setJobTimer(_jobTimer);
71 handler.setZeroDependents(false);
72
73 auto& indexJrowDcl = *handler.makeIndexDclrNode("jrow");
74 auto& indexLocalItDcl = *handler.makeIndexDclrNode("it");
75 auto& indexLocalItCountDcl = *handler.makeIndexDclrNode("itCount");
76 auto& indexIterationDcl = *handler.makeIndexDclrNode(LoopModel<Base>::ITERATION_INDEX_NAME);
77 auto& jrowIndexOp = *handler.makeIndexNode(indexJrowDcl);
78
79 std::vector<OperationNode<Base>* > localNodes(5);
80 localNodes[0] = &indexJrowDcl;
81 localNodes[1] = &indexLocalItDcl;
82 localNodes[2] = &indexLocalItCountDcl;
83 localNodes[3] = &indexIterationDcl;
84 localNodes[4] = &jrowIndexOp;
85
86 // independent variables
87 std::vector<CGBase> x(n);
88 handler.makeVariables(x);
89 if (_x.size() > 0) {
90 for (size_t i = 0; i < n; i++) {
91 x[i].setValue(_x[i]);
92 }
93 }
94
95 CGBase tx1;
96 handler.makeVariable(tx1);
97 if (_x.size() > 0) {
98 tx1.setValue(Base(1.0));
99 }
100
101 // multipliers
102 std::vector<CGBase> py(m); // (k+1)*m is not used because we are not interested in all values
103 handler.makeVariables(py);
104 if (_x.size() > 0) {
105 for (size_t i = 0; i < m; i++) {
106 py[i].setValue(Base(1.0));
107 }
108 }
109
110 size_t nonIndexdedEqSize = _funNoLoops != nullptr ? _funNoLoops->getOrigDependentIndexes().size() : 0;
111
112 size_t nnz = 0;
113 for (const auto& itJrow2jcols : elements) {
114 nnz += itJrow2jcols.second.size();
115 }
116
117 std::vector<size_t> hessRows(nnz);
118 std::vector<size_t> hessCols(nnz);
119 std::vector<size_t> hessOrder(nnz);
120 size_t ge = 0;
121 for (const auto& itJrow2jcols : elements) {
122 size_t jrow = itJrow2jcols.first;
123 const std::vector<size_t>& jcols = itJrow2jcols.second;
124
125 for (size_t e = 0; e < jcols.size(); e++) {
126 hessRows[ge] = jrow;
127 hessCols[ge] = jcols[e];
128 hessOrder[ge] = e;
129 ge++;
130 }
131 }
132
133 std::vector<set<size_t> > noLoopEvalJacSparsity;
134 std::vector<set<size_t> > noLoopEvalHessSparsity;
135 std::vector<map<size_t, set<size_t> > > noLoopEvalHessLocations;
136 map<LoopModel<Base>*, loops::HessianWithLoopsInfo<Base> > loopHessInfo;
137
138 analyseSparseHessianWithLoops(hessRows, hessCols, hessOrder,
139 noLoopEvalJacSparsity, noLoopEvalHessSparsity,
140 noLoopEvalHessLocations, loopHessInfo, false);
141
142 /***********************************************************************
143 * generate the operation graph
144 **********************************************************************/
148 // temporaries (zero orders)
149 std::vector<CGBase> tmpsAlias;
150 if (_funNoLoops != nullptr) {
151 ADFun<CGBase>& fun = _funNoLoops->getTape();
152
153 tmpsAlias.resize(fun.Range() - nonIndexdedEqSize);
154 for (size_t k = 0; k < tmpsAlias.size(); k++) {
155 // to be defined later
156 tmpsAlias[k] = CG<Base>(*handler.makeNode(CGOpCode::Alias));
157 }
158 }
159
163 typename map<LoopModel<Base>*, HessianWithLoopsInfo<Base> >::iterator itLoop2Info;
164 for (itLoop2Info = loopHessInfo.begin(); itLoop2Info != loopHessInfo.end(); ++itLoop2Info) {
165 LoopModel<Base>& lModel = *itLoop2Info->first;
166 HessianWithLoopsInfo<Base>& info = itLoop2Info->second;
167
168 info.iterationIndexOp = handler.makeIndexNode(indexIterationDcl);
169 set<IndexOperationNode<Base>*> indexesOps;
170 indexesOps.insert(info.iterationIndexOp);
171
175 std::vector<CGBase> indexedIndeps = createIndexedIndependents(handler, lModel, *info.iterationIndexOp);
176 info.x = createLoopIndependentVector(handler, lModel, indexedIndeps, x, tmpsAlias);
177
178 info.w = createLoopDependentVector(handler, lModel, *info.iterationIndexOp);
179 }
180
187 bool hasAtomics = isAtomicsUsed(); // TODO: improve this by checking only the current fun
188 //const std::map<size_t, std::set<size_t> >& aaa = getAtomicsIndeps();
189
190 for (itLoop2Info = loopHessInfo.begin(); itLoop2Info != loopHessInfo.end(); ++itLoop2Info) {
191 LoopModel<Base>& lModel = *itLoop2Info->first;
192 HessianWithLoopsInfo<Base>& info = itLoop2Info->second;
193
194 _cache.str("");
195 _cache << "model (Jacobian + Hessian, loop " << lModel.getLoopId() << ")";
196 std::string jobName = _cache.str();
197
198 startingJob("'" + jobName + "'", JobTimer::GRAPH);
199
200 info.evalLoopModelJacobianHessian(hasAtomics);
201
202 finishedJob();
203 }
204
208 map<size_t, map<size_t, CGBase> > dzDx;
209 if (_funNoLoops != nullptr) {
210 ADFun<CGBase>& fun = _funNoLoops->getTape();
211 std::vector<CGBase> yNL(fun.Range());
212
216 startingJob("'model (Jacobian + Hessian, temporaries)'", JobTimer::GRAPH);
217
218 dzDx = _funNoLoops->calculateJacobianHessianUsedByLoops(handler,
219 loopHessInfo, x, yNL,
220 noLoopEvalJacSparsity,
221 hasAtomics);
222
223 finishedJob();
224
225 for (size_t i = 0; i < tmpsAlias.size(); i++)
226 tmpsAlias[i].getOperationNode()->getArguments().push_back(asArgument(yNL[nonIndexdedEqSize + i]));
227
228 for (itLoop2Info = loopHessInfo.begin(); itLoop2Info != loopHessInfo.end(); ++itLoop2Info) {
229 HessianWithLoopsInfo<Base>& info = itLoop2Info->second;
230 // not needed anymore:
231 info.dyiDzk.clear();
232 }
233 }
234
238 for (itLoop2Info = loopHessInfo.begin(); itLoop2Info != loopHessInfo.end(); ++itLoop2Info) {
239 LoopModel<Base>& lModel = *itLoop2Info->first;
240 HessianWithLoopsInfo<Base>& info = itLoop2Info->second;
241
242 /*******************************************************************
243 * create Hessian row groups
244 * for the contributions from the equations in loops
245 ******************************************************************/
247
248 generateHessianRowGroups(lModel, info, n, loopGroups);
249
250 /*******************************************************************
251 * generate the operation graph for each Hessian row subgroup
252 ******************************************************************/
253 for (size_t g = 0; g < loopGroups.size(); g++) {
254 HessianRowGroup<Base>& group = *loopGroups[g];
255
259 LoopStartOperationNode<Base>* loopStart = nullptr;
260
261 map<size_t, set<size_t> > localIterCount2Jrows;
262
263 for (const auto& itJrow2It : group.jRow2Iterations) {
264 size_t jrow = itJrow2It.first;
265 size_t itCount = itJrow2It.second.size();
266 localIterCount2Jrows[itCount].insert(jrow);
267 }
268
269 bool createsLoop = localIterCount2Jrows.size() != 1 || // is there a different number of it
270 localIterCount2Jrows.begin()->first != 1; // is there always just on iteration?
271
278 map<size_t, map<size_t, size_t> > jrow2localIt2ModelIt;
279
280 for (const auto& itJrow2It : group.jRow2Iterations) {
281 size_t jrow = itJrow2It.first;
282
283 map<size_t, size_t>& localIt2ModelIt = jrow2localIt2ModelIt[jrow];
284 size_t localIt = 0;
285 for (auto itIt = itJrow2It.second.begin(); itIt != itJrow2It.second.end(); ++itIt, localIt++) {
286 localIt2ModelIt[localIt] = *itIt;
287 }
288 }
289
294 std::unique_ptr<IndexPattern> itPattern(Plane2DIndexPattern::detectPlane2D(jrow2localIt2ModelIt));
295
296 if (itPattern.get() == nullptr) {
297 // did not match!
298 itPattern.reset(new Random2DIndexPattern(jrow2localIt2ModelIt));
299 }
300
304 IndexOperationNode<Base>* localIterIndexOp = nullptr;
305 IndexOperationNode<Base>* localIterCountIndexOp = nullptr;
306 IndexAssignOperationNode<Base>* itCountAssignOp = nullptr;
307 std::unique_ptr<IndexPattern> indexLocalItCountPattern;
308
309 if (createsLoop) {
310 map<size_t, size_t> jrow2litCount;
311
312 for (const auto& itJrow2Its : group.jRow2Iterations) {
313 size_t jrow = itJrow2Its.first;
314 jrow2litCount[jrow] = itJrow2Its.second.size();
315 }
316
317 indexLocalItCountPattern.reset(IndexPattern::detect(jrow2litCount));
318
319 if (IndexPattern::isConstant(*indexLocalItCountPattern.get())) {
320 size_t itCount = group.jRow2Iterations.begin()->second.size();
321 loopStart = handler.makeLoopStartNode(indexLocalItDcl, itCount);
322 } else {
323 itCountAssignOp = handler.makeIndexAssignNode(indexLocalItCountDcl, *indexLocalItCountPattern.get(), jrowIndexOp);
324 localIterCountIndexOp = handler.makeIndexNode(*itCountAssignOp);
325 loopStart = handler.makeLoopStartNode(indexLocalItDcl, *localIterCountIndexOp);
326 }
327
328 localIterIndexOp = handler.makeIndexNode(*loopStart);
329 }
330
331
332 auto* iterationIndexPatternOp = handler.makeIndexAssignNode(indexIterationDcl, *itPattern.get(), &jrowIndexOp, localIterIndexOp);
333 info.iterationIndexOp->makeAssigmentDependent(*iterationIndexPatternOp);
334
335 map<size_t, set<size_t> > jrow2CompressedLoc;
336 std::vector<pair<CG<Base>, IndexPattern*> > indexedLoopResults;
337
338 indexedLoopResults = generateReverseTwoGroupOps(handler, lModel, info,
339 group, tx1,
340 dzDx,
341 jrow2CompressedLoc);
342
343 _loopRev2Groups[&lModel][g] = jrow2CompressedLoc;
344
345 LoopEndOperationNode<Base>* loopEnd = nullptr;
346 std::vector<CGBase> pxCustom;
347 if (createsLoop) {
351 size_t assignOrAdd = 1;
352 set<IndexOperationNode<Base>*> indexesOps;
353 indexesOps.insert(info.iterationIndexOp);
354 loopEnd = createLoopEnd(handler, *loopStart, indexedLoopResults, indexesOps, assignOrAdd);
355
359 moveNonIndexedOutsideLoop(handler, *loopStart, *loopEnd);
360
364 pxCustom.resize(1);
365
366 // {0} : must point to itself since there is only one dependent
367 pxCustom[0] = handler.createCG(*handler.makeNode(CGOpCode::DependentRefRhs,{0},{*loopEnd}));
368
369 } else {
373 pxCustom.resize(indexedLoopResults.size());
374 for (size_t i = 0; i < indexedLoopResults.size(); i++) {
375 const CGBase& val = indexedLoopResults[i].first;
376 IndexPattern* ip = indexedLoopResults[i].second;
377
378 pxCustom[i] = createLoopDependentFunctionResult(handler, i, val, ip, *info.iterationIndexOp);
379 }
380
381 }
382
383 LanguageC<Base> langC(_baseTypeName);
384 langC.setFunctionIndexArgument(indexJrowDcl);
385 langC.setParameterPrecision(_parameterPrecision);
386
387 std::ostringstream code;
388 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("px"));
389 LangCDefaultReverse2VarNameGenerator<Base> nameGenRev2(nameGen.get(), n, 1);
390
394 _cache.str("");
395 _cache << "model (reverse two, loop " << lModel.getLoopId() << ", group " << g << ")";
396 string jobName = _cache.str();
397 handler.generateCode(code, langC, pxCustom, nameGenRev2, _atomicFunctions, jobName);
398
399 _cache.str("");
400 generateFunctionNameLoopRev2(_cache, lModel, g);
401 std::string functionName = _cache.str();
402
403 std::string argsDcl = langC.generateFunctionArgumentsDcl();
404
405 _cache.str("");
406 _cache << "#include <stdlib.h>\n"
407 "#include <math.h>\n"
408 "\n"
410 "\n"
411 "void " << functionName << "(" << argsDcl << ") {\n";
412 nameGenRev2.customFunctionVariableDeclarations(_cache);
413 _cache << langC.generateIndependentVariableDeclaration() << "\n";
414 _cache << langC.generateDependentVariableDeclaration() << "\n";
415 _cache << langC.generateTemporaryVariableDeclaration(false, false,
417 handler.getExternalFuncMaxReverseOrder()) << "\n";
418 nameGenRev2.prepareCustomFunctionVariables(_cache);
419
420 // code inside the loop
421 _cache << code.str();
422
423 nameGenRev2.finalizeCustomFunctionVariables(_cache);
424 _cache << "}\n\n";
425
426 _sources[functionName + ".c"] = _cache.str();
427 _cache.str("");
428
432 if (g + 1 < loopGroups.size()) {
433 handler.resetNodes(); // uncolor nodes
434 }
435 }
436
437 }
438
439 /*******************************************************************
440 * equations NOT in loops
441 ******************************************************************/
442 if (_funNoLoops != nullptr) {
443 ADFun<CGBase>& fun = _funNoLoops->getTape();
444
448 std::vector<size_t> row, col;
449 generateSparsityIndexes(noLoopEvalHessSparsity, row, col);
450
451 if (row.size() > 0) {
452 const string jobName = "model (reverse two, no loops)";
453 startingJob("'" + jobName + "'", JobTimer::SOURCE_GENERATION);
454
455 // we can use a new handler to reduce memory usage
456 CodeHandler<Base> handlerNL;
457 handlerNL.setJobTimer(_jobTimer);
458
459 std::vector<CGBase> tx0(n);
460 handlerNL.makeVariables(tx0);
461 if (_x.size() > 0) {
462 for (size_t i = 0; i < n; i++) {
463 tx0[i].setValue(_x[i]);
464 }
465 }
466
467 CGBase tx1;
468 handlerNL.makeVariable(tx1);
469 if (_x.size() > 0) {
470 tx1.setValue(Base(1.0));
471 }
472
473 std::vector<CGBase> py(m); // (k+1)*m is not used because we are not interested in all values
474 handlerNL.makeVariables(py);
475
476 std::vector<CGBase> pyNoLoop(_funNoLoops->getTapeDependentCount());
477
478 const std::vector<size_t>& origIndexes = _funNoLoops->getOrigDependentIndexes();
479 for (size_t inl = 0; inl < origIndexes.size(); inl++) {
480 pyNoLoop[inl] = py[origIndexes[inl]];
481 if (_x.size() > 0) {
482 pyNoLoop[inl].setValue(Base(1.0));
483 }
484 }
485
486 std::vector<CGBase> hessNoLoop(row.size());
487
488 CppAD::sparse_hessian_work work; // temporary structure for CPPAD
489 // "cppad.symmetric" may have missing values for functions using
490 // atomic functions which only provide half of the elements
491 // (some values could be zeroed)
492 work.color_method = "cppad.general";
493 fun.SparseHessian(tx0, pyNoLoop, _funNoLoops->getHessianOrigEqsSparsity(), row, col, hessNoLoop, work);
494
495 map<size_t, map<size_t, CGBase> > hess;
496 // save non-indexed hessian elements
497 for (size_t el = 0; el < row.size(); el++) {
498 size_t j1 = row[el];
499 size_t j2 = col[el];
500 const set<size_t>& locations = noLoopEvalHessLocations[j1][j2];
501 for (size_t itE : locations) {
502 hess[j1][itE] = hessNoLoop[el];
503 _nonLoopRev2Elements[j1].insert(itE);
504 }
505 }
506
510 for (const auto& it : hess) {
511 size_t j = it.first;
512 const map<size_t, CGBase>& cols = it.second;
513
514 _cache.str("");
515 _cache << "model (reverse two, no loops, indep " << j << ")";
516 const string subJobName = _cache.str();
517
518 std::vector<CGBase> pxCustom(elements.at(j).size());
519
520 for (const auto& it2 : cols) {
521 size_t e = it2.first;
522 pxCustom[e] = it2.second * tx1;
523 }
524
525 LanguageC<Base> langC(_baseTypeName);
526 langC.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
527 langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
528 langC.setParameterPrecision(_parameterPrecision);
529 _cache.str("");
530 _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "_noloop_indep" << j;
531 string functionName = _cache.str();
532 langC.setGenerateFunction(functionName);
533
534 std::ostringstream code;
535 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("px"));
536 LangCDefaultReverse2VarNameGenerator<Base> nameGenRev2(nameGen.get(), n, 1);
537
538 handlerNL.generateCode(code, langC, pxCustom, nameGenRev2, _atomicFunctions, subJobName);
539 }
540
541 finishedJob();
542 }
543
544 }
545
549 string functionRev2 = _name + "_" + FUNCTION_SPARSE_REVERSE_TWO;
550 _sources[functionRev2 + ".c"] = generateGlobalForRevWithLoopsFunctionSource(elements,
551 _loopRev2Groups, _nonLoopRev2Elements,
552 functionRev2, _name, _baseTypeName, "indep",
553 generateFunctionNameLoopRev2);
557 _cache.str("");
558 generateSparsity1DSource2(_name + "_" + FUNCTION_REVERSE_TWO_SPARSITY, elements);
559 _sources[_name + "_" + FUNCTION_REVERSE_TWO_SPARSITY + ".c"] = _cache.str();
560 _cache.str("");
561}
562
563namespace loops {
564
565template<class Base>
566void generateHessianRowGroups(const LoopModel<Base>& lModel,
567 const HessianWithLoopsInfo<Base>& info,
568 size_t n,
570 using namespace std;
571 using namespace CppAD::cg::loops;
572
576 map<pairss, map<size_t, set<size_t> > > indexedIndexed2jrow2Iter;
577 map<pairss, map<size_t, set<size_t> > > indexedNonIndexed2jrow2Iter;
578 map<pairss, map<size_t, set<size_t> > > indexedTemp2jrow2Iter;
579 map<pairss, map<size_t, set<size_t> > > nonIndexedIndexed2jrow2Iter;
580 map<pairss, map<size_t, set<size_t> > > tempIndexed2jrow2Iter;
581
582 map<HessianTermContrib<Base>, set<size_t> > contrib2jrows = groupHessianRowsByContrib(info, n,
583 indexedIndexed2jrow2Iter,
584 indexedNonIndexed2jrow2Iter,
585 indexedTemp2jrow2Iter,
586 nonIndexedIndexed2jrow2Iter,
587 tempIndexed2jrow2Iter);
588
589 loopGroups.reserve(contrib2jrows.size() *2); // TODO: improve this
590
591 for (const auto& itC : contrib2jrows) {
592 const HessianTermContrib<Base>& c = itC.first;
593 const set<size_t>& jrows = itC.second;
594
598 subgroupHessianRowsByContrib(info, c, jrows,
599 indexedIndexed2jrow2Iter,
600 indexedNonIndexed2jrow2Iter,
601 indexedTemp2jrow2Iter,
602 nonIndexedIndexed2jrow2Iter,
603 tempIndexed2jrow2Iter,
604 loopGroups);
605 }
606
607}
608
609template<class Base>
610std::vector<std::pair<CG<Base>, IndexPattern*> > generateReverseTwoGroupOps(CodeHandler<Base>& handler,
611 const LoopModel<Base>& lModel,
612 const HessianWithLoopsInfo<Base>& info,
614 const CG<Base>& tx1,
615 const std::map<size_t, std::map<size_t, CG<Base> > >& dzDx,
616 std::map<size_t, std::set<size_t> >& jrow2CompressedLoc) {
617 using namespace std;
618 using namespace CppAD::cg::loops;
619
620 using CGBase = CG<Base>;
621
622 IndexOperationNode<Base>& iterationIndexOp = *info.iterationIndexOp;
623
624 // store results in indexedLoopResults
625 size_t hessElSize = group.size();
626
627 std::vector<pair<CGBase, IndexPattern*> > indexedLoopResults(hessElSize);
628 size_t hessLE = 0;
629
630 map<pairss, std::vector<HessianElement> >::const_iterator itPos;
631
635 for (size_t g = 0; g < info.equationGroups.size(); g++) {
636
637 const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
638
639 /***************************************************************
640 * indexed - indexed
641 */
642 for (const pairss& it : group.indexedIndexed) {
643 size_t tapeJ1 = it.first;
644 size_t tapeJ2 = it.second;
645
646 itPos = infog.indexedIndexedPositions.find(it);
647 if (itPos != infog.indexedIndexedPositions.end()) {
648 const std::vector<HessianElement>& positions = itPos->second;
649
650 addContribution(indexedLoopResults, hessLE,
651 createReverseMode2Contribution(handler, group,
652 positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
653 iterationIndexOp,
654 jrow2CompressedLoc));
655 }
656 }
657
661 for (const pairss& it : group.indexedNonIndexed) {
662 size_t tapeJ1 = it.first;
663 size_t tapeJ2 = it.second;
664
665 itPos = infog.indexedNonIndexedPositions.find(it);
666 if (itPos != infog.indexedNonIndexedPositions.end()) {
667 const std::vector<HessianElement>& positions = itPos->second;
668
669 addContribution(indexedLoopResults, hessLE,
670 createReverseMode2Contribution(handler, group,
671 positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
672 iterationIndexOp,
673 jrow2CompressedLoc));
674 }
675 }
676
680 for (const pairss& it : group.indexedTemp) {
681 size_t tapeJ1 = it.first;
682 size_t j2 = it.second;
683
684 itPos = infog.indexedTempPositions.find(it);
685 if (itPos != infog.indexedTempPositions.end()) {
686 const std::vector<HessianElement>& positions = itPos->second;
687 const set<size_t>& ks = infog.indexedTempEvals.at(it);
688
689 CGBase val = Base(0);
690 for (size_t k : ks) {
691 size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
692 val += infog.hess.at(tapeJ1).at(tapeK) * dzDx.at(k).at(j2);
693 }
694
695 addContribution(indexedLoopResults, hessLE,
696 createReverseMode2Contribution(handler, group,
697 positions, val, tx1,
698 iterationIndexOp,
699 jrow2CompressedLoc));
700 }
701 }
702
703
704 /***************************************************************
705 * non-indexed - indexed
706 */
707 for (const pairss& it : group.nonIndexedIndexed) {
708 size_t tapeJ1 = it.first;
709 size_t tapeJ2 = it.second;
710
711 itPos = infog.nonIndexedIndexedPositions.find(it);
712 if (itPos != infog.nonIndexedIndexedPositions.end()) {
713 const std::vector<HessianElement>& positions = itPos->second;
714
715 addContribution(indexedLoopResults, hessLE,
716 createReverseMode2Contribution(handler, group,
717 positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
718 iterationIndexOp,
719 jrow2CompressedLoc));
720 }
721 }
722
723 /***************************************************************
724 * temporary - indexed
725 *
726 * d f_i . d x_k1
727 * d x_l2 d z_k1 d x_j1
728 */
729 for (const pairss& it : group.tempIndexed) {
730 size_t j1 = it.first;
731 size_t tapeJ2 = it.second;
732
733 itPos = infog.tempIndexedPositions.find(it);
734 if (itPos != infog.tempIndexedPositions.end()) {
735 const std::vector<HessianElement>& positions = itPos->second;
736 const set<size_t>& ks = infog.indexedTempEvals.at(pairss(tapeJ2, j1));
737
738 CGBase val = Base(0);
739 for (size_t k : ks) {
740 size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
741 val += infog.hess.at(tapeK).at(tapeJ2) * dzDx.at(k).at(j1);
742 }
743
744 addContribution(indexedLoopResults, hessLE,
745 createReverseMode2Contribution(handler, group,
746 positions, val, tx1,
747 iterationIndexOp,
748 jrow2CompressedLoc));
749 }
750 }
751 }
752
753 /*******************************************************************
754 * contributions to a constant location
755 */
756 for (const pairss& orig : group.nonIndexedNonIndexed) {
757 size_t e = info.nonIndexedNonIndexedPosition.at(orig);
758
759 size_t j1 = orig.first;
760 size_t j2 = orig.second;
761 const LoopPosition* posJ1 = lModel.getNonIndexedIndepIndexes(j1);
762 const LoopPosition* posJ2 = lModel.getNonIndexedIndepIndexes(j2);
763
764 // location
765 LinearIndexPattern* pattern = new LinearIndexPattern(0, 0, 0, e);
766 handler.manageLoopDependentIndexPattern(pattern);
767
771 CGBase hessVal = Base(0);
772
776 for (size_t g = 0; g < info.equationGroups.size(); g++) {
777 const IterEquationGroup<Base>& eqGroup = lModel.getEquationsGroups()[g];
778 set<size_t> iterations;
779 set_intersection(group.iterations.begin(), group.iterations.end(),
780 eqGroup.iterations.begin(), eqGroup.iterations.end(),
781 std::inserter(iterations, iterations.begin()));
782
783 CGBase gHessVal = Base(0);
784 const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
785
786 if (infog.nonIndexedNonIndexedEvals.find(orig) != infog.nonIndexedNonIndexedEvals.end()) {
787 gHessVal = infog.hess.at(posJ1->tape).at(posJ2->tape);
788 }
789
793 const auto itNT = infog.nonIndexedTempEvals.find(orig);
794 if (itNT != infog.nonIndexedTempEvals.end()) {
795 const set<size_t>& ks = itNT->second;
796
797 for (size_t k : ks) {
798 size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
799 gHessVal += infog.hess.at(posJ1->tape).at(tapeK) * dzDx.at(k).at(j2);
800 }
801 }
802
809 const auto itTN = infog.tempNonIndexedEvals.find(orig);
810 if (itTN != infog.tempNonIndexedEvals.end()) {
811 const set<size_t>& ks = itTN->second;
812
813 for (size_t k1 : ks) {
814 size_t tapeK = lModel.getTempIndepIndexes(k1)->tape;
815 gHessVal += infog.hess.at(tapeK).at(posJ2->tape) * dzDx.at(k1).at(j1);
816 }
817 }
818
822 const auto itTT = infog.tempTempEvals.find(orig);
823 if (itTT != infog.tempTempEvals.end()) {
824 const map<size_t, set<size_t> >& k1k2 = itTT->second;
825
826 CGBase sum = Base(0);
827
828 for (const auto& itzz : k1k2) {
829 size_t k1 = itzz.first;
830 const set<size_t>& k2s = itzz.second;
831 size_t tapeK1 = lModel.getTempIndepIndexes(k1)->tape;
832
833 CGBase tmp = Base(0);
834 for (size_t k2 : k2s) {
835 size_t tapeK2 = lModel.getTempIndepIndexes(k2)->tape;
836
837 tmp += infog.hess.at(tapeK1).at(tapeK2) * dzDx.at(k2).at(j2);
838 }
839
840 sum += tmp * dzDx.at(k1).at(j1);
841 }
842
843 gHessVal += sum;
844 }
845
846 if (iterations.size() != group.iterations.size()) {
847 CGBase v = createReverseMode2Contribution(handler, group,
848 *pattern, iterations,
849 gHessVal,
850 *info.iterationIndexOp,
851 group.ifElses);
852 addContribution(indexedLoopResults, hessLE, make_pair(v, (IndexPattern*) nullptr));
853 jrow2CompressedLoc[j1].insert(e);
854 } else {
855 hessVal += gHessVal;
856 }
857 }
858
862 const auto itTT2 = info.nonLoopNonIndexedNonIndexed.find(orig);
863 if (itTT2 != info.nonLoopNonIndexedNonIndexed.end()) {
864 hessVal += info.dzDxx.at(j1).at(j2); // it is already the sum of ddz / dx_j1 dx_j2
865 }
866
867 hessVal *= tx1;
868
869 // place the result
870 if (!hessVal.isIdenticalZero()) {
871 addContribution(indexedLoopResults, hessLE, make_pair(hessVal, (IndexPattern*) pattern));
872
873 jrow2CompressedLoc[j1].insert(e);
874 }
875 }
876
877 indexedLoopResults.resize(hessLE);
878
879 return indexedLoopResults;
880}
881
886 size_t jrow;
887 std::set<size_t> iterations;
888
889 inline Reverse2Jrow2Iter() {
890 }
891
892 inline Reverse2Jrow2Iter(size_t row,
893 const std::set<size_t>& iters) :
894 jrow(row),
895 iterations(iters) {
896 }
897};
898
899inline bool operator<(const Reverse2Jrow2Iter& l, const Reverse2Jrow2Iter& r) {
900 if (l.jrow < r.jrow)
901 return true;
902 else if (l.jrow > r.jrow)
903 return false;
904
905 return compare(l.iterations, r.iterations) == -1;
906}
907
911template<class Base>
912inline std::map<HessianTermContrib<Base>, std::set<size_t> > groupHessianRowsByContrib(const loops::HessianWithLoopsInfo<Base>& info,
913 size_t n,
914 std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedIndexed2jrow2Iter,
915 std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedNonIndexed2jrow2Iter,
916 std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedTemp2jrow2Iter,
917 std::map<pairss, std::map<size_t, std::set<size_t> > >& nonIndexedIndexed2jrow2Iter,
918 std::map<pairss, std::map<size_t, std::set<size_t> > >& tempIndexed2jrow2Iter) {
919 using namespace std;
920
921 size_t nIterations = info.model->getIterationCount();
922
926 std::vector<HessianTermContrib<Base> > jrows(n);
927
928 for (size_t g = 0; g < info.equationGroups.size(); g++) {
929 const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
930
931 // indexed-indexed
932 for (const auto& it : infog.indexedIndexedPositions) {
933 map<size_t, set<size_t> >& jrow2Iter = indexedIndexed2jrow2Iter[it.first];
934 const std::vector<HessianElement>& positions = it.second;
935 for (size_t iter = 0; iter < nIterations; iter++) {
936 if (positions[iter].count > 0) {
937 jrows[positions[iter].row].indexedIndexed.insert(it.first);
938 jrow2Iter[positions[iter].row].insert(iter);
939 }
940 }
941 }
942
943 // indexed - non-indexed
944 for (const auto& it : infog.indexedNonIndexedPositions) {
945 map<size_t, set<size_t> >& jrow2Iter = indexedNonIndexed2jrow2Iter[it.first];
946 const std::vector<HessianElement>& positions = it.second;
947 for (size_t iter = 0; iter < nIterations; iter++) {
948 if (positions[iter].count > 0) {
949 jrows[positions[iter].row].indexedNonIndexed.insert(it.first);
950 jrow2Iter[positions[iter].row].insert(iter);
951 }
952 }
953 }
954
955 // indexed - temporary
956 for (const auto& it : infog.indexedTempPositions) {
957 map<size_t, set<size_t> >& jrow2Iter = indexedTemp2jrow2Iter[it.first];
958 const std::vector<HessianElement>& positions = it.second;
959 for (size_t iter = 0; iter < nIterations; iter++) {
960 if (positions[iter].count > 0) {
961 jrows[positions[iter].row].indexedTemp.insert(it.first);
962 jrow2Iter[positions[iter].row].insert(iter);
963 }
964 }
965 }
966
967 // non-indexed - indexed
968 for (const auto& it : infog.nonIndexedIndexedPositions) {
969 map<size_t, set<size_t> >& jrow2Iter = nonIndexedIndexed2jrow2Iter[it.first];
970 const std::vector<HessianElement>& positions = it.second;
971 for (size_t iter = 0; iter < nIterations; iter++) {
972 if (positions[iter].count > 0) {
973 jrows[positions[iter].row].nonIndexedIndexed.insert(it.first);
974 jrow2Iter[positions[iter].row].insert(iter);
975 }
976 }
977 }
978
979 // temporary - indexed
980 for (const auto& it : infog.tempIndexedPositions) {
981 map<size_t, set<size_t> >& jrow2Iter = tempIndexed2jrow2Iter[it.first];
982 const std::vector<HessianElement>& positions = it.second;
983 for (size_t iter = 0; iter < nIterations; iter++) {
984 if (positions[iter].count > 0) {
985 jrows[positions[iter].row].tempIndexed.insert(it.first);
986 jrow2Iter[positions[iter].row].insert(iter);
987 }
988 }
989 }
990 }
991
992 // non-indexed - non-indexed
993 for (const auto& orig2PosIt : info.nonIndexedNonIndexedPosition) {
994 size_t j1 = orig2PosIt.first.first;
995 jrows[j1].nonIndexedNonIndexed.insert(orig2PosIt.first);
996 }
997
1001 map<HessianTermContrib<Base>, set<size_t> > contrib2jrows;
1002 for (size_t j = 0; j < n; j++) {
1003 if (!jrows[j].empty())
1004 contrib2jrows[jrows[j]].insert(j);
1005 }
1006
1007 return contrib2jrows;
1008}
1009
1016template<class Base>
1017inline void subgroupHessianRowsByContrib(const HessianWithLoopsInfo<Base>& info,
1018 const HessianTermContrib<Base>& c,
1019 const std::set<size_t>& jrows,
1020 const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedIndexed2jrow2Iter,
1021 const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedNonIndexed2jrow2Iter,
1022 const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedTemp2jrow2Iter,
1023 const std::map<pairss, std::map<size_t, std::set<size_t> > >& nonIndexedIndexed2jrow2Iter,
1024 const std::map<pairss, std::map<size_t, std::set<size_t> > >& tempIndexed2jrow2Iter,
1026 using namespace std;
1027
1028 map<Reverse2Jrow2Iter, HessianTermContrib<Base> > contribs;
1029
1030 set<pairss>::const_iterator it;
1031 map<size_t, set<size_t> >::const_iterator itJrow2Iter;
1032
1033 // indexed - indexed
1034 for (pairss pos : c.indexedIndexed) {
1035 map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedIndexed2jrow2Iter.at(pos), jrows);
1036 for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1037 Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1038 contribs[k].indexedIndexed.insert(pos);
1039 }
1040 }
1041
1042 // indexed - non-indexed
1043 for (pairss pos : c.indexedNonIndexed) {
1044 map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedNonIndexed2jrow2Iter.at(pos), jrows);
1045 for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1046 Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1047 contribs[k].indexedNonIndexed.insert(pos);
1048 }
1049 }
1050
1051 // indexed - temporary
1052 for (pairss pos : c.indexedTemp) {
1053 map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedTemp2jrow2Iter.at(pos), jrows);
1054 for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1055 Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1056 contribs[k].indexedTemp.insert(pos);
1057 }
1058 }
1059
1060 // non-indexed - indexed
1061 for (pairss pos : c.nonIndexedIndexed) {
1062 map<size_t, set<size_t> > jrow2Iter = filterBykeys(nonIndexedIndexed2jrow2Iter.at(pos), jrows);
1063 for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1064 Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1065 contribs[k].nonIndexedIndexed.insert(pos);
1066 }
1067 }
1068
1069 // non-indexed - non-indexed
1070 if (!c.nonIndexedNonIndexed.empty()) {
1071 set<size_t> allIters;
1072 size_t nIterations = info.model->getIterationCount();
1073 for (size_t iter = 0; iter < nIterations; iter++)
1074 allIters.insert(allIters.end(), iter);
1075
1076 for (pairss pos : c.nonIndexedNonIndexed) {
1077 Reverse2Jrow2Iter k(pos.first, allIters);
1078 contribs[k].nonIndexedNonIndexed.insert(pos);
1079 }
1080 }
1081
1082 // temporary - indexed
1083 for (pairss pos : c.tempIndexed) {
1084 map<size_t, set<size_t> > jrow2Iter = filterBykeys(tempIndexed2jrow2Iter.at(pos), jrows);
1085 for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1086 Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1087 contribs[k].tempIndexed.insert(pos);
1088 }
1089 }
1090
1094 map<HessianTermContrib<Base>, HessianRowGroup<Base>*> c2subgroups; // add pair<jrow, set<iter> > here
1095
1096 for (const auto& itK2C : contribs) {
1097 const Reverse2Jrow2Iter& jrow2Iters = itK2C.first;
1098 const HessianTermContrib<Base>& hc = itK2C.second;
1099
1100 const auto its = c2subgroups.find(hc);
1101 if (its != c2subgroups.end()) {
1102 HessianRowGroup<Base>* sg = its->second;
1103 sg->jRow2Iterations[jrow2Iters.jrow] = jrow2Iters.iterations;
1104 sg->iterations.insert(jrow2Iters.iterations.begin(), jrow2Iters.iterations.end());
1105 } else {
1106 HessianRowGroup<Base>* sg = new HessianRowGroup<Base>(hc, jrow2Iters);
1107 subGroups.push_back(sg);
1108 c2subgroups[hc] = sg;
1109 }
1110 }
1111}
1112
1113template<class Base>
1114std::pair<CG<Base>, IndexPattern*> createReverseMode2Contribution(CodeHandler<Base>& handler,
1115 HessianRowGroup<Base>& group,
1116 const std::vector<HessianElement>& positions,
1117 const CG<Base>& ddfdxdx,
1118 const CG<Base>& tx1,
1119 IndexOperationNode<Base>& iterationIndexOp,
1120 std::map<size_t, std::set<size_t> >& jrow2CompressedLoc) {
1121 using namespace std;
1122
1123 if (ddfdxdx.isIdenticalZero()) {
1124 return make_pair(ddfdxdx, (IndexPattern*) nullptr);
1125 }
1126
1130 std::map<size_t, size_t> iteration2pos;
1131
1132 // combine iterations with the same number of additions
1133 map<size_t, map<size_t, size_t> > locations;
1134 for (size_t iter : group.iterations) {
1135 size_t c = positions[iter].count;
1136 if (c > 0) {
1137 locations[c][iter] = positions[iter].location;
1138 iteration2pos[iter] = positions[iter].location;
1139 jrow2CompressedLoc[positions[iter].row].insert(positions[iter].location);
1140 }
1141 }
1142
1143 if (locations.empty()) {
1144 return make_pair(CG<Base>(Base(0)), (IndexPattern*) nullptr);
1145 }
1146
1147 map<size_t, CG<Base> > results;
1148
1149 // generate the index pattern for the Hessian compressed element
1150 for (const auto& countIt : locations) {
1151 size_t count = countIt.first;
1152
1153 CG<Base> val = ddfdxdx;
1154 for (size_t c = 1; c < count; c++)
1155 val += ddfdxdx;
1156
1157 results[count] = val * tx1;
1158 }
1159
1160 if (results.size() == 1 && locations.begin()->second.size() == group.iterations.size()) {
1161 // same expression present in all iterations
1162
1163 // generate the index pattern for the Hessian compressed element
1164 IndexPattern* pattern = IndexPattern::detect(locations.begin()->second);
1165 handler.manageLoopDependentIndexPattern(pattern);
1166
1167 return make_pair(results.begin()->second, pattern);
1168
1169 } else {
1175 map<size_t, IfBranchData<Base> > branches;
1176
1177 // try to find an existing if-else where these operations can be added
1178 for (const auto& countIt : locations) {
1179 size_t count = countIt.first;
1180 IfBranchData<Base> branch(results[count], countIt.second);
1181 branches[count] = branch;
1182 }
1183
1184 CG<Base> v = createConditionalContribution(handler,
1185 branches,
1186 positions.size() - 1,
1187 group.iterations.size(),
1188 iterationIndexOp,
1189 group.ifElses);
1190
1191 return make_pair(v, (IndexPattern*) nullptr);
1192 }
1193
1194}
1195
1199template<class Base>
1200CG<Base> createReverseMode2Contribution(CodeHandler<Base>& handler,
1201 HessianRowGroup<Base>& group,
1202 LinearIndexPattern& pattern,
1203 const std::set<size_t>& iterations,
1204 const CG<Base>& ddfdxdx,
1205 IndexOperationNode<Base>& iterationIndexOp,
1206 std::vector<IfElseInfo<Base> >& ifElses) {
1207 using namespace std;
1208
1209 if (ddfdxdx.isIdenticalZero()) {
1210 return ddfdxdx;
1211 }
1212
1213 CPPADCG_ASSERT_UNKNOWN(pattern.getLinearSlopeDy() == 0); // must be a constant index
1214
1215 if (iterations.size() == group.iterations.size()) {
1216 // same expression present in all iterations
1217 return ddfdxdx;
1218
1219 } else {
1225 return createConditionalContribution(handler, pattern,
1226 iterations, *group.iterations.rbegin(),
1227 ddfdxdx, iterationIndexOp,
1228 ifElses);
1229 }
1230}
1231
1235template<class Base>
1237public:
1238 // (tapeJ1, tapeJ2)
1239 std::set<pairss> indexedIndexed;
1240 // (tapeJ1, tapeJ2(j2))
1241 std::set<pairss> indexedNonIndexed;
1242 // (tapeJ1, j2)
1243 std::set<pairss> indexedTemp;
1244 // (tapeJ1(j1), tapeJ2)
1245 std::set<pairss> nonIndexedIndexed;
1246 //(j1, j2)
1247 std::set<pairss> nonIndexedNonIndexed;
1248 // (j1, tapeJ2)
1249 std::set<pairss> tempIndexed;
1250
1251public:
1252
1253 inline bool empty() const {
1254 return indexedIndexed.empty() && indexedNonIndexed.empty() && indexedTemp.empty() &&
1255 nonIndexedIndexed.empty() && nonIndexedNonIndexed.empty() &&
1256 tempIndexed.empty();
1257 }
1258
1259 inline size_t size() const {
1260 return indexedIndexed.size() + indexedNonIndexed.size() + indexedTemp.size() +
1261 nonIndexedIndexed.size() + nonIndexedNonIndexed.size() +
1262 tempIndexed.size();
1263 }
1264};
1265
1266template<class Base>
1267bool operator<(const HessianTermContrib<Base>& l, const HessianTermContrib<Base>& r) {
1268 int c = compare(l.indexedIndexed, r.indexedIndexed);
1269 if (c != 0) return c == -1;
1270 c = compare(l.indexedNonIndexed, r.indexedNonIndexed);
1271 if (c != 0) return c == -1;
1272 c = compare(l.indexedTemp, r.indexedTemp);
1273 if (c != 0) return c == -1;
1274 c = compare(l.nonIndexedIndexed, r.nonIndexedIndexed);
1275 if (c != 0) return c == -1;
1276 c = compare(l.nonIndexedNonIndexed, r.nonIndexedNonIndexed);
1277 if (c != 0) return c == -1;
1278 c = compare(l.tempIndexed, r.tempIndexed);
1279 if (c != 0) return c == -1;
1280 return false;
1281}
1282
1287template<class Base>
1289public:
1290 // all the required iterations for each jrow
1291 std::map<size_t, std::set<size_t> > jRow2Iterations;
1292 // all iterations
1293 std::set<size_t> iterations;
1294 // if-else branches
1295 std::vector<IfElseInfo<Base> > ifElses;
1296public:
1297
1299 const Reverse2Jrow2Iter& jrow2Iters) :
1301 iterations(jrow2Iters.iterations) {
1302 jRow2Iterations[jrow2Iters.jrow] = jrow2Iters.iterations;
1303 }
1304};
1305
1306} // END loops namespace
1307
1308template<class Base>
1309void ModelCSourceGen<Base>::generateFunctionNameLoopRev2(std::ostringstream& cache,
1310 const LoopModel<Base>& loop,
1311 size_t g) {
1312 generateFunctionNameLoopRev2(cache, _name, loop, g);
1313}
1314
1315template<class Base>
1316void ModelCSourceGen<Base>::generateFunctionNameLoopRev2(std::ostringstream& cache,
1317 const std::string& modelName,
1318 const LoopModel<Base>& loop,
1319 size_t g) {
1320 cache << modelName << "_" << FUNCTION_SPARSE_REVERSE_TWO <<
1321 "_loop" << loop.getLoopId() << "_g" << g;
1322}
1323
1324} // END cg namespace
1325} // END CppAD namespace
1326
1327#endif
void setValue(const Base &val)
Definition variable.hpp:54
const std::vector< int > & getExternalFuncMaxReverseOrder() const
void makeVariables(VectorCG &variables)
void makeVariable(AD< CGB > &variable)
void setZeroDependents(bool zeroDependents)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
const std::vector< int > & getExternalFuncMaxForwardOrder() const
static IndexPattern * detect(const VectorSizeT &x2y)
std::set< size_t > iterations
iterations which only have these equations defined
virtual void setParameterPrecision(size_t p)
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
const std::vector< IterEquationGroup< Base > > & getEquationsGroups() const
size_t getLoopId() const
const LoopPosition * getTempIndepIndexes(size_t k) const
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
virtual void prepareSparseReverseTwoWithLoops(const std::map< size_t, std::vector< size_t > > &elements)
static Plane2DIndexPattern * detectPlane2D(const std::map< size_t, std::map< size_t, size_t > > &x2y2z)
std::map< size_t, std::map< size_t, CG< Base > > > hess
std::vector< std::map< size_t, CG< Base > > > dyiDzk
void evalLoopModelJacobianHessian(bool individualColoring)