CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
dummy_deriv.hpp
1 #ifndef CPPAD_CG_DUMMY_DERIV_INCLUDED
2 #define CPPAD_CG_DUMMY_DERIV_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 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 #include <Eigen/Dense>
19 #include <Eigen/Sparse>
20 #include <Eigen/Eigenvalues>
21 #include <Eigen/LU>
22 #include <Eigen/QR>
23 
24 #include <cppad/cg/dae_index_reduction/pantelides.hpp>
25 #include <cppad/cg/dae_index_reduction/dummy_deriv_util.hpp>
26 
27 namespace CppAD {
28 namespace cg {
29 
33 template<class Base>
34 class DummyDerivatives : public DaeIndexReduction<Base> {
35  using CGBase = CG<Base>;
36  using ADCG = AD<CGBase>;
37  using VectorB = Eigen::Matrix<Base, Eigen::Dynamic, 1>;
38  using VectorCB = Eigen::Matrix<std::complex<Base>, Eigen::Dynamic, 1>;
39  using MatrixB = Eigen::Matrix<Base, Eigen::Dynamic, Eigen::Dynamic>;
40 protected:
48  std::vector<Base> x_;
52  std::vector<Base> normVar_;
56  std::vector<Base> normEq_;
60  std::unique_ptr<ADFun<CGBase> > reducedFun_;
65  std::vector<bool> jacSparsity_;
66  // the initial index of time derivatives
67  size_t diffVarStart_;
68  // the initial index of the differentiated equations
69  size_t diffEqStart_;
75  Eigen::SparseMatrix<Base, Eigen::RowMajor> jacobian_;
79  std::vector<Vnode<Base>*> dummyD_;
92  bool reorder_;
96  bool avoidConvertAlg2DifVars_;
100  std::set<std::string> avoidAsDummy_;
101 public:
102 
115  const std::vector<Base>& x,
116  const std::vector<Base>& normVar,
117  const std::vector<Base>& normEq) :
118  DaeIndexReduction<Base>(idxIdentify.getOriginalModel()),
119  idxIdentify_(&idxIdentify),
120  x_(x),
121  normVar_(normVar),
122  normEq_(normEq),
123  diffVarStart_(0),
124  diffEqStart_(idxIdentify.getOriginalModel().Range()),
125  reduceEquations_(true),
126  generateSemiExplicitDae_(false),
127  reorder_(true),
128  avoidConvertAlg2DifVars_(true) {
129 
130  for (Vnode<Base>* jj : idxIdentify.getGraph().variables()) {
131  if (jj->antiDerivative() != nullptr) {
132  diffVarStart_ = jj->index();
133  break;
134  }
135  }
136  }
137 
138  inline virtual ~DummyDerivatives() {
139  }
140 
148  inline bool isAvoidConvertAlg2DifVars() const {
149  return avoidConvertAlg2DifVars_;
150  }
151 
159  inline void setAvoidConvertAlg2DifVars(bool avoid) {
160  avoidConvertAlg2DifVars_ = avoid;
161  }
162 
167  inline bool isGenerateSemiExplicitDae() const {
169  }
170 
178  inline void setGenerateSemiExplicitDae(bool generateSemiExplicitDae) {
179  generateSemiExplicitDae_ = generateSemiExplicitDae;
180  }
181 
186  inline bool isReduceEquations() const {
187  return reduceEquations_;
188  }
189 
195  reduceEquations_ = reduceEquations;
196  }
197 
201  inline bool isReorder() const {
202  return reorder_;
203  }
204 
212  inline void setReorder(bool reorder) {
213  reorder_ = reorder;
214  }
215 
225  inline void setAvoidVarsAsDummies(const std::set<std::string>& avoidAsDummy) {
226  avoidAsDummy_ = avoidAsDummy;
227  }
228 
235  inline const std::set<std::string>& getAvoidVarsAsDummies() const {
236  return avoidAsDummy_;
237  }
238 
239  inline std::unique_ptr<ADFun<CG<Base>>> reduceIndex(std::vector<DaeVarInfo>& newVarInfo,
240  std::vector<DaeEquationInfo>& newEqInfo) override {
241 
245  std::vector<DaeVarInfo> reducedVarInfo;
249  std::vector<DaeEquationInfo> reducedEqInfo;
250 
251  reducedFun_ = idxIdentify_->reduceIndex(reducedVarInfo, reducedEqInfo);
252  if (reducedFun_.get() == nullptr)
253  return nullptr; //nothing to do (no index reduction required)
254 
255  if (this->verbosity_ >= Verbosity::Low)
256  log() << "######## Dummy derivatives method ########" << std::endl;
257 
258  newEqInfo = reducedEqInfo; // copy
259  addDummyDerivatives(reducedVarInfo, reducedEqInfo, newVarInfo);
260 
261  if (reduceEquations_ || generateSemiExplicitDae_) {
262 
263  matchVars2Eqs4Elimination(newVarInfo, newEqInfo);
264 
265  if (reduceEquations_) {
266  std::vector<DaeVarInfo> varInfo = newVarInfo; // copy
267  std::vector<DaeEquationInfo> eqInfo = newEqInfo; // copy
268  std::unique_ptr<ADFun<CG<Base> > > funShort = reduceEquations(varInfo, newVarInfo,
269  eqInfo, newEqInfo);
270  reducedFun_.swap(funShort);
271  }
272 
273  if (generateSemiExplicitDae_) {
274  std::vector<DaeVarInfo> varInfo = newVarInfo; // copy
275  std::vector<DaeEquationInfo> eqInfo = newEqInfo; // copy
276  std::unique_ptr<ADFun<CG<Base> > > semiExplicit = generateSemiExplicitDAE(*reducedFun_,
277  varInfo, newVarInfo,
278  eqInfo, newEqInfo);
279  reducedFun_.swap(semiExplicit);
280  }
281  }
282 
283  if (reorder_) {
284  std::vector<DaeVarInfo> varInfo = newVarInfo; // copy
285  std::vector<DaeEquationInfo> eqInfo = newEqInfo; // copy
286  std::unique_ptr<ADFun<CG<Base>>> reorderedFun = reorderModelEqNVars(*reducedFun_,
287  varInfo, newVarInfo,
288  eqInfo, newEqInfo);
289  reducedFun_.swap(reorderedFun);
290  }
291 
292  return std::unique_ptr<ADFun<CG<Base>>>(reducedFun_.release());
293  }
294 
295 protected:
296 
298 
299  virtual inline void addDummyDerivatives(const std::vector<DaeVarInfo>& varInfo,
300  const std::vector<DaeEquationInfo>& eqInfo,
301  std::vector<DaeVarInfo>& newVarInfo) {
302  auto& graph = idxIdentify_->getGraph();
303  auto& vnodes = graph.variables();
304  auto& enodes = graph.equations();
305 
307 
308  // variables of interest
309  std::vector<Vnode<Base>*> vars;
310  vars.reserve(vnodes.size() - diffVarStart_);
311  typename std::vector<Vnode<Base>*>::const_reverse_iterator rj;
312  for (rj = vnodes.rbegin(); rj != vnodes.rend(); ++rj) {
313  Vnode<Base>* jj = *rj;
314  if (jj->antiDerivative() != nullptr && jj->derivative() == nullptr) {
315  vars.push_back(jj); // highest order time derivatives in the index 1 model
316  }
317  }
318 
319  // should be already fairly sorted, but sort anyway
320  std::sort(vars.begin(), vars.end(), sortVnodesByOrder<Base>);
321 
322  // equations of interest
323  typename std::vector<Enode<Base>*>::const_reverse_iterator ri;
324  std::vector<Enode<Base>*> eqs;
325  eqs.reserve(enodes.size() - diffEqStart_);
326  for (ri = enodes.rbegin(); ri != enodes.rend(); ++ri) {
327  Enode<Base>* ii = *ri;
328  if (ii->derivativeOf() != nullptr && ii->derivative() == nullptr) {
329  eqs.push_back(ii);
330  }
331  }
332 
333 
334  MatrixB workJac;
335 
336  while (true) {
337 
338  if (this->verbosity_ >= Verbosity::High) {
339  log() << "# equation selection: ";
340  for (size_t i = 0; i < eqs.size(); i++)
341  log() << *eqs[i] << "; ";
342  log() << "\n";
343 
344  log() << "# variable selection: ";
345  for (size_t j = 0; j < vars.size(); j++)
346  log() << *vars[j] << "; ";
347  log() << "\n";
348  }
349 
350  // Exploit the current equations for elimination of candidates
351  selectDummyDerivatives(eqs, vars, workJac);
352 
359  std::vector<Enode<Base>*> newEqs;
360  newEqs.reserve(eqs.size());
361 
362  for (Enode<Base>* i : eqs) {
363  Enode<Base>* ii = i->derivativeOf();
364  if (ii != nullptr && ii->derivativeOf() != nullptr) {
365  newEqs.push_back(ii);
366  }
367  }
368  eqs.swap(newEqs);
369 
370  if (eqs.empty()) {
371  break;
372  }
373 
380  std::vector<Vnode<Base>*> varsNew;
381  varsNew.reserve(vars.size());
382  for (Vnode<Base>* j : vars) {
383  Vnode<Base>* v = j->antiDerivative();
384  if (v != nullptr && v->antiDerivative() != nullptr) {
385  varsNew.push_back(v);
386  }
387  }
388  vars.swap(varsNew);
389  }
390 
391 
395  newVarInfo = varInfo; //copy
396  for (Vnode<Base>* j : dummyD_) {
397  CPPADCG_ASSERT_UNKNOWN(j->tapeIndex() >= 0);
398  CPPADCG_ASSERT_UNKNOWN(j->antiDerivative() != nullptr);
399  CPPADCG_ASSERT_UNKNOWN(j->antiDerivative()->tapeIndex() >= 0);
400 
401  newVarInfo[j->tapeIndex()].setAntiDerivative(-1);
402  newVarInfo[j->antiDerivative()->tapeIndex()].setDerivative(-1);
403  }
404 
405  if (this->verbosity_ >= Verbosity::Low) {
406  log() << "## dummy derivatives:\n";
407 
408  for (Vnode<Base>* j : dummyD_)
409  log() << "# " << *j << " \t" << newVarInfo[j->tapeIndex()].getName() << "\n";
410  log() << "# \n";
411  if (this->verbosity_ >= Verbosity::High) {
412  graph.printModel(log(), *reducedFun_, newVarInfo, eqInfo);
413  }
414  }
415 
416  }
417 
425  inline std::unique_ptr<ADFun<CGBase> > reduceEquations(const std::vector<DaeVarInfo>& reducedVarInfo,
426  std::vector<DaeVarInfo>& newVarInfo,
427  const std::vector<DaeEquationInfo>& reducedEqInfo,
428  std::vector<DaeEquationInfo>& newEqInfo) {
429  using namespace std;
430  using std::vector;
431  using std::map;
432 
433  auto& graph = idxIdentify_->getGraph();
434  //auto& vnodes = graph.variables();
435  auto& enodes = graph.equations();
436 
437  CPPADCG_ASSERT_UNKNOWN(reducedVarInfo.size() == reducedFun_->Domain());
438  CPPADCG_ASSERT_UNKNOWN(reducedEqInfo.size() == reducedFun_->Range());
439 
440  newEqInfo = reducedEqInfo; // copy
441 
445  CodeHandler<Base> handler;
446 
447  vector<CGBase> indep0(reducedFun_->Domain());
448  handler.makeVariables(indep0);
449 
450  vector<CGBase> res0 = graph.forward0(*reducedFun_, indep0);
451 
452  map<int, int> assignedVar2Eq;
453  for (size_t i = 0; i < newEqInfo.size(); ++i) {
454  DaeEquationInfo& newEq = newEqInfo[i];
455  if (newEq.getAssignedVarIndex() >= 0)
456  assignedVar2Eq[newEq.getAssignedVarIndex()] = i;
457  }
458 
464  vector<int> eqIndexReduced2Short(enodes.size());
465  for (size_t i = 0; i < eqIndexReduced2Short.size(); i++) {
466  eqIndexReduced2Short[i] = i;
467  }
468 
474  vector<int> tapeIndexReduced2Short(reducedVarInfo.size());
475  for (size_t j = 0; j < tapeIndexReduced2Short.size(); j++) {
476  tapeIndexReduced2Short[j] = j;
477  }
478 
483  set<size_t> erasedVariables;
484  set<size_t> erasedEquations;
485 
486  if (this->verbosity_ >= Verbosity::High)
487  log() << "Reducing total number of equations by symbolic manipulation:" << std::endl;
488 
489  for (Vnode<Base>* dummy : dummyD_) {
490 
494  map<int, int>::const_iterator ita = assignedVar2Eq.find(dummy->tapeIndex());
495  if (ita == assignedVar2Eq.end()) {
496  if (this->verbosity_ >= Verbosity::High)
497  log() << "unable to solve for variable " << dummy->name() << "." << std::endl;
498 
499  continue; // unable to solve for a dummy variable: keep the equation and variable
500  }
501  int bestEquation = ita->second;
502 
503  try {
504  // eliminate all references to the dummy variable by substitution
505  handler.substituteIndependent(indep0[dummy->tapeIndex()], res0[bestEquation]);
506  tapeIndexReduced2Short[dummy->tapeIndex()] = -1;
507  eqIndexReduced2Short[bestEquation] = -1;
508 
509  if (this->verbosity_ >= Verbosity::High) {
510  log() << "######### use equation " << *enodes[newEqInfo[bestEquation].getId()] << " to solve for variable " << dummy->name() << std::endl;
511  erasedVariables.insert(dummy->tapeIndex());
512  erasedEquations.insert(bestEquation);
513  printModel(log(), handler, res0, reducedVarInfo, erasedVariables, erasedEquations);
514  }
515 
516  } catch (const CGException& ex) {
517  // unable to solve for a dummy variable: keep the equation and variable
518  if (this->verbosity_ >= Verbosity::High)
519  log() << "unable to use equation " << *enodes[newEqInfo[bestEquation].getId()] << " to solve for variable " << dummy->name() << ": " << ex.what() << std::endl;
520  }
521  }
522 
523  // determine the new equation indexes
524  for (size_t i = 0; i < eqIndexReduced2Short.size(); i++) {
525  if (eqIndexReduced2Short[i] < 0) { // removed equation
526  for (size_t ii = i + 1; ii < eqIndexReduced2Short.size(); ii++) {
527  if (eqIndexReduced2Short[ii] >= 0) {
528  eqIndexReduced2Short[ii]--;
529  }
530  }
531  }
532  }
533 
534  // determine the new indexes in the tape
535  for (size_t p = 0; p < tapeIndexReduced2Short.size(); p++) {
536  if (tapeIndexReduced2Short[p] < 0) {
537  // removed from model
538  for (size_t p2 = p + 1; p2 < tapeIndexReduced2Short.size(); p2++) {
539  if (tapeIndexReduced2Short[p2] >= 0) {
540  tapeIndexReduced2Short[p2]--;
541  }
542  }
543  }
544  }
545 
549  CPPADCG_ASSERT_UNKNOWN(tapeIndexReduced2Short.size() == reducedVarInfo.size());
550 
551  newVarInfo = reducedVarInfo; // copy
552  for (int p = tapeIndexReduced2Short.size() - 1; p >= 0; p--) {
553  if (tapeIndexReduced2Short[p] < 0) { // removed from model
554  newVarInfo.erase(newVarInfo.begin() + p);
555  for (size_t pp = 0; pp < tapeIndexReduced2Short.size(); pp++) {
556  DaeVarInfo& v = newVarInfo[pp];
557  if (v.getAntiDerivative() > p) {
558  v.setAntiDerivative(v.getAntiDerivative() - 1);
559  } else if (v.getAntiDerivative() == p) {
560  v.setAntiDerivative(-1);
561  }
562  if (v.getDerivative() > p) {
563  v.setDerivative(v.getDerivative() - 1);
564  } else if (v.getDerivative() == p) {
565  v.setDerivative(-1);
566  }
567  }
568  }
569  }
570 
571  for (int p = eqIndexReduced2Short.size() - 1; p >= 0; p--) {
572  if (eqIndexReduced2Short[p] < 0) {// removed from model
573  newEqInfo.erase(newEqInfo.begin() + p);
574  } else {
575  DaeEquationInfo& eq = newEqInfo[p];
576  int reducedVIndex = eq.getAssignedVarIndex();
577  if (reducedVIndex >= 0)
578  eq.setAssignedVarIndex(tapeIndexReduced2Short[reducedVIndex]);
579  if (eq.getAntiDerivative() >= 0)
580  eq.setAntiDerivative(eqIndexReduced2Short[eq.getAntiDerivative()]);
581  }
582  }
583 
588  std::unique_ptr<ADFun<CGBase> > shortFun(generateReorderedModel(handler, res0,
589  reducedVarInfo, newVarInfo,
590  reducedEqInfo, newEqInfo));
591 
592  if (this->verbosity_ >= Verbosity::High) {
593  log() << "DAE with less equations and variables:\n";
594  graph.printModel(log(), *shortFun, newVarInfo, newEqInfo);
595  }
596 
597  return shortFun;
598  }
599 
610  inline std::unique_ptr<ADFun<CGBase> > generateSemiExplicitDAE(ADFun<CG<Base> >& fun,
611  const std::vector<DaeVarInfo>& varInfo,
612  std::vector<DaeVarInfo>& newVarInfo,
613  const std::vector<DaeEquationInfo>& eqInfo,
614  std::vector<DaeEquationInfo>& newEqInfo) {
615  using namespace std;
616  using std::vector;
617  using std::map;
618 
619  auto& graph = idxIdentify_->getGraph();
620 
621  newEqInfo = eqInfo; // copy (we will have the same number of equations)
622 
626  CodeHandler<Base> handler;
627 
628  vector<CGBase> indep0(fun.Domain());
629  handler.makeVariables(indep0);
630 
631  vector<CGBase> res0 = graph.forward0(fun, indep0);
632 
633  map<int, int> assignedVar2Eq;
634  for (size_t i = 0; i < newEqInfo.size(); ++i) {
635  DaeEquationInfo& newEq = newEqInfo[i];
636  assignedVar2Eq[newEq.getAssignedVarIndex()] = i;
637  }
638 
642  for (size_t j = 0; j < varInfo.size(); ++j) {
643  const DaeVarInfo& jj = varInfo[j];
644  if (jj.getAntiDerivative() < 0) {
645  continue; // not a time derivative
646  }
647  CGBase& indep = indep0[j]; // the time derivative
651  map<int, int>::const_iterator ita = assignedVar2Eq.find(j);
652  if (ita == assignedVar2Eq.end()) {
653  throw CGException("Failed to generate semi-explicit DAE: unable to create an explicit equation for ", jj.getName());
654  }
655 
656  int bestEquation = ita->second;
657 
658  try {
659  CGBase& dep = res0[bestEquation]; // the equation residual
660 
661  handler.substituteIndependent(indep, dep); // removes indep from the list of variables
662 
663  OperationNode<Base>* alias = indep.getOperationNode();
664  CPPADCG_ASSERT_UNKNOWN(alias != nullptr && alias->getOperationType() == CGOpCode::Alias);
665  dep.getOperationNode()->makeAlias(alias->getArguments()[0]); // not a residual anymore but equal to alias (explicit equation)
666 
667  // it is now an explicit differential equation
668  newEqInfo[bestEquation].setExplicit(true);
669  // the derivative variable will disappear, associate the equation with the original variable
670  newEqInfo[bestEquation].setAssignedVarIndex(jj.getAntiDerivative());
671  } catch (const CGException& ex) {
672  // unable to solve for a dummy variable: keep the equation and variable
673  throw CGException("Failed to generate semi-explicit DAE: ", ex.what());
674  }
675  }
676 
681  vector<int> varIndexOld2New(varInfo.size(), -1);
682  size_t count = 0;
683  for (size_t j = 0; j != varInfo.size(); ++j) {
684  // exclude derivatives (they will be removed)
685  if (varInfo[j].getAntiDerivative() < 0) {
686  varIndexOld2New[j] = count++;
687  }
688  }
689 
690  for (size_t i = 0; i < newEqInfo.size(); ++i) {
691  const DaeEquationInfo& ii = newEqInfo[i];
692  int j = ii.getAssignedVarIndex();
693  if (j >= 0)
694  newEqInfo[i].setAssignedVarIndex(varIndexOld2New[j]);
695  }
696 
700  newVarInfo = varInfo;
701  for (int j = newVarInfo.size() - 1; j >= 0; --j) {
702  if (newVarInfo[j].getAntiDerivative() >= 0) {
703  // a derivative
704  newVarInfo.erase(newVarInfo.begin() + j);
705  }
706  }
707  for (size_t j = 0; j < newVarInfo.size(); j++) {
708  newVarInfo[j].setDerivative(-1); // no derivatives in tape
709  }
710 
715  std::unique_ptr<ADFun<CGBase> > semiExplicitFun(generateReorderedModel(handler, res0, varInfo, newVarInfo, eqInfo, newEqInfo));
716 
717  if (this->verbosity_ >= Verbosity::High) {
718  log() << "Semi-Eplicit DAE:\n";
719  graph.printModel(log(), *semiExplicitFun, newVarInfo, newEqInfo);
720  }
721 
722  return semiExplicitFun;
723  }
724 
725  inline void matchVars2Eqs4Elimination(std::vector<DaeVarInfo>& varInfo,
726  std::vector<DaeEquationInfo>& eqInfo) {
727  using std::vector;
728  using std::map;
729 
730  auto& graph = idxIdentify_->getGraph();
731  auto& vnodes = graph.variables();
732  auto& enodes = graph.equations();
733 
734  CPPADCG_ASSERT_UNKNOWN(eqInfo.size() == enodes.size());
735  CPPADCG_ASSERT_UNKNOWN(varInfo.size() == reducedFun_->Domain());
736  CPPADCG_ASSERT_UNKNOWN(eqInfo.size() == reducedFun_->Range());
737 
738  CodeHandler<Base> handler;
739 
740  vector<CGBase> indep0(reducedFun_->Domain());
741  handler.makeVariables(indep0);
742 
743  vector<CGBase> res0 = graph.forward0(*reducedFun_, indep0);
744 
745  vector<bool> jacSparsity = jacobianSparsity<vector<bool> >(*reducedFun_);
746 
747  vector<Vnode<Base>*> diffVariables;
748  vector<Vnode<Base>*> dummyVariables;
749  vector<Vnode<Base>*> variables;
750  vector<Enode<Base>*> equations(enodes.size(), nullptr);
751  try {
755  // create variable nodes
756  map<Vnode<Base>*, Vnode<Base>*> eliminateOrig2New;
757  for (size_t j = 0; j < vnodes.size(); j++) {
758  Vnode<Base>* v = vnodes[j];
759  if (std::find(dummyD_.begin(), dummyD_.end(), v) != dummyD_.end()) {
760  if (reduceEquations_) {
761  dummyVariables.push_back(new Vnode<Base>(j, v->tapeIndex(), v->name()));
762  eliminateOrig2New[v] = dummyVariables.back();
763  }
764  } else if (v->antiDerivative() != nullptr) {
765  if (generateSemiExplicitDae_) {
766  diffVariables.push_back(new Vnode<Base>(j, v->tapeIndex(), v->name()));
767  eliminateOrig2New[v] = diffVariables.back();
768  }
769  }
770  }
771 
772  variables.reserve(diffVariables.size() + dummyVariables.size());
773  variables.insert(variables.end(), diffVariables.begin(), diffVariables.end()); // must be added 1st (priority)
774  variables.insert(variables.end(), dummyVariables.begin(), dummyVariables.end());
775 
776  // create equation nodes
777  for (size_t i = 0; i < enodes.size(); i++) {
778  equations[i] = new Enode<Base>(i, enodes[i]->name());
779  const vector<Vnode<Base>*>& origVars = enodes[i]->originalVariables();
780  for (size_t p = 0; p < origVars.size(); p++) {
781  Vnode<Base>* jOrig = origVars[p];
782 
783  typename map<Vnode<Base>*, Vnode<Base>*>::const_iterator it;
784  it = eliminateOrig2New.find(jOrig);
785  if (it != eliminateOrig2New.end() &&
786  jacSparsity[varInfo.size() * i + jOrig->tapeIndex()]) {
787  Vnode<Base>* j = it->second;
788 
789  CGBase& dep = res0[i]; // the equation residual
790  CGBase& indep = indep0[j->tapeIndex()];
791 
792  if (handler.isSolvable(*dep.getOperationNode(), *indep.getOperationNode())) {
793  equations[i]->addVariable(j);
794  }
795  }
796  }
797  }
798 
799  map<size_t, Vnode<Base>*> tape2FreeVariables;
800  for (Vnode<Base>* j : variables) {
801  tape2FreeVariables[j->tapeIndex()] = j;
802  }
803 
804 
808  while (true) {
809  size_t assigned;
810  do {
811  do {
815  do {
816  assigned = 0;
817  for (Vnode<Base>* j : diffVariables) {
818  if (!j->isDeleted() && j->equations().size() == 1) {
819  Enode<Base>& i = *j->equations()[0];
820  if (i.assignmentVariable() == nullptr) {
821  if (!assignVar2Equation(i, res0, *j, indep0, handler,
822  jacSparsity, tape2FreeVariables,
823  equations, varInfo)) {
824  throw CGException("Failed to solve equation ", i.name(), " for variable ", j->name());
825  }
826  assigned++;
827  }
828  }
829  }
830  } while (assigned > 0);
831 
836  assigned = 0;
837  for (Vnode<Base>* j : dummyVariables) {
838  if (!j->isDeleted() && j->equations().size() == 1) {
839  Enode<Base>& i = *j->equations()[0];
840  if (i.assignmentVariable() == nullptr) {
841  if (assignVar2Equation(i, res0, *j, indep0, handler,
842  jacSparsity, tape2FreeVariables,
843  equations, varInfo))
844  assigned++;
845  }
846  }
847  }
848  } while (assigned > 0);
849 
854  assigned = 0;
855  for (Enode<Base>* i : equations) {
856  if (i->assignmentVariable() == nullptr && i->variables().size() == 1) {
857  Vnode<Base>* j = i->variables()[0];
858  if (assignVar2Equation(*i, res0, *j, indep0, handler,
859  jacSparsity, tape2FreeVariables,
860  equations, varInfo))
861  assigned++;
862  }
863  }
864 
865  } while (assigned > 0);
866 
872  assigned = 0;
873  for (Vnode<Base>* j : variables) {
874  if (!j->isDeleted()) {
875  for (Enode<Base>* i : j->equations()) {
876  if (i->assignmentVariable() == nullptr) {
877  if (assignVar2Equation(*i, res0, *j, indep0, handler,
878  jacSparsity, tape2FreeVariables,
879  equations, varInfo)) {
880  assigned++;
881  break;
882  }
883  }
884  }
885  if (assigned > 0)
886  break;
887  }
888  }
889 
890  if (assigned == 0) {
891  break; // done
892  }
893  }
894 
895 
900  for (Vnode<Base>* j : variables) { // previous assignments must not change!
901  if (j->assignmentEquation() != nullptr) {
902  j->deleteNode();
903  }
904  }
905 
907  for(Enode<Base>* i: equations) {
908  if (i->assignmentVariable() == nullptr) {
909  augment.augmentPath(*i);
910  }
911  }
912 
916  for (Vnode<Base>* j : variables) {
917  if (j->assignmentEquation() != nullptr) {
918  int i = j->assignmentEquation()->index();
919  DaeEquationInfo& eq = eqInfo[i];
920 
921  if (eq.getAssignedVarIndex() != int(j->tapeIndex())) {
922  eq.setAssignedVarIndex(j->tapeIndex());
923  }
924  }
925  }
926 
927  // verify results
928  if (generateSemiExplicitDae_) {
929  std::string error;
930  for (Vnode<Base>* j : diffVariables) {
931  if (j->assignmentEquation() == nullptr) {
932  // failed!!!
933  if (!error.empty())
934  error += ",";
935  error += " " + j->name();
936  }
937  }
938  if (!error.empty())
939  throw CGException("Failed to generate semi-explicit DAE. Could not solve system for the following variables:", error);
940  }
941 
942  } catch (...) {
943  deleteVectorValues(diffVariables);
944  deleteVectorValues(dummyVariables);
945  deleteVectorValues(equations);
946  throw;
947  }
948 
949  if (this->verbosity_ >= Verbosity::High) {
950  for (Vnode<Base>* j : variables) {
951  if (j->assignmentEquation() != nullptr)
952  log() << "## Variable " + j->name() << " assigned to equation " << j->assignmentEquation()->name() << "\n";
953  }
954  log() << std::endl;
955  }
956  deleteVectorValues(diffVariables);
957  deleteVectorValues(dummyVariables);
958  deleteVectorValues(equations);
959  }
960 
961  inline bool assignVar2Equation(Enode<Base>& i, std::vector<CGBase>& res0,
962  Vnode<Base>& j, std::vector<CGBase>& indep0,
963  CodeHandler<Base>& handler,
964  std::vector<bool>& jacSparsity,
965  const std::map<size_t, Vnode<Base>*>& tape2FreeVariables,
966  std::vector<Enode<Base>*>& equations,
967  std::vector<DaeVarInfo>& varInfo) {
968  using namespace std;
969  using std::vector;
970  using std::map;
971 
972  std::vector<bool> localJacSparsity = jacSparsity;
973  const size_t n = varInfo.size();
974 
978  CGBase& dep = res0[i.index()];
979  CGBase& indep = indep0[j.tapeIndex()];
980 
981  std::string indepName;
982  if (indep.getOperationNode()->getName() != nullptr) {
983  indepName = *indep.getOperationNode()->getName();
984  }
985 
986 
987  try {
988  handler.substituteIndependent(indep, dep, false); // indep not removed from the list of variables yet
989 
990  OperationNode<Base>* alias = indep.getOperationNode();
991  CPPADCG_ASSERT_UNKNOWN(alias != nullptr && alias->getOperationType() == CGOpCode::Alias);
992 
993  // it is now an explicit differential equation
994  //newEqInfo[bestEquation].setExplicit(true);
995  // the derivative variable will disappear, associate the equation with the original variable
996  //newEqInfo[bestEquation].setAssignedVarIndex(jj.getAntiDerivative());
997  } catch (const CGException& ex) {
998  // unable to solve for a dummy variable: keep the equation and variable
999  throw CGException("Failed to solve equation ", i.name(), " for variable ", j.name(), ": ", ex.what());
1000  }
1001 
1002 
1007  vector<size_t> nnzs;
1008  for (const auto& it : tape2FreeVariables) {
1009  size_t tapeJ = it.first;
1010  if (localJacSparsity[n * i.index() + tapeJ] && tapeJ != j.tapeIndex()) {
1011  nnzs.push_back(tapeJ);
1012  }
1013  }
1014  set<Enode<Base>*> affected;
1015  for (size_t e = 0; e < equations.size(); ++e) {
1016  if (equations[e] != &i && localJacSparsity[n * e + j.tapeIndex()]) {
1017  localJacSparsity[n * e + j.tapeIndex()] = false; // eliminated by substitution
1018  affected.insert(equations[e]);
1019  for (size_t p = 0; p < nnzs.size(); ++p) {
1020  localJacSparsity[n * e + nnzs[p]] = true;
1021  }
1022  }
1023  }
1024 
1025  if (affected.size() > 0) {
1029  map<size_t, set<Enode<Base>*> > solvable;
1030  for (size_t e = 0; e < equations.size(); ++e) {
1031  Enode<Base>* eq = equations[e];
1032  if (&i != eq && affected.find(eq) == affected.end()) {
1033  // no change
1034  for (size_t v = 0; v < eq->variables().size(); ++v) {
1035  solvable[eq->variables()[v]->tapeIndex()].insert(eq);
1036  }
1037  }
1038  }
1039 
1040  // redetermine solvability
1041  for (Enode<Base>* itAff : affected) {
1042  Enode<Base>& a = *itAff;
1043  for (const auto& it : tape2FreeVariables) {
1044  size_t jj = it.first;
1045  if (localJacSparsity[n * a.index() + jj]) {
1046  if (handler.isSolvable(*res0[a.index()].getOperationNode(), *indep0[jj].getOperationNode())) {
1047  solvable[jj].insert(&a);
1048  }
1049  }
1050  }
1051  }
1052 
1053  // check if any variable stops being solvable
1054  bool ok = true;
1055  for (const auto& it : tape2FreeVariables) {
1056  Vnode<Base>* v = it.second;
1057  if (v == &j)
1058  continue;
1059 
1060  if (v->assignmentEquation() != nullptr) {
1061  if (affected.count(v->assignmentEquation()) > 0 &&
1062  solvable[v->tapeIndex()].count(v->assignmentEquation()) == 0) {
1063  ok = false;
1064  break;
1065  }
1066  } else if (solvable[v->tapeIndex()].size() == 0) {
1067  ok = false;
1068  break;
1069  }
1070  }
1071 
1072  if (!ok) {
1073  handler.undoSubstituteIndependent(*indep.getOperationNode());
1074  if (indepName.size() > 0) {
1075  indep.getOperationNode()->setName(indepName);
1076  }
1077  return false;
1078  }
1079 
1083  for (Enode<Base>* itAff : affected) {
1084  Enode<Base>& a = *itAff;
1085  for (const auto& it : tape2FreeVariables) {
1086  size_t v = it.first;
1087  if (localJacSparsity[n * a.index() + v]) {
1088  if (solvable[v].count(&a) > 0) {
1089  a.addVariable(it.second);
1090  } else {
1091  // not solvable anymore
1092  a.deleteNode(it.second);
1093  }
1094  }
1095  }
1096  }
1097 
1098  }
1099 
1103  handler.removeIndependent(*indep.getOperationNode());
1104 
1108  j.setAssignmentEquation(i, log(), this->verbosity_);
1109  j.deleteNode(log(), this->verbosity_);
1110 
1111  jacSparsity = localJacSparsity;
1112 
1113  return true;
1114  }
1115 
1116  inline std::unique_ptr<ADFun<CGBase> > reorderModelEqNVars(ADFun<CG<Base> >& fun,
1117  const std::vector<DaeVarInfo>& varInfo,
1118  std::vector<DaeVarInfo>& newVarInfo,
1119  const std::vector<DaeEquationInfo>& eqInfo,
1120  std::vector<DaeEquationInfo>& newEqInfo) {
1121 
1122  using namespace std;
1123  using std::vector;
1124 
1125  auto& graph = idxIdentify_->getGraph();
1126 
1130  std::set<size_t> oldVarWithDerivatives; // indexes of old variables (before reordering) with derivatives
1131  for (size_t i = 0; i < eqInfo.size(); i++) {
1132  if (eqInfo[i].isExplicit() && eqInfo[i].getAssignedVarIndex() >= 0) {
1133  oldVarWithDerivatives.insert(eqInfo[i].getAssignedVarIndex());
1134  }
1135  }
1136 
1137  if (oldVarWithDerivatives.empty()) {
1138  // no semi-explicit model generated
1139  for (size_t j = 0; j < varInfo.size(); j++) {
1140  int index = j;
1141  bool differential = false;
1142  while (varInfo[index].getAntiDerivative() >= 0) {
1143  index = varInfo[index].getAntiDerivative();
1144  differential = true;
1145  }
1146 
1147  if (differential) {
1148  oldVarWithDerivatives.insert(index);
1149  }
1150  }
1151  }
1152 
1156  std::vector<DaeVarOrderInfo> varOrder(varInfo.size());
1157  for (size_t j = 0; j < varInfo.size(); j++) {
1158  size_t j0;
1159  int derivOrder = graph.determineVariableDiffOrder(varInfo, j, j0);
1160  if (varInfo[j].isIntegratedVariable()) {
1161  derivOrder = -2; // so that it goes last
1162  }
1163  bool hasDerivatives = oldVarWithDerivatives.find(j) != oldVarWithDerivatives.end();
1164  varOrder[j] = DaeVarOrderInfo(j, j0, hasDerivatives, derivOrder);
1165  }
1166 
1167  std::sort(varOrder.begin(), varOrder.end(), sortVariablesByOrder);
1168 
1172  std::vector<size_t> varIndexOld2New(varInfo.size(), -1);
1173  for (size_t j = 0; j < varOrder.size(); ++j) {
1174  varIndexOld2New[varOrder[j].originalIndex] = j;
1175  }
1176 
1177  newVarInfo.resize(varInfo.size());
1178  for (size_t j = 0; j < varOrder.size(); ++j) {
1179  newVarInfo[j] = varInfo[varOrder[j].originalIndex];
1180  int oldDerivOfIndex = newVarInfo[j].getAntiDerivative();
1181  if (oldDerivOfIndex >= 0)
1182  newVarInfo[j].setAntiDerivative(varIndexOld2New[oldDerivOfIndex]);
1183  int oldDerivIndex = newVarInfo[j].getDerivative();
1184  if (oldDerivIndex >= 0)
1185  newVarInfo[j].setDerivative(varIndexOld2New[oldDerivIndex]);
1186  }
1187 
1191  newEqInfo = eqInfo; //copy
1192  for (size_t i = 0; i < newEqInfo.size(); i++) {
1193  int oldVIndex = newEqInfo[i].getAssignedVarIndex();
1194  if (oldVIndex >= 0) {
1195  newEqInfo[i].setAssignedVarIndex(varIndexOld2New[oldVIndex]);
1196  }
1197  }
1198 
1199  std::vector<DaeEqOrderInfo> eqOrder(newEqInfo.size());
1200  for (size_t i = 0; i < newEqInfo.size(); i++) {
1201  int assignedVar = newEqInfo[i].getAssignedVarIndex();
1202  size_t i0 = i;
1203  while (newEqInfo[i0].getAntiDerivative() >= 0) {
1204  i0 = newEqInfo[i0].getAntiDerivative();
1205  }
1206  bool isDifferential = newEqInfo[i].isExplicit() || (assignedVar >= 0 && newVarInfo[assignedVar].getAntiDerivative() >= 0);
1207  eqOrder[i] = DaeEqOrderInfo(i, i0, isDifferential, assignedVar);
1208  }
1209 
1210  std::sort(eqOrder.begin(), eqOrder.end(), sortEquationByAssignedOrder2);
1211 
1212  std::vector<DaeEquationInfo> newEqInfo2(newEqInfo.size());
1213  for (size_t i = 0; i < eqOrder.size(); i++) {
1214  newEqInfo2[i] = newEqInfo[eqOrder[i].originalIndex];
1215  }
1216  newEqInfo = newEqInfo2;
1217 
1218 
1222  CodeHandler<Base> handler;
1223 
1224  vector<CGBase> indep0(fun.Domain());
1225  handler.makeVariables(indep0);
1226 
1227  const vector<CGBase> res0 = graph.forward0(fun, indep0);
1228 
1232  std::unique_ptr<ADFun<CGBase> > reorderedFun(generateReorderedModel(handler, res0, varInfo, newVarInfo, eqInfo, newEqInfo));
1233 
1234  if (this->verbosity_ >= Verbosity::High) {
1235  log() << "reordered DAE equations and variables:\n";
1236  graph.printModel(log(), *reorderedFun, newVarInfo, newEqInfo);
1237  }
1238 
1239  return reorderedFun;
1240  }
1241 
1243  const std::vector<CGBase>& res0,
1244  const std::vector<DaeVarInfo>& varInfo,
1245  const std::vector<DaeVarInfo>& newVarInfo,
1246  const std::vector<DaeEquationInfo>& eqInfo,
1247  const std::vector<DaeEquationInfo>& newEqInfo) const {
1248  using std::vector;
1249 
1250  vector<ADCG> indepNewOrder(handler.getIndependentVariableSize());
1251  CPPADCG_ASSERT_UNKNOWN(indepNewOrder.size() == newVarInfo.size());
1252 
1253  for (size_t p = 0; p < newVarInfo.size(); p++) {
1254  int origIndex = newVarInfo[p].getOriginalIndex();
1255  if (origIndex >= 0) {
1256  indepNewOrder[p] = x_[origIndex];
1257  }
1258  }
1259 
1260  Independent(indepNewOrder);
1261 
1268  std::set<size_t> newIds;
1269  for (size_t j = 0; j < newVarInfo.size(); j++) {
1270  newIds.insert(newVarInfo[j].getId());
1271  }
1272 
1273  std::map<size_t, size_t> varId2HandlerIndex;
1274  size_t handlerIndex = 0; // start the variable count again since some variable might have been removed
1275  for (size_t j = 0; j < varInfo.size(); j++) {
1276  int id = varInfo[j].getId();
1277  if (newIds.find(id) != newIds.end()) {
1278  varId2HandlerIndex[id] = handlerIndex++; // not removed from model
1279  }
1280  }
1281 
1282  vector<ADCG> indepHandlerOrder(handler.getIndependentVariableSize());
1283  for (size_t p = 0; p < newVarInfo.size(); p++) {
1284  size_t id = newVarInfo[p].getId();
1285  indepHandlerOrder[varId2HandlerIndex[id]] = indepNewOrder[p];
1286  }
1287 
1288  // reorder equations
1289  std::map<size_t, size_t> eqId2OldIndex;
1290  for (size_t i = 0; i < eqInfo.size(); i++) {
1291  eqId2OldIndex[eqInfo[i].getId()] = i;
1292  }
1293 
1294  vector<CGBase> resNewOrder(newEqInfo.size());
1295  for (size_t i = 0; i < newEqInfo.size(); i++) {
1296  size_t oldIndex = eqId2OldIndex[newEqInfo[i].getId()];
1297  resNewOrder[i] = res0[oldIndex];
1298  }
1299 
1300  // evaluate the model
1301  Evaluator<Base, CGBase> evaluator0(handler);
1302  evaluator0.setPrintFor(idxIdentify_->getGraph().isPreserveNames()); // variable names saved with CppAD::PrintFor
1303  vector<ADCG> depNewOrder = evaluator0.evaluate(indepHandlerOrder, resNewOrder);
1304 
1305  return new ADFun<CGBase>(indepNewOrder, depNewOrder);
1306  }
1307 
1312  inline void determineJacobian() {
1313  using namespace std;
1314  using std::vector;
1315 
1316  const size_t n = reducedFun_->Domain();
1317  const size_t m = reducedFun_->Range();
1318 
1319  auto& graph = idxIdentify_->getGraph();
1320  auto& vnodes = graph.variables();
1321  auto& enodes = graph.equations();
1322 
1323  jacSparsity_ = jacobianReverseSparsity<vector<bool>, CGBase>(*reducedFun_); // in the original variable order
1324 
1325  vector<size_t> row, col;
1326  row.reserve((vnodes.size() - diffVarStart_) * (m - diffEqStart_));
1327  col.reserve(row.capacity());
1328 
1329  for (size_t i = diffEqStart_; i < m; i++) {
1330  for (size_t j = diffVarStart_; j < vnodes.size(); j++) {
1331  CPPADCG_ASSERT_UNKNOWN(vnodes[j]->antiDerivative() != nullptr);
1332  size_t t = vnodes[j]->tapeIndex();
1333  if (jacSparsity_[i * n + t]) {
1334  row.push_back(i);
1335  col.push_back(t);
1336  }
1337  }
1338  }
1339 
1340  vector<CG<Base> > jac(row.size());
1341 
1342  vector<CG<Base> > indep(n);
1343  std::copy(x_.begin(), x_.end(), indep.begin());
1344  std::fill(indep.begin() + x_.size(), indep.end(), 0);
1345 
1346  CppAD::sparse_jacobian_work work; // temporary structure for CPPAD
1347  reducedFun_->SparseJacobianReverse(indep, jacSparsity_,
1348  row, col, jac, work);
1349 
1350  // resize and zero matrix
1351  jacobian_.resize(m - diffEqStart_, vnodes.size() - diffVarStart_);
1352 
1353  map<size_t, Vnode<Base>*> origIndex2var;
1354  for (size_t j = diffVarStart_; j< vnodes.size(); j++) {
1355  Vnode<Base>* jj = vnodes[j];
1356  origIndex2var[jj->tapeIndex()] = jj;
1357  }
1358 
1359  // normalize values
1360  for (size_t e = 0; e < jac.size(); e++) {
1361  Enode<Base>* eqOrig = enodes[row[e]]->originalEquation();
1362  Vnode<Base>* vOrig = origIndex2var[col[e]]->originalVariable(graph.getOrigTimeDependentCount());
1363 
1364  // normalized jacobian value
1365  Base normVal = jac[e].getValue() * normVar_[vOrig->tapeIndex()]
1366  / normEq_[eqOrig->index()];
1367 
1368  size_t i = row[e]; // same order
1369  size_t j = origIndex2var[col[e]]->index(); // different order than in model/tape
1370 
1371  jacobian_.coeffRef(i - diffEqStart_, j - diffVarStart_) = normVal;
1372  }
1373 
1374  jacobian_.makeCompressed();
1375 
1376  if (this->verbosity_ >= Verbosity::High) {
1377  log() << "\npartial jacobian:\n" << jacobian_ << "\n\n";
1378  //cout << jacobian_.triangularView<Eigen::Lower > () << "\n\n";
1379  }
1380  }
1381 
1382  inline void selectDummyDerivatives(const std::vector<Enode<Base>* >& eqs,
1383  const std::vector<Vnode<Base>* >& vars,
1384  MatrixB& work) {
1385 
1386  if (eqs.size() == vars.size()) {
1387  dummyD_.insert(dummyD_.end(), vars.begin(), vars.end());
1388  if (this->verbosity_ >= Verbosity::High) {
1389  log() << "# new dummy derivatives: ";
1390  for (size_t j = 0; j < vars.size(); j++)
1391  log() << *vars[j] << "; ";
1392  log() << " \n";
1393  }
1394 #ifndef NDEBUG
1395  for (Vnode<Base>* it : vars) {
1396  CPPADCG_ASSERT_UNKNOWN(std::find(dummyD_.begin(), dummyD_.end(), it) == dummyD_.end());
1397  }
1398 #endif
1399  return;
1400  }
1401 
1405  std::set<size_t> excludeCols;
1406  std::set<size_t> avoidCols;
1407  for (size_t j = 0; j < vars.size(); j++) {
1408  Vnode<Base>* jj = vars[j];
1409  bool notZero = false;
1410  for (size_t i = 0; i < eqs.size(); i++) {
1411  Enode<Base>* ii = eqs[i];
1412  Base val = jacobian_.coeff(ii->index() - diffEqStart_, jj->index() - diffVarStart_);
1413  if (val != Base(0.0)) {
1414  notZero = true;
1415  break;
1416  }
1417  }
1418  if (!notZero) {
1419  // all zeros: must not choose this column/variable
1420  excludeCols.insert(j);
1421  } else if (avoidAsDummy_.find(vars[j]->name()) != avoidAsDummy_.end()) {
1422  // avoid using this column/variable if there are other alternatives
1423  avoidCols.insert(j);
1424  }
1425  }
1426 
1427  if (eqs.size() <= vars.size() - (excludeCols.size() + avoidCols.size())) {
1428  // there might be sufficient alternatives to avoid using the columns/variables disabled by the user
1429  excludeCols.insert(avoidCols.begin(), avoidCols.end());
1430  } else {
1431  if (this->verbosity_ >= Verbosity::Low)
1432  log() << "Must use variables defined to be avoided by the user!\n";
1433  }
1434 
1435  std::vector<Vnode<Base>* > varsLocal;
1436 
1437  Eigen::ColPivHouseholderQR<MatrixB> qr;
1438 
1439  auto orderColumns = [&]() {
1440  varsLocal.reserve(vars.size() - excludeCols.size());
1441  for (size_t j = 0; j < vars.size(); j++) {
1442  if (excludeCols.find(j) == excludeCols.end()) {
1443  varsLocal.push_back(vars[j]);
1444  }
1445  }
1446 
1447 
1448  work.setZero(eqs.size(), varsLocal.size());
1449 
1450  // determine the rows that only contain a single nonzero (a single column)
1451  for (size_t i = 0; i < eqs.size(); i++) {
1452  Enode<Base>* ii = eqs[i];
1453  for (size_t j = 0; j < varsLocal.size(); j++) {
1454  const Vnode<Base>* jj = varsLocal[j];
1455  Base val = jacobian_.coeff(ii->index() - diffEqStart_, jj->index() - diffVarStart_);
1456  if (val != Base(0.0)) {
1457  work(i, j) = val;
1458  }
1459  }
1460  }
1461 
1462  if (this->verbosity_ >= Verbosity::High)
1463  log() << "subset Jac:\n" << work << "\n";
1464 
1465  qr.compute(work);
1466 
1467  if (qr.info() != Eigen::Success) {
1468  throw CGException("Failed to select dummy derivatives! "
1469  "QR decomposition of a submatrix of the Jacobian failed!");
1470  } else if (qr.rank() < work.rows()) {
1471  throw CGException("Failed to select dummy derivatives! "
1472  "The resulting system is probably singular for the provided data.");
1473  }
1474 
1475  using PermutationMatrix = typename Eigen::ColPivHouseholderQR<MatrixB>::PermutationType;
1476  using Indices = typename PermutationMatrix::IndicesType;
1477 
1478  const PermutationMatrix& p = qr.colsPermutation();
1479  const Indices& indices = p.indices();
1480 
1481  if (this->verbosity_ >= Verbosity::High) {
1482  log() << "## matrix Q:\n";
1483  MatrixB q = qr.matrixQ();
1484  log() << q << "\n";
1485  log() << "## matrix R:\n";
1486  MatrixB r = qr.matrixR().template triangularView<Eigen::Upper>();
1487  log() << r << "\n";
1488  log() << "## matrix P: " << indices.transpose() << "\n";
1489  }
1490 
1491  if (indices.size() < work.rows()) {
1492  throw CGException("Failed to select dummy derivatives! "
1493  "The resulting system is probably singular for the provided data.");
1494  }
1495  };
1496 
1497  try {
1498  orderColumns();
1499  } catch (const CGException& ex) {
1500  if (avoidCols.empty()) {
1501  throw;
1502  }
1503 
1504  if (this->verbosity_ >= Verbosity::Low)
1505  log() << "Failed to determine dummy derivatives without the variables defined to be avoided by the user\n";
1506 
1507  // try again with the variables selected to be avoided by the user
1508  for (size_t j : avoidCols)
1509  excludeCols.erase(j);
1510 
1511  varsLocal.clear();
1512 
1513  orderColumns();
1514  }
1515 
1516  const auto& p = qr.colsPermutation();
1517  const auto& indices = p.indices();
1518 
1519  std::vector<Vnode<Base>* > newDummies;
1520  if (avoidConvertAlg2DifVars_) {
1521  auto& graph = idxIdentify_->getGraph();
1522  const auto& varInfo = graph.getOriginalVariableInfo();
1523 
1524  // add algebraic first
1525  for (int i = 0; newDummies.size() < size_t(work.rows()) && i < qr.rank(); i++) {
1526  Vnode<Base>* v = varsLocal[indices(i)];
1527  CPPADCG_ASSERT_UNKNOWN(v->originalVariable() != nullptr);
1528  size_t tape = v->originalVariable()->tapeIndex();
1529  CPPADCG_ASSERT_UNKNOWN(tape < varInfo.size());
1530  if (varInfo[tape].getDerivative() < 0) {
1531  // derivative of a variable which was originally algebraic only
1532  newDummies.push_back(v);
1533  }
1534  }
1535  // add remaining
1536  for (int i = 0; newDummies.size() < size_t(work.rows()); i++) {
1537  Vnode<Base>* v = varsLocal[indices(i)];
1538  CPPADCG_ASSERT_UNKNOWN(v->originalVariable() != nullptr);
1539  size_t tape = v->originalVariable()->tapeIndex();
1540  CPPADCG_ASSERT_UNKNOWN(tape < varInfo.size());
1541  if (varInfo[tape].getDerivative() >= 0) {
1542  // derivative of a variable which was already differential
1543  newDummies.push_back(v);
1544  }
1545  }
1546 
1547  } else {
1548  // use order provided by the householder column pivoting
1549  for (int i = 0; i < work.rows(); i++) {
1550  newDummies.push_back(varsLocal[indices(i)]);
1551  }
1552  }
1553 
1554  if (this->verbosity_ >= Verbosity::High) {
1555  log() << "## new dummy derivatives: "; //"(condition = " << bestCond << "): ";
1556  for (Vnode<Base>* it : newDummies)
1557  log() << *it << "; ";
1558  log() << " \n\n";
1559  }
1560 #ifndef NDEBUG
1561  for (Vnode<Base>* it : newDummies) {
1562  CPPADCG_ASSERT_UNKNOWN(std::find(dummyD_.begin(), dummyD_.end(), it) == dummyD_.end());
1563  }
1564 #endif
1565 
1566  dummyD_.insert(dummyD_.end(), newDummies.begin(), newDummies.end());
1567  }
1568 
1569  inline static void printModel(std::ostream& out,
1570  CodeHandler<Base>& handler,
1571  const std::vector<CGBase>& res,
1572  const std::vector<DaeVarInfo>& varInfo,
1573  const std::set<size_t>& erasedVariables,
1574  const std::set<size_t>& erasedEquations) {
1575  using std::vector;
1576 
1577  std::vector<std::string> indepNames;
1578  for (size_t p = 0; p < varInfo.size(); p++) {
1579  if (erasedVariables.find(p) == erasedVariables.end()) {
1580  // not erased from model
1581  indepNames.push_back(varInfo[p].getName());
1582  }
1583  }
1584  CPPADCG_ASSERT_UNKNOWN(handler.getIndependentVariableSize() == indepNames.size());
1585 
1586  LanguageC<Base> lang("double");
1587  vector<CGBase> resAux;
1588  for (size_t p = 0; p < res.size(); ++p) {
1589  if (erasedEquations.find(p) == erasedEquations.end()) {
1590  resAux.push_back(res[p]);
1591  }
1592  }
1593  std::vector<std::string> depNames;
1594  LangCCustomVariableNameGenerator<Base> nameGen(depNames, indepNames);
1595  handler.generateCode(out, lang, resAux, nameGen);
1596  }
1597 
1598  inline static void printGraphSparsity(std::ostream& out,
1599  const std::vector<bool>& jacSparsity,
1600  const std::map<size_t, Vnode<Base>*>& tape2FreeVariables,
1601  const std::vector<Enode<Base>*>& equations,
1602  const size_t n) {
1603  for (size_t e = 0; e < equations.size(); ++e) {
1604  Enode<Base>* eq = equations[e];
1605  size_t count = 0;
1606  for (const auto& it : tape2FreeVariables) {
1607  if (jacSparsity[n * eq->index() + it.first]) {
1608  if (count == 0)
1609  out << "# Equation " << e << ": \t";
1610  out << " " << it.second->name();
1611  count++;
1612  }
1613  }
1614  if (count > 0)
1615  out << "\n";
1616  }
1617 
1618  out << std::endl;
1619  }
1620 
1621  template<class T>
1622  inline static void deleteVectorValues(std::vector<T*>& v) {
1623  for (size_t i = 0; i < v.size(); i++) {
1624  delete v[i];
1625  }
1626  v.clear();
1627  }
1628 
1629 };
1630 
1631 } // END cg namespace
1632 } // END CppAD namespace
1633 
1634 #endif
std::vector< ActiveOut > evaluate(ArrayView< const ActiveOut > indepNew, ArrayView< const CG< ScalarIn > > depOld)
Definition: evaluator.hpp:93
virtual std::unique_ptr< ADFun< CG< Base > > > reduceIndex(std::vector< DaeVarInfo > &newVarInfo, std::vector< DaeEquationInfo > &equationInfo)=0
void selectDummyDerivatives(const std::vector< Enode< Base > * > &eqs, const std::vector< Vnode< Base > * > &vars, MatrixB &work)
bool isGenerateSemiExplicitDae() const
void substituteIndependent(const CGB &indep, const CGB &dep, bool removeFromIndeps=true)
Definition: graph_mod.hpp:22
std::unique_ptr< ADFun< CGBase > > generateSemiExplicitDAE(ADFun< CG< Base > > &fun, const std::vector< DaeVarInfo > &varInfo, std::vector< DaeVarInfo > &newVarInfo, const std::vector< DaeEquationInfo > &eqInfo, std::vector< DaeEquationInfo > &newEqInfo)
std::unique_ptr< ADFun< CGBase > > reduceEquations(const std::vector< DaeVarInfo > &reducedVarInfo, std::vector< DaeVarInfo > &newVarInfo, const std::vector< DaeEquationInfo > &reducedEqInfo, std::vector< DaeEquationInfo > &newEqInfo)
Vnode< Base > * derivative() const
const std::vector< Argument< Base > > & getArguments() const
bool isAvoidConvertAlg2DifVars() const
std::vector< Base > normEq_
Definition: dummy_deriv.hpp:56
STL namespace.
Eigen::SparseMatrix< Base, Eigen::RowMajor > jacobian_
Definition: dummy_deriv.hpp:75
std::unique_ptr< ADFun< CGBase > > reorderModelEqNVars(ADFun< CG< Base > > &fun, const std::vector< DaeVarInfo > &varInfo, std::vector< DaeVarInfo > &newVarInfo, const std::vector< DaeEquationInfo > &eqInfo, std::vector< DaeEquationInfo > &newEqInfo)
std::vector< bool > jacSparsity_
Definition: dummy_deriv.hpp:65
void setReduceEquations(bool reduceEquations)
size_t getIndependentVariableSize() const
bool assignVar2Equation(Enode< Base > &i, std::vector< CGBase > &res0, Vnode< Base > &j, std::vector< CGBase > &indep0, CodeHandler< Base > &handler, std::vector< bool > &jacSparsity, const std::map< size_t, Vnode< Base > *> &tape2FreeVariables, std::vector< Enode< Base > *> &equations, std::vector< DaeVarInfo > &varInfo)
const std::set< std::string > & getAvoidVarsAsDummies() const
void setAvoidConvertAlg2DifVars(bool avoid)
bool augmentPath(Enode< Base > &i) override final
void removeIndependent(Node &indep)
Definition: graph_mod.hpp:76
CGOpCode getOperationType() const
void makeVariables(VectorCG &variables)
const std::string & getName() const
ADFun< CG< Base > > & getOriginalModel() const
std::unique_ptr< ADFun< CGBase > > reducedFun_
Definition: dummy_deriv.hpp:60
void undoSubstituteIndependent(Node &indep)
Definition: graph_mod.hpp:65
Enode< Base > * derivative() const
DaeStructuralIndexReduction< Base > *const idxIdentify_
Definition: dummy_deriv.hpp:44
void setReorder(bool reorder)
Vnode< Base > * antiDerivative() const
virtual void addDummyDerivatives(const std::vector< DaeVarInfo > &varInfo, const std::vector< DaeEquationInfo > &eqInfo, std::vector< DaeVarInfo > &newVarInfo)
std::vector< Base > x_
Definition: dummy_deriv.hpp:48
void setDerivative(int derivative)
void setAvoidVarsAsDummies(const std::set< std::string > &avoidAsDummy)
ADFun< CGBase > * generateReorderedModel(CodeHandler< Base > &handler, const std::vector< CGBase > &res0, const std::vector< DaeVarInfo > &varInfo, const std::vector< DaeVarInfo > &newVarInfo, const std::vector< DaeEquationInfo > &eqInfo, const std::vector< DaeEquationInfo > &newEqInfo) const
std::vector< Base > normVar_
Definition: dummy_deriv.hpp:52
int getAntiDerivative() const
std::unique_ptr< ADFun< CG< Base > > > reduceIndex(std::vector< DaeVarInfo > &newVarInfo, std::vector< DaeEquationInfo > &newEqInfo) override
void setGenerateSemiExplicitDae(bool generateSemiExplicitDae)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
std::set< std::string > avoidAsDummy_
void matchVars2Eqs4Elimination(std::vector< DaeVarInfo > &varInfo, std::vector< DaeEquationInfo > &eqInfo)
DummyDerivatives(DaeStructuralIndexReduction< Base > &idxIdentify, const std::vector< Base > &x, const std::vector< Base > &normVar, const std::vector< Base > &normEq)
std::vector< Vnode< Base > * > dummyD_
Definition: dummy_deriv.hpp:79