CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
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 
18 namespace CppAD {
19 namespace cg {
20 
26 template <class Base>
27 class LoopModel {
28 public:
29  using CGB = CppAD::cg::CG<Base>;
30  using Arg = Argument<Base>;
31  using pairss = std::pair<size_t, size_t>;
32 public:
33  static const std::string ITERATION_INDEX_NAME;
34 private:
35  static const std::set<size_t> EMPTYSET;
36 private:
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_;
111 public:
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 
504 private:
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 
515 template<class Base>
516 const std::string LoopModel<Base>::ITERATION_INDEX_NAME("j");
517 
518 template<class Base>
519 const std::set<size_t> LoopModel<Base>::EMPTYSET;
520 
521 } // END cg namespace
522 } // END CppAD namespace
523 
524 #endif
const std::set< size_t > & getIndexedTapeIndexes(size_t iteration, size_t origJ) const
Definition: loop_model.hpp:374
std::map< size_t, std::set< size_t > > getIndexedTapeIndexes(size_t origJ) const
Definition: loop_model.hpp:393
const LoopPosition * getNonIndexedIndepIndexes(size_t origJ) const
Definition: loop_model.hpp:345
const std::vector< LoopPosition > & getTemporaryIndependents() const
Definition: loop_model.hpp:324
size_t index
iteration group index/ID
size_t getTapeDependentCount() const
Definition: loop_model.hpp:274
STL namespace.
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)
Definition: loop_model.hpp:125
const LoopIndexedPosition & getTapeDependentIndex(size_t origI) const
Definition: loop_model.hpp:334
size_t getLoopId() const
Definition: loop_model.hpp:236
ADFun< CGB > & getTape() const
Definition: loop_model.hpp:263
bool isContainsAtomics() const
Definition: loop_model.hpp:245
static IndexPattern * detect(const VectorSizeT &x2y)
const LoopPosition * getTempIndepIndexes(size_t k) const
Definition: loop_model.hpp:357
const std::vector< LoopPosition > & getNonIndexedIndepIndexes() const
Definition: loop_model.hpp:316
const size_t getIterationCount() const
Definition: loop_model.hpp:254
const std::vector< IterEquationGroup< Base > > & getEquationsGroups() const
Definition: loop_model.hpp:298
const std::vector< std::vector< LoopPosition > > & getDependentIndexes() const
Definition: loop_model.hpp:291
const std::vector< std::vector< LoopPosition > > & getIndexedIndepIndexes() const
Definition: loop_model.hpp:309
std::set< size_t > tapeI
equations indexes in tape of the loop model
size_t getTapeIndependentCount() const
Definition: loop_model.hpp:284
std::set< size_t > iterations
iterations which only have these equations defined