CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
language_c_loops.hpp
1 #ifndef CPPAD_CG_LANGUAGE_C_LOOPS_INCLUDED
2 #define CPPAD_CG_LANGUAGE_C_LOOPS_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2015 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 void LanguageC<Base>::printLoopIndexedDep(OperationNode<Base>& node) {
23  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for loop indexed dependent operation");
24 
25  // LoopIndexedDep
26  print(node.getArguments()[0]);
27 }
28 
29 template<class Base>
30 size_t LanguageC<Base>::printLoopIndexDeps(const std::vector<OperationNode<Base>*>& variableOrder,
31  size_t pos) {
32  CPPADCG_ASSERT_KNOWN(pos < variableOrder.size(), "Invalid number of arguments for array creation operation");
33  CPPADCG_ASSERT_KNOWN(variableOrder[pos]->getOperationType() == CGOpCode::LoopIndexedDep, "Invalid operation type");
34 
35  const size_t vSize = variableOrder.size();
36 
37  for (size_t i = pos; i < vSize; i++) {
38  if (variableOrder[i]->getOperationType() != CGOpCode::LoopIndexedDep) {
39  return i - 1;
40  }
41 
42  // try to use a loop for element assignment
43  size_t newI = printLoopIndexedDepsUsingLoop(variableOrder, i);
44 
45  if (newI == i) {
46  // individual element assignment
47  printAssignment(*variableOrder[i]);
48  } else {
49  i = newI;
50  }
51  }
52 
53  return vSize - 1;
54 }
55 
56 template<class Base>
57 inline size_t LanguageC<Base>::printLoopIndexedDepsUsingLoop(const std::vector<OperationNode<Base>*>& variableOrder,
58  size_t starti) {
59  CPPADCG_ASSERT_KNOWN(variableOrder[starti] != nullptr, "Invalid node");
60  CPPADCG_ASSERT_KNOWN(variableOrder[starti]->getOperationType() == CGOpCode::LoopIndexedDep, "Invalid operation type");
61 
62  const size_t vSize = variableOrder.size();
63 
64  const OperationNode<Base>& ref = *variableOrder[starti];
65 
66  const IndexPattern* refIp = _info->loopDependentIndexPatterns[ref.getInfo()[0]];
67  size_t refAssignOrAdd = ref.getInfo()[1];
68 
72  const OperationNode<Base>* refLeft = ref.getArguments()[0].getOperation();
73  if (refLeft == nullptr) {
74  return starti;
75  } else if (refLeft->getOperationType() != CGOpCode::ArrayElement) {
76  return starti;
77  }
78 
82  const LinearIndexPattern* refLIp = nullptr;
83  const SectionedIndexPattern* refSecp = nullptr;
84 
85  if (refIp->getType() == IndexPatternType::Linear) {
86  refLIp = static_cast<const LinearIndexPattern*> (refIp);
87  } else if (refIp->getType() == IndexPatternType::Sectioned) {
88  refSecp = static_cast<const SectionedIndexPattern*> (refIp);
89  } else {
90  return starti; // cannot determine consecutive elements
91  }
92 
96  const OperationNode<Base>* refArray = refLeft->getArguments()[0].getOperation();
97  const size_t startArrayIndex = refLeft->getInfo()[0];
98 
99  size_t i = starti + 1;
100 
101  for (; i < vSize; i++) {
102  OperationNode<Base>* node = variableOrder[i];
103  if (node->getOperationType() != CGOpCode::LoopIndexedDep)
104  break;
105 
106  const OperationNode<Base>* nodeLeft = variableOrder[i]->getArguments()[0].getOperation();
107  if (nodeLeft->getOperationType() != CGOpCode::ArrayElement)
108  break;
109 
110  const OperationNode<Base>* arrayi = nodeLeft->getArguments()[0].getOperation();
111  if (arrayi != refArray)
112  break;
113 
114  long offset = long(i) - long(starti);
115 
116  if (nodeLeft->getInfo()[0] != startArrayIndex + offset)
117  break;
118 
119  if (node->getInfo()[1] != refAssignOrAdd)
120  break;
121 
122  const IndexPattern* ip = _info->loopDependentIndexPatterns[node->getInfo()[0]];
123  if (!isOffsetBy(ip, refIp, offset)) {
124  break; // different pattern type
125  }
126  }
127 
128  if (i - starti < 3)
129  return starti; // no point in looping for 2 elements
130 
134  std::unique_ptr<Plane2DIndexPattern> p2dip;
135  if (refLIp != nullptr) {
136  p2dip.reset(encapsulateIndexPattern(*refLIp, 0));
137  } else {
138  assert(refSecp != nullptr);
139  p2dip.reset(encapsulateIndexPattern(*refSecp, 0));
140  }
141 
142  std::unique_ptr<OperationNode<Base>> op2(OperationNode<Base>::makeTemporaryNode(CGOpCode::LoopIndexedDep, ref.getInfo(), ref.getArguments()));
143  op2->getInfo()[1] = std::numeric_limits<size_t>::max(); // just to be safe (this would be the index pattern id in the handler)
144  op2->getArguments().push_back(_info->auxIterationIndexOp);
145 
146  std::ostringstream rightAssign;
147 
148  rightAssign << _nameGen->generateIndexedDependent(*op2, 0, *p2dip);
149 
153  size_t depVarCount = i - starti;
154  _code << _indentation << "for(i = 0; i < " << depVarCount << "; i++) ";
155  _code << rightAssign.str() << " ";
156  if (refAssignOrAdd == 1) {
157  _code << "+=";
158  } else {
159  _code << _depAssignOperation;
160  }
161  _code << " ";
162 
163  std::string arrayName;
164  if (refArray->getOperationType() == CGOpCode::ArrayCreation)
165  arrayName = _nameGen->generateTemporaryArray(*refArray, getVariableID(*refArray));
166  else
167  arrayName = _nameGen->generateTemporarySparseArray(*refArray, getVariableID(*refArray));
168 
169  _code << "(" << arrayName << ")[i + " << startArrayIndex << "];\n";
170 
171  return i - 1;
172 }
173 
174 
175 } // END cg namespace
176 } // END CppAD namespace
177 
178 #endif
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const
virtual size_t printLoopIndexedDepsUsingLoop(const std::vector< Node *> &variableOrder, size_t starti)
const std::vector< size_t > & getInfo() const