CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
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 
18 namespace CppAD {
19 namespace cg {
20 
21 /***************************************************************************
22  * Utility classes and functions
23  **************************************************************************/
24 namespace loops {
25 
26 template<class Base>
27 class HessianWithLoopsInfo;
28 
29 template<class Base>
31 
32 template<class Base>
33 bool operator<(const HessianTermContrib<Base>& l, const HessianTermContrib<Base>& r);
34 
35 template<class Base>
36 class HessianRowGroup;
37 
38 template<class Base>
39 std::vector<std::pair<CG<Base>, IndexPattern*> > generateReverseTwoGroupOps(CodeHandler<Base>& handler,
40  const LoopModel<Base>& lModel,
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 
47 template<class Base>
48 std::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 
61 template<class Base>
62 void 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 
563 namespace loops {
564 
565 template<class Base>
566 void 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 
609 template<class Base>
610 std::vector<std::pair<CG<Base>, IndexPattern*> > generateReverseTwoGroupOps(CodeHandler<Base>& handler,
611  const LoopModel<Base>& lModel,
612  const HessianWithLoopsInfo<Base>& info,
613  HessianRowGroup<Base>& group,
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 
899 inline 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 
911 template<class Base>
912 inline 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 
1016 template<class Base>
1017 inline 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 
1113 template<class Base>
1114 std::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 
1199 template<class Base>
1200 CG<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 
1235 template<class Base>
1236 class HessianTermContrib {
1237 public:
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 
1251 public:
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 
1266 template<class Base>
1267 bool 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 
1287 template<class Base>
1288 class HessianRowGroup : public HessianTermContrib<Base> {
1289 public:
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;
1296 public:
1297 
1298  inline HessianRowGroup(const HessianTermContrib<Base>& c,
1299  const Reverse2Jrow2Iter& jrow2Iters) :
1301  iterations(jrow2Iters.iterations) {
1302  jRow2Iterations[jrow2Iters.jrow] = jrow2Iters.iterations;
1303  }
1304 };
1305 
1306 } // END loops namespace
1307 
1308 template<class Base>
1309 void ModelCSourceGen<Base>::generateFunctionNameLoopRev2(std::ostringstream& cache,
1310  const LoopModel<Base>& loop,
1311  size_t g) {
1312  generateFunctionNameLoopRev2(cache, _name, loop, g);
1313 }
1314 
1315 template<class Base>
1316 void 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 evalLoopModelJacobianHessian(bool individualColoring)
std::map< size_t, std::map< size_t, CG< Base > > > hess
STL namespace.
void setValue(const Base &val)
Definition: variable.hpp:54
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
Definition: language_c.hpp:273
static Plane2DIndexPattern * detectPlane2D(const std::map< size_t, std::map< size_t, size_t > > &x2y2z)
size_t getLoopId() const
Definition: loop_model.hpp:236
std::vector< std::map< size_t, CG< Base > > > dyiDzk
const std::vector< int > & getExternalFuncMaxForwardOrder() const
static IndexPattern * detect(const VectorSizeT &x2y)
void makeVariables(VectorCG &variables)
const LoopPosition * getTempIndepIndexes(size_t k) const
Definition: loop_model.hpp:357
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
Definition: language_c.hpp:252
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:237
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
Definition: loop_model.hpp:316
virtual void prepareSparseReverseTwoWithLoops(const std::map< size_t, std::vector< size_t > > &elements)
const std::vector< IterEquationGroup< Base > > & getEquationsGroups() const
Definition: loop_model.hpp:298
void setZeroDependents(bool zeroDependents)
const std::vector< int > & getExternalFuncMaxReverseOrder() const
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
std::set< size_t > iterations
iterations which only have these equations defined