1 #ifndef CPPAD_CG_DUMMY_DERIV_INCLUDED 2 #define CPPAD_CG_DUMMY_DERIV_INCLUDED 18 #include <Eigen/Dense> 19 #include <Eigen/Sparse> 20 #include <Eigen/Eigenvalues> 24 #include <cppad/cg/dae_index_reduction/pantelides.hpp> 25 #include <cppad/cg/dae_index_reduction/dummy_deriv_util.hpp> 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>;
75 Eigen::SparseMatrix<Base, Eigen::RowMajor>
jacobian_;
96 bool avoidConvertAlg2DifVars_;
115 const std::vector<Base>& x,
116 const std::vector<Base>& normVar,
117 const std::vector<Base>& normEq) :
119 idxIdentify_(&idxIdentify),
125 reduceEquations_(true),
126 generateSemiExplicitDae_(false),
128 avoidConvertAlg2DifVars_(true) {
130 for (
Vnode<Base>* jj : idxIdentify.getGraph().variables()) {
131 if (jj->antiDerivative() !=
nullptr) {
132 diffVarStart_ = jj->index();
149 return avoidConvertAlg2DifVars_;
160 avoidConvertAlg2DifVars_ = avoid;
179 generateSemiExplicitDae_ = generateSemiExplicitDae;
226 avoidAsDummy_ = avoidAsDummy;
239 inline std::unique_ptr<ADFun<CG<Base>>>
reduceIndex(std::vector<DaeVarInfo>& newVarInfo,
240 std::vector<DaeEquationInfo>& newEqInfo)
override {
245 std::vector<DaeVarInfo> reducedVarInfo;
249 std::vector<DaeEquationInfo> reducedEqInfo;
251 reducedFun_ = idxIdentify_->
reduceIndex(reducedVarInfo, reducedEqInfo);
252 if (reducedFun_.get() ==
nullptr)
255 if (this->verbosity_ >= Verbosity::Low)
256 log() <<
"######## Dummy derivatives method ########" << std::endl;
258 newEqInfo = reducedEqInfo;
261 if (reduceEquations_ || generateSemiExplicitDae_) {
265 if (reduceEquations_) {
266 std::vector<DaeVarInfo> varInfo = newVarInfo;
267 std::vector<DaeEquationInfo> eqInfo = newEqInfo;
268 std::unique_ptr<ADFun<CG<Base> > > funShort =
reduceEquations(varInfo, newVarInfo,
270 reducedFun_.swap(funShort);
273 if (generateSemiExplicitDae_) {
274 std::vector<DaeVarInfo> varInfo = newVarInfo;
275 std::vector<DaeEquationInfo> eqInfo = newEqInfo;
279 reducedFun_.swap(semiExplicit);
284 std::vector<DaeVarInfo> varInfo = newVarInfo;
285 std::vector<DaeEquationInfo> eqInfo = newEqInfo;
289 reducedFun_.swap(reorderedFun);
292 return std::unique_ptr<ADFun<CG<Base>>>(reducedFun_.release());
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();
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) {
320 std::sort(vars.begin(), vars.end(), sortVnodesByOrder<Base>);
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) {
328 if (ii->derivativeOf() !=
nullptr && ii->
derivative() ==
nullptr) {
338 if (this->verbosity_ >= Verbosity::High) {
339 log() <<
"# equation selection: ";
340 for (
size_t i = 0; i < eqs.size(); i++)
341 log() << *eqs[i] <<
"; ";
344 log() <<
"# variable selection: ";
345 for (
size_t j = 0; j < vars.size(); j++)
346 log() << *vars[j] <<
"; ";
359 std::vector<Enode<Base>*> newEqs;
360 newEqs.reserve(eqs.size());
364 if (ii !=
nullptr && ii->derivativeOf() !=
nullptr) {
365 newEqs.push_back(ii);
380 std::vector<Vnode<Base>*> varsNew;
381 varsNew.reserve(vars.size());
385 varsNew.push_back(v);
395 newVarInfo = varInfo;
397 CPPADCG_ASSERT_UNKNOWN(j->tapeIndex() >= 0);
398 CPPADCG_ASSERT_UNKNOWN(j->antiDerivative() !=
nullptr);
399 CPPADCG_ASSERT_UNKNOWN(j->antiDerivative()->tapeIndex() >= 0);
401 newVarInfo[j->tapeIndex()].setAntiDerivative(-1);
402 newVarInfo[j->antiDerivative()->tapeIndex()].setDerivative(-1);
405 if (this->verbosity_ >= Verbosity::Low) {
406 log() <<
"## dummy derivatives:\n";
409 log() <<
"# " << *j <<
" \t" << newVarInfo[j->tapeIndex()].getName() <<
"\n";
411 if (this->verbosity_ >= Verbosity::High) {
412 graph.printModel(log(), *reducedFun_, newVarInfo, eqInfo);
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) {
433 auto& graph = idxIdentify_->getGraph();
435 auto& enodes = graph.equations();
437 CPPADCG_ASSERT_UNKNOWN(reducedVarInfo.size() == reducedFun_->Domain());
438 CPPADCG_ASSERT_UNKNOWN(reducedEqInfo.size() == reducedFun_->Range());
440 newEqInfo = reducedEqInfo;
452 map<int, int> assignedVar2Eq;
453 for (
size_t i = 0; i < newEqInfo.size(); ++i) {
455 if (newEq.getAssignedVarIndex() >= 0)
456 assignedVar2Eq[newEq.getAssignedVarIndex()] = i;
465 for (
size_t i = 0; i < eqIndexReduced2Short.size(); i++) {
466 eqIndexReduced2Short[i] = i;
474 vector<int> tapeIndexReduced2Short(reducedVarInfo.size());
475 for (
size_t j = 0; j < tapeIndexReduced2Short.size(); j++) {
476 tapeIndexReduced2Short[j] = j;
483 set<size_t> erasedVariables;
484 set<size_t> erasedEquations;
486 if (this->verbosity_ >= Verbosity::High)
487 log() <<
"Reducing total number of equations by symbolic manipulation:" << std::endl;
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;
501 int bestEquation = ita->second;
506 tapeIndexReduced2Short[dummy->tapeIndex()] = -1;
507 eqIndexReduced2Short[bestEquation] = -1;
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);
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;
524 for (
size_t i = 0; i < eqIndexReduced2Short.size(); i++) {
525 if (eqIndexReduced2Short[i] < 0) {
526 for (
size_t ii = i + 1; ii < eqIndexReduced2Short.size(); ii++) {
527 if (eqIndexReduced2Short[ii] >= 0) {
528 eqIndexReduced2Short[ii]--;
535 for (
size_t p = 0; p < tapeIndexReduced2Short.size(); p++) {
536 if (tapeIndexReduced2Short[p] < 0) {
538 for (
size_t p2 = p + 1; p2 < tapeIndexReduced2Short.size(); p2++) {
539 if (tapeIndexReduced2Short[p2] >= 0) {
540 tapeIndexReduced2Short[p2]--;
549 CPPADCG_ASSERT_UNKNOWN(tapeIndexReduced2Short.size() == reducedVarInfo.size());
551 newVarInfo = reducedVarInfo;
552 for (
int p = tapeIndexReduced2Short.size() - 1; p >= 0; p--) {
553 if (tapeIndexReduced2Short[p] < 0) {
554 newVarInfo.erase(newVarInfo.begin() + p);
555 for (
size_t pp = 0; pp < tapeIndexReduced2Short.size(); pp++) {
560 v.setAntiDerivative(-1);
571 for (
int p = eqIndexReduced2Short.size() - 1; p >= 0; p--) {
572 if (eqIndexReduced2Short[p] < 0) {
573 newEqInfo.erase(newEqInfo.begin() + 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()]);
589 reducedVarInfo, newVarInfo,
590 reducedEqInfo, newEqInfo));
592 if (this->verbosity_ >= Verbosity::High) {
593 log() <<
"DAE with less equations and variables:\n";
594 graph.printModel(log(), *shortFun, newVarInfo, newEqInfo);
611 const std::vector<DaeVarInfo>& varInfo,
612 std::vector<DaeVarInfo>& newVarInfo,
613 const std::vector<DaeEquationInfo>& eqInfo,
614 std::vector<DaeEquationInfo>& newEqInfo) {
619 auto& graph = idxIdentify_->getGraph();
633 map<int, int> assignedVar2Eq;
634 for (
size_t i = 0; i < newEqInfo.size(); ++i) {
636 assignedVar2Eq[newEq.getAssignedVarIndex()] = i;
642 for (
size_t j = 0; j < varInfo.size(); ++j) {
647 CGBase& indep = indep0[j];
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());
656 int bestEquation = ita->second;
659 CGBase& dep = res0[bestEquation];
664 CPPADCG_ASSERT_UNKNOWN(alias !=
nullptr && alias->
getOperationType() == CGOpCode::Alias);
665 dep.getOperationNode()->makeAlias(alias->
getArguments()[0]);
668 newEqInfo[bestEquation].setExplicit(
true);
673 throw CGException(
"Failed to generate semi-explicit DAE: ", ex.what());
683 for (
size_t j = 0; j != varInfo.size(); ++j) {
685 if (varInfo[j].getAntiDerivative() < 0) {
686 varIndexOld2New[j] = count++;
690 for (
size_t i = 0; i < newEqInfo.size(); ++i) {
692 int j = ii.getAssignedVarIndex();
694 newEqInfo[i].setAssignedVarIndex(varIndexOld2New[j]);
700 newVarInfo = varInfo;
701 for (
int j = newVarInfo.size() - 1; j >= 0; --j) {
702 if (newVarInfo[j].getAntiDerivative() >= 0) {
704 newVarInfo.erase(newVarInfo.begin() + j);
707 for (
size_t j = 0; j < newVarInfo.size(); j++) {
708 newVarInfo[j].setDerivative(-1);
715 std::unique_ptr<ADFun<CGBase> > semiExplicitFun(
generateReorderedModel(handler, res0, varInfo, newVarInfo, eqInfo, newEqInfo));
717 if (this->verbosity_ >= Verbosity::High) {
718 log() <<
"Semi-Eplicit DAE:\n";
719 graph.printModel(log(), *semiExplicitFun, newVarInfo, newEqInfo);
722 return semiExplicitFun;
726 std::vector<DaeEquationInfo>& eqInfo) {
730 auto& graph = idxIdentify_->getGraph();
731 auto& vnodes = graph.variables();
732 auto& enodes = graph.equations();
734 CPPADCG_ASSERT_UNKNOWN(eqInfo.size() == enodes.size());
735 CPPADCG_ASSERT_UNKNOWN(varInfo.size() == reducedFun_->Domain());
736 CPPADCG_ASSERT_UNKNOWN(eqInfo.size() == reducedFun_->Range());
741 handler.makeVariables(indep0);
745 vector<bool> jacSparsity = jacobianSparsity<vector<bool> >(*reducedFun_);
757 for (
size_t j = 0; j < vnodes.size(); 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();
765 if (generateSemiExplicitDae_) {
766 diffVariables.push_back(
new Vnode<Base>(j, v->tapeIndex(), v->name()));
767 eliminateOrig2New[v] = diffVariables.back();
772 variables.reserve(diffVariables.size() + dummyVariables.size());
773 variables.insert(variables.end(), diffVariables.begin(), diffVariables.end());
774 variables.insert(variables.end(), dummyVariables.begin(), dummyVariables.end());
777 for (
size_t i = 0; i < enodes.size(); i++) {
778 equations[i] =
new Enode<Base>(i, enodes[i]->name());
780 for (
size_t p = 0; p < origVars.size(); p++) {
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()]) {
790 CGBase& indep = indep0[j->tapeIndex()];
792 if (handler.isSolvable(*dep.getOperationNode(), *indep.getOperationNode())) {
793 equations[i]->addVariable(j);
799 map<size_t, Vnode<Base>*> tape2FreeVariables;
801 tape2FreeVariables[j->tapeIndex()] = j;
818 if (!j->isDeleted() && j->equations().size() == 1) {
820 if (i.assignmentVariable() ==
nullptr) {
822 jacSparsity, tape2FreeVariables,
823 equations, varInfo)) {
824 throw CGException(
"Failed to solve equation ", i.name(),
" for variable ", j->name());
830 }
while (assigned > 0);
838 if (!j->isDeleted() && j->equations().size() == 1) {
840 if (i.assignmentVariable() ==
nullptr) {
842 jacSparsity, tape2FreeVariables,
848 }
while (assigned > 0);
856 if (i->assignmentVariable() ==
nullptr && i->variables().size() == 1) {
859 jacSparsity, tape2FreeVariables,
865 }
while (assigned > 0);
874 if (!j->isDeleted()) {
876 if (i->assignmentVariable() ==
nullptr) {
878 jacSparsity, tape2FreeVariables,
879 equations, varInfo)) {
901 if (j->assignmentEquation() !=
nullptr) {
908 if (i->assignmentVariable() ==
nullptr) {
917 if (j->assignmentEquation() !=
nullptr) {
918 int i = j->assignmentEquation()->index();
921 if (eq.getAssignedVarIndex() != int(j->tapeIndex())) {
922 eq.setAssignedVarIndex(j->tapeIndex());
928 if (generateSemiExplicitDae_) {
931 if (j->assignmentEquation() ==
nullptr) {
935 error +=
" " + j->name();
939 throw CGException(
"Failed to generate semi-explicit DAE. Could not solve system for the following variables:", error);
943 deleteVectorValues(diffVariables);
944 deleteVectorValues(dummyVariables);
945 deleteVectorValues(equations);
949 if (this->verbosity_ >= Verbosity::High) {
951 if (j->assignmentEquation() !=
nullptr)
952 log() <<
"## Variable " + j->name() <<
" assigned to equation " << j->assignmentEquation()->name() <<
"\n";
956 deleteVectorValues(diffVariables);
957 deleteVectorValues(dummyVariables);
958 deleteVectorValues(equations);
964 std::vector<bool>& jacSparsity,
965 const std::map<
size_t,
Vnode<Base>*>& tape2FreeVariables,
967 std::vector<DaeVarInfo>& varInfo) {
972 std::vector<bool> localJacSparsity = jacSparsity;
973 const size_t n = varInfo.size();
978 CGBase& dep = res0[i.index()];
979 CGBase& indep = indep0[j.tapeIndex()];
981 std::string indepName;
982 if (indep.getOperationNode()->getName() !=
nullptr) {
983 indepName = *indep.getOperationNode()->getName();
991 CPPADCG_ASSERT_UNKNOWN(alias !=
nullptr && alias->
getOperationType() == CGOpCode::Alias);
999 throw CGException(
"Failed to solve equation ", i.name(),
" for variable ", j.name(),
": ", ex.what());
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);
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;
1018 affected.insert(equations[e]);
1019 for (
size_t p = 0; p < nnzs.size(); ++p) {
1020 localJacSparsity[n * e + nnzs[p]] =
true;
1025 if (affected.size() > 0) {
1029 map<size_t, set<Enode<Base>*> > solvable;
1030 for (
size_t e = 0; e < equations.size(); ++e) {
1032 if (&i != eq && affected.find(eq) == affected.end()) {
1034 for (
size_t v = 0; v < eq->variables().size(); ++v) {
1035 solvable[eq->variables()[v]->tapeIndex()].insert(eq);
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);
1055 for (
const auto& it : tape2FreeVariables) {
1060 if (v->assignmentEquation() !=
nullptr) {
1061 if (affected.count(v->assignmentEquation()) > 0 &&
1062 solvable[v->tapeIndex()].count(v->assignmentEquation()) == 0) {
1066 }
else if (solvable[v->tapeIndex()].size() == 0) {
1074 if (indepName.size() > 0) {
1075 indep.getOperationNode()->setName(indepName);
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);
1092 a.deleteNode(it.second);
1108 j.setAssignmentEquation(i, log(), this->verbosity_);
1109 j.deleteNode(log(), this->verbosity_);
1111 jacSparsity = localJacSparsity;
1117 const std::vector<DaeVarInfo>& varInfo,
1118 std::vector<DaeVarInfo>& newVarInfo,
1119 const std::vector<DaeEquationInfo>& eqInfo,
1120 std::vector<DaeEquationInfo>& newEqInfo) {
1122 using namespace std;
1125 auto& graph = idxIdentify_->getGraph();
1130 std::set<size_t> oldVarWithDerivatives;
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());
1137 if (oldVarWithDerivatives.empty()) {
1139 for (
size_t j = 0; j < varInfo.size(); j++) {
1141 bool differential =
false;
1142 while (varInfo[index].getAntiDerivative() >= 0) {
1143 index = varInfo[index].getAntiDerivative();
1144 differential =
true;
1148 oldVarWithDerivatives.insert(index);
1156 std::vector<DaeVarOrderInfo> varOrder(varInfo.size());
1157 for (
size_t j = 0; j < varInfo.size(); j++) {
1159 int derivOrder = graph.determineVariableDiffOrder(varInfo, j, j0);
1160 if (varInfo[j].isIntegratedVariable()) {
1163 bool hasDerivatives = oldVarWithDerivatives.find(j) != oldVarWithDerivatives.end();
1167 std::sort(varOrder.begin(), varOrder.end(), sortVariablesByOrder);
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;
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]);
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]);
1199 std::vector<DaeEqOrderInfo> eqOrder(newEqInfo.size());
1200 for (
size_t i = 0; i < newEqInfo.size(); i++) {
1201 int assignedVar = newEqInfo[i].getAssignedVarIndex();
1203 while (newEqInfo[i0].getAntiDerivative() >= 0) {
1204 i0 = newEqInfo[i0].getAntiDerivative();
1206 bool isDifferential = newEqInfo[i].isExplicit() || (assignedVar >= 0 && newVarInfo[assignedVar].getAntiDerivative() >= 0);
1210 std::sort(eqOrder.begin(), eqOrder.end(), sortEquationByAssignedOrder2);
1212 std::vector<DaeEquationInfo> newEqInfo2(newEqInfo.size());
1213 for (
size_t i = 0; i < eqOrder.size(); i++) {
1214 newEqInfo2[i] = newEqInfo[eqOrder[i].originalIndex];
1216 newEqInfo = newEqInfo2;
1232 std::unique_ptr<ADFun<CGBase> > reorderedFun(
generateReorderedModel(handler, res0, varInfo, newVarInfo, eqInfo, newEqInfo));
1234 if (this->verbosity_ >= Verbosity::High) {
1235 log() <<
"reordered DAE equations and variables:\n";
1236 graph.printModel(log(), *reorderedFun, newVarInfo, newEqInfo);
1239 return reorderedFun;
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 {
1251 CPPADCG_ASSERT_UNKNOWN(indepNewOrder.size() == newVarInfo.size());
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];
1260 Independent(indepNewOrder);
1268 std::set<size_t> newIds;
1269 for (
size_t j = 0; j < newVarInfo.size(); j++) {
1270 newIds.insert(newVarInfo[j].getId());
1273 std::map<size_t, size_t> varId2HandlerIndex;
1274 size_t handlerIndex = 0;
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++;
1283 for (
size_t p = 0; p < newVarInfo.size(); p++) {
1284 size_t id = newVarInfo[p].getId();
1285 indepHandlerOrder[varId2HandlerIndex[id]] = indepNewOrder[p];
1289 std::map<size_t, size_t> eqId2OldIndex;
1290 for (
size_t i = 0; i < eqInfo.size(); i++) {
1291 eqId2OldIndex[eqInfo[i].getId()] = i;
1295 for (
size_t i = 0; i < newEqInfo.size(); i++) {
1296 size_t oldIndex = eqId2OldIndex[newEqInfo[i].getId()];
1297 resNewOrder[i] = res0[oldIndex];
1302 evaluator0.setPrintFor(idxIdentify_->getGraph().isPreserveNames());
1313 using namespace std;
1316 const size_t n = reducedFun_->Domain();
1317 const size_t m = reducedFun_->Range();
1319 auto& graph = idxIdentify_->getGraph();
1320 auto& vnodes = graph.variables();
1321 auto& enodes = graph.equations();
1323 jacSparsity_ = jacobianReverseSparsity<vector<bool>,
CGBase>(*reducedFun_);
1326 row.reserve((vnodes.size() - diffVarStart_) * (m - diffEqStart_));
1327 col.reserve(row.capacity());
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]) {
1343 std::copy(x_.begin(), x_.end(), indep.begin());
1344 std::fill(indep.begin() + x_.size(), indep.end(), 0);
1346 CppAD::sparse_jacobian_work work;
1347 reducedFun_->SparseJacobianReverse(indep, jacSparsity_,
1348 row, col, jac, work);
1351 jacobian_.resize(m - diffEqStart_, vnodes.size() - diffVarStart_);
1353 map<size_t, Vnode<Base>*> origIndex2var;
1354 for (
size_t j = diffVarStart_; j< vnodes.size(); j++) {
1356 origIndex2var[jj->tapeIndex()] = jj;
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());
1365 Base normVal = jac[e].getValue() * normVar_[vOrig->tapeIndex()]
1366 / normEq_[eqOrig->index()];
1369 size_t j = origIndex2var[col[e]]->index();
1371 jacobian_.coeffRef(i - diffEqStart_, j - diffVarStart_) = normVal;
1374 jacobian_.makeCompressed();
1376 if (this->verbosity_ >= Verbosity::High) {
1377 log() <<
"\npartial jacobian:\n" << jacobian_ <<
"\n\n";
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] <<
"; ";
1396 CPPADCG_ASSERT_UNKNOWN(std::find(dummyD_.begin(), dummyD_.end(), it) == dummyD_.end());
1405 std::set<size_t> excludeCols;
1406 std::set<size_t> avoidCols;
1407 for (
size_t j = 0; j < vars.size(); j++) {
1409 bool notZero =
false;
1410 for (
size_t i = 0; i < eqs.size(); i++) {
1412 Base val = jacobian_.coeff(ii->index() - diffEqStart_, jj->index() - diffVarStart_);
1413 if (val != Base(0.0)) {
1420 excludeCols.insert(j);
1421 }
else if (avoidAsDummy_.find(vars[j]->name()) != avoidAsDummy_.end()) {
1423 avoidCols.insert(j);
1427 if (eqs.size() <= vars.size() - (excludeCols.size() + avoidCols.size())) {
1429 excludeCols.insert(avoidCols.begin(), avoidCols.end());
1431 if (this->verbosity_ >= Verbosity::Low)
1432 log() <<
"Must use variables defined to be avoided by the user!\n";
1435 std::vector<Vnode<Base>* > varsLocal;
1437 Eigen::ColPivHouseholderQR<MatrixB> qr;
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]);
1448 work.setZero(eqs.size(), varsLocal.size());
1451 for (
size_t i = 0; i < eqs.size(); i++) {
1453 for (
size_t j = 0; j < varsLocal.size(); j++) {
1455 Base val = jacobian_.coeff(ii->index() - diffEqStart_, jj->index() - diffVarStart_);
1456 if (val != Base(0.0)) {
1462 if (this->verbosity_ >= Verbosity::High)
1463 log() <<
"subset Jac:\n" << work <<
"\n";
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.");
1475 using PermutationMatrix =
typename Eigen::ColPivHouseholderQR<MatrixB>::PermutationType;
1476 using Indices =
typename PermutationMatrix::IndicesType;
1478 const PermutationMatrix& p = qr.colsPermutation();
1479 const Indices& indices = p.indices();
1481 if (this->verbosity_ >= Verbosity::High) {
1482 log() <<
"## matrix Q:\n";
1483 MatrixB q = qr.matrixQ();
1485 log() <<
"## matrix R:\n";
1486 MatrixB r = qr.matrixR().template triangularView<Eigen::Upper>();
1488 log() <<
"## matrix P: " << indices.transpose() <<
"\n";
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.");
1500 if (avoidCols.empty()) {
1504 if (this->verbosity_ >= Verbosity::Low)
1505 log() <<
"Failed to determine dummy derivatives without the variables defined to be avoided by the user\n";
1508 for (
size_t j : avoidCols)
1509 excludeCols.erase(j);
1516 const auto& p = qr.colsPermutation();
1517 const auto& indices = p.indices();
1519 std::vector<Vnode<Base>* > newDummies;
1520 if (avoidConvertAlg2DifVars_) {
1521 auto& graph = idxIdentify_->getGraph();
1522 const auto& varInfo = graph.getOriginalVariableInfo();
1525 for (
int i = 0; newDummies.size() < size_t(work.rows()) && i < qr.rank(); 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) {
1532 newDummies.push_back(v);
1536 for (
int i = 0; newDummies.size() < size_t(work.rows()); 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) {
1543 newDummies.push_back(v);
1549 for (
int i = 0; i < work.rows(); i++) {
1550 newDummies.push_back(varsLocal[indices(i)]);
1554 if (this->verbosity_ >= Verbosity::High) {
1555 log() <<
"## new dummy derivatives: ";
1557 log() << *it <<
"; ";
1562 CPPADCG_ASSERT_UNKNOWN(std::find(dummyD_.begin(), dummyD_.end(), it) == dummyD_.end());
1566 dummyD_.insert(dummyD_.end(), newDummies.begin(), newDummies.end());
1569 inline static void printModel(std::ostream& out,
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) {
1577 std::vector<std::string> indepNames;
1578 for (
size_t p = 0; p < varInfo.size(); p++) {
1579 if (erasedVariables.find(p) == erasedVariables.end()) {
1581 indepNames.push_back(varInfo[p].getName());
1588 for (
size_t p = 0; p < res.size(); ++p) {
1589 if (erasedEquations.find(p) == erasedEquations.end()) {
1590 resAux.push_back(res[p]);
1593 std::vector<std::string> depNames;
1598 inline static void printGraphSparsity(std::ostream& out,
1599 const std::vector<bool>& jacSparsity,
1600 const std::map<
size_t,
Vnode<Base>*>& tape2FreeVariables,
1603 for (
size_t e = 0; e < equations.size(); ++e) {
1606 for (
const auto& it : tape2FreeVariables) {
1607 if (jacSparsity[n * eq->index() + it.first]) {
1609 out <<
"# Equation " << e <<
": \t";
1610 out <<
" " << it.second->name();
1622 inline static void deleteVectorValues(std::vector<T*>& v) {
1623 for (
size_t i = 0; i < v.size(); i++) {
std::vector< ActiveOut > evaluate(ArrayView< const ActiveOut > indepNew, ArrayView< const CG< ScalarIn > > depOld)
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)
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_
Eigen::SparseMatrix< Base, Eigen::RowMajor > jacobian_
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_
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)
CGOpCode getOperationType() const
void makeVariables(VectorCG &variables)
bool generateSemiExplicitDae_
const std::string & getName() const
ADFun< CG< Base > > & getOriginalModel() const
std::unique_ptr< ADFun< CGBase > > reducedFun_
void undoSubstituteIndependent(Node &indep)
Enode< Base > * derivative() const
DaeStructuralIndexReduction< Base > *const idxIdentify_
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)
bool isReduceEquations() const
int getDerivative() const
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_
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_