CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
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 
19 namespace CppAD {
20 namespace cg {
21 
22 template<class Base>
23 inline 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 
55 template<class Base>
56 inline 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 
85 template<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 
113 template<class Base>
114 void 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 
127 template<class Base>
128 void 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 
181 template<class Base>
182 inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
183  const OperationNode<Base>& index) {
184  return indexPattern2String(ip,{index.getName()});
185 }
186 
187 template<class Base>
188 inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
189  const std::string& index) {
190  return indexPattern2String(ip,{&index});
191 }
192 
193 template<class Base>
194 inline 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 
202 template<class Base>
203 inline 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 
276 template<class Base>
278  const OperationNode<Base>& index) {
279  return linearIndexPattern2String(lip, *index.getName());
280 }
281 
282 template<class Base>
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 
318 template<class Base>
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 
351 template<class Base>
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 
362 template<class Base>
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 
372 template<class Base>
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 
382 template<class Base>
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 
412 template<class Base>
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 
424 template<class Base>
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
const std::string * getName() const
static void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)