1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_FOR1_INCLUDED 2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_FOR1_INCLUDED 31 size_t n = _fun.Domain();
34 handler.setJobTimer(_jobTimer);
37 auto& indexJcolDcl = *handler.makeIndexDclrNode(
"jcol");
38 auto& indexLocalItDcl = *handler.makeIndexDclrNode(
"it");
39 auto& indexLocalItCountDcl = *handler.makeIndexDclrNode(
"itCount");
41 auto& iterationIndexOp = *handler.makeIndexNode(indexIterationDcl);
42 auto& jcolIndexOp = *handler.makeIndexNode(indexJcolDcl);
44 std::vector<OperationNode<Base>*> localNodes(6);
45 localNodes[0] = &indexJcolDcl;
46 localNodes[1] = &indexLocalItDcl;
47 localNodes[2] = &indexLocalItCountDcl;
48 localNodes[3] = &indexIterationDcl;
49 localNodes[4] = &iterationIndexOp;
50 localNodes[5] = &jcolIndexOp;
52 size_t nonIndexdedEqSize = _funNoLoops !=
nullptr ? _funNoLoops->getOrigDependentIndexes().size() : 0;
54 std::vector<set<size_t> > noLoopEvalSparsity;
55 std::vector<map<size_t, set<size_t> > > noLoopEvalLocations;
56 map<LoopModel<Base>*, std::vector<set<size_t> > > loopsEvalSparsities;
57 map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> > loopEqInfo;
59 size_t nnz = _jacSparsity.rows.size();
60 std::vector<size_t> rows(nnz);
61 std::vector<size_t> cols(nnz);
62 std::vector<size_t> locations(nnz);
65 for (
const auto& itJ : elements) {
67 const std::vector<size_t>& r = itJ.second;
69 for (
size_t e = 0; e < r.size(); e++) {
76 CPPADCG_ASSERT_UNKNOWN(p == nnz);
78 analyseSparseJacobianWithLoops(rows, cols, locations,
79 noLoopEvalSparsity, noLoopEvalLocations, loopsEvalSparsities, loopEqInfo);
81 std::vector<CGBase> x(n);
84 for (
size_t i = 0; i < n; i++) {
103 std::vector<CGBase> tmps;
106 map<size_t, map<size_t, CGBase> > dzDx;
111 if (_funNoLoops !=
nullptr) {
117 std::vector<CGBase> depNL = _funNoLoops->getTape().Forward(0, x);
119 tmps.resize(depNL.size() - nonIndexdedEqSize);
120 for (
size_t i = 0; i < tmps.size(); i++)
121 tmps[i] = depNL[nonIndexdedEqSize + i];
126 bool hasAtomics = isAtomicsUsed();
127 map<size_t, map<size_t, CGBase> > dydxT = generateLoopFor1Jac(fun,
128 _funNoLoops->getJacobianSparsity(),
132 map<size_t, std::vector<CGBase> > jacNl;
133 for (
const auto& itDydxT : dydxT) {
134 size_t j = itDydxT.first;
135 const map<size_t, CGBase>& dydxjT = itDydxT.second;
138 std::vector<CGBase>& col = jacNl[j];
139 col.resize(elements.at(j).size());
141 for (
const auto& itiv : dydxjT) {
142 size_t inl = itiv.first;
144 if (inl < nonIndexdedEqSize) {
146 const set<size_t>& locations = noLoopEvalLocations[inl][j];
148 CPPADCG_ASSERT_UNKNOWN(locations.size() == 1);
149 size_t e = *locations.begin();
151 col[e] = itiv.second * dx;
153 _nonLoopFor1Elements[j].insert(e);
156 size_t k = inl - nonIndexdedEqSize;
157 dzDx[k][j] = itiv.second;
166 typename map<size_t, std::vector<CGBase> >::iterator itJ;
167 for (itJ = jacNl.begin(); itJ != jacNl.end(); ++itJ) {
168 size_t j = itJ->first;
169 if (_nonLoopFor1Elements.find(j) != _nonLoopFor1Elements.end())
170 createForwardOneWithLoopsNL(handler, j, itJ->second);
177 typename map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> >::iterator itl2Eq;
178 for (itl2Eq = loopEqInfo.begin(); itl2Eq != loopEqInfo.end(); ++itl2Eq) {
180 const std::vector<JacobianWithLoopsRowInfo>& info = itl2Eq->second;
187 _cache <<
"model (forward one, loop " << lModel.
getLoopId() <<
")";
188 std::string jobName = _cache.str();
193 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
195 std::vector<CGBase> indexedIndeps = createIndexedIndependents(handler, lModel, iterationIndexOp);
196 std::vector<CGBase> xl = createLoopIndependentVector(handler, lModel, indexedIndeps, x, tmps);
198 bool hasAtomics = isAtomicsUsed();
199 map<size_t, map<size_t, CGBase> > dyiDxtapeT = generateLoopFor1Jac(fun,
200 lModel.getJacobianSparsity(),
201 loopsEvalSparsities[&lModel],
212 generateForOneColumnGroups(lModel, info, nnz, n, loopGroups);
217 for (
size_t g = 0; g < loopGroups.size(); g++) {
225 map<size_t, set<size_t> > localIterCount2Jcols;
227 for (
const auto& itJcol2It : group.jCol2Iterations) {
228 size_t jcol = itJcol2It.first;
229 size_t itCount = itJcol2It.second.size();
230 localIterCount2Jcols[itCount].insert(jcol);
233 bool createsLoop = localIterCount2Jcols.size() != 1 ||
234 localIterCount2Jcols.begin()->first != 1;
242 map<size_t, map<size_t, size_t> > jcol2localIt2ModelIt;
244 for (
const auto& itJcol2It : group.jCol2Iterations) {
245 size_t jcol = itJcol2It.first;
247 map<size_t, size_t>& localIt2ModelIt = jcol2localIt2ModelIt[jcol];
249 set<size_t>::const_iterator itIt;
250 for (itIt = itJcol2It.second.begin(); itIt != itJcol2It.second.end(); ++itIt, localIt++) {
251 localIt2ModelIt[localIt] = *itIt;
261 if (itPattern.get() ==
nullptr) {
272 std::unique_ptr<IndexPattern> indexLocalItCountPattern;
275 map<size_t, size_t> jcol2litCount;
277 for (
const auto& itJcol2Its : group.jCol2Iterations) {
278 size_t jcol = itJcol2Its.first;
279 jcol2litCount[jcol] = itJcol2Its.second.size();
284 if (IndexPattern::isConstant(*indexLocalItCountPattern.get())) {
285 size_t itCount = group.jCol2Iterations.begin()->second.size();
286 loopStart = handler.makeLoopStartNode(indexLocalItDcl, itCount);
288 itCountAssignOp = handler.makeIndexAssignNode(indexLocalItCountDcl, *indexLocalItCountPattern.get(), jcolIndexOp);
289 localIterCountIndexOp = handler.makeIndexNode(*itCountAssignOp);
290 loopStart = handler.makeLoopStartNode(indexLocalItDcl, *localIterCountIndexOp);
293 localIterIndexOp = handler.makeIndexNode(*loopStart);
297 auto* iterationIndexPatternOp = handler.makeIndexAssignNode(indexIterationDcl, *itPattern.get(), &jcolIndexOp, localIterIndexOp);
298 iterationIndexOp.makeAssigmentDependent(*iterationIndexPatternOp);
300 map<size_t, set<size_t> > jcol2CompressedLoc;
301 std::vector<pair<CG<Base>,
IndexPattern*> > indexedLoopResults;
303 indexedLoopResults = generateForwardOneGroupOps(handler, lModel, info,
304 group, iterationIndexOp,
305 dx, dyiDxtapeT, dzDx,
308 _loopFor1Groups[&lModel][g] = jcol2CompressedLoc;
311 std::vector<CGBase> pxCustom;
316 size_t assignOrAdd = 1;
317 set<IndexOperationNode<Base>*> indexesOps;
318 indexesOps.insert(&iterationIndexOp);
319 loopEnd = createLoopEnd(handler, *loopStart, indexedLoopResults, indexesOps, assignOrAdd);
324 moveNonIndexedOutsideLoop(handler, *loopStart, *loopEnd);
331 pxCustom[0] = handler.createCG(*handler.makeNode(CGOpCode::DependentRefRhs,{0}, {*loopEnd}));
337 pxCustom.resize(indexedLoopResults.size());
338 for (
size_t i = 0; i < indexedLoopResults.size(); i++) {
339 const CGBase& val = indexedLoopResults[i].first;
342 pxCustom[i] = createLoopDependentFunctionResult(handler, i, val, ip, iterationIndexOp);
348 langC.setFunctionIndexArgument(indexJcolDcl);
352 std::ostringstream code;
353 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"dy"));
360 _cache <<
"model (forward one, loop " << lModel.
getLoopId() <<
", group " << g <<
")";
361 string jobName = _cache.str();
362 handler.
generateCode(code, langC, pxCustom, nameGenHess, _atomicFunctions, jobName);
365 generateFunctionNameLoopFor1(_cache, lModel, g);
366 std::string functionName = _cache.str();
368 std::string argsDcl = langC.generateFunctionArgumentsDcl();
371 _cache <<
"#include <stdlib.h>\n" 372 "#include <math.h>\n" 376 "void " << functionName <<
"(" << argsDcl <<
") {\n";
377 nameGenHess.customFunctionVariableDeclarations(_cache);
378 _cache << langC.generateIndependentVariableDeclaration() <<
"\n";
379 _cache << langC.generateDependentVariableDeclaration() <<
"\n";
380 _cache << langC.generateTemporaryVariableDeclaration(
false,
false,
383 nameGenHess.prepareCustomFunctionVariables(_cache);
386 _cache << code.str();
388 nameGenHess.finalizeCustomFunctionVariables(_cache);
391 _sources[functionName +
".c"] = _cache.str();
397 if (g + 1 < loopGroups.size()) {
407 string functionFor1 = _name +
"_" + FUNCTION_SPARSE_FORWARD_ONE;
408 _sources[functionFor1 +
".c"] = generateGlobalForRevWithLoopsFunctionSource(elements,
409 _loopFor1Groups, _nonLoopFor1Elements,
410 functionFor1, _name, _baseTypeName,
"indep",
411 generateFunctionNameLoopFor1);
416 generateSparsity1DSource2(_name +
"_" + FUNCTION_FORWARD_ONE_SPARSITY, elements);
417 _sources[_name +
"_" + FUNCTION_FORWARD_ONE_SPARSITY +
".c"] = _cache.str();
425 size_t n = _fun.Domain();
428 _cache <<
"model (forward one, indep " << j <<
") no loop";
429 const std::string jobName = _cache.str();
435 _cache << _name <<
"_" << FUNCTION_SPARSE_FORWARD_ONE <<
"_noloop_indep" << j;
436 langC.setGenerateFunction(_cache.str());
438 std::ostringstream code;
439 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"dy"));
442 handler.
generateCode(code, langC, jacCol, nameGenHess, _atomicFunctions, jobName);
455 std::set<size_t> iterations;
461 const std::set<size_t>& iters) :
470 else if (l.jcol > r.jcol)
473 return compare(l.iterations, r.iterations) == -1;
482 std::set<size_t> indexed;
483 std::set<size_t> nonIndexed;
486 inline bool empty()
const {
487 return indexed.empty() && nonIndexed.empty();
490 inline size_t size()
const {
491 return indexed.size() + nonIndexed.size();
497 int c = compare(l.indexed, r.indexed);
498 if (c != 0)
return c == -1;
499 c = compare(l.nonIndexed, r.nonIndexed);
500 if (c != 0)
return c == -1;
512 std::map<size_t, std::set<size_t> > jCol2Iterations;
514 std::set<size_t> iterations;
516 std::vector<IfElseInfo<Base> > ifElses;
522 iterations(jcol2Iters.iterations) {
523 jCol2Iterations[jcol2Iters.jcol] = jcol2Iters.iterations;
529 const std::vector<JacobianWithLoopsRowInfo>& loopEqInfo,
539 map<size_t, map<size_t, set<size_t> > > indexed2jcol2Iter;
540 map<size_t, set<size_t> > nonIndexed2Iter;
542 map<JacobianTermContrib<Base>, set<size_t> > contrib2jcols = groupForOneByContrib(lModel, loopEqInfo,
547 loopGroups.reserve(contrib2jcols.size() * 2);
550 for (
const auto& itC : contrib2jcols) {
552 const set<size_t>& jcols = itC.second;
557 subgroupForOneByContrib(loopEqInfo, c, jcols,
558 indexed2jcol2Iter, nonIndexed2Iter,
559 loopGroups, c2subgroups);
571 std::map<JacobianTermContrib<Base>, std::set<size_t> > groupForOneByContrib(
const LoopModel<Base>& lModel,
572 const std::vector<JacobianWithLoopsRowInfo>& loopEqInfo,
574 std::map<
size_t, std::map<
size_t, std::set<size_t> > >& indexed2jcol2Iter,
575 std::map<
size_t, std::set<size_t> >& nonIndexed2Iter) {
582 std::vector<JacobianTermContrib<Base> > jcols(n);
588 for (
size_t i = 0; i < loopEqInfo.size(); i++) {
592 for (
const auto& it : row.indexedPositions) {
593 size_t tapeJ = it.first;
594 const std::vector<size_t>& positions = it.second;
595 map<size_t, set<size_t> >& jcol2Iter = indexed2jcol2Iter[tapeJ];
597 for (
size_t iter = 0; iter < nIterations; iter++) {
600 if (positions[iter] != (std::numeric_limits<size_t>::max)()) {
601 size_t j = indexedIndepIndexes[tapeJ][iter].original;
602 jcols[j].indexed.insert(tapeJ);
603 jcol2Iter[j].insert(iter);
609 for (
const auto& it : row.nonIndexedPositions) {
611 const std::vector<size_t>& positions = it.second;
612 set<size_t>& jcol2Iter = nonIndexed2Iter[j];
615 for (
size_t iter = 0; iter < nIterations; iter++) {
618 if (positions[iter] != (std::numeric_limits<size_t>::max)()) {
620 jcol2Iter.insert(iter);
624 jcols[j].nonIndexed.insert(j);
633 map<JacobianTermContrib<Base>, set<size_t> > contrib2jcols;
634 for (
size_t j = 0; j < n; j++) {
635 if (!jcols[j].empty())
636 contrib2jcols[jcols[j]].insert(j);
639 return contrib2jcols;
649 inline void subgroupForOneByContrib(
const std::vector<JacobianWithLoopsRowInfo>& loopEqInfo,
651 const std::set<size_t>& jcols,
652 const std::map<
size_t, std::map<
size_t, std::set<size_t> > >& indexed2jcol2Iter,
653 const std::map<
size_t, std::set<size_t> >& nonIndexed2Iter,
658 map<Forward1Jcol2Iter, JacobianTermContrib<Base> > contribs;
660 map<size_t, set<size_t> >::const_iterator itJcol2Iter;
663 for (
size_t tapeJ : c.indexed) {
664 map<size_t, set<size_t> > jcol2Iters = filterBykeys(indexed2jcol2Iter.at(tapeJ), jcols);
665 for (itJcol2Iter = jcol2Iters.begin(); itJcol2Iter != jcol2Iters.end(); ++itJcol2Iter) {
667 contribs[k].indexed.insert(tapeJ);
672 for (
size_t j : c.nonIndexed) {
675 const set<size_t>& iters = nonIndexed2Iter.at(j);
677 contribs[k].nonIndexed.insert(j);
683 for (
const auto& itK2C : contribs) {
687 typename map<JacobianTermContrib<Base>,
JacobianColGroup<Base>*>::const_iterator its = c2subgroups.find(hc);
688 if (its != c2subgroups.end()) {
690 sg->jCol2Iterations[jcol2Iters.jcol] = jcol2Iters.iterations;
691 sg->iterations.insert(jcol2Iters.iterations.begin(), jcol2Iters.iterations.end());
694 subGroups.push_back(sg);
695 c2subgroups[hc] = sg;
703 const std::vector<JacobianWithLoopsRowInfo>& info,
707 const std::map<
size_t, std::map<
size_t,
CG<Base> > >& dyiDxtapeT,
708 const std::map<
size_t, std::map<
size_t,
CG<Base> > >& dzDx,
709 std::map<
size_t, std::set<size_t> >& jcol2CompressedLoc) {
717 size_t jacElSize = group.size();
719 std::vector<pair<CGBase, IndexPattern*> > indexedLoopResults(jacElSize * info.size());
722 map<size_t, size_t> iter2jcols;
724 for (
size_t tapeI = 0; tapeI < info.size(); tapeI++) {
731 for (
size_t tapeJ : group.indexed) {
733 map<size_t, std::vector<size_t> >::const_iterator itPos = jlrw.indexedPositions.find(tapeJ);
734 if (itPos != jlrw.indexedPositions.end()) {
735 const std::vector<size_t>& positions = itPos->second;
737 const std::vector<LoopPosition>& tapeJPos = indexedIndepIndexes[tapeJ];
739 for (
size_t iter : group.iterations) {
740 if (positions[iter] != (std::numeric_limits<size_t>::max)()) {
741 CPPADCG_ASSERT_UNKNOWN(tapeJPos[iter].original != (std::numeric_limits<size_t>::max)());
742 iter2jcols[iter] = tapeJPos[iter].original;
746 if (!iter2jcols.empty()) {
747 CGBase val = dyiDxtapeT.at(tapeJ).at(tapeI) * dx;
748 indexedLoopResults[jacLE++] = createForwardOneElement(handler, group, positions, iter2jcols,
749 val, iterationIndexOp, jcol2CompressedLoc);
759 for (
size_t j : group.nonIndexed) {
761 map<size_t, std::vector<size_t> >::const_iterator itPos = jlrw.nonIndexedPositions.find(j);
762 if (itPos == jlrw.nonIndexedPositions.end()) {
765 const std::vector<size_t>& positions = itPos->second;
768 for (
size_t iter : group.iterations) {
769 if (positions[iter] != (std::numeric_limits<size_t>::max)()) {
770 CPPADCG_ASSERT_UNKNOWN(lModel.
getDependentIndexes()[tapeI][iter].original != (std::numeric_limits<size_t>::max)());
771 iter2jcols[iter] = j;
774 if (!iter2jcols.empty()) {
776 CGBase jacVal = Base(0);
780 if (pos !=
nullptr) {
781 size_t tapeJ = pos->tape;
783 const map<size_t, CG<Base> >& dyiDxJtapeT = dyiDxtapeT.at(tapeJ);
784 typename map<size_t, CGBase>::const_iterator itVal = dyiDxJtapeT.find(tapeI);
785 if (itVal != dyiDxJtapeT.end()) {
786 jacVal += itVal->second;
791 map<size_t, set<size_t> >::const_iterator itks = jlrw.tmpEvals.find(j);
792 if (itks != jlrw.tmpEvals.end()) {
793 const set<size_t>& ks = itks->second;
794 for (
size_t k : ks) {
797 jacVal += dyiDxtapeT.at(tapeJ).at(tapeI) * dzDx.at(k).at(j);
801 CGBase val = jacVal * dx;
802 indexedLoopResults[jacLE++] = createForwardOneElement(handler, group, positions, iter2jcols,
803 val, iterationIndexOp, jcol2CompressedLoc);
808 indexedLoopResults.resize(jacLE);
810 return indexedLoopResults;
816 const std::vector<size_t>& positions,
817 const std::map<size_t, size_t>& iter2jcols,
820 std::map<
size_t, std::set<size_t> >& jcol2CompressedLoc) {
826 map<size_t, size_t> locationsIter2Pos;
828 for (
const auto& itIt : iter2jcols) {
829 size_t iter = itIt.first;
830 size_t jcol = itIt.second;
831 CPPADCG_ASSERT_UNKNOWN(positions[iter] != (std::numeric_limits<size_t>::max)());
832 locationsIter2Pos[iter] = positions[iter];
833 jcol2CompressedLoc[jcol].insert(positions[iter]);
838 handler.manageLoopDependentIndexPattern(pattern);
840 size_t assignOrAdd = 1;
841 return createLoopResult(handler, locationsIter2Pos, positions.size(),
842 dfdx, pattern, assignOrAdd,
843 iterationIndexOp, group.ifElses);
850 const SparsitySetType& sparsity,
851 const SparsitySetType& evalSparsity,
852 const std::vector<CGBase>& x,
853 bool constainsAtomics) {
856 size_t n = fun.Domain();
858 map<size_t, map<size_t, CGBase> > dyDxT;
860 if (!constainsAtomics) {
861 std::vector<size_t> row, col;
862 generateSparsityIndexes(evalSparsity, row, col);
867 std::vector<CGBase> jacLoop(row.size());
869 CppAD::sparse_jacobian_work work;
870 fun.SparseJacobianForward(x, sparsity, row, col, jacLoop, work);
873 for (
size_t el = 0; el < jacLoop.size(); el++) {
876 dyDxT[j][i] = jacLoop[el];
881 std::vector<set<size_t> > evalSparsityT(n);
882 addTransMatrixSparsity(evalSparsity, evalSparsityT);
884 std::vector<CGBase> dx(n);
886 for (
size_t j = 0; j < n; j++) {
887 const set<size_t>& column = evalSparsityT[j];
895 std::vector<CGBase> dy = fun.Forward(1, dx);
896 CPPADCG_ASSERT_UNKNOWN(dy.size() == fun.Range());
899 map<size_t, CGBase>& dyDxJT = dyDxT[j];
901 for (
size_t i : column) {
915 generateFunctionNameLoopFor1(cache, _name, loop, g);
920 const std::string& modelName,
923 cache << modelName <<
"_" << FUNCTION_SPARSE_FORWARD_ONE <<
924 "_loop" << loop.
getLoopId() <<
"_g" << g;
void setValue(const Base &val)
static Plane2DIndexPattern * detectPlane2D(const std::map< size_t, std::map< size_t, size_t > > &x2y2z)
ADFun< CGB > & getTape() const
const std::vector< int > & getExternalFuncMaxForwardOrder() const
static IndexPattern * detect(const VectorSizeT &x2y)
void makeVariables(VectorCG &variables)
virtual void prepareSparseForwardOneWithLoops(const std::map< size_t, std::vector< size_t > > &elements)
const LoopPosition * getTempIndepIndexes(size_t k) const
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
const size_t getIterationCount() const
void setZeroDependents(bool zeroDependents)
const std::vector< std::vector< LoopPosition > > & getDependentIndexes() const
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
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")