CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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 * Copyright (C) 2020 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
19namespace CppAD {
20namespace cg {
21
26template<class Base>
28public:
29 using MapDep2Indep_type = std::map<size_t, const OperationNode<Base>*>;
35 std::vector<MapDep2Indep_type> arg2Independents;
36};
37
38template<class Base>
40public:
41 std::map<const OperationNode<Base>*, OperationIndexedIndependents<Base> > op2Arguments;
42public:
43
44 const OperationIndexedIndependents<Base>& arguments(const OperationNode<Base>* operation) const {
45 return op2Arguments.at(operation);
46 }
47
48 bool isIndexedOperationArgument(const OperationNode<Base>* node, size_t argIndex) const {
49 const auto itIndexes = op2Arguments.find(node);
50 if (itIndexes == op2Arguments.end()) {
51 return false;
52 }
53 const OperationIndexedIndependents<Base>& indexedArgs = itIndexes->second;
54 return indexedArgs.arg2Independents.size() > argIndex && !indexedArgs.arg2Independents[argIndex].empty();
55 }
56
57};
58
63template<class Base>
65public:
66 const CG<Base>& depRef; // dependent reference
67 const size_t depRefIndex;
68 std::set<size_t> dependents;
74 std::map<size_t, std::map<const OperationNode<Base>*, OperationNode<Base>*> > operationEO2Reference;
75 // std::map<size_t, std::vector<OperationNode<Base>*> > operationEO2Reference;
85 std::map<const OperationNode<Base>*, std::set<size_t> > constOperationIndependents;
86
87private:
88 CodeHandler<Base>* const handler_;
89 size_t currDep_;
90 size_t minColor_;
91 size_t cmpColor_;
92public:
93
94 explicit EquationPattern(const CG<Base>& ref,
95 size_t iDepRef) :
96 depRef(ref),
97 depRefIndex(iDepRef),
98 dependents {iDepRef},
99 handler_(ref.getCodeHandler()) {
100 }
101
102 EquationPattern(const EquationPattern<Base>& other) = delete;
103
104 EquationPattern& operator=(const EquationPattern<Base>& rhs) = delete;
105
106 bool testAdd(size_t iDep2,
107 const CG<Base>& dep2,
108 size_t& minColor,
110 IndexedIndependent<Base> independentsBackup = indexedOpIndep;
111 std::map<const OperationNode<Base>*, std::set<size_t> > constOperationIndependentsBackup = constOperationIndependents;
112 std::map<size_t, std::map<const OperationNode<Base>*, OperationNode<Base>*> > operation2ReferenceBackup = operationEO2Reference;
113
114 currDep_ = iDep2;
115 minColor_ = minColor;
116 cmpColor_ = minColor_;
117
118 bool equals = comparePath(depRef, dep2, iDep2, varColor);
119
120 minColor = cmpColor_;
121
122 if (equals) {
123 dependents.insert(iDep2);
124
125 return true; // matches the reference pattern
126 } else {
127 // restore
128 indexedOpIndep.op2Arguments.swap(independentsBackup.op2Arguments);
129 constOperationIndependents.swap(constOperationIndependentsBackup);
130 operationEO2Reference.swap(operation2ReferenceBackup);
131
132 return false; // cannot be added
133 }
134 }
135
136 inline void findIndexedPath(size_t dep,
137 const std::vector<CG<Base> >& depVals,
138 CodeHandlerVector<Base, bool>& varIndexed,
139 std::set<const OperationNode<Base>*>& indexedOperations) {
140 findIndexedPath(depRef, depVals[dep], varIndexed, indexedOperations);
141 }
142
143 std::set<const OperationNode<Base>*> findOperationsUsingIndependents(OperationNode<Base>& node) const {
144 std::set<const OperationNode<Base>*> ops;
145
146 handler_->startNewOperationTreeVisit();
147
148 findOperationsWithIndeps(node, ops);
149
150 return ops;
151 }
152
153 static inline void uncolor(OperationNode<Base>* node,
154 CodeHandlerVector<Base, bool>& varIndexed) {
155 if (node == nullptr || !varIndexed[*node])
156 return;
157
158 varIndexed[*node] = false;
159
160 const std::vector<Argument<Base> >& args = node->getArguments();
161 size_t size = args.size();
162 for (size_t a = 0; a < size; a++) {
163 uncolor(args[a].getOperation(), varIndexed);
164 }
165 }
166
167 inline bool containsConstantIndependent(const OperationNode<Base>* operation, size_t argumentIndex) const {
168 const auto it = constOperationIndependents.find(operation);
169 if (it != constOperationIndependents.end()) {
170 if (it->second.find(argumentIndex) != it->second.end()) {
171 return true;
172 }
173 }
174 return false;
175 }
176
182 using MapIndep2Dep_type = typename OperationIndexedIndependents<Base>::MapDep2Indep_type;
183
184 // loop operations using independents
185 auto itop2a = indexedOpIndep.op2Arguments.begin();
186 while (itop2a != indexedOpIndep.op2Arguments.end()) {
187 const OperationNode<Base>* parentOp = itop2a->first;
188 OperationIndexedIndependents<Base>& arg2It = itop2a->second;
189
190 bool emptyOp = true;
191
192 // loop the arguments
193 size_t aSize = arg2It.arg2Independents.size();
194 for (size_t argIndex = 0; argIndex < aSize; argIndex++) {
195 MapIndep2Dep_type& dep2Ind = arg2It.arg2Independents[argIndex];
196
197 if (dep2Ind.empty())
198 continue; // argument does not use independents
199
200 // loop dependents (iterations)
201 bool isIndexed = false;
202 typename MapIndep2Dep_type::const_iterator itDep2Ind = dep2Ind.begin();
203 const OperationNode<Base>* indep = itDep2Ind->second;
204
205 for (++itDep2Ind; itDep2Ind != dep2Ind.end(); ++itDep2Ind) {
206 if (indep != itDep2Ind->second) {
207 isIndexed = true;
208 break;
209 }
210 }
211
212 if (!isIndexed) {
213 // make it a non indexed independent
214 constOperationIndependents[parentOp].insert(argIndex);
215
216 // remove it from the indexed independents
217 dep2Ind.clear();
218 } else {
219 emptyOp = false;
220 }
221
222 }
223
224 if (emptyOp) {
225 indexedOpIndep.op2Arguments.erase(itop2a++);
226 } else {
227 ++itop2a;
228 }
229
230 }
231
232 }
233
234 virtual ~EquationPattern() = default;
235
236private:
237
238 bool comparePath(const CG<Base>& dep1,
239 const CG<Base>& dep2,
240 size_t dep2Index,
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,
268 CodeHandlerVector<Base, size_t>& varColor) {
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
const Base & getValue() const
Definition variable.hpp:45
CodeHandler< Base > * getCodeHandler() const
Definition variable.hpp:22
bool isParameter() const
Definition variable.hpp:35
bool isVariable() const
Definition variable.hpp:30
std::map< const OperationNode< Base > *, std::set< size_t > > constOperationIndependents
IndexedIndependent< Base > indexedOpIndep
std::map< size_t, std::map< const OperationNode< Base > *, OperationNode< Base > * > > operationEO2Reference
std::vector< MapDep2Indep_type > arg2Independents