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