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