CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
loop_model.hpp
1#ifndef CPPAD_CG_LOOP_MODEL_INCLUDED
2#define CPPAD_CG_LOOP_MODEL_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2013 Ciengis
6 *
7 * CppADCodeGen is distributed under multiple licenses:
8 *
9 * - Eclipse Public License Version 1.0 (EPL1), and
10 * - GNU General Public License Version 3 (GPL3).
11 *
12 * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13 * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14 * ----------------------------------------------------------------------------
15 * Author: Joao Leal
16 */
17
18namespace CppAD {
19namespace cg {
20
26template <class Base>
27class LoopModel {
28public:
30 using Arg = Argument<Base>;
31 using pairss = std::pair<size_t, size_t>;
32public:
33 static const std::string ITERATION_INDEX_NAME;
34private:
35 static const std::set<size_t> EMPTYSET;
36private:
37 const size_t loopId_;
41 ADFun<CGB>* const fun_;
45 const bool containsAtoms_;
49 const size_t iterationCount_;
53 const size_t m_;
57 std::vector<std::vector<LoopPosition> > dependentIndexes_;
61 std::vector<std::vector<LoopPosition> > indexedIndepIndexes_;
65 std::vector<LoopPosition> nonIndexedIndepIndexes_;
70 std::vector<LoopPosition> temporaryIndependents_;
75 std::map<size_t, LoopIndexedPosition> depOrigIndexes_;
79 std::vector<IterEquationGroup<Base> > equationGroups_;
80 std::vector<std::set<const IterEquationGroup<Base>*> > iteration2eqGroups_;
84 std::vector<std::map<size_t, std::set<size_t> > > iteration2orig2indexedIndepIndexes_;
88 std::map<size_t, LoopPosition*> orig2nonIndexedIndepIndexes_;
92 std::map<size_t, LoopPosition*> orig2tempIndepIndexes_;
96 std::vector<IndexPattern*> indepIndexPatterns_;
100 std::vector<IndexPattern*> depIndexPatterns_;
104 std::vector<std::set<size_t> > jacTapeSparsity_;
105 bool jacSparsity_;
109 std::vector<std::set<size_t> > hessTapeSparsity_;
110 bool hessSparsity_;
111public:
112
126 bool containsAtoms,
127 size_t iterationCount,
128 const std::vector<std::vector<size_t> >& dependentOrigIndexes,
129 const std::vector<std::vector<size_t> >& indexedIndepOrigIndexes,
130 const std::vector<size_t>& nonIndexedIndepOrigIndexes,
131 const std::vector<size_t>& temporaryIndependents) :
132 loopId_(createNewLoopId()),
133 fun_(fun),
134 containsAtoms_(containsAtoms),
135 iterationCount_(iterationCount),
136 m_(dependentOrigIndexes.size()),
137 dependentIndexes_(m_, std::vector<LoopPosition>(iterationCount)),
138 indexedIndepIndexes_(indexedIndepOrigIndexes.size(), std::vector<LoopPosition>(iterationCount)),
139 nonIndexedIndepIndexes_(nonIndexedIndepOrigIndexes.size()),
140 temporaryIndependents_(temporaryIndependents.size()),
141 iteration2orig2indexedIndepIndexes_(iterationCount),
142 jacSparsity_(false),
143 hessSparsity_(false) {
144 CPPADCG_ASSERT_KNOWN(fun != nullptr, "fun cannot be null");
145
149 for (size_t i = 0; i < m_; i++) {
150 for (size_t it = 0; it < iterationCount_; it++) {
151 size_t orig = dependentOrigIndexes[i][it];
152 dependentIndexes_[i][it] = LoopPosition(i, orig);
153 if (orig != (std::numeric_limits<size_t>::max)()) // some equations are not present in all iterations
154 depOrigIndexes_[orig] = LoopIndexedPosition(dependentIndexes_[i][it].tape,
155 dependentIndexes_[i][it].original,
156 it);
157 }
158 }
159
164 std::map<std::set<size_t>, std::set<size_t>, SetComparator<size_t> > iterations2equations;
165 size_t lm = dependentIndexes_.size();
166
167 for (size_t i = 0; i < lm; i++) {
168 std::set<size_t> iterations;
169 for (size_t it = 0; it < iterationCount_; it++) {
170 if (dependentIndexes_[i][it].original != (std::numeric_limits<size_t>::max)()) {
171 iterations.insert(it);
172 }
173 }
174 iterations2equations[iterations].insert(i);
175 }
176
177 equationGroups_.resize(iterations2equations.size());
178 iteration2eqGroups_.resize(iterationCount_);
179
180 std::map<std::set<size_t>, std::set<size_t>, SetComparator<size_t> >::const_iterator itEqeIt;
181 size_t g = 0;
182 for (itEqeIt = iterations2equations.begin(); itEqeIt != iterations2equations.end(); ++itEqeIt, g++) {
183 const std::set<size_t>& iterations = itEqeIt->first;
184
185 IterEquationGroup<Base>& group = equationGroups_[g];
186 group.index = g;
187 group.tapeI = itEqeIt->second;
188 group.iterations = iterations;
189 group.model = this;
190
191 // map iterations to the equation groups
192 for (size_t itIt : iterations) {
193 iteration2eqGroups_[itIt].insert(&group);
194 }
195 }
196
200 size_t nIndexed = indexedIndepOrigIndexes.size();
201
202 // indexed
203 for (size_t it = 0; it < iterationCount_; it++) {
204 for (size_t j = 0; j < nIndexed; j++) {
205 size_t orig = indexedIndepOrigIndexes[j][it];
206 indexedIndepIndexes_[j][it] = LoopPosition(j, orig);
207 if (orig != (std::numeric_limits<size_t>::max)()) //some variables are not present in all iterations
208 iteration2orig2indexedIndepIndexes_[it][orig].insert(j);
209 }
210 }
211
212 // non-indexed
213 size_t nNonIndexed = nonIndexedIndepOrigIndexes.size();
214 for (size_t j = 0; j < nNonIndexed; j++) {
215 size_t orig = nonIndexedIndepOrigIndexes[j];
216 nonIndexedIndepIndexes_[j] = LoopPosition(nIndexed + j, orig);
217 orig2nonIndexedIndepIndexes_[orig] = &nonIndexedIndepIndexes_[j];
218 }
219
220 // temporary
221 for (size_t j = 0; j < temporaryIndependents.size(); j++) {
222 size_t k = temporaryIndependents[j];
223 temporaryIndependents_[j] = LoopPosition(nIndexed + nNonIndexed + j, k);
224 orig2tempIndepIndexes_[k] = &temporaryIndependents_[j];
225 }
226 }
227
228 LoopModel(const LoopModel<Base>&) = delete;
229 LoopModel& operator=(const LoopModel<Base>&) = delete;
230
236 inline size_t getLoopId() const {
237 return loopId_;
238 }
239
245 inline bool isContainsAtomics() const {
246 return containsAtoms_;
247 }
248
254 inline const size_t getIterationCount() const {
255 return iterationCount_;
256 }
257
263 inline ADFun<CGB>& getTape() const {
264 return *fun_;
265 }
266
274 inline size_t getTapeDependentCount() const {
275 return m_;
276 }
277
284 inline size_t getTapeIndependentCount() const {
285 return fun_->Domain();
286 }
287
291 inline const std::vector<std::vector<LoopPosition> >& getDependentIndexes() const {
292 return dependentIndexes_;
293 }
294
298 inline const std::vector<IterEquationGroup<Base> >& getEquationsGroups() const {
299 return equationGroups_;
300 }
301
302 inline const std::vector<std::set<const IterEquationGroup<Base>*> >& getIterationEquationsGroup() const {
303 return iteration2eqGroups_;
304 }
305
309 inline const std::vector<std::vector<LoopPosition> >& getIndexedIndepIndexes() const {
310 return indexedIndepIndexes_;
311 }
312
316 inline const std::vector<LoopPosition>& getNonIndexedIndepIndexes() const {
317 return nonIndexedIndepIndexes_;
318 }
319
324 inline const std::vector<LoopPosition>& getTemporaryIndependents() const {
325 return temporaryIndependents_;
326 }
327
334 inline const LoopIndexedPosition& getTapeDependentIndex(size_t origI) const {
335 return depOrigIndexes_.at(origI);
336 }
337
338 inline const std::map<size_t, LoopIndexedPosition>& getOriginalDependentIndexes() const {
339 return depOrigIndexes_;
340 }
341
345 inline const LoopPosition* getNonIndexedIndepIndexes(size_t origJ) const {
346 std::map<size_t, LoopPosition*>::const_iterator it = orig2nonIndexedIndepIndexes_.find(origJ);
347 if (it != orig2nonIndexedIndepIndexes_.end()) {
348 return it->second;
349 } else {
350 return nullptr;
351 }
352 }
353
357 inline const LoopPosition* getTempIndepIndexes(size_t k) const {
358 std::map<size_t, LoopPosition*>::const_iterator it = orig2tempIndepIndexes_.find(k);
359 if (it != orig2tempIndepIndexes_.end()) {
360 return it->second;
361 } else {
362 return nullptr;
363 }
364 }
365
374 inline const std::set<size_t>& getIndexedTapeIndexes(size_t iteration, size_t origJ) const {
375 CPPADCG_ASSERT_UNKNOWN(iteration < iteration2orig2indexedIndepIndexes_.size());
376
377 const std::map<size_t, std::set<size_t> >& itOrigs = iteration2orig2indexedIndepIndexes_[iteration];
378 std::map<size_t, std::set<size_t> >::const_iterator it = itOrigs.find(origJ);
379 if (it != itOrigs.end()) {
380 return it->second;
381 } else {
382 return EMPTYSET;
383 }
384 }
385
393 inline std::map<size_t, std::set<size_t> > getIndexedTapeIndexes(size_t origJ) const {
394 std::map<size_t, std::set<size_t> > iter2TapeJs;
395
396 for (size_t iter = 0; iter < iterationCount_; iter++) {
397 const std::map<size_t, std::set<size_t> >& itOrigs = iteration2orig2indexedIndepIndexes_[iter];
398 std::map<size_t, std::set<size_t> >::const_iterator it = itOrigs.find(origJ);
399 if (it != itOrigs.end()) {
400 iter2TapeJs[iter] = it->second;
401 }
402 }
403
404 return iter2TapeJs;
405 }
406
407 inline void detectIndexPatterns() {
408 if (indepIndexPatterns_.size() > 0)
409 return; // already done
410
411 indepIndexPatterns_.resize(indexedIndepIndexes_.size());
412 for (size_t j = 0; j < indepIndexPatterns_.size(); j++) {
413 std::map<size_t, size_t> indexes;
414 for (size_t it = 0; it < iterationCount_; it++) {
415 size_t orig = indexedIndepIndexes_[j][it].original;
416 if (orig != (std::numeric_limits<size_t>::max)()) // some variables are not present in all iteration
417 indexes[it] = orig;
418 }
419 indepIndexPatterns_[j] = IndexPattern::detect(indexes);
420 }
421
422 depIndexPatterns_.resize(dependentIndexes_.size());
423 for (size_t j = 0; j < depIndexPatterns_.size(); j++) {
424 std::map<size_t, size_t> indexes;
425 for (size_t it = 0; it < iterationCount_; it++) {
426 size_t e = dependentIndexes_[j][it].original;
427 if (e != (std::numeric_limits<size_t>::max)()) // some equations are not present in all iteration
428 indexes[it] = e;
429 }
430
431 depIndexPatterns_[j] = IndexPattern::detect(indexes);
432 }
433 }
434
435 inline const std::vector<IndexPattern*>& getDependentIndexPatterns() const {
436 return depIndexPatterns_;
437 }
438
439 inline const std::vector<IndexPattern*>& getIndependentIndexPatterns() const {
440 return indepIndexPatterns_;
441 }
442
443 inline bool isTemporary(size_t tapeJ) const {
444 size_t nIndexed = indexedIndepIndexes_.size();
445 size_t nNonIndexed = nonIndexedIndepIndexes_.size();
446
447 return nIndexed + nNonIndexed <= tapeJ;
448 }
449
450 inline bool isIndexedIndependent(size_t tapeJ) const {
451 return tapeJ < indexedIndepIndexes_.size();
452 }
453
454 inline void evalJacobianSparsity() {
455 if (!jacSparsity_) {
456 jacTapeSparsity_ = jacobianSparsitySet<std::vector<std::set<size_t> >, CGB>(*fun_);
457 jacSparsity_ = true;
458 }
459 }
460
461 inline const std::vector<std::set<size_t> >& getJacobianSparsity() const {
462 return jacTapeSparsity_;
463 }
464
465 inline void evalHessianSparsity() {
466 if (!hessSparsity_) {
467 size_t n = fun_->Domain();
468 hessTapeSparsity_.resize(n);
469
470 for (size_t g = 0; g < equationGroups_.size(); g++) {
471 equationGroups_[g].evalHessianSparsity();
472 const std::vector<std::set<size_t> >& ghess = equationGroups_[g].getHessianSparsity();
473 for (size_t j = 0; j < n; j++) {
474 hessTapeSparsity_[j].insert(ghess[j].begin(), ghess[j].end());
475 }
476 }
477
478 hessSparsity_ = true;
479 }
480 }
481
482 inline const std::vector<std::set<size_t> >& getHessianSparsity() const {
483 return hessTapeSparsity_;
484 }
485
486 virtual ~LoopModel() {
487 delete fun_;
488 for (size_t i = 0; i < indepIndexPatterns_.size(); i++) {
489 delete indepIndexPatterns_[i];
490 }
491 for (size_t i = 0; i < depIndexPatterns_.size(); i++) {
492 delete depIndexPatterns_[i];
493 }
494 }
495
496 static inline void printOriginalVariableIndexes(std::ostringstream& ss,
497 const std::vector<LoopPosition>& indexes) {
498 for (size_t iter = 0; iter < indexes.size(); iter++) {
499 if (iter > 0) ss << ", ";
500 ss << indexes[iter].original;
501 }
502 }
503
504private:
505
506 static size_t createNewLoopId() {
507 CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
508 static size_t count = 0;
509 count++;
510 return count;
511 }
512
513};
514
515template<class Base>
516const std::string LoopModel<Base>::ITERATION_INDEX_NAME("j");
517
518template<class Base>
519const std::set<size_t> LoopModel<Base>::EMPTYSET;
520
521} // END cg namespace
522} // END CppAD namespace
523
524#endif
static IndexPattern * detect(const VectorSizeT &x2y)
std::set< size_t > tapeI
equations indexes in tape of the loop model
std::set< size_t > iterations
iterations which only have these equations defined
size_t index
iteration group index/ID
const LoopPosition * getNonIndexedIndepIndexes(size_t origJ) const
const LoopIndexedPosition & getTapeDependentIndex(size_t origI) const
const std::vector< IterEquationGroup< Base > > & getEquationsGroups() const
const std::vector< LoopPosition > & getTemporaryIndependents() const
bool isContainsAtomics() const
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
const size_t getIterationCount() const
size_t getLoopId() const
std::map< size_t, std::set< size_t > > getIndexedTapeIndexes(size_t origJ) const
size_t getTapeDependentCount() const
const LoopPosition * getTempIndepIndexes(size_t k) const
size_t getTapeIndependentCount() const
LoopModel(ADFun< CGB > *fun, bool containsAtoms, size_t iterationCount, const std::vector< std::vector< size_t > > &dependentOrigIndexes, const std::vector< std::vector< size_t > > &indexedIndepOrigIndexes, const std::vector< size_t > &nonIndexedIndepOrigIndexes, const std::vector< size_t > &temporaryIndependents)
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
ADFun< CGB > & getTape() const
const std::vector< std::vector< LoopPosition > > & getDependentIndexes() const
const std::set< size_t > & getIndexedTapeIndexes(size_t iteration, size_t origJ) const