CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
soares_secchi.hpp
1 #ifndef CPPAD_CG_SOARES_SECCHI_HPP
2 #define CPPAD_CG_SOARES_SECCHI_HPP
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2016 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 #include <cppad/cg/dae_index_reduction/dae_structural_index_reduction.hpp>
20 #include <cppad/cg/dae_index_reduction/augment_path_depth_lookahead.hpp>
21 #include <cppad/cg/dae_index_reduction/augment_path_depth_lookahead_a.hpp>
22 
23 namespace CppAD {
24 namespace cg {
25 
29 template<class Base>
31 protected:
33  using ADCG = CppAD::AD<CGBase>;
34 protected:
35  // avoids having to type this->graph_
37  // typical values used to avoid NaNs in the tape validation by CppAD
38  std::vector<Base> x_;
43  std::set<Enode<Base>*> lastAddEq_;
44  // whether or not reduceIndex() has been called
45  bool reduced_;
46  //
47  AugmentPathDepthLookahead<Base> defaultAugmentPath_;
48  AugmentPathDepthLookaheadA<Base> defaultAugmentPathA_;
49  AugmentPath<Base>* augmentPath_;
50  AugmentPath<Base>* augmentPathA_;
51 public:
52 
64  const std::vector<DaeVarInfo>& varInfo,
65  const std::vector<std::string>& eqName,
66  const std::vector<Base>& x) :
67  DaeStructuralIndexReduction<Base>(fun, varInfo, eqName),
68  x_(x),
69  reduced_(false),
70  augmentPath_(&defaultAugmentPath_),
71  augmentPathA_(&defaultAugmentPathA_){
72 
73  }
74 
75  SoaresSecchi(const SoaresSecchi& p) = delete;
76 
77  SoaresSecchi& operator=(const SoaresSecchi& p) = delete;
78 
79  virtual ~SoaresSecchi() {
80  }
81 
82  AugmentPath<Base>& getAugmentPath() const {
83  return *augmentPath_;
84  }
85 
86  void setAugmentPath(AugmentPath<Base>& a) const {
87  augmentPath_ = &a;
88  }
89 
95  inline void setPreserveNames(bool p) {
96  graph_.setPreserveNames(p);
97  }
98 
104  inline bool isPreserveNames() const {
105  return graph_.isPreserveNames();
106  }
107 
118  inline std::unique_ptr<ADFun<CG<Base>>> reduceIndex(std::vector<DaeVarInfo>& newVarInfo,
119  std::vector<DaeEquationInfo>& equationInfo) override {
120  if (reduced_)
121  throw CGException("reduceIndex() can only be called once!");
122 
123  if (this->verbosity_ >= Verbosity::High)
124  log() << "######## Soares Secchi method ########\n";
125 
126  augmentPath_->setLogger(*this);
127  augmentPathA_->setLogger(*this);
128 
129  reduced_ = true;
130 
131  // detects which equations have to be differentiated to get an ODE
132  detectSubset2Dif();
133 
134  // we want an index 1 DAE (ignore the last equations added to the graph)
135  for(const Enode<Base>* i: lastAddEq_) {
136  graph_.remove(*i);
137  }
138 
139  if (this->verbosity_ >= Verbosity::Low) {
140  graph_.printResultInfo("Soares Secchi");
141 
142  log() << "Structural index: " << graph_.getStructuralIndex() << std::endl;
143  }
144 
145  std::unique_ptr<ADFun<CGBase>> reducedFun(graph_.generateNewModel(newVarInfo, equationInfo, x_));
146 
147  return reducedFun;
148  }
149 
157  inline size_t getStructuralIndex() const {
158  return graph_.getStructuralIndex();
159  }
160 
161 protected:
163 
167  inline void detectSubset2Dif() {
168  auto& vnodes = graph_.variables();
169  auto& enodes = graph_.equations();
170 
171  std::set<Enode<Base>*> marked;
172  std::set<Enode<Base>*> lastMarked;
173 
174  if (this->verbosity_ >= Verbosity::High)
175  graph_.printDot(this->log());
176 
177  while (true) {
178  // augment the matching one by one
179  for (size_t k = 0; k < enodes.size(); k++) {
180  Enode<Base>* i = enodes[k];
181 
182  if (this->verbosity_ >= Verbosity::High)
183  log() << "Outer loop: equation k = " << *i << "\n";
184 
185  if (i->assignmentVariable() != nullptr) {
186  continue;
187  }
188 
189  bool pathFound = augmentPathA_->augmentPath(*i);
190  if (!pathFound) {
191 
192  for (Enode<Base>* ii: enodes) {
193  // mark colored equations to be differentiated
194  if (ii->isColored() && ii->derivative() == nullptr) {
195  marked.insert(ii);
196 
197  // uncolor equations
198  ii->uncolor();
199  }
200  }
201 
202  pathFound = augmentPath_->augmentPath(*i);
203  if (!pathFound) {
204  throw CGException("Singular system detected.");
205  }
206 
207  for (auto* jj: vnodes)
208  jj->uncolor();
209 
210  } else {
211  for (auto* ii: enodes)
212  ii->uncolor();
213  }
214  }
215 
216  if (marked.empty())
217  break;
218 
219  // diff all MARKED equations
220  for (Enode<Base>* i: marked) {
221  graph_.createDerivate(*i, false);
222  }
223 
224  if (this->verbosity_ >= Verbosity::High)
225  graph_.printDot(this->log());
226 
227  lastMarked.swap(marked);
228  marked.clear();
229  }
230 
231  lastAddEq_.clear();
232  for (const Enode<Base>* i: lastMarked) {
233  lastAddEq_.insert(i->derivative());
234  }
235 
236  }
237 
238 };
239 
240 } // END cg namespace
241 } // END CppAD namespace
242 
243 #endif
std::set< Enode< Base > * > lastAddEq_
void setPreserveNames(bool p)
size_t getStructuralIndex() const
SoaresSecchi(ADFun< CG< Base > > &fun, const std::vector< DaeVarInfo > &varInfo, const std::vector< std::string > &eqName, const std::vector< Base > &x)
std::unique_ptr< ADFun< CG< Base > > > reduceIndex(std::vector< DaeVarInfo > &newVarInfo, std::vector< DaeEquationInfo > &equationInfo) override
virtual bool augmentPath(Enode< Base > &i)=0