1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_JAC_INCLUDED 2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_JAC_INCLUDED 24 std::pair<CG<Base>, IndexPattern*> createJacobianElement(CodeHandler<Base>& handler,
25 const std::vector<size_t>& positions,
27 IndexOperationNode<Base>& iterationIndexOp,
28 std::vector<IfElseInfo<Base> >& ifElses,
29 std::set<size_t>& allLocations);
39 const std::vector<size_t>& cols,
40 const std::vector<size_t>& location,
41 std::vector<std::set<size_t> >& noLoopEvalSparsity,
42 std::vector<std::map<
size_t, std::set<size_t> > >& noLoopEvalLocations,
43 std::map<
LoopModel<Base>*, std::vector<std::set<size_t> > >& loopsEvalSparsities,
44 std::map<
LoopModel<Base>*, std::vector<loops::JacobianWithLoopsRowInfo> >& loopEqInfo) {
47 using namespace loops;
49 CPPADCG_ASSERT_UNKNOWN(rows.size() == cols.size());
50 CPPADCG_ASSERT_UNKNOWN(rows.size() == location.size());
56 l->evalJacobianSparsity();
59 if (_funNoLoops !=
nullptr)
60 _funNoLoops->evalJacobianSparsity();
65 size_t nonIndexdedEqSize = _funNoLoops !=
nullptr ? _funNoLoops->getOrigDependentIndexes().size() : 0;
66 noLoopEvalSparsity.resize(_funNoLoops !=
nullptr ? _funNoLoops->getTapeDependentCount() : 0);
69 noLoopEvalLocations.resize(noLoopEvalSparsity.size());
73 loopEqInfo[loop].resize(loop->getTapeDependentCount());
74 loopsEvalSparsities[loop].resize(loop->getTapeDependentCount());
77 size_t nnz = rows.size();
82 for (
size_t el = 0; el < nnz; el++) {
85 size_t e = location[el];
94 const std::map<size_t, LoopIndexedPosition>& depIndexes = l->getOriginalDependentIndexes();
95 const auto iti = depIndexes.find(i);
96 if (iti != depIndexes.end()) {
98 tapeI = iti->second.tape;
99 iteration = iti->second.iteration;
104 if (loop ==
nullptr) {
108 CPPADCG_ASSERT_UNKNOWN(_funNoLoops !=
nullptr);
109 size_t il = _funNoLoops->getLocalDependentIndex(i);
111 noLoopEvalSparsity[il].insert(j);
112 noLoopEvalLocations[il][j].insert(e);
124 size_t nIndexed = indexedIndepIndexes.size();
125 size_t nNonIndexed = nonIndexedIndepIndexes.size();
127 const std::vector<std::set<size_t> >& loopSparsity = loop->getJacobianSparsity();
128 const std::set<size_t>& loopRow = loopSparsity[tapeI];
130 JacobianWithLoopsRowInfo& rowInfo = loopEqInfo[loop][tapeI];
132 std::set<size_t>& loopEvalRow = loopsEvalSparsities[loop][tapeI];
139 for (
size_t tapeJ : tapeJs) {
140 if (loopRow.find(tapeJ) != loopRow.end()) {
141 loopEvalRow.insert(tapeJ);
144 std::vector<size_t>& positions = rowInfo.indexedPositions[tapeJ];
145 positions.resize(iterations, (std::numeric_limits<size_t>::max)());
146 if (positions[iteration] != (std::numeric_limits<size_t>::max)()) {
147 throw CGException(
"Repeated Jacobian elements requested (equation ", i,
", variable ", j,
")");
149 positions[iteration] = e;
157 bool jInNonIndexed =
false;
158 if (pos !=
nullptr && loopRow.find(pos->tape) != loopRow.end()) {
159 loopEvalRow.insert(pos->tape);
162 std::vector<size_t>& positions = rowInfo.nonIndexedPositions[j];
163 positions.resize(iterations, (std::numeric_limits<size_t>::max)());
164 if (positions[iteration] != (std::numeric_limits<size_t>::max)()) {
165 throw CGException(
"Repeated Jacobian elements requested (equation ", i,
", variable ", j,
")");
167 positions[iteration] = e;
169 rowInfo.nonIndexedEvals.insert(j);
171 jInNonIndexed =
true;
177 if (_funNoLoops !=
nullptr) {
178 set<size_t>::const_iterator itz = loopRow.lower_bound(nIndexed + nNonIndexed);
181 for (; itz != loopRow.end(); ++itz) {
183 size_t k = temporaryIndependents[tapeJ - nIndexed - nNonIndexed].original;
189 const set<size_t>& sparsity = _funNoLoops->getJacobianSparsity()[nonIndexdedEqSize + k];
190 if (sparsity.find(j) != sparsity.end()) {
191 noLoopEvalSparsity[nonIndexdedEqSize + k].insert(j);
192 if (!jInNonIndexed) {
193 std::vector<size_t>& positions = rowInfo.nonIndexedPositions[j];
194 positions.resize(iterations, (std::numeric_limits<size_t>::max)());
195 if (positions[iteration] != (std::numeric_limits<size_t>::max)()) {
196 throw CGException(
"Repeated Jacobian elements requested (equation ", i,
", variable ", j,
")");
198 positions[iteration] = e;
199 jInNonIndexed =
true;
201 rowInfo.tmpEvals[j].insert(k);
207 loopEvalRow.insert(tapeJ);
218 const std::vector<CGBase>& x,
226 size_t nonIndexdedEqSize = _funNoLoops !=
nullptr ? _funNoLoops->getOrigDependentIndexes().size() : 0;
228 std::vector<set<size_t> > noLoopEvalSparsity;
229 std::vector<map<size_t, set<size_t> > > noLoopEvalLocations;
230 map<LoopModel<Base>*, std::vector<set<size_t> > > loopsEvalSparsities;
231 map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> > loopEqInfo;
233 size_t nnz = _jacSparsity.rows.size();
234 std::vector<size_t> locations(nnz);
235 for (
size_t e = 0; e < nnz; e++)
238 analyseSparseJacobianWithLoops(_jacSparsity.rows, _jacSparsity.cols, locations,
239 noLoopEvalSparsity, noLoopEvalLocations, loopsEvalSparsities, loopEqInfo);
242 std::vector<CGBase> jac(nnz);
252 std::vector<CGBase> tmps;
255 std::vector<map<size_t, CGBase> > dzDx(_funNoLoops !=
nullptr ? _funNoLoops->getTemporaryDependentCount() : 0);
258 std::vector<CGBase> jacNoLoop;
259 if (_funNoLoops !=
nullptr) {
265 std::vector<CGBase> depNL = _funNoLoops->getTape().Forward(0, x);
267 tmps.resize(depNL.size() - nonIndexdedEqSize);
268 for (
size_t i = 0; i < tmps.size(); i++)
269 tmps[i] = depNL[nonIndexdedEqSize + i];
274 std::vector<size_t> row, col;
275 generateSparsityIndexes(noLoopEvalSparsity, row, col);
276 jacNoLoop.resize(row.size());
278 CppAD::sparse_jacobian_work work;
280 fun.SparseJacobianForward(x, _funNoLoops->getJacobianSparsity(), row, col, jacNoLoop, work);
282 fun.SparseJacobianReverse(x, _funNoLoops->getJacobianSparsity(), row, col, jacNoLoop, work);
285 for (
size_t el = 0; el < row.size(); el++) {
288 if (il < nonIndexdedEqSize) {
290 const std::set<size_t>& locations = noLoopEvalLocations[il][j];
291 for (
size_t itE : locations)
292 jac[itE] = jacNoLoop[el];
295 size_t k = il - nonIndexdedEqSize;
296 dzDx[k][j] = jacNoLoop[el];
306 std::vector<CGBase> jacLoop;
309 typename map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> >::iterator itl2Eq;
310 for (itl2Eq = loopEqInfo.begin(); itl2Eq != loopEqInfo.end(); ++itl2Eq) {
312 std::vector<JacobianWithLoopsRowInfo>& eqs = itl2Eq->second;
315 std::vector<IfElseInfo<Base> > ifElses;
323 std::set<IndexOperationNode<Base>*> indexesOps;
324 indexesOps.insert(iterationIndexOp);
329 std::vector<CGBase> indexedIndeps = createIndexedIndependents(handler, lModel, *iterationIndexOp);
330 std::vector<CGBase> xl = createLoopIndependentVector(handler, lModel, indexedIndeps, x, tmps);
332 std::vector<size_t> row, col;
333 generateSparsityIndexes(loopsEvalSparsities[&lModel], row, col);
334 jacLoop.resize(row.size());
336 if (row.size() == 0) {
340 CppAD::sparse_jacobian_work work;
342 fun.SparseJacobianForward(xl, lModel.getJacobianSparsity(), row, col, jacLoop, work);
344 fun.SparseJacobianReverse(xl, lModel.getJacobianSparsity(), row, col, jacLoop, work);
348 std::vector<std::map<size_t, CGBase> > dyiDxtape(lModel.getTapeDependentCount());
349 for (
size_t el = 0; el < jacLoop.size(); el++) {
350 size_t tapeI = row[el];
351 size_t tapeJ = col[el];
352 dyiDxtape[tapeI][tapeJ] = jacLoop[el];
356 std::set<size_t> allLocations;
359 size_t maxJacElSize = 0;
360 for (
size_t tapeI = 0; tapeI < eqs.size(); tapeI++) {
361 JacobianWithLoopsRowInfo& rowInfo = eqs[tapeI];
362 maxJacElSize += rowInfo.indexedPositions.size();
363 maxJacElSize += rowInfo.nonIndexedPositions.size();
366 std::vector<std::pair<CGBase, IndexPattern*> > indexedLoopResults(maxJacElSize);
370 for (
size_t tapeI = 0; tapeI < eqs.size(); tapeI++) {
371 JacobianWithLoopsRowInfo& rowInfo = eqs[tapeI];
373 prepareSparseJacobianRowWithLoops(handler, lModel,
377 *iterationIndexOp, ifElses,
378 jacLE, indexedLoopResults, allLocations);
381 indexedLoopResults.resize(jacLE);
386 size_t assignOrAdd = 1;
389 for (
size_t e : allLocations) {
391 jac[e] = handler.createCG(*handler.makeNode(CGOpCode::DependentRefRhs,{e}, {*loopEnd}));
397 moveNonIndexedOutsideLoop(handler, *loopStart, *loopEnd);
408 const std::vector<std::map<size_t, CGBase> >& dyiDxtape,
409 const std::vector<std::map<size_t, CGBase> >& dzDx,
415 std::set<size_t>& allLocations) {
417 using namespace loops;
423 for (
const auto& itJ2Pos : rowInfo.indexedPositions) {
424 size_t tapeJ = itJ2Pos.first;
425 const std::vector<size_t>& positions = itJ2Pos.second;
427 CGBase jacVal = dyiDxtape[tapeI].at(tapeJ) * py;
429 indexedLoopResults[jacLE++] = createJacobianElement(handler, positions,
430 jacVal, iterationIndexOp, ifElses,
438 for (
const auto& itJ2Pos : rowInfo.nonIndexedPositions) {
439 size_t j = itJ2Pos.first;
440 const std::vector<size_t>& positions = itJ2Pos.second;
446 if (pos !=
nullptr) {
447 size_t tapeJ = pos->tape;
448 const auto itVal = dyiDxtape[tapeI].find(tapeJ);
449 if (itVal != dyiDxtape[tapeI].end()) {
450 jacVal += itVal->second;
455 const auto itks = rowInfo.tmpEvals.find(j);
456 if (itks != rowInfo.tmpEvals.end()) {
457 const std::set<size_t>& ks = itks->second;
458 for (
size_t k : ks) {
461 jacVal += dyiDxtape[tapeI].at(tapeJ) * dzDx[k].at(j);
467 indexedLoopResults[jacLE++] = createJacobianElement(handler, positions,
468 jacVal, iterationIndexOp, ifElses,
478 const std::vector<size_t>& positions,
482 std::set<size_t>& allLocations) {
485 size_t nIter = positions.size();
487 map<size_t, size_t> locations;
488 for (
size_t iter = 0; iter < nIter; iter++) {
489 if (positions[iter] != (std::numeric_limits<size_t>::max)()) {
490 locations[iter] = positions[iter];
491 allLocations.insert(positions[iter]);
496 if (locations.size() == nIter) {
501 handler.manageLoopDependentIndexPattern(pattern);
511 handler.manageLoopDependentIndexPattern(pattern);
515 return createLoopResult(handler, locations, nIter,
517 iterationIndexOp, ifElses);
const std::set< size_t > & getIndexedTapeIndexes(size_t iteration, size_t origJ) const
void analyseSparseJacobianWithLoops(const std::vector< size_t > &rows, const std::vector< size_t > &cols, const std::vector< size_t > &location, SparsitySetType &noLoopEvalSparsity, std::vector< std::map< size_t, std::set< size_t > > > &noLoopEvalLocations, std::map< LoopModel< Base > *, SparsitySetType > &loopsEvalSparsities, std::map< LoopModel< Base > *, std::vector< loops::JacobianWithLoopsRowInfo > > &loopEqInfo)
void prepareSparseJacobianRowWithLoops(CodeHandler< Base > &handler, LoopModel< Base > &lModel, size_t tapeI, const loops::JacobianWithLoopsRowInfo &rowInfo, const std::vector< std::map< size_t, CGBase > > &dyiDxtape, const std::vector< std::map< size_t, CGBase > > &dzDx, const CGBase &py, IndexOperationNode< Base > &iterationIndexOp, std::vector< loops::IfElseInfo< Base > > &ifElses, size_t &jacLE, std::vector< std::pair< CG< Base >, IndexPattern *> > &indexedLoopResults, std::set< size_t > &allLocations)
const std::vector< LoopPosition > & getTemporaryIndependents() const
ADFun< CGB > & getTape() const
static IndexPattern * detect(const VectorSizeT &x2y)
const LoopPosition * getTempIndepIndexes(size_t k) const
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
const size_t getIterationCount() const
void setZeroDependents(bool zeroDependents)
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
virtual std::vector< CGBase > prepareSparseJacobianWithLoops(CodeHandler< Base > &handler, const std::vector< CGBase > &x, bool forward)