CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
array_id_compresser.hpp
1 #ifndef CPPAD_CG_ARRAY_COMPRESSER_INCLUDED
2 #define CPPAD_CG_ARRAY_COMPRESSER_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2014 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>
28 private:
32  std::map<size_t, size_t> _freeArrayStartSpace;
36  std::map<size_t, size_t> _freeArrayEndSpace;
40  std::vector<const Argument<Base>*> _tmpArrayValues;
48  size_t _idArrayCount;
49 public:
50 
56  size_t maxArraySize) :
57  _tmpArrayValues(maxArraySize, nullptr),
58  _varId(varId),
59  _idArrayCount(1) {
60  }
61 
62  inline size_t getIdCount() const {
63  return _idArrayCount;
64  }
65 
66  inline void addFreeArraySpace(const OperationNode<Base>& released) {
67  size_t arrayStart = _varId[released] - 1;
68  const size_t arraySize = released.getArguments().size();
69  if (arraySize == 0)
70  return; // nothing to do (no free space)
71  size_t arrayEnd = arrayStart + arraySize - 1;
72 
73  std::map<size_t, size_t>::iterator it;
74  if (arrayStart > 0) {
75  // try to merge with previous free space
76  it = _freeArrayEndSpace.find(arrayStart - 1); // previous
77  if (it != _freeArrayEndSpace.end()) {
78  arrayStart = it->second; // merge space
79  _freeArrayEndSpace.erase(it);
80  _freeArrayStartSpace.erase(arrayStart);
81  }
82  }
83 
84  // try to merge with the next free space
85  it = _freeArrayStartSpace.find(arrayEnd + 1); // next
86  if (it != _freeArrayStartSpace.end()) {
87  arrayEnd = it->second; // merge space
88  _freeArrayStartSpace.erase(it);
89  _freeArrayEndSpace.erase(arrayEnd);
90  }
91 
92  _freeArrayStartSpace[arrayStart] = arrayEnd;
93  _freeArrayEndSpace[arrayEnd] = arrayStart;
94 
95  CPPADCG_ASSERT_UNKNOWN(_freeArrayStartSpace.size() == _freeArrayEndSpace.size());
96  }
97 
98  inline size_t reserveArraySpace(const OperationNode<Base>& newArray) {
99  size_t arraySize = newArray.getArguments().size();
100 
101  if (arraySize == 0)
102  return 0; // nothing to do (no space required)
103 
104  std::set<size_t> blackList;
105  const std::vector<Argument<Base> >& args = newArray.getArguments();
106  for (size_t i = 0; i < args.size(); i++) {
107  const OperationNode<Base>* argOp = args[i].getOperation();
108  if (argOp != nullptr && argOp->getOperationType() == CGOpCode::ArrayElement) {
109  const OperationNode<Base>& otherArray = *argOp->getArguments()[0].getOperation();
110  CPPADCG_ASSERT_UNKNOWN(_varId[otherArray] > 0); // make sure it had already been assigned space
111  size_t otherArrayStart = _varId[otherArray] - 1;
112  size_t index = argOp->getInfo()[0];
113  blackList.insert(otherArrayStart + index);
114  }
115  }
116 
120  std::map<size_t, size_t>::reverse_iterator it;
121  std::map<size_t, size_t>::reverse_iterator itBestFit = _freeArrayStartSpace.rend();
122  size_t bestCommonValues = 0; // the number of values likely to be the same
123  for (it = _freeArrayStartSpace.rbegin(); it != _freeArrayStartSpace.rend(); ++it) {
124  size_t start = it->first;
125  size_t end = it->second;
126  size_t space = end - start + 1;
127  if (space < arraySize) {
128  continue;
129  }
130 
131  std::set<size_t>::const_iterator itBlack = blackList.lower_bound(start);
132  if (itBlack != blackList.end() && *itBlack <= end) {
133  continue; // cannot use this space
134  }
135 
136  //possible candidate
137  if (itBestFit == _freeArrayStartSpace.rend()) {
138  itBestFit = it;
139  } else {
140  size_t bestSpace = itBestFit->second - itBestFit->first + 1;
141 
142  size_t commonVals = 0;
143  for (size_t i = 0; i < arraySize; i++) {
144  if (isSameArrayElement(_tmpArrayValues[start + i], args[i])) {
145  commonVals++;
146  }
147  }
148 
149  if (space < bestSpace || commonVals > bestCommonValues) {
150  // better fit
151  itBestFit = it;
152  bestCommonValues = commonVals;
153  if (bestCommonValues == arraySize) {
154  break; // jackpot
155  }
156  }
157  }
158  }
159 
160  size_t bestStart = (std::numeric_limits<size_t>::max)();
161  if (itBestFit != _freeArrayStartSpace.rend()) {
165  bestStart = itBestFit->first;
166  size_t bestEnd = itBestFit->second;
167  size_t bestSpace = bestEnd - bestStart + 1;
168  _freeArrayStartSpace.erase(bestStart);
169  if (bestSpace == arraySize) {
170  // entire space
171  _freeArrayEndSpace.erase(bestEnd);
172  } else {
173  // some space left
174  size_t newFreeStart = bestStart + arraySize;
175  _freeArrayStartSpace[newFreeStart] = bestEnd;
176  _freeArrayEndSpace.at(bestEnd) = newFreeStart;
177  }
178 
179  } else {
183  // check if there is some free space at the end
184  std::map<size_t, size_t>::iterator itEnd;
185  itEnd = _freeArrayEndSpace.find(_idArrayCount - 1 - 1); // IDcount - initialID - 1
186  if (itEnd != _freeArrayEndSpace.end()) {
187  // check if it can be used
188  size_t lastSpotStart = itEnd->second;
189  size_t lastSpotEnd = itEnd->first;
190  size_t lastSpotSize = lastSpotEnd - lastSpotStart + 1;
191  std::set<size_t>::const_iterator itBlack = blackList.lower_bound(lastSpotStart);
192  if (itBlack == blackList.end()) {
193  // can use this space
194  _freeArrayEndSpace.erase(itEnd);
195  _freeArrayStartSpace.erase(lastSpotStart);
196 
197  _idArrayCount += arraySize - lastSpotSize;
198  bestStart = lastSpotStart;
199  }
200  }
201 
202  if (bestStart == (std::numeric_limits<size_t>::max)()) {
203  // brand new space
204  size_t id = _idArrayCount;
205  _idArrayCount += arraySize;
206  bestStart = id - 1;
207  }
208  }
209 
210  for (size_t i = 0; i < arraySize; i++) {
211  _tmpArrayValues[bestStart + i] = &args[i];
212  }
213 
214  CPPADCG_ASSERT_UNKNOWN(_freeArrayStartSpace.size() == _freeArrayEndSpace.size());
215 
216  return bestStart;
217  }
218 
219  inline static bool isSameArrayElement(const Argument<Base>* oldArg,
220  const Argument<Base>& arg) {
221  if (oldArg != nullptr) {
222  if (oldArg->getParameter() != nullptr) {
223  if (arg.getParameter() != nullptr) {
224  return (*arg.getParameter() == *oldArg->getParameter());
225  }
226  } else {
227  return (arg.getOperation() == oldArg->getOperation());
228  }
229  }
230  return false;
231  }
232 
233  virtual ~ArrayIdCompresser() {
234  }
235 };
236 
237 } // END cg namespace
238 } // END CppAD namespace
239 
240 #endif
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const
ArrayIdCompresser(CodeHandlerVector< Base, size_t > &varId, size_t maxArraySize)
size_t reserveArraySpace(const OperationNode< Base > &newArray)
const std::vector< size_t > & getInfo() const