CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_c_index_patterns.hpp
1#ifndef CPPAD_CG_LANGUAGE_C_INDEX_PATTERNS_INCLUDED
2#define CPPAD_CG_LANGUAGE_C_INDEX_PATTERNS_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2013 Ciengis
6 * Copyright (C) 2019 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
19namespace CppAD {
20namespace cg {
21
22template<class Base>
23inline void LanguageC<Base>::generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns) {
24 std::ostringstream os;
25
26 std::set<std::string> usedNames;
27
28 // save existing names so that they are not to overridden
29 // (independent variable names might have already used them)
30 for (RandomIndexPattern* ip : randomPatterns) {
31 if (!ip->getName().empty()) {
32 usedNames.insert(ip->getName());
33 }
34 }
35
36 // create new names for the index pattern arrays without a name
37 size_t c = 0;
38 for (RandomIndexPattern* ip : randomPatterns) {
39 if (ip->getName().empty()) {
40 // new name required
41 std::string name;
42 do {
43 os << _C_STATIC_INDEX_ARRAY << c;
44 name = os.str();
45 os.str("");
46 c++;
47 } while (usedNames.find(name) != usedNames.end());
48
49 ip->setName(name);
50 }
51 }
52
53}
54
55template<class Base>
56inline void LanguageC<Base>::printRandomIndexPatternDeclaration(std::ostringstream& os,
57 const std::string& indentation,
58 const std::set<RandomIndexPattern*>& randomPatterns) {
59 for (RandomIndexPattern* ip : randomPatterns) {
60 if (ip->getType() == IndexPatternType::Random1D) {
64 auto* ip1 = static_cast<Random1DIndexPattern*> (ip);
65 const std::map<size_t, size_t>& x2y = ip1->getValues();
66
67 std::vector<size_t> y(x2y.rbegin()->first + 1);
68 for (const auto& p : x2y)
69 y[p.first] = p.second;
70
71 os << indentation;
72 printStaticIndexArray(os, ip->getName(), y);
73 } else {
74 CPPADCG_ASSERT_UNKNOWN(ip->getType() == IndexPatternType::Random2D)
78 auto* ip2 = static_cast<Random2DIndexPattern*> (ip);
79 os << indentation;
80 printStaticIndexMatrix(os, ip->getName(), ip2->getValues());
81 }
82 }
83}
84
85template<class Base>
87 if (_info == nullptr)
88 return;
89
90 if (_info->indexes.empty())
91 return;
92
93 std::set<const OperationNode<Base>*> funcArgs(_funcArgIndexes.begin(), _funcArgIndexes.end());
94
95 bool first = true;
96
97 printRandomIndexPatternDeclaration(_ss, _spaces, _info->indexRandomPatterns);
98
99 _ss << _spaces << U_INDEX_TYPE;
100 for (const OperationNode<Base>* iti : _info->indexes) {
101
102 if (funcArgs.find(iti) == funcArgs.end()) {
103 if (first) first = false;
104 else _ss << ",";
105
106 _ss << " " << (*iti->getName());
107 }
108
109 }
110 _ss << ";\n";
111}
112
113template<class Base>
114void LanguageC<Base>::printStaticIndexArray(std::ostringstream& os,
115 const std::string& name,
116 const std::vector<size_t>& values) {
117 os << "static " << U_INDEX_TYPE << " const " << name << "[" << values.size() << "] = {";
118 if (!values.empty()) {
119 os << values[0];
120 for (size_t i = 1; i < values.size(); i++) {
121 os << "," << values[i];
122 }
123 }
124 os << "};\n";
125}
126
127template<class Base>
128void LanguageC<Base>::printStaticIndexMatrix(std::ostringstream& os,
129 const std::string& name,
130 const std::map<size_t, std::map<size_t, size_t> >& values) {
131 size_t m = 0;
132 size_t n = 0;
133
134 std::map<size_t, std::map<size_t, size_t> >::const_iterator it;
135 std::map<size_t, size_t>::const_iterator ity2z;
136
137 if (!values.empty()) {
138 m = values.rbegin()->first + 1;
139
140 for (it = values.begin(); it != values.end(); ++it) {
141 if (!it->second.empty())
142 n = std::max<size_t>(n, it->second.rbegin()->first + 1);
143 }
144 }
145
146 os << "static " << U_INDEX_TYPE << " const " << name << "[" << m << "][" << n << "] = {";
147 size_t x = 0;
148 for (it = values.begin(); it != values.end(); ++it) {
149 if (it->first != x) {
150 while (it->first != x) {
151 os << "{},";
152 x++;
153 }
154 }
155
156 os << "{";
157
158 size_t y = 0;
159 for (ity2z = it->second.begin(); ity2z != it->second.end(); ++ity2z) {
160 if (ity2z->first != y) {
161 while (ity2z->first != y) {
162 os << "0,";
163 y++;
164 }
165 }
166
167 os << ity2z->second;
168 if (ity2z->first != it->second.rbegin()->first) os << ",";
169
170 y++;
171 }
172
173 os << "}";
174 if (it->first != values.rbegin()->first) os << ",";
175
176 x++;
177 }
178 os << "};\n";
179}
180
181template<class Base>
182inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
183 const OperationNode<Base>& index) {
184 return indexPattern2String(ip,{index.getName()});
185}
186
187template<class Base>
188inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
189 const std::string& index) {
190 return indexPattern2String(ip,{&index});
191}
192
193template<class Base>
194inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
195 const std::vector<const OperationNode<Base>*>& indexes) {
196 std::vector<const std::string*> indexStr(indexes.size());
197 for (size_t i = 0; i < indexes.size(); ++i)
198 indexStr[i] = indexes[i]->getName();
199 return indexPattern2String(ip, indexStr);
200}
201
202template<class Base>
203inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
204 const std::vector<const std::string*>& indexes) {
205 std::stringstream ss;
206 switch (ip.getType()) {
207 case IndexPatternType::Linear: // y = x * a + b
208 {
209 CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes")
210 const auto& lip = static_cast<const LinearIndexPattern&> (ip);
211 return linearIndexPattern2String(lip, *indexes[0]);
212 }
213 case IndexPatternType::Sectioned:
214 {
215 CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes")
216 const auto* lip = static_cast<const SectionedIndexPattern*> (&ip);
217 const std::map<size_t, IndexPattern*>& sections = lip->getLinearSections();
218 size_t sSize = sections.size();
219 CPPADCG_ASSERT_UNKNOWN(sSize > 1)
220
221 auto its = sections.begin();
222 for (size_t s = 0; s < sSize - 1; s++) {
223 const IndexPattern* lp = its->second;
224 ++its;
225 size_t xStart = its->first;
226
227 ss << "(" << (*indexes[0]) << "<" << xStart << ")? "
228 << indexPattern2String(*lp, *indexes[0]) << ": ";
229 }
230 ss << indexPattern2String(*its->second, *indexes[0]);
231
232 return ss.str();
233 }
234
235 case IndexPatternType::Plane2D: // y = f(x) + f(z)
236 {
237 CPPADCG_ASSERT_KNOWN(!indexes.empty(), "Invalid number of indexes")
238 std::string indexExpr;
239 const auto& pip = static_cast<const Plane2DIndexPattern&> (ip);
240 bool useParens = pip.getPattern1() != nullptr && pip.getPattern2() != nullptr;
241
242 if (useParens) indexExpr += "(";
243
244 if (pip.getPattern1() != nullptr)
245 indexExpr += indexPattern2String(*pip.getPattern1(), *indexes[0]);
246
247 if (useParens) indexExpr += ") + (";
248
249 if (pip.getPattern2() != nullptr)
250 indexExpr += indexPattern2String(*pip.getPattern2(), *indexes.back());
251
252 if (useParens) indexExpr += ")";
253
254 return indexExpr;
255 }
256 case IndexPatternType::Random1D:
257 {
258 CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes")
259 const auto& rip = static_cast<const Random1DIndexPattern&> (ip);
260 CPPADCG_ASSERT_KNOWN(!rip.getName().empty(), "Invalid name for array")
261 return rip.getName() + "[" + (*indexes[0]) + "]";
262 }
263 case IndexPatternType::Random2D:
264 {
265 CPPADCG_ASSERT_KNOWN(indexes.size() == 2, "Invalid number of indexes")
266 const auto& rip = static_cast<const Random2DIndexPattern&> (ip);
267 CPPADCG_ASSERT_KNOWN(!rip.getName().empty(), "Invalid name for array")
268 return rip.getName() + "[" + (*indexes[0]) + "][" + (*indexes[1]) + "]";
269 }
270 default:
271 CPPADCG_ASSERT_UNKNOWN(false); // should never reach this
272 return "";
273 }
274}
275
276template<class Base>
277inline std::string LanguageC<Base>::linearIndexPattern2String(const LinearIndexPattern& lip,
278 const OperationNode<Base>& index) {
279 return linearIndexPattern2String(lip, *index.getName());
280}
281
282template<class Base>
283inline std::string LanguageC<Base>::linearIndexPattern2String(const LinearIndexPattern& lip,
284 const std::string& index) {
285 long dy = lip.getLinearSlopeDy();
286 long dx = lip.getLinearSlopeDx();
287 long b = lip.getLinearConstantTerm();
288 long xOffset = lip.getXOffset();
289
290 std::stringstream ss;
291 if (dy != 0) {
292 if (xOffset != 0) {
293 ss << "(";
294 }
295 ss << index;
296 if (xOffset != 0) {
297 ss << " - " << xOffset << ")";
298 }
299
300 if (dx != 1) {
301 ss << " / " << dx;
302 }
303 if (dy != 1) {
304 ss << " * " << dy;
305 }
306 } else if (b == 0) {
307 ss << "0"; // when dy == 0 and b == 0
308 }
309
310 if (b != 0) {
311 if (dy != 0)
312 ss << " + ";
313 ss << b;
314 }
315 return ss.str();
316}
317
318template<class Base>
319bool LanguageC<Base>::isOffsetBy(const IndexPattern* ip,
320 const IndexPattern* refIp,
321 long offset) {
322
323 if (ip->getType() == IndexPatternType::Linear) {
324 const auto* lIp = dynamic_cast<const LinearIndexPattern*> (ip);
325 assert(lIp != nullptr);
326
327 if (refIp->getType() != IndexPatternType::Linear)
328 return false;
329 const auto* refLIp = dynamic_cast<const LinearIndexPattern*> (refIp);
330 assert(refLIp != nullptr);
331
332 return isOffsetBy(*lIp, *refLIp, offset);
333
334 } else if (ip->getType() == IndexPatternType::Sectioned) {
335 const auto* sIp = dynamic_cast<const SectionedIndexPattern*> (ip);
336 assert(sIp != nullptr);
337
338 if (refIp->getType() != IndexPatternType::Sectioned)
339 return false;
340 const auto* refSecp = dynamic_cast<const SectionedIndexPattern*> (refIp);
341 assert(refSecp != nullptr);
342
343 return isOffsetBy(*sIp, *refSecp, offset);
344
345
346 } else {
347 return false; // different pattern type
348 }
349}
350
351template<class Base>
352bool LanguageC<Base>::isOffsetBy(const LinearIndexPattern* lIp,
353 const LinearIndexPattern* refLIp,
354 long offset) {
355
356 if (lIp == nullptr || refLIp == nullptr)
357 return false; // different pattern type
358
359 return isOffsetBy(*lIp, *refLIp, offset);
360}
361
362template<class Base>
363bool LanguageC<Base>::isOffsetBy(const LinearIndexPattern& lIp,
364 const LinearIndexPattern& refLIp,
365 long offset) {
366 return refLIp.getLinearSlopeDx() == lIp.getLinearSlopeDx() &&
367 refLIp.getLinearSlopeDy() == lIp.getLinearSlopeDy() &&
368 refLIp.getXOffset() == lIp.getXOffset() &&
369 refLIp.getLinearConstantTerm() + offset == lIp.getLinearConstantTerm();
370}
371
372template<class Base>
373bool LanguageC<Base>::isOffsetBy(const SectionedIndexPattern* sIp,
374 const SectionedIndexPattern* refSecp,
375 long offset) {
376 if (refSecp == nullptr || sIp == nullptr)
377 return false; // different pattern type
378
379 return isOffsetBy(*sIp, *refSecp, offset);
380}
381
382template<class Base>
383bool LanguageC<Base>::isOffsetBy(const SectionedIndexPattern& sIp,
384 const SectionedIndexPattern& refSecp,
385 long offset) {
386
387 if (refSecp.getLinearSections().size() != sIp.getLinearSections().size())
388 return false; // different pattern type
389
390 auto itRef = refSecp.getLinearSections().begin();
391 for (const auto& section : sIp.getLinearSections()) {
392
393 if (itRef->first != section.first) {
394 return false; // different pattern type
395 } else if (itRef->second->getType() != IndexPatternType::Linear || section.second->getType() != IndexPatternType::Linear) {
396 return false; // unable to handle this now, consider different patterns
397 }
398
399 auto* refSecLIp = static_cast<LinearIndexPattern*> (itRef->second);
400 auto* secLIp = static_cast<LinearIndexPattern*> (section.second);
401
402 if (!isOffsetBy(secLIp, refSecLIp, offset)) {
403 return false; // different pattern type
404 }
405
406 ++itRef;
407 }
408
409 return true;
410}
411
412template<class Base>
413Plane2DIndexPattern* LanguageC<Base>::encapsulateIndexPattern(const LinearIndexPattern& refLIp,
414 size_t starti) {
415 std::unique_ptr<IndexPattern> ip2;
416
417 auto* lip2 = new LinearIndexPattern(refLIp);
418 ip2.reset(lip2);
419 lip2->setLinearConstantTerm(lip2->getLinearConstantTerm() - starti);
420
421 return new Plane2DIndexPattern(ip2.release(), new LinearIndexPattern(0, 1, 1, 0));
422}
423
424template<class Base>
425Plane2DIndexPattern* LanguageC<Base>::encapsulateIndexPattern(const SectionedIndexPattern& refSecp,
426 size_t starti) {
427 std::unique_ptr<IndexPattern> ip2;
428
429 std::map<size_t, IndexPattern*> sections;
430 for (const auto& section : refSecp.getLinearSections()) {
431 auto* lip2 = new LinearIndexPattern(*static_cast<LinearIndexPattern*> (section.second));
432 lip2->setLinearConstantTerm(lip2->getLinearConstantTerm() - starti);
433 sections[section.first] = lip2;
434 }
435 ip2.reset(new SectionedIndexPattern(sections));
436
437 return new Plane2DIndexPattern(ip2.release(), new LinearIndexPattern(0, 1, 1, 0));
438}
439
440} // END cg namespace
441} // END CppAD namespace
442
443#endif
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern * > &randomPatterns)