CppADCodeGen  2.3.0
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.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
527  langC.setParameterPrecision(_parameterPrecision);
528  _cache.str("");
529  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "_noloop_indep" << j;
530  string functionName = _cache.str();
531  langC.setGenerateFunction(functionName);
532 
533  std::ostringstream code;
534  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("px"));
535  LangCDefaultReverse2VarNameGenerator<Base> nameGenRev2(nameGen.get(), n, 1);
536 
537  handlerNL.generateCode(code, langC, pxCustom, nameGenRev2, _atomicFunctions, subJobName);
538  }
539 
540  finishedJob();
541  }
542 
543  }
544 
548  string functionRev2 = _name + "_" + FUNCTION_SPARSE_REVERSE_TWO;
549  _sources[functionRev2 + ".c"] = generateGlobalForRevWithLoopsFunctionSource(elements,
550  _loopRev2Groups, _nonLoopRev2Elements,
551  functionRev2, _name, _baseTypeName, "indep",
552  generateFunctionNameLoopRev2);
556  _cache.str("");
557  generateSparsity1DSource2(_name + "_" + FUNCTION_REVERSE_TWO_SPARSITY, elements);
558  _sources[_name + "_" + FUNCTION_REVERSE_TWO_SPARSITY + ".c"] = _cache.str();
559  _cache.str("");
560 }
561 
562 namespace loops {
563 
564 template<class Base>
565 void generateHessianRowGroups(const LoopModel<Base>& lModel,
566  const HessianWithLoopsInfo<Base>& info,
567  size_t n,
569  using namespace std;
570  using namespace CppAD::cg::loops;
571 
575  map<pairss, map<size_t, set<size_t> > > indexedIndexed2jrow2Iter;
576  map<pairss, map<size_t, set<size_t> > > indexedNonIndexed2jrow2Iter;
577  map<pairss, map<size_t, set<size_t> > > indexedTemp2jrow2Iter;
578  map<pairss, map<size_t, set<size_t> > > nonIndexedIndexed2jrow2Iter;
579  map<pairss, map<size_t, set<size_t> > > tempIndexed2jrow2Iter;
580 
581  map<HessianTermContrib<Base>, set<size_t> > contrib2jrows = groupHessianRowsByContrib(info, n,
582  indexedIndexed2jrow2Iter,
583  indexedNonIndexed2jrow2Iter,
584  indexedTemp2jrow2Iter,
585  nonIndexedIndexed2jrow2Iter,
586  tempIndexed2jrow2Iter);
587 
588  loopGroups.reserve(contrib2jrows.size() *2); // TODO: improve this
589 
590  for (const auto& itC : contrib2jrows) {
591  const HessianTermContrib<Base>& c = itC.first;
592  const set<size_t>& jrows = itC.second;
593 
597  subgroupHessianRowsByContrib(info, c, jrows,
598  indexedIndexed2jrow2Iter,
599  indexedNonIndexed2jrow2Iter,
600  indexedTemp2jrow2Iter,
601  nonIndexedIndexed2jrow2Iter,
602  tempIndexed2jrow2Iter,
603  loopGroups);
604  }
605 
606 }
607 
608 template<class Base>
609 std::vector<std::pair<CG<Base>, IndexPattern*> > generateReverseTwoGroupOps(CodeHandler<Base>& handler,
610  const LoopModel<Base>& lModel,
611  const HessianWithLoopsInfo<Base>& info,
612  HessianRowGroup<Base>& group,
613  const CG<Base>& tx1,
614  const std::map<size_t, std::map<size_t, CG<Base> > >& dzDx,
615  std::map<size_t, std::set<size_t> >& jrow2CompressedLoc) {
616  using namespace std;
617  using namespace CppAD::cg::loops;
618 
619  using CGBase = CG<Base>;
620 
621  IndexOperationNode<Base>& iterationIndexOp = *info.iterationIndexOp;
622 
623  // store results in indexedLoopResults
624  size_t hessElSize = group.size();
625 
626  std::vector<pair<CGBase, IndexPattern*> > indexedLoopResults(hessElSize);
627  size_t hessLE = 0;
628 
629  map<pairss, std::vector<HessianElement> >::const_iterator itPos;
630 
634  for (size_t g = 0; g < info.equationGroups.size(); g++) {
635 
636  const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
637 
638  /***************************************************************
639  * indexed - indexed
640  */
641  for (const pairss& it : group.indexedIndexed) {
642  size_t tapeJ1 = it.first;
643  size_t tapeJ2 = it.second;
644 
645  itPos = infog.indexedIndexedPositions.find(it);
646  if (itPos != infog.indexedIndexedPositions.end()) {
647  const std::vector<HessianElement>& positions = itPos->second;
648 
649  addContribution(indexedLoopResults, hessLE,
650  createReverseMode2Contribution(handler, group,
651  positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
652  iterationIndexOp,
653  jrow2CompressedLoc));
654  }
655  }
656 
660  for (const pairss& it : group.indexedNonIndexed) {
661  size_t tapeJ1 = it.first;
662  size_t tapeJ2 = it.second;
663 
664  itPos = infog.indexedNonIndexedPositions.find(it);
665  if (itPos != infog.indexedNonIndexedPositions.end()) {
666  const std::vector<HessianElement>& positions = itPos->second;
667 
668  addContribution(indexedLoopResults, hessLE,
669  createReverseMode2Contribution(handler, group,
670  positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
671  iterationIndexOp,
672  jrow2CompressedLoc));
673  }
674  }
675 
679  for (const pairss& it : group.indexedTemp) {
680  size_t tapeJ1 = it.first;
681  size_t j2 = it.second;
682 
683  itPos = infog.indexedTempPositions.find(it);
684  if (itPos != infog.indexedTempPositions.end()) {
685  const std::vector<HessianElement>& positions = itPos->second;
686  const set<size_t>& ks = infog.indexedTempEvals.at(it);
687 
688  CGBase val = Base(0);
689  for (size_t k : ks) {
690  size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
691  val += infog.hess.at(tapeJ1).at(tapeK) * dzDx.at(k).at(j2);
692  }
693 
694  addContribution(indexedLoopResults, hessLE,
695  createReverseMode2Contribution(handler, group,
696  positions, val, tx1,
697  iterationIndexOp,
698  jrow2CompressedLoc));
699  }
700  }
701 
702 
703  /***************************************************************
704  * non-indexed - indexed
705  */
706  for (const pairss& it : group.nonIndexedIndexed) {
707  size_t tapeJ1 = it.first;
708  size_t tapeJ2 = it.second;
709 
710  itPos = infog.nonIndexedIndexedPositions.find(it);
711  if (itPos != infog.nonIndexedIndexedPositions.end()) {
712  const std::vector<HessianElement>& positions = itPos->second;
713 
714  addContribution(indexedLoopResults, hessLE,
715  createReverseMode2Contribution(handler, group,
716  positions, infog.hess.at(tapeJ1).at(tapeJ2), tx1,
717  iterationIndexOp,
718  jrow2CompressedLoc));
719  }
720  }
721 
722  /***************************************************************
723  * temporary - indexed
724  *
725  * d f_i . d x_k1
726  * d x_l2 d z_k1 d x_j1
727  */
728  for (const pairss& it : group.tempIndexed) {
729  size_t j1 = it.first;
730  size_t tapeJ2 = it.second;
731 
732  itPos = infog.tempIndexedPositions.find(it);
733  if (itPos != infog.tempIndexedPositions.end()) {
734  const std::vector<HessianElement>& positions = itPos->second;
735  const set<size_t>& ks = infog.indexedTempEvals.at(pairss(tapeJ2, j1));
736 
737  CGBase val = Base(0);
738  for (size_t k : ks) {
739  size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
740  val += infog.hess.at(tapeK).at(tapeJ2) * dzDx.at(k).at(j1);
741  }
742 
743  addContribution(indexedLoopResults, hessLE,
744  createReverseMode2Contribution(handler, group,
745  positions, val, tx1,
746  iterationIndexOp,
747  jrow2CompressedLoc));
748  }
749  }
750  }
751 
752  /*******************************************************************
753  * contributions to a constant location
754  */
755  for (const pairss& orig : group.nonIndexedNonIndexed) {
756  size_t e = info.nonIndexedNonIndexedPosition.at(orig);
757 
758  size_t j1 = orig.first;
759  size_t j2 = orig.second;
760  const LoopPosition* posJ1 = lModel.getNonIndexedIndepIndexes(j1);
761  const LoopPosition* posJ2 = lModel.getNonIndexedIndepIndexes(j2);
762 
763  // location
764  LinearIndexPattern* pattern = new LinearIndexPattern(0, 0, 0, e);
765  handler.manageLoopDependentIndexPattern(pattern);
766 
770  CGBase hessVal = Base(0);
771 
775  for (size_t g = 0; g < info.equationGroups.size(); g++) {
776  const IterEquationGroup<Base>& eqGroup = lModel.getEquationsGroups()[g];
777  set<size_t> iterations;
778  set_intersection(group.iterations.begin(), group.iterations.end(),
779  eqGroup.iterations.begin(), eqGroup.iterations.end(),
780  std::inserter(iterations, iterations.begin()));
781 
782  CGBase gHessVal = Base(0);
783  const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
784 
785  if (infog.nonIndexedNonIndexedEvals.find(orig) != infog.nonIndexedNonIndexedEvals.end()) {
786  gHessVal = infog.hess.at(posJ1->tape).at(posJ2->tape);
787  }
788 
792  const auto itNT = infog.nonIndexedTempEvals.find(orig);
793  if (itNT != infog.nonIndexedTempEvals.end()) {
794  const set<size_t>& ks = itNT->second;
795 
796  for (size_t k : ks) {
797  size_t tapeK = lModel.getTempIndepIndexes(k)->tape;
798  gHessVal += infog.hess.at(posJ1->tape).at(tapeK) * dzDx.at(k).at(j2);
799  }
800  }
801 
808  const auto itTN = infog.tempNonIndexedEvals.find(orig);
809  if (itTN != infog.tempNonIndexedEvals.end()) {
810  const set<size_t>& ks = itTN->second;
811 
812  for (size_t k1 : ks) {
813  size_t tapeK = lModel.getTempIndepIndexes(k1)->tape;
814  gHessVal += infog.hess.at(tapeK).at(posJ2->tape) * dzDx.at(k1).at(j1);
815  }
816  }
817 
821  const auto itTT = infog.tempTempEvals.find(orig);
822  if (itTT != infog.tempTempEvals.end()) {
823  const map<size_t, set<size_t> >& k1k2 = itTT->second;
824 
825  CGBase sum = Base(0);
826 
827  for (const auto& itzz : k1k2) {
828  size_t k1 = itzz.first;
829  const set<size_t>& k2s = itzz.second;
830  size_t tapeK1 = lModel.getTempIndepIndexes(k1)->tape;
831 
832  CGBase tmp = Base(0);
833  for (size_t k2 : k2s) {
834  size_t tapeK2 = lModel.getTempIndepIndexes(k2)->tape;
835 
836  tmp += infog.hess.at(tapeK1).at(tapeK2) * dzDx.at(k2).at(j2);
837  }
838 
839  sum += tmp * dzDx.at(k1).at(j1);
840  }
841 
842  gHessVal += sum;
843  }
844 
845  if (iterations.size() != group.iterations.size()) {
846  CGBase v = createReverseMode2Contribution(handler, group,
847  *pattern, iterations,
848  gHessVal,
849  *info.iterationIndexOp,
850  group.ifElses);
851  addContribution(indexedLoopResults, hessLE, make_pair(v, (IndexPattern*) nullptr));
852  jrow2CompressedLoc[j1].insert(e);
853  } else {
854  hessVal += gHessVal;
855  }
856  }
857 
861  const auto itTT2 = info.nonLoopNonIndexedNonIndexed.find(orig);
862  if (itTT2 != info.nonLoopNonIndexedNonIndexed.end()) {
863  hessVal += info.dzDxx.at(j1).at(j2); // it is already the sum of ddz / dx_j1 dx_j2
864  }
865 
866  hessVal *= tx1;
867 
868  // place the result
869  if (!hessVal.isIdenticalZero()) {
870  addContribution(indexedLoopResults, hessLE, make_pair(hessVal, (IndexPattern*) pattern));
871 
872  jrow2CompressedLoc[j1].insert(e);
873  }
874  }
875 
876  indexedLoopResults.resize(hessLE);
877 
878  return indexedLoopResults;
879 }
880 
885  size_t jrow;
886  std::set<size_t> iterations;
887 
888  inline Reverse2Jrow2Iter() {
889  }
890 
891  inline Reverse2Jrow2Iter(size_t row,
892  const std::set<size_t>& iters) :
893  jrow(row),
894  iterations(iters) {
895  }
896 };
897 
898 inline bool operator<(const Reverse2Jrow2Iter& l, const Reverse2Jrow2Iter& r) {
899  if (l.jrow < r.jrow)
900  return true;
901  else if (l.jrow > r.jrow)
902  return false;
903 
904  return compare(l.iterations, r.iterations) == -1;
905 }
906 
910 template<class Base>
911 inline std::map<HessianTermContrib<Base>, std::set<size_t> > groupHessianRowsByContrib(const loops::HessianWithLoopsInfo<Base>& info,
912  size_t n,
913  std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedIndexed2jrow2Iter,
914  std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedNonIndexed2jrow2Iter,
915  std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedTemp2jrow2Iter,
916  std::map<pairss, std::map<size_t, std::set<size_t> > >& nonIndexedIndexed2jrow2Iter,
917  std::map<pairss, std::map<size_t, std::set<size_t> > >& tempIndexed2jrow2Iter) {
918  using namespace std;
919 
920  size_t nIterations = info.model->getIterationCount();
921 
925  std::vector<HessianTermContrib<Base> > jrows(n);
926 
927  for (size_t g = 0; g < info.equationGroups.size(); g++) {
928  const HessianWithLoopsEquationGroupInfo<Base>& infog = info.equationGroups[g];
929 
930  // indexed-indexed
931  for (const auto& it : infog.indexedIndexedPositions) {
932  map<size_t, set<size_t> >& jrow2Iter = indexedIndexed2jrow2Iter[it.first];
933  const std::vector<HessianElement>& positions = it.second;
934  for (size_t iter = 0; iter < nIterations; iter++) {
935  if (positions[iter].count > 0) {
936  jrows[positions[iter].row].indexedIndexed.insert(it.first);
937  jrow2Iter[positions[iter].row].insert(iter);
938  }
939  }
940  }
941 
942  // indexed - non-indexed
943  for (const auto& it : infog.indexedNonIndexedPositions) {
944  map<size_t, set<size_t> >& jrow2Iter = indexedNonIndexed2jrow2Iter[it.first];
945  const std::vector<HessianElement>& positions = it.second;
946  for (size_t iter = 0; iter < nIterations; iter++) {
947  if (positions[iter].count > 0) {
948  jrows[positions[iter].row].indexedNonIndexed.insert(it.first);
949  jrow2Iter[positions[iter].row].insert(iter);
950  }
951  }
952  }
953 
954  // indexed - temporary
955  for (const auto& it : infog.indexedTempPositions) {
956  map<size_t, set<size_t> >& jrow2Iter = indexedTemp2jrow2Iter[it.first];
957  const std::vector<HessianElement>& positions = it.second;
958  for (size_t iter = 0; iter < nIterations; iter++) {
959  if (positions[iter].count > 0) {
960  jrows[positions[iter].row].indexedTemp.insert(it.first);
961  jrow2Iter[positions[iter].row].insert(iter);
962  }
963  }
964  }
965 
966  // non-indexed - indexed
967  for (const auto& it : infog.nonIndexedIndexedPositions) {
968  map<size_t, set<size_t> >& jrow2Iter = nonIndexedIndexed2jrow2Iter[it.first];
969  const std::vector<HessianElement>& positions = it.second;
970  for (size_t iter = 0; iter < nIterations; iter++) {
971  if (positions[iter].count > 0) {
972  jrows[positions[iter].row].nonIndexedIndexed.insert(it.first);
973  jrow2Iter[positions[iter].row].insert(iter);
974  }
975  }
976  }
977 
978  // temporary - indexed
979  for (const auto& it : infog.tempIndexedPositions) {
980  map<size_t, set<size_t> >& jrow2Iter = tempIndexed2jrow2Iter[it.first];
981  const std::vector<HessianElement>& positions = it.second;
982  for (size_t iter = 0; iter < nIterations; iter++) {
983  if (positions[iter].count > 0) {
984  jrows[positions[iter].row].tempIndexed.insert(it.first);
985  jrow2Iter[positions[iter].row].insert(iter);
986  }
987  }
988  }
989  }
990 
991  // non-indexed - non-indexed
992  for (const auto& orig2PosIt : info.nonIndexedNonIndexedPosition) {
993  size_t j1 = orig2PosIt.first.first;
994  jrows[j1].nonIndexedNonIndexed.insert(orig2PosIt.first);
995  }
996 
1000  map<HessianTermContrib<Base>, set<size_t> > contrib2jrows;
1001  for (size_t j = 0; j < n; j++) {
1002  if (!jrows[j].empty())
1003  contrib2jrows[jrows[j]].insert(j);
1004  }
1005 
1006  return contrib2jrows;
1007 }
1008 
1015 template<class Base>
1016 inline void subgroupHessianRowsByContrib(const HessianWithLoopsInfo<Base>& info,
1017  const HessianTermContrib<Base>& c,
1018  const std::set<size_t>& jrows,
1019  const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedIndexed2jrow2Iter,
1020  const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedNonIndexed2jrow2Iter,
1021  const std::map<pairss, std::map<size_t, std::set<size_t> > >& indexedTemp2jrow2Iter,
1022  const std::map<pairss, std::map<size_t, std::set<size_t> > >& nonIndexedIndexed2jrow2Iter,
1023  const std::map<pairss, std::map<size_t, std::set<size_t> > >& tempIndexed2jrow2Iter,
1025  using namespace std;
1026 
1027  map<Reverse2Jrow2Iter, HessianTermContrib<Base> > contribs;
1028 
1029  set<pairss>::const_iterator it;
1030  map<size_t, set<size_t> >::const_iterator itJrow2Iter;
1031 
1032  // indexed - indexed
1033  for (pairss pos : c.indexedIndexed) {
1034  map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedIndexed2jrow2Iter.at(pos), jrows);
1035  for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1036  Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1037  contribs[k].indexedIndexed.insert(pos);
1038  }
1039  }
1040 
1041  // indexed - non-indexed
1042  for (pairss pos : c.indexedNonIndexed) {
1043  map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedNonIndexed2jrow2Iter.at(pos), jrows);
1044  for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1045  Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1046  contribs[k].indexedNonIndexed.insert(pos);
1047  }
1048  }
1049 
1050  // indexed - temporary
1051  for (pairss pos : c.indexedTemp) {
1052  map<size_t, set<size_t> > jrow2Iter = filterBykeys(indexedTemp2jrow2Iter.at(pos), jrows);
1053  for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1054  Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1055  contribs[k].indexedTemp.insert(pos);
1056  }
1057  }
1058 
1059  // non-indexed - indexed
1060  for (pairss pos : c.nonIndexedIndexed) {
1061  map<size_t, set<size_t> > jrow2Iter = filterBykeys(nonIndexedIndexed2jrow2Iter.at(pos), jrows);
1062  for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1063  Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1064  contribs[k].nonIndexedIndexed.insert(pos);
1065  }
1066  }
1067 
1068  // non-indexed - non-indexed
1069  if (!c.nonIndexedNonIndexed.empty()) {
1070  set<size_t> allIters;
1071  size_t nIterations = info.model->getIterationCount();
1072  for (size_t iter = 0; iter < nIterations; iter++)
1073  allIters.insert(allIters.end(), iter);
1074 
1075  for (pairss pos : c.nonIndexedNonIndexed) {
1076  Reverse2Jrow2Iter k(pos.first, allIters);
1077  contribs[k].nonIndexedNonIndexed.insert(pos);
1078  }
1079  }
1080 
1081  // temporary - indexed
1082  for (pairss pos : c.tempIndexed) {
1083  map<size_t, set<size_t> > jrow2Iter = filterBykeys(tempIndexed2jrow2Iter.at(pos), jrows);
1084  for (itJrow2Iter = jrow2Iter.begin(); itJrow2Iter != jrow2Iter.end(); ++itJrow2Iter) {
1085  Reverse2Jrow2Iter k(itJrow2Iter->first, itJrow2Iter->second);
1086  contribs[k].tempIndexed.insert(pos);
1087  }
1088  }
1089 
1093  map<HessianTermContrib<Base>, HessianRowGroup<Base>*> c2subgroups; // add pair<jrow, set<iter> > here
1094 
1095  for (const auto& itK2C : contribs) {
1096  const Reverse2Jrow2Iter& jrow2Iters = itK2C.first;
1097  const HessianTermContrib<Base>& hc = itK2C.second;
1098 
1099  const auto its = c2subgroups.find(hc);
1100  if (its != c2subgroups.end()) {
1101  HessianRowGroup<Base>* sg = its->second;
1102  sg->jRow2Iterations[jrow2Iters.jrow] = jrow2Iters.iterations;
1103  sg->iterations.insert(jrow2Iters.iterations.begin(), jrow2Iters.iterations.end());
1104  } else {
1105  HessianRowGroup<Base>* sg = new HessianRowGroup<Base>(hc, jrow2Iters);
1106  subGroups.push_back(sg);
1107  c2subgroups[hc] = sg;
1108  }
1109  }
1110 }
1111 
1112 template<class Base>
1113 std::pair<CG<Base>, IndexPattern*> createReverseMode2Contribution(CodeHandler<Base>& handler,
1114  HessianRowGroup<Base>& group,
1115  const std::vector<HessianElement>& positions,
1116  const CG<Base>& ddfdxdx,
1117  const CG<Base>& tx1,
1118  IndexOperationNode<Base>& iterationIndexOp,
1119  std::map<size_t, std::set<size_t> >& jrow2CompressedLoc) {
1120  using namespace std;
1121 
1122  if (ddfdxdx.isIdenticalZero()) {
1123  return make_pair(ddfdxdx, (IndexPattern*) nullptr);
1124  }
1125 
1129  std::map<size_t, size_t> iteration2pos;
1130 
1131  // combine iterations with the same number of additions
1132  map<size_t, map<size_t, size_t> > locations;
1133  for (size_t iter : group.iterations) {
1134  size_t c = positions[iter].count;
1135  if (c > 0) {
1136  locations[c][iter] = positions[iter].location;
1137  iteration2pos[iter] = positions[iter].location;
1138  jrow2CompressedLoc[positions[iter].row].insert(positions[iter].location);
1139  }
1140  }
1141 
1142  if (locations.empty()) {
1143  return make_pair(CG<Base>(Base(0)), (IndexPattern*) nullptr);
1144  }
1145 
1146  map<size_t, CG<Base> > results;
1147 
1148  // generate the index pattern for the Hessian compressed element
1149  for (const auto& countIt : locations) {
1150  size_t count = countIt.first;
1151 
1152  CG<Base> val = ddfdxdx;
1153  for (size_t c = 1; c < count; c++)
1154  val += ddfdxdx;
1155 
1156  results[count] = val * tx1;
1157  }
1158 
1159  if (results.size() == 1 && locations.begin()->second.size() == group.iterations.size()) {
1160  // same expression present in all iterations
1161 
1162  // generate the index pattern for the Hessian compressed element
1163  IndexPattern* pattern = IndexPattern::detect(locations.begin()->second);
1164  handler.manageLoopDependentIndexPattern(pattern);
1165 
1166  return make_pair(results.begin()->second, pattern);
1167 
1168  } else {
1174  map<size_t, IfBranchData<Base> > branches;
1175 
1176  // try to find an existing if-else where these operations can be added
1177  for (const auto& countIt : locations) {
1178  size_t count = countIt.first;
1179  IfBranchData<Base> branch(results[count], countIt.second);
1180  branches[count] = branch;
1181  }
1182 
1183  CG<Base> v = createConditionalContribution(handler,
1184  branches,
1185  positions.size() - 1,
1186  group.iterations.size(),
1187  iterationIndexOp,
1188  group.ifElses);
1189 
1190  return make_pair(v, (IndexPattern*) nullptr);
1191  }
1192 
1193 }
1194 
1198 template<class Base>
1199 CG<Base> createReverseMode2Contribution(CodeHandler<Base>& handler,
1200  HessianRowGroup<Base>& group,
1201  LinearIndexPattern& pattern,
1202  const std::set<size_t>& iterations,
1203  const CG<Base>& ddfdxdx,
1204  IndexOperationNode<Base>& iterationIndexOp,
1205  std::vector<IfElseInfo<Base> >& ifElses) {
1206  using namespace std;
1207 
1208  if (ddfdxdx.isIdenticalZero()) {
1209  return ddfdxdx;
1210  }
1211 
1212  CPPADCG_ASSERT_UNKNOWN(pattern.getLinearSlopeDy() == 0); // must be a constant index
1213 
1214  if (iterations.size() == group.iterations.size()) {
1215  // same expression present in all iterations
1216  return ddfdxdx;
1217 
1218  } else {
1224  return createConditionalContribution(handler, pattern,
1225  iterations, *group.iterations.rbegin(),
1226  ddfdxdx, iterationIndexOp,
1227  ifElses);
1228  }
1229 }
1230 
1234 template<class Base>
1235 class HessianTermContrib {
1236 public:
1237  // (tapeJ1, tapeJ2)
1238  std::set<pairss> indexedIndexed;
1239  // (tapeJ1, tapeJ2(j2))
1240  std::set<pairss> indexedNonIndexed;
1241  // (tapeJ1, j2)
1242  std::set<pairss> indexedTemp;
1243  // (tapeJ1(j1), tapeJ2)
1244  std::set<pairss> nonIndexedIndexed;
1245  //(j1, j2)
1246  std::set<pairss> nonIndexedNonIndexed;
1247  // (j1, tapeJ2)
1248  std::set<pairss> tempIndexed;
1249 
1250 public:
1251 
1252  inline bool empty() const {
1253  return indexedIndexed.empty() && indexedNonIndexed.empty() && indexedTemp.empty() &&
1254  nonIndexedIndexed.empty() && nonIndexedNonIndexed.empty() &&
1255  tempIndexed.empty();
1256  }
1257 
1258  inline size_t size() const {
1259  return indexedIndexed.size() + indexedNonIndexed.size() + indexedTemp.size() +
1260  nonIndexedIndexed.size() + nonIndexedNonIndexed.size() +
1261  tempIndexed.size();
1262  }
1263 };
1264 
1265 template<class Base>
1266 bool operator<(const HessianTermContrib<Base>& l, const HessianTermContrib<Base>& r) {
1267  int c = compare(l.indexedIndexed, r.indexedIndexed);
1268  if (c != 0) return c == -1;
1269  c = compare(l.indexedNonIndexed, r.indexedNonIndexed);
1270  if (c != 0) return c == -1;
1271  c = compare(l.indexedTemp, r.indexedTemp);
1272  if (c != 0) return c == -1;
1273  c = compare(l.nonIndexedIndexed, r.nonIndexedIndexed);
1274  if (c != 0) return c == -1;
1275  c = compare(l.nonIndexedNonIndexed, r.nonIndexedNonIndexed);
1276  if (c != 0) return c == -1;
1277  c = compare(l.tempIndexed, r.tempIndexed);
1278  if (c != 0) return c == -1;
1279  return false;
1280 }
1281 
1286 template<class Base>
1287 class HessianRowGroup : public HessianTermContrib<Base> {
1288 public:
1289  // all the required iterations for each jrow
1290  std::map<size_t, std::set<size_t> > jRow2Iterations;
1291  // all iterations
1292  std::set<size_t> iterations;
1293  // if-else branches
1294  std::vector<IfElseInfo<Base> > ifElses;
1295 public:
1296 
1297  inline HessianRowGroup(const HessianTermContrib<Base>& c,
1298  const Reverse2Jrow2Iter& jrow2Iters) :
1300  iterations(jrow2Iters.iterations) {
1301  jRow2Iterations[jrow2Iters.jrow] = jrow2Iters.iterations;
1302  }
1303 };
1304 
1305 } // END loops namespace
1306 
1307 template<class Base>
1308 void ModelCSourceGen<Base>::generateFunctionNameLoopRev2(std::ostringstream& cache,
1309  const LoopModel<Base>& loop,
1310  size_t g) {
1311  generateFunctionNameLoopRev2(cache, _name, loop, g);
1312 }
1313 
1314 template<class Base>
1315 void ModelCSourceGen<Base>::generateFunctionNameLoopRev2(std::ostringstream& cache,
1316  const std::string& modelName,
1317  const LoopModel<Base>& loop,
1318  size_t g) {
1319  cache << modelName << "_" << FUNCTION_SPARSE_REVERSE_TWO <<
1320  "_loop" << loop.getLoopId() << "_g" << g;
1321 }
1322 
1323 } // END cg namespace
1324 } // END CppAD namespace
1325 
1326 #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
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
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:219
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