CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
sectioned_index_pattern.hpp
1 #ifndef CPPAD_CG_SECTIONED_INDEX_PATTERN_INCLUDED
2 #define CPPAD_CG_SECTIONED_INDEX_PATTERN_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2013 Ciengis
6  * Copyright (C) 2018 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 
19 namespace CppAD {
20 namespace cg {
21 
26 protected:
30  std::map<size_t, IndexPattern*> sections_;
31 public:
32 
33  inline SectionedIndexPattern(const std::map<size_t, IndexPattern*>& sections) :
34  sections_(sections) {
35  }
36 
37  inline const std::map<size_t, IndexPattern*>& getLinearSections() const {
38  return sections_;
39  }
40 
41  inline IndexPatternType getType() const override {
42  return IndexPatternType::Sectioned;
43  }
44 
45  inline void getSubIndexes(std::set<IndexPattern*>& indexes) const override {
46  for (const auto& it : sections_) {
47  indexes.insert(it.second);
48  it.second->getSubIndexes(indexes);
49  }
50  }
51 
52  inline virtual ~SectionedIndexPattern() {
53  deleteIndexPatterns(sections_);
54  }
55 
56  /***********************************************************************
57  * static methods
58  **********************************************************************/
59 
60  template<class VectorSizeT>
61  static inline std::map<size_t, IndexPattern*> detectLinearSections(const VectorSizeT& indexes,
62  size_t maxCount = 0) {
63  CPPADCG_ASSERT_UNKNOWN(indexes.size() > 0);
64 
65  long dx = 1;
66  long xOffset = 0;
67 
68  LinearIndexPattern* prevPattern = nullptr;
69  size_t prevXStart = 0;
70 
72  size_t xStart = 0;
73  while (xStart != indexes.size()) {
74  long dy, b;
75  size_t lastLinear;
76  if (xStart + 1 == indexes.size()) {
77  dy = 0;
78  b = indexes[xStart];
79  lastLinear = xStart + 1;
80  } else {
81  dy = long(indexes[xStart + 1]) - indexes[xStart];
82  b = long(indexes[xStart]) - dy * xStart;
83  lastLinear = indexes.size();
84  for (size_t x = xStart + 2; x < indexes.size(); x++) {
85  if (indexes[x] != dy * x + b) {
86  lastLinear = x;
87  break;
88  }
89  }
90  }
91 
92  LinearIndexPattern* p = new LinearIndexPattern(xOffset, dy, dx, b);
93  if (dy == 0 && prevPattern != nullptr) { // constant
94  // can we take the last element out of the previous section?
95  while (xStart > 0 && prevPattern->evaluate(xStart - 1) == b) {
96  // yes
97  xStart--;
98  if (prevXStart + 1 == xStart) {
99  // it has only one element -> make it a constant section
100  size_t bb = prevPattern->evaluate(prevXStart);
101  prevPattern->setLinearSlopeDy(0);
102  prevPattern->setLinearConstantTerm(bb);
103  }
104  }
105  }
106  linearSections[xStart] = p;
107 
108  prevXStart = xStart;
109  prevPattern = p;
110  xStart = lastLinear;
111 
112  if (linearSections.size() == maxCount && xStart != indexes.size()) {
113  // over the limit -> stop
114  return std::map<size_t, IndexPattern*>(); // empty
115  }
116  }
117 
118  return linearSections.release();
119  }
120 
121  static inline std::map<size_t, IndexPattern*> detectLinearSections(const std::map<size_t, size_t>& x2y,
122  size_t maxCount = 0) {
123  using c_iter = std::map<size_t, size_t>::const_iterator;
124 
126 
127  LinearIndexPattern* prevPattern = nullptr;
128  c_iter prevStart = x2y.begin();
129 
130  c_iter pStart = x2y.begin();
131  while (pStart != x2y.end()) {
132  c_iter pNextSection = x2y.end();
133  c_iter p1 = pStart;
134  ++p1;
135 
136  long xOffset, dy, dx, b;
137  if (p1 == x2y.end()) {
138  xOffset = 0;
139  dy = 0;
140  dx = 1;
141  b = pStart->second;
142  pNextSection = p1;
143 
144  } else {
145  long x0 = pStart->first;
146  long y0 = pStart->second;
147 
148  dy = long(p1->second) - y0;
149  if (dy != 0) {
150  dx = long(p1->first) - x0;
151  xOffset = x0 % dx;
152  // y = ((x - offset) / dx) * dy + b
153  b = y0 - ((x0 - xOffset) / dx) * dy;
154  } else {
155  dx = 1;
156  xOffset = 0;
157  b = y0;
158  }
159 
160  for (std::map<size_t, size_t>::const_iterator itp = p1; itp != x2y.end(); ++itp) {
161  size_t x = itp->first;
162  size_t y = itp->second;
163 
164  if (y != ((x - xOffset) / dx) * dy + b) {
165  pNextSection = itp;
166  break;
167  }
168  }
169  }
170 
171  LinearIndexPattern* p = new LinearIndexPattern(xOffset, dy, dx, b);
172  size_t xStart = pStart->first;
173  if (dy == 0 && prevPattern != nullptr) { // constant
174  // can we take the last element from the previous section?
175 
176  while (pStart != x2y.begin()) {
177  c_iter prevBack = pStart;
178  --prevBack; // the values at the end of the previous section
179  if (prevPattern->evaluate(prevBack->first) != b)
180  break; // no
181 
182  // yes
183  --pStart;
184  xStart = pStart->first;
185  c_iter prevStartN = prevStart;
186  prevStartN++;
187  if (prevStartN == pStart) {
188  // it has only one element -> make it a constant section
189  size_t bb = prevPattern->evaluate(prevStart->first);
190  prevPattern->setLinearSlopeDy(0);
191  prevPattern->setLinearConstantTerm(bb);
192  }
193  }
194  }
195  linearSections[xStart] = p;
196 
197  prevStart = pStart;
198  prevPattern = p;
199  pStart = pNextSection;
200 
201  if (linearSections.size() == maxCount && pStart != x2y.end()) {
202  // over the limit -> stop
203  return std::map<size_t, IndexPattern*>(); // empty
204  }
205  }
206 
207  return linearSections.release();
208  }
209 
210 private:
211 
212  static inline void deleteIndexPatterns(std::map<size_t, IndexPattern*>& sections) {
213  for (const auto& it : sections) {
214  delete it.second;
215  }
216  sections.clear();
217  }
218 };
219 
220 } // END cg namespace
221 } // END CppAD namespace
222 
223 #endif
std::map< size_t, IndexPattern * > sections_