CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
plane_2d_index_pattern.hpp
1 #ifndef CPPAD_CG_PLANE_2D_INDEX_PATTERN_INCLUDED
2 #define CPPAD_CG_PLANE_2D_INDEX_PATTERN_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2013 Ciengis
6  * Copyright (C) 2018 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 
29 protected:
34  IndexPattern* pattern2_;
35 public:
36 
37  inline Plane2DIndexPattern(IndexPattern* pattern1,
38  IndexPattern* pattern2) :
39  pattern1_(pattern1),
40  pattern2_(pattern2) {
41  CPPADCG_ASSERT_UNKNOWN(pattern1_ != nullptr || pattern2_ != nullptr);
42  }
43 
44  Plane2DIndexPattern(const Plane2DIndexPattern& orig) = delete;
45 
46  inline const IndexPattern* getPattern1() const {
47  return pattern1_;
48  }
49 
50  inline const IndexPattern* getPattern2() const {
51  return pattern2_;
52  }
53 
54  inline IndexPatternType getType() const override {
55  return IndexPatternType::Plane2D;
56  }
57 
58  inline void getSubIndexes(std::set<IndexPattern*>& indexes) const override {
59  if (pattern1_ != nullptr) {
60  indexes.insert(pattern1_);
61  pattern1_->getSubIndexes(indexes);
62  }
63  if (pattern2_ != nullptr) {
64  indexes.insert(pattern2_);
65  pattern2_->getSubIndexes(indexes);
66  }
67  }
68 
69  inline virtual ~Plane2DIndexPattern() {
70  delete pattern1_;
71  delete pattern2_;
72  }
73 
74  /***********************************************************************
75  * static methods
76  **********************************************************************/
77 
78  static inline Plane2DIndexPattern* detectPlane2D(const std::map<size_t, std::map<size_t, size_t> >& x2y2z) {
84  if (x2y2z.size() == 1) {
85  // only one x -> fit z to y
86  const std::map<size_t, size_t>& y2z = x2y2z.begin()->second;
87  return new Plane2DIndexPattern(nullptr, IndexPattern::detect(y2z));
88  }
89 
90  // perhaps there is always only one y
91  size_t y = x2y2z.begin()->second.begin()->first;
92  std::map<size_t, size_t> x2z;
93  std::map<size_t, std::map<size_t, size_t> >::const_iterator itx2y2z;
94  for (itx2y2z = x2y2z.begin(); itx2y2z != x2y2z.end(); ++itx2y2z) {
95  size_t x = itx2y2z->first;
96  const std::map<size_t, size_t>& y2z = itx2y2z->second;
97 
98  if (y2z.size() != 1 ||
99  y != y2z.begin()->first) {
100  x2z.clear(); // not always the same y
101  break;
102  }
103 
104  size_t z = y2z.begin()->second;
105  x2z[x] = z;
106  }
107 
108  if (!x2z.empty()) {
109  return new Plane2DIndexPattern(IndexPattern::detect(x2z), nullptr);
110  }
111 
116  std::map<size_t, size_t> x2zStart;
117  std::map<size_t, size_t> y2zOffset;
118 
119  for (itx2y2z = x2y2z.begin(); itx2y2z != x2y2z.end(); ++itx2y2z) {
120  size_t x = itx2y2z->first;
121  const std::map<size_t, size_t>& y2z = itx2y2z->second;
122 
123  size_t zFirst = y2z.begin()->second;
124  x2zStart[x] = zFirst;
125 
126  std::map<size_t, size_t>::const_iterator ity2z;
127 
128  for (ity2z = y2z.begin(); ity2z != y2z.end(); ++ity2z) {
129  size_t y = ity2z->first;
130  size_t offset = ity2z->second - zFirst;
131  std::map<size_t, size_t>::const_iterator itY2zOffset = y2zOffset.find(y);
132  if (itY2zOffset == y2zOffset.end()) {
133  y2zOffset[y] = offset;
134  } else if (itY2zOffset->second != offset) {
135  return nullptr; // does not fit the pattern
136  }
137  }
138  }
139 
143  std::unique_ptr<IndexPattern> fx;
144 
145  std::map<size_t, IndexPattern*> startSections = SectionedIndexPattern::detectLinearSections(x2zStart, 2);
146  if (startSections.empty()) {
147  return nullptr; // does not fit the pattern
148  }
149 
150  // detected a pattern for the first z based on x
151  if (startSections.size() == 1) {
152  fx = std::unique_ptr<IndexPattern> (startSections.begin()->second);
153  } else {
154  fx = std::unique_ptr<IndexPattern> (new SectionedIndexPattern(startSections));
155  }
156 
161  std::map<size_t, IndexPattern*> sections = SectionedIndexPattern::detectLinearSections(y2zOffset, 2);
162  if (sections.empty()) {
163  return nullptr; // does not fit the pattern
164  }
165 
166  // detected a pattern for the z offset based on y
167  std::unique_ptr<IndexPattern> fy;
168  if (sections.size() == 1) {
169  fy = std::unique_ptr<IndexPattern> (sections.begin()->second);
170  } else {
171  fy = std::unique_ptr<IndexPattern> (new SectionedIndexPattern(sections));
172  }
173 
174  // simplify when both patterns are constant
175  if (fx->getType() == IndexPatternType::Linear && fy->getType() == IndexPatternType::Linear) {
176  LinearIndexPattern* ipx = static_cast<LinearIndexPattern*> (fx.get());
177  LinearIndexPattern* ipy = static_cast<LinearIndexPattern*> (fy.get());
178 
179  if (ipx->getLinearSlopeDy() == 0 && ipy->getLinearSlopeDy() == 0) {
183  ipx->setLinearConstantTerm(ipx->getLinearConstantTerm() + ipy->getLinearConstantTerm());
184  fy.reset();
185  }
186  }
187 
188  return new Plane2DIndexPattern(fx.release(), fy.release());
189  }
190 
191 };
192 
193 } // END cg namespace
194 } // END CppAD namespace
195 
196 #endif
static Plane2DIndexPattern * detectPlane2D(const std::map< size_t, std::map< size_t, size_t > > &x2y2z)
static IndexPattern * detect(const VectorSizeT &x2y)