CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
18namespace CppAD {
19namespace cg {
20
26template<class Base>
28private:
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;
49public:
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
ArrayIdCompresser(CodeHandlerVector< Base, size_t > &varId, size_t maxArraySize)
size_t reserveArraySpace(const OperationNode< Base > &newArray)
const std::vector< size_t > & getInfo() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const