CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
equation_pattern.hpp
1 #ifndef CPPAD_CG_EQUATION_PATTERN_INCLUDED
2 #define CPPAD_CG_EQUATION_PATTERN_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 
25 template<class Base>
27 public:
28  using MapDep2Indep_type = std::map<size_t, const OperationNode<Base>*>;
34  std::vector<MapDep2Indep_type> arg2Independents;
35 };
36 
37 template<class Base>
39 public:
40  std::map<const OperationNode<Base>*, OperationIndexedIndependents<Base> > op2Arguments;
41 public:
42 
43  const OperationIndexedIndependents<Base>& arguments(const OperationNode<Base>* operation) const {
44  return op2Arguments.at(operation);
45  }
46 
47  bool isIndexedOperationArgument(const OperationNode<Base>* node, size_t argIndex) const {
48  const auto itIndexes = op2Arguments.find(node);
49  if (itIndexes == op2Arguments.end()) {
50  return false;
51  }
52  const OperationIndexedIndependents<Base>& indexedArgs = itIndexes->second;
53  return indexedArgs.arg2Independents.size() > argIndex && !indexedArgs.arg2Independents[argIndex].empty();
54  }
55 
56 };
57 
62 template<class Base>
63 class EquationPattern {
64 public:
65  const CG<Base>& depRef; // dependent reference
66  const size_t depRefIndex;
67  std::set<size_t> dependents;
73  std::map<size_t, std::map<const OperationNode<Base>*, OperationNode<Base>*> > operationEO2Reference;
74  // std::map<size_t, std::vector<OperationNode<Base>*> > operationEO2Reference;
84  std::map<const OperationNode<Base>*, std::set<size_t> > constOperationIndependents;
85 
86 private:
87  CodeHandler<Base>* const handler_;
88  size_t currDep_;
89  size_t minColor_;
90  size_t cmpColor_;
91 public:
92 
93  explicit EquationPattern(const CG<Base>& ref,
94  size_t iDepRef) :
95  depRef(ref),
96  depRefIndex(iDepRef),
97  dependents {iDepRef},
98  handler_(ref.getCodeHandler()) {
99  }
100 
101  EquationPattern(const EquationPattern<Base>& other) = delete;
102 
103  EquationPattern& operator=(const EquationPattern<Base>& rhs) = delete;
104 
105  bool testAdd(size_t iDep2,
106  const CG<Base>& dep2,
107  size_t& minColor,
109  IndexedIndependent<Base> independentsBackup = indexedOpIndep;
110  std::map<const OperationNode<Base>*, std::set<size_t> > constOperationIndependentsBackup = constOperationIndependents;
111  std::map<size_t, std::map<const OperationNode<Base>*, OperationNode<Base>*> > operation2ReferenceBackup = operationEO2Reference;
112 
113  currDep_ = iDep2;
114  minColor_ = minColor;
115  cmpColor_ = minColor_;
116 
117  bool equals = comparePath(depRef, dep2, iDep2, varColor);
118 
119  minColor = cmpColor_;
120 
121  if (equals) {
122  dependents.insert(iDep2);
123 
124  return true; // matches the reference pattern
125  } else {
126  // restore
127  indexedOpIndep.op2Arguments.swap(independentsBackup.op2Arguments);
128  constOperationIndependents.swap(constOperationIndependentsBackup);
129  operationEO2Reference.swap(operation2ReferenceBackup);
130 
131  return false; // cannot be added
132  }
133  }
134 
135  inline void findIndexedPath(size_t dep,
136  const std::vector<CG<Base> >& depVals,
137  CodeHandlerVector<Base, bool>& varIndexed,
138  std::set<const OperationNode<Base>*>& indexedOperations) {
139  findIndexedPath(depRef, depVals[dep], varIndexed, indexedOperations);
140  }
141 
142  std::set<const OperationNode<Base>*> findOperationsUsingIndependents(OperationNode<Base>& node) const {
143  std::set<const OperationNode<Base>*> ops;
144 
145  handler_->startNewOperationTreeVisit();
146 
147  findOperationsWithIndeps(node, ops);
148 
149  return ops;
150  }
151 
152  static inline void uncolor(OperationNode<Base>* node,
153  CodeHandlerVector<Base, bool>& varIndexed) {
154  if (node == nullptr || !varIndexed[*node])
155  return;
156 
157  varIndexed[*node] = false;
158 
159  const std::vector<Argument<Base> >& args = node->getArguments();
160  size_t size = args.size();
161  for (size_t a = 0; a < size; a++) {
162  uncolor(args[a].getOperation(), varIndexed);
163  }
164  }
165 
166  inline bool containsConstantIndependent(const OperationNode<Base>* operation, size_t argumentIndex) const {
167  const auto it = constOperationIndependents.find(operation);
168  if (it != constOperationIndependents.end()) {
169  if (it->second.find(argumentIndex) != it->second.end()) {
170  return true;
171  }
172  }
173  return false;
174  }
175 
181  using MapIndep2Dep_type = typename OperationIndexedIndependents<Base>::MapDep2Indep_type;
182 
183  // loop operations using independents
184  auto itop2a = indexedOpIndep.op2Arguments.begin();
185  while (itop2a != indexedOpIndep.op2Arguments.end()) {
186  const OperationNode<Base>* parentOp = itop2a->first;
187  OperationIndexedIndependents<Base>& arg2It = itop2a->second;
188 
189  bool emptyOp = true;
190 
191  // loop the arguments
192  size_t aSize = arg2It.arg2Independents.size();
193  for (size_t argIndex = 0; argIndex < aSize; argIndex++) {
194  MapIndep2Dep_type& dep2Ind = arg2It.arg2Independents[argIndex];
195 
196  if (dep2Ind.empty())
197  continue; // argument does not use independents
198 
199  // loop dependents (iterations)
200  bool isIndexed = false;
201  typename MapIndep2Dep_type::const_iterator itDep2Ind = dep2Ind.begin();
202  const OperationNode<Base>* indep = itDep2Ind->second;
203 
204  for (++itDep2Ind; itDep2Ind != dep2Ind.end(); ++itDep2Ind) {
205  if (indep != itDep2Ind->second) {
206  isIndexed = true;
207  break;
208  }
209  }
210 
211  if (!isIndexed) {
212  // make it a non indexed independent
213  constOperationIndependents[parentOp].insert(argIndex);
214 
215  // remove it from the indexed independents
216  dep2Ind.clear();
217  } else {
218  emptyOp = false;
219  }
220 
221  }
222 
223  if (emptyOp) {
224  indexedOpIndep.op2Arguments.erase(itop2a++);
225  } else {
226  ++itop2a;
227  }
228 
229  }
230 
231  }
232 
233  virtual ~EquationPattern() {
234  }
235 
236 private:
237 
238  bool comparePath(const CG<Base>& dep1,
239  const CG<Base>& dep2,
240  size_t dep2Index,
242  CodeHandler<Base>* h1 = dep1.getCodeHandler();
243  CodeHandler<Base>* h2 = dep2.getCodeHandler();
244 
245  if (h1 != h2) {
246  if (h1 != nullptr && h2 != nullptr)
247  throw CGException("Only one code handler allowed");
248  return false;
249  }
250 
251  if (dep1.isParameter() && dep2.isParameter()) {
252  return dep1.getValue() == dep2.getValue();
253 
254  } else if (dep1.isVariable() && dep2.isVariable()) {
255  OperationNode<Base>* depRefOp = dep1.getOperationNode();
256  OperationNode<Base>* dep2Op = dep2.getOperationNode();
257  CPPADCG_ASSERT_UNKNOWN(depRefOp->getOperationType() != CGOpCode::Inv);
258 
259  return comparePath(depRefOp, dep2Op, dep2Index, varColor);
260  }
261 
262  return false;
263  }
264 
265  bool comparePath(OperationNode<Base>* scRef,
266  OperationNode<Base>* sc2,
267  size_t dep2,
269  saveOperationReference(dep2, sc2, scRef);
270  if (dependents.size() == 1) {
271  saveOperationReference(depRefIndex, scRef, scRef);
272  }
273 
274  while (scRef->getOperationType() == CGOpCode::Alias) {
275  CPPADCG_ASSERT_KNOWN(scRef->getArguments().size() == 1, "Invalid number of arguments for alias");
276  OperationNode<Base>* sc = scRef->getArguments()[0].getOperation();
277  if (sc != nullptr && sc->getOperationType() == CGOpCode::Inv) break; // an alias is used to distinguish between indexed dependents and indexed independents
278  scRef = sc;
279  }
280  while (sc2->getOperationType() == CGOpCode::Alias) {
281  CPPADCG_ASSERT_KNOWN(sc2->getArguments().size() == 1, "Invalid number of arguments for alias");
282  OperationNode<Base>* sc = sc2->getArguments()[0].getOperation();
283  if (sc != nullptr && sc->getOperationType() == CGOpCode::Inv) break; // an alias is used to distinguish between indexed dependents and indexed independents
284  sc2 = sc;
285  }
286 
287  // check if these nodes where visited before
288  if (varColor[*sc2] >= minColor_ && varColor[*scRef] >= minColor_) {
298  if (varColor[*sc2] == varColor[*scRef])
299  return true;
300  }
301  varColor[*scRef] = cmpColor_;
302  varColor[*sc2] = cmpColor_;
303  cmpColor_++;
304 
305 
306  if (scRef->getOperationType() != sc2->getOperationType()) {
307  return false;
308  }
309 
310  CPPADCG_ASSERT_UNKNOWN(scRef->getOperationType() != CGOpCode::Inv);
311 
312  const std::vector<size_t>& info1 = scRef->getInfo();
313  const std::vector<size_t>& info2 = sc2->getInfo();
314  if (info1.size() != info2.size()) {
315  return false;
316  }
317 
318  for (size_t e = 0; e < info1.size(); e++) {
319  if (info1[e] != info2[e]) {
320  return false;
321  }
322  }
323 
324  const std::vector<Argument<Base> >& args1 = scRef->getArguments();
325  const std::vector<Argument<Base> >& args2 = sc2->getArguments();
326  size_t size = args1.size();
327  if (size != args2.size()) {
328  return false;
329  }
330  for (size_t a = 0; a < size; a++) {
331  const Argument<Base>& a1 = args1[a];
332  const Argument<Base>& a2 = args2[a];
333 
334  if (a1.getParameter() != nullptr) {
335  if (a2.getParameter() == nullptr || *a1.getParameter() != *a2.getParameter())
336  return false;
337  } else {
338  if (a2.getOperation() == nullptr) {
339  return false;
340  }
341  OperationNode<Base>* argRefOp = a1.getOperation();
342  OperationNode<Base>* arg2Op = a2.getOperation();
343  bool related;
344  if (argRefOp->getOperationType() == CGOpCode::Inv) {
345  related = saveIndependent(scRef, a, argRefOp, arg2Op);
346  } else {
347  related = comparePath(argRefOp, arg2Op, dep2, varColor);
348  }
349 
350  if (!related)
351  return false;
352  }
353  }
354 
355  return true; // same pattern
356  }
357 
358  inline void saveOperationReference(size_t dep2,
359  const OperationNode<Base>* sc2,
360  OperationNode<Base>* scRef) {
361  operationEO2Reference[dep2][sc2] = scRef;
362  }
363 
364  bool saveIndependent(const OperationNode<Base>* parentOp,
365  size_t argIndex,
366  const OperationNode<Base>* argRefOp,
367  const OperationNode<Base>* arg2Op) {
368  if (argRefOp->getOperationType() != CGOpCode::Inv || arg2Op->getOperationType() != CGOpCode::Inv) {
369  return false;
370  }
371 
376  const auto it = constOperationIndependents.find(parentOp);
377  if (it != constOperationIndependents.end()) {
378  if (it->second.find(argIndex) != it->second.end()) {
379  return false;
380  }
381  }
382 
383  OperationIndexedIndependents<Base>& opIndexedIndep = indexedOpIndep.op2Arguments[parentOp];
384  opIndexedIndep.arg2Independents.resize(parentOp != nullptr ? parentOp->getArguments().size() : 1);
385 
386  std::map<size_t, const OperationNode<Base>*>& dep2Indeps = opIndexedIndep.arg2Independents[argIndex];
387  if (dep2Indeps.empty())
388  dep2Indeps[depRefIndex] = argRefOp;
389  dep2Indeps[currDep_] = arg2Op;
390 
391  return true; // same pattern
392  }
393 
394  inline void findIndexedPath(const CG<Base>& depRef,
395  const CG<Base>& dep2,
396  CodeHandlerVector<Base, bool>& varIndexed,
397  std::set<const OperationNode<Base>*>& indexedOperations) {
398  if (depRef.isVariable() && dep2.isVariable()) {
399  OperationNode<Base>* depRefOp = depRef.getOperationNode();
400  OperationNode<Base>* dep2Op = dep2.getOperationNode();
401  if (depRefOp->getOperationType() != CGOpCode::Inv) {
402  findIndexedPath(depRefOp, dep2Op, varIndexed, indexedOperations);
403  } else {
404 
405  typename std::map<const OperationNode<Base>*, OperationIndexedIndependents<Base> >::iterator itop2a;
406  itop2a = indexedOpIndep.op2Arguments.find(nullptr);
407  if (itop2a != indexedOpIndep.op2Arguments.end() && !itop2a->second.arg2Independents[0].empty()) {
408  // depends on an index
409  indexedOperations.insert(nullptr);
410  }
411  }
412  }
413  }
414 
415  inline bool findIndexedPath(const OperationNode<Base>* scRef,
416  OperationNode<Base>* sc2,
417  CodeHandlerVector<Base, bool>& varIndexed,
418  std::set<const OperationNode<Base>*>& indexedOperations) {
419 
420  while (scRef->getOperationType() == CGOpCode::Alias) {
421  CPPADCG_ASSERT_KNOWN(scRef->getArguments().size() == 1, "Invalid number of arguments for alias");
422  OperationNode<Base>* sc = scRef->getArguments()[0].getOperation();
423  if (sc != nullptr && sc->getOperationType() == CGOpCode::Inv) break; // an alias is used to distinguish between indexed dependents and indexed independents
424  scRef = sc;
425  }
426  while (sc2->getOperationType() == CGOpCode::Alias) {
427  CPPADCG_ASSERT_KNOWN(sc2->getArguments().size() == 1, "Invalid number of arguments for alias");
428  OperationNode<Base>* sc = sc2->getArguments()[0].getOperation();
429  if (sc != nullptr && sc->getOperationType() == CGOpCode::Inv) break; // an alias is used to distinguish between indexed dependents and indexed independents
430  sc2 = sc;
431  }
432 
433  CPPADCG_ASSERT_UNKNOWN(scRef->getOperationType() == sc2->getOperationType());
434 
435  const std::vector<Argument<Base> >& argsRef = scRef->getArguments();
436 
437  typename std::map<const OperationNode<Base>*, OperationIndexedIndependents<Base> >::iterator itop2a;
438  bool searched = false;
439  bool indexedDependentPath = false;
440  bool usesIndexedIndependent = false; // directly uses an indexed independent
441 
442  size_t size = argsRef.size();
443  for (size_t a = 0; a < size; a++) {
444  OperationNode<Base>* argRefOp = argsRef[a].getOperation();
445  if (argRefOp != nullptr) {
446  bool indexedArg = false;
447  if (argRefOp->getOperationType() == CGOpCode::Inv) {
448  // same independent variable can be used in multiple iterations
449  if (!searched) {
450  itop2a = indexedOpIndep.op2Arguments.find(scRef);
451  searched = true;
452  }
453  if (itop2a != indexedOpIndep.op2Arguments.end() && !itop2a->second.arg2Independents[a].empty()) {
454  // depends on an index
455  indexedArg = true;
456  indexedDependentPath = true;
457  usesIndexedIndependent = true;
458  }
459  }
460 
461  if (!indexedArg) {
462  const std::vector<Argument<Base> >& args2 = sc2->getArguments();
463  CPPADCG_ASSERT_UNKNOWN(size == args2.size());
464  indexedDependentPath |= findIndexedPath(argsRef[a].getOperation(), args2[a].getOperation(), varIndexed, indexedOperations);
465  }
466  }
467  }
468 
469  varIndexed[*sc2] = indexedDependentPath;
470 
471  if (usesIndexedIndependent)
472  indexedOperations.insert(sc2);
473 
474  return indexedDependentPath;
475  }
476 
477  void findOperationsWithIndeps(OperationNode<Base>& node,
478  std::set<const OperationNode<Base>*>& ops) const {
479  if (handler_->isVisited(node))
480  return; // been here before
481 
482  handler_->markVisited(node);
483 
484  const std::vector<Argument<Base> >& args = node.getArguments();
485  size_t size = args.size();
486  for (size_t a = 0; a < size; a++) {
487  OperationNode<Base>* argOp = args[a].getOperation();
488  if (argOp != nullptr) {
489  if (argOp->getOperationType() == CGOpCode::Inv) {
490  ops.insert(&node);
491  } else {
492  findOperationsWithIndeps(*argOp, ops);
493  }
494  }
495  }
496  }
497 
498 };
499 
500 } // END cg namespace
501 } // END CppAD namespace
502 
503 #endif
std::map< const OperationNode< Base > *, std::set< size_t > > constOperationIndependents
std::map< size_t, std::map< const OperationNode< Base > *, OperationNode< Base > * > > operationEO2Reference
const Base & getValue() const
Definition: variable.hpp:45
const std::vector< Argument< Base > > & getArguments() const
bool isVariable() const
Definition: variable.hpp:30
std::vector< MapDep2Indep_type > arg2Independents
IndexedIndependent< Base > indexedOpIndep
CGOpCode getOperationType() const
CodeHandler< Base > * getCodeHandler() const
Definition: variable.hpp:22
bool isParameter() const
Definition: variable.hpp:35
const std::vector< size_t > & getInfo() const