1#ifndef CPPAD_CG_DUMMY_DERIV_INCLUDED
2#define CPPAD_CG_DUMMY_DERIV_INCLUDED
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) :
128 avoidConvertAlg2DifVars_(
true) {
131 if (
jj->antiDerivative() !=
nullptr) {
132 diffVarStart_ =
jj->index();
149 return avoidConvertAlg2DifVars_;
160 avoidConvertAlg2DifVars_ =
avoid;
240 std::vector<DaeEquationInfo>&
newEqInfo)
override {
255 if (this->verbosity_ >= Verbosity::Low)
256 log() <<
"######## Dummy derivatives method ########" << std::endl;
292 return std::unique_ptr<ADFun<CG<Base>>>(
reducedFun_.release());
300 const std::vector<DaeEquationInfo>&
eqInfo,
309 std::vector<Vnode<Base>*>
vars;
311 typename std::vector<Vnode<Base>*>::const_reverse_iterator
rj;
314 if (
jj->antiDerivative() !=
nullptr &&
jj->derivative() ==
nullptr) {
323 typename std::vector<Enode<Base>*>::const_reverse_iterator
ri;
324 std::vector<Enode<Base>*>
eqs;
325 eqs.reserve(
enodes.size() - diffEqStart_);
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;
364 if (
ii !=
nullptr &&
ii->derivativeOf() !=
nullptr) {
380 std::vector<Vnode<Base>*>
varsNew;
397 CPPADCG_ASSERT_UNKNOWN(
j->tapeIndex() >= 0);
398 CPPADCG_ASSERT_UNKNOWN(
j->antiDerivative() !=
nullptr);
399 CPPADCG_ASSERT_UNKNOWN(
j->antiDerivative()->tapeIndex() >= 0);
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) {
428 std::vector<DaeEquationInfo>&
newEqInfo) {
456 if (
newEq.getAssignedVarIndex() >= 0)
487 if (this->verbosity_ >= Verbosity::High)
488 log() <<
"Reducing total number of equations by symbolic manipulation:" << std::endl;
497 if (this->verbosity_ >= Verbosity::High)
498 log() <<
"unable to solve for variable " <<
dummy->name() <<
"." << std::endl;
510 if (this->verbosity_ >= Verbosity::High) {
519 if (this->verbosity_ >= Verbosity::High)
561 v.setAntiDerivative(-1);
580 if (
eq.getAntiDerivative() >= 0)
593 if (this->verbosity_ >= Verbosity::High) {
594 log() <<
"DAE with less equations and variables:\n";
612 const std::vector<DaeVarInfo>&
varInfo,
614 const std::vector<DaeEquationInfo>&
eqInfo,
615 std::vector<DaeEquationInfo>&
newEqInfo) {
645 if (
jj.getAntiDerivative() < 0) {
654 throw CGException(
"Failed to generate semi-explicit DAE: unable to create an explicit equation for ",
jj.getName());
665 CPPADCG_ASSERT_UNKNOWN(
alias !=
nullptr &&
alias->getOperationType() == CGOpCode::Alias);
666 dep.getOperationNode()->makeAlias(
alias->getArguments()[0]);
674 throw CGException(
"Failed to generate semi-explicit DAE: ",
ex.what());
684 for (
size_t j = 0;
j !=
varInfo.size(); ++
j) {
686 if (
varInfo[
j].getAntiDerivative() < 0) {
693 int j =
ii.getAssignedVarIndex();
718 if (this->verbosity_ >= Verbosity::High) {
719 log() <<
"Semi-Eplicit DAE:\n";
727 std::vector<DaeEquationInfo>&
eqInfo) {
758 for (
size_t j = 0;
j <
vnodes.size();
j++) {
778 for (
size_t i = 0;
i <
enodes.size();
i++) {
793 if (
handler.isSolvable(*
dep.getOperationNode(), *
indep.getOperationNode())) {
794 equations[
i]->addVariable(
j);
819 if (!
j->isDeleted() &&
j->equations().size() == 1) {
821 if (
i.assignmentVariable() ==
nullptr) {
825 throw CGException(
"Failed to solve equation ",
i.name(),
" for variable ",
j->name());
839 if (!
j->isDeleted() &&
j->equations().size() == 1) {
841 if (
i.assignmentVariable() ==
nullptr) {
857 if (
i->assignmentVariable() ==
nullptr &&
i->variables().size() == 1) {
875 if (!
j->isDeleted()) {
877 if (
i->assignmentVariable() ==
nullptr) {
902 if (
j->assignmentEquation() !=
nullptr) {
909 if (
i->assignmentVariable() ==
nullptr) {
918 if (
j->assignmentEquation() !=
nullptr) {
919 int i =
j->assignmentEquation()->index();
922 if (
eq.getAssignedVarIndex() !=
int(
j->tapeIndex())) {
923 eq.setAssignedVarIndex(
j->tapeIndex());
932 if (
j->assignmentEquation() ==
nullptr) {
940 throw CGException(
"Failed to generate semi-explicit DAE. Could not solve system for the following variables:",
error);
946 deleteVectorValues(equations);
950 if (this->verbosity_ >= Verbosity::High) {
952 if (
j->assignmentEquation() !=
nullptr)
953 log() <<
"## Variable " +
j->name() <<
" assigned to equation " <<
j->assignmentEquation()->name() <<
"\n";
959 deleteVectorValues(equations);
968 std::vector<DaeVarInfo>&
varInfo) {
983 if (
indep.getOperationNode()->getName() !=
nullptr) {
992 CPPADCG_ASSERT_UNKNOWN(
alias !=
nullptr &&
alias->getOperationType() == CGOpCode::Alias);
1000 throw CGException(
"Failed to solve equation ",
i.name(),
" for variable ",
j.name(),
": ",
ex.what());
1016 for (
size_t e = 0;
e < equations.size(); ++
e) {
1020 for (
size_t p = 0;
p <
nnzs.size(); ++
p) {
1030 map<size_t, set<Enode<Base>*> >
solvable;
1031 for (
size_t e = 0;
e < equations.size(); ++
e) {
1035 for (
size_t v = 0; v <
eq->variables().size(); ++v) {
1045 size_t jj =
it.first;
1061 if (v->assignmentEquation() !=
nullptr) {
1062 if (
affected.count(v->assignmentEquation()) > 0 &&
1063 solvable[v->tapeIndex()].count(v->assignmentEquation()) == 0) {
1067 }
else if (
solvable[v->tapeIndex()].size() == 0) {
1074 handler.undoSubstituteIndependent(*
indep.getOperationNode());
1087 size_t v =
it.first;
1090 a.addVariable(
it.second);
1093 a.deleteNode(
it.second);
1109 j.setAssignmentEquation(
i, log(), this->verbosity_);
1110 j.deleteNode(log(), this->verbosity_);
1118 const std::vector<DaeVarInfo>&
varInfo,
1120 const std::vector<DaeEquationInfo>&
eqInfo,
1121 std::vector<DaeEquationInfo>&
newEqInfo) {
1123 using namespace std;
1132 for (
size_t i = 0;
i <
eqInfo.size();
i++) {
1133 if (
eqInfo[
i].isExplicit() &&
eqInfo[
i].getAssignedVarIndex() >= 0) {
1140 for (
size_t j = 0;
j <
varInfo.size();
j++) {
1142 bool differential =
false;
1143 while (
varInfo[index].getAntiDerivative() >= 0) {
1144 index =
varInfo[index].getAntiDerivative();
1145 differential =
true;
1158 for (
size_t j = 0;
j <
varInfo.size();
j++) {
1161 if (
varInfo[
j].isIntegratedVariable()) {
1202 int assignedVar =
newEqInfo[
i].getAssignedVarIndex();
1211 std::sort(
eqOrder.begin(),
eqOrder.end(), sortEquationByAssignedOrder2);
1214 for (
size_t i = 0;
i <
eqOrder.size();
i++) {
1235 if (this->verbosity_ >= Verbosity::High) {
1236 log() <<
"reordered DAE equations and variables:\n";
1244 const std::vector<CGBase>&
res0,
1245 const std::vector<DaeVarInfo>&
varInfo,
1247 const std::vector<DaeEquationInfo>&
eqInfo,
1248 const std::vector<DaeEquationInfo>&
newEqInfo)
const {
1276 for (
size_t j = 0;
j <
varInfo.size();
j++) {
1291 for (
size_t i = 0;
i <
eqInfo.size();
i++) {
1314 using namespace std;
1327 row.reserve((
vnodes.size() - diffVarStart_) * (m - diffEqStart_));
1328 col.reserve(row.capacity());
1330 for (
size_t i = diffEqStart_;
i < m;
i++) {
1331 for (
size_t j = diffVarStart_;
j <
vnodes.size();
j++) {
1332 CPPADCG_ASSERT_UNKNOWN(
vnodes[
j]->antiDerivative() !=
nullptr);
1344 std::copy(
x_.begin(),
x_.end(),
indep.begin());
1349 row, col, jac,
work);
1355 for (
size_t j = diffVarStart_;
j<
vnodes.size();
j++) {
1361 for (
size_t e = 0;
e < jac.size();
e++) {
1377 if (this->verbosity_ >= Verbosity::High) {
1378 log() <<
"\npartial jacobian:\n" <<
jacobian_ <<
"\n\n";
1387 if (
eqs.size() ==
vars.size()) {
1389 if (this->verbosity_ >= Verbosity::High) {
1390 log() <<
"# new dummy derivatives: ";
1391 for (
size_t j = 0;
j <
vars.size();
j++)
1392 log() << *
vars[
j] <<
"; ";
1408 for (
size_t j = 0;
j <
vars.size();
j++) {
1411 for (
size_t i = 0;
i <
eqs.size();
i++) {
1413 Base
val =
jacobian_.coeff(
ii->index() - diffEqStart_,
jj->index() - diffVarStart_);
1414 if (
val != Base(0.0)) {
1432 if (this->verbosity_ >= Verbosity::Low)
1433 log() <<
"Must use variables defined to be avoided by the user!\n";
1438 Eigen::ColPivHouseholderQR<MatrixB>
qr;
1442 for (
size_t j = 0;
j <
vars.size();
j++) {
1452 for (
size_t i = 0;
i <
eqs.size();
i++) {
1456 Base
val =
jacobian_.coeff(
ii->index() - diffEqStart_,
jj->index() - diffVarStart_);
1457 if (
val != Base(0.0)) {
1463 if (this->verbosity_ >= Verbosity::High)
1464 log() <<
"subset Jac:\n" <<
work <<
"\n";
1468 if (
qr.info() != Eigen::Success) {
1469 throw CGException(
"Failed to select dummy derivatives! "
1470 "QR decomposition of a submatrix of the Jacobian failed!");
1471 }
else if (
qr.rank() <
work.rows()) {
1472 throw CGException(
"Failed to select dummy derivatives! "
1473 "The resulting system is probably singular for the provided data.");
1476 using PermutationMatrix =
typename Eigen::ColPivHouseholderQR<MatrixB>::PermutationType;
1477 using Indices =
typename PermutationMatrix::IndicesType;
1482 if (this->verbosity_ >= Verbosity::High) {
1483 log() <<
"## matrix Q:\n";
1484 MatrixB
q =
qr.matrixQ();
1486 log() <<
"## matrix R:\n";
1489 log() <<
"## matrix P: " <<
indices.transpose() <<
"\n";
1493 throw CGException(
"Failed to select dummy derivatives! "
1494 "The resulting system is probably singular for the provided data.");
1505 if (this->verbosity_ >= Verbosity::Low)
1506 log() <<
"Failed to determine dummy derivatives without the variables defined to be avoided by the user\n";
1517 const auto&
p =
qr.colsPermutation();
1521 if (avoidConvertAlg2DifVars_) {
1528 CPPADCG_ASSERT_UNKNOWN(v->originalVariable() !=
nullptr);
1529 size_t tape = v->originalVariable()->tapeIndex();
1530 CPPADCG_ASSERT_UNKNOWN(tape <
varInfo.size());
1531 if (
varInfo[tape].getDerivative() < 0) {
1539 CPPADCG_ASSERT_UNKNOWN(v->originalVariable() !=
nullptr);
1540 size_t tape = v->originalVariable()->tapeIndex();
1541 CPPADCG_ASSERT_UNKNOWN(tape <
varInfo.size());
1542 if (
varInfo[tape].getDerivative() >= 0) {
1550 for (
int i = 0;
i <
work.rows();
i++) {
1555 if (this->verbosity_ >= Verbosity::High) {
1556 log() <<
"## new dummy derivatives: ";
1558 log() << *
it <<
"; ";
1570 inline static void printModel(std::ostream&
out,
1572 const std::vector<CGBase>&
res,
1573 const std::vector<DaeVarInfo>&
varInfo,
1579 for (
size_t p = 0;
p <
varInfo.size();
p++) {
1585 CPPADCG_ASSERT_UNKNOWN(
handler.getIndependentVariableSize() ==
indepNames.size());
1589 for (
size_t p = 0;
p <
res.size(); ++
p) {
1599 inline static void printGraphSparsity(std::ostream&
out,
1602 const std::vector<Enode<Base>*>& equations,
1604 for (
size_t e = 0;
e < equations.size(); ++
e) {
1605 Enode<Base>*
eq = equations[
e];
1610 out <<
"# Equation " <<
e <<
": \t";
1611 out <<
" " <<
it.second->name();
1623 inline static void deleteVectorValues(std::vector<T*>& v) {
1624 for (
size_t i = 0;
i < v.size();
i++) {
bool augmentPath(Enode< Base > &i) override final
ADFun< CG< Base > > & getOriginalModel() const
void setDerivative(int derivative)
int getDerivative() const
int getAntiDerivative() const
std::vector< bool > jacSparsity_
bool isReduceEquations() const
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::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)
bool isGenerateSemiExplicitDae() const
void setReorder(bool reorder)
std::vector< Base > normEq_
std::unique_ptr< ADFun< CGBase > > reducedFun_
std::vector< Vnode< Base > * > dummyD_
void selectDummyDerivatives(const std::vector< Enode< Base > * > &eqs, const std::vector< Vnode< Base > * > &vars, MatrixB &work)
void setGenerateSemiExplicitDae(bool generateSemiExplicitDae)
void matchVars2Eqs4Elimination(std::vector< DaeVarInfo > &varInfo, std::vector< DaeEquationInfo > &eqInfo)
std::vector< Base > normVar_
void setAvoidVarsAsDummies(const std::set< std::string > &avoidAsDummy)
void setAvoidConvertAlg2DifVars(bool avoid)
std::unique_ptr< ADFun< CGBase > > reduceEquations(const std::vector< DaeVarInfo > &reducedVarInfo, std::vector< DaeVarInfo > &newVarInfo, const std::vector< DaeEquationInfo > &reducedEqInfo, std::vector< DaeEquationInfo > &newEqInfo)
bool isAvoidConvertAlg2DifVars() const
std::unique_ptr< ADFun< CG< Base > > > reduceIndex(std::vector< DaeVarInfo > &newVarInfo, std::vector< DaeEquationInfo > &newEqInfo) override
DummyDerivatives(DaeStructuralIndexReduction< Base > &idxIdentify, const std::vector< Base > &x, const std::vector< Base > &normVar, const std::vector< Base > &normEq)
std::set< std::string > avoidAsDummy_
const std::set< std::string > & getAvoidVarsAsDummies() const
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)
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)
DaeStructuralIndexReduction< Base > *const idxIdentify_
void setReduceEquations(bool reduceEquations)
Eigen::SparseMatrix< Base, Eigen::RowMajor > jacobian_
bool generateSemiExplicitDae_
virtual void addDummyDerivatives(const std::vector< DaeVarInfo > &varInfo, const std::vector< DaeEquationInfo > &eqInfo, std::vector< DaeVarInfo > &newVarInfo)
Vnode< Base > * antiDerivative() const
bool GreaterThanZero(const cg::CG< Base > &x)