CppADCodeGen  2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
range.hpp
1 #ifndef CPPAD_CG_RANGE_INCLUDED
2 #define CPPAD_CG_RANGE_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 
27 inline void combineNonOverlapingIterationRanges(std::vector<size_t>& iterRegions,
28  const std::vector<size_t>& newIterRegions) {
29  if (iterRegions.empty()) {
30  iterRegions = newIterRegions;
31  return;
32  } else if (newIterRegions.empty()) {
33  return;
34  }
35 
39  std::vector<size_t>::iterator itPos = iterRegions.begin();
40  std::vector<size_t>::const_iterator itNew;
41  for (itNew = newIterRegions.begin(); itNew != newIterRegions.end(); ++itNew) {
42  size_t pos = *itNew;
43  itPos = std::lower_bound(itPos, iterRegions.end(), pos);
44  if (itPos == iterRegions.end()) {
45  iterRegions.insert(iterRegions.end(), itNew, newIterRegions.end());
46  break; // done
47  } else if (*itPos == pos) {
48  // same value -> must merge
49  itPos = iterRegions.erase(itPos);
50  } else {
51  itPos = iterRegions.insert(itPos, pos);
52  }
53  }
54  CPPADCG_ASSERT_UNKNOWN(iterRegions.size() % 2 == 0);
55 }
56 
63 inline void combineOverlapingIterationRanges(std::vector<size_t>& iterRegions,
64  const std::vector<size_t>& newIterRegions) {
65  if (iterRegions.empty()) {
66  iterRegions = newIterRegions;
67  return;
68  } else if (newIterRegions.empty()) {
69  return;
70  }
71 
72  std::vector<std::pair<size_t, size_t> > sorted;
73  for (size_t i = 0; i < iterRegions.size(); i += 2) {
74  sorted.insert(sorted.end(), std::make_pair(iterRegions[i], iterRegions[i + 1]));
75  }
76 
77  std::vector<std::pair<size_t, size_t> >::iterator begin = sorted.begin();
78  for (size_t i = 0; i < newIterRegions.size(); i += 2) {
79  std::pair<size_t, size_t> p(newIterRegions[i], newIterRegions[i + 1]);
80  begin = std::lower_bound(begin, sorted.end(), p);
81  begin = sorted.insert(begin, p);
82  begin++;
83  }
84 
85  std::vector<std::pair<size_t, size_t> > result;
86  result.reserve(sorted.size());
87  result.push_back(sorted[0]);
88  for (size_t i = 1; i < sorted.size(); i++) {
89  const std::pair<size_t, size_t>& curr = sorted[i]; // interval to be added
90  std::pair<size_t, size_t>& top = result.back();
91 
92  if (top.second == (std::numeric_limits<size_t>::max)()) // avoid overflow
93  break; // done, nothing can be added
94 
95  // if current interval is not overlapping with stack top,
96  // push it to the stack
97  if (top.second + 1 < curr.first) {
98  result.push_back(curr);
99  } else if (top.second < curr.second) {
100  // Otherwise update the ending time of top if ending of current
101  // interval is more
102  top.second = curr.second;
103  }
104  }
105 
106  iterRegions.resize(result.size() * 2);
107  for (size_t i = 0; i < result.size(); i++) {
108  iterRegions[2 * i] = result[i].first;
109  iterRegions[2 * i + 1] = result[i].second;
110  }
111 }
112 
122 inline std::vector<size_t> invertIterationRanges(const std::vector<size_t>& iterRegions) {
123  std::vector<size_t> inverted;
124  if (iterRegions.empty()) {
125  inverted.resize(2);
126  inverted[1] = (std::numeric_limits<size_t>::max)();
127  return inverted;
128  }
129 
130  CPPADCG_ASSERT_UNKNOWN(iterRegions.size() % 2 == 0);
131  inverted.reserve(iterRegions.size() + 4);
132 
133  if (iterRegions[0] != 0) {
134  inverted.push_back(0);
135  inverted.push_back(iterRegions[0] - 1);
136  }
137 
138  for (size_t i = 2; i < iterRegions.size(); i += 2) {
139  CPPADCG_ASSERT_UNKNOWN(iterRegions[i - 1] < iterRegions[i]);
140  inverted.push_back(iterRegions[i - 1] + 1);
141  inverted.push_back(iterRegions[i] - 1);
142  }
143 
144  if (iterRegions.back() != (std::numeric_limits<size_t>::max)()) {
145  inverted.push_back(iterRegions.back() + 1);
146  inverted.push_back((std::numeric_limits<size_t>::max)());
147  }
148 
149  return inverted;
150 }
151 
160 template<class Base>
161 inline std::vector<size_t> ifBranchIterationRanges(const OperationNode<Base>* bScope,
162  IndexOperationNode<Base>*& iterationIndexOp) {
163  CGOpCode bOp = bScope->getOperationType();
164 
165  if (bOp == CGOpCode::StartIf || bOp == CGOpCode::ElseIf) {
166  OperationNode<Base>* cond = bScope->getArguments()[bOp == CGOpCode::StartIf ? 0 : 1].getOperation();
167  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr);
168  CPPADCG_ASSERT_UNKNOWN(cond->getArguments().size() == 1);
169  CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation() != nullptr);
170  CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index);
171  iterationIndexOp = static_cast<IndexOperationNode<Base>*> (cond->getArguments()[0].getOperation());
172  return cond->getInfo();
173 
174  } else {
175  // else
176  CPPADCG_ASSERT_UNKNOWN(bOp == CGOpCode::Else);
177 
178  std::vector<size_t> nonIterationRegions;
179  OperationNode<Base>* ifBranch = bScope->getArguments()[0].getOperation();
180  do {
181  CGOpCode bbOp = ifBranch->getOperationType();
182  OperationNode<Base>* cond = ifBranch->getArguments()[bbOp == CGOpCode::StartIf ? 0 : 1].getOperation();
183  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr);
184  CPPADCG_ASSERT_UNKNOWN(cond->getArguments().size() == 1);
185  CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation() != nullptr);
186  CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index);
187  IndexOperationNode<Base>* indexOp = static_cast<IndexOperationNode<Base>*> (cond->getArguments()[0].getOperation());
188  CPPADCG_ASSERT_UNKNOWN(iterationIndexOp == nullptr || iterationIndexOp == indexOp);
189  iterationIndexOp = indexOp;
190 
191  combineOverlapingIterationRanges(nonIterationRegions, cond->getInfo());
192 
193  ifBranch = ifBranch->getArguments()[0].getOperation();
194  } while (ifBranch->getOperationType() == CGOpCode::ElseIf);
195 
196  CPPADCG_ASSERT_UNKNOWN(iterationIndexOp != nullptr);
197 
198  // invert
199  return invertIterationRanges(nonIterationRegions);
200  }
201 
202 }
203 
204 } // END cg namespace
205 } // END CppAD namespace
206 
207 #endif